Skip to content
2 changes: 1 addition & 1 deletion pallets/admin-utils/src/tests/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ parameter_types! {
pub const SwapProtocolId: PalletId = PalletId(*b"ten/swap");
pub const SwapMaxFeeRate: u16 = 10000; // 15.26%
pub const SwapMaxPositions: u32 = 100;
pub const SwapMinimumLiquidity: u64 = 1_000;
pub const SwapMinimumLiquidity: u128 = 1_000;
pub const SwapMinimumReserve: NonZeroU64 = NonZeroU64::new(1_000_000).unwrap();
}

Expand Down
2 changes: 2 additions & 0 deletions pallets/subtensor/src/macros/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ mod hooks {
.saturating_add(migrations::migrate_fix_childkeys::migrate_fix_childkeys::<T>())
// Migrate AutoStakeDestinationColdkeys
.saturating_add(migrations::migrate_auto_stake_destination::migrate_auto_stake_destination::<T>())
// Migrate and fix LP ticks that saturated
.saturating_add(migrations::migrate_fix_liquidity_ticks::migrate_fix_liquidity_ticks::<T>())
// Migrate Kappa to default (0.5)
.saturating_add(migrations::migrate_kappa_map_to_default::migrate_kappa_map_to_default::<T>())
// Remove obsolete map entries
Expand Down
50 changes: 50 additions & 0 deletions pallets/subtensor/src/migrations/migrate_fix_liquidity_ticks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use super::*;
use alloc::string::String;
use subtensor_swap_interface::SwapHandler;

/// Migrate and fix LP ticks that saturated
pub fn migrate_fix_liquidity_ticks<T: Config>() -> Weight {
let migration_name = b"migrate_fix_liquidity_ticks".to_vec();
let mut weight = T::DbWeight::get().reads(1);

if HasMigrationRun::<T>::get(&migration_name) {
log::info!(
"Migration '{:?}' has already run. Skipping.",
String::from_utf8_lossy(&migration_name)
);
return weight;
}

log::info!(
"Running migration '{}'",
String::from_utf8_lossy(&migration_name)
);

////////////////////////////////////////////////////////
// Actual migration

T::SwapInterface::migrate_fix_liquidity_ticks(&mut weight);
T::SwapInterface::migrate_fix_current_liquidity(&mut weight);

// Fix protocol liquidity for all subnets
let netuids: Vec<NetUid> = NetworksAdded::<T>::iter()
.map(|(netuid, _)| netuid)
.collect();
weight = weight.saturating_add(T::DbWeight::get().reads_writes(netuids.len() as u64, 0));

for netuid in netuids.into_iter() {
T::SwapInterface::migrate_fix_protocol_liquidity(netuid, &mut weight);
}

////////////////////////////////////////////////////////

HasMigrationRun::<T>::insert(&migration_name, true);
weight = weight.saturating_add(T::DbWeight::get().writes(1));

log::info!(
target: "runtime",
"Migration '{}' completed successfully.",
String::from_utf8_lossy(&migration_name)
);
weight
}
1 change: 1 addition & 0 deletions pallets/subtensor/src/migrations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub mod migrate_delete_subnet_3;
pub mod migrate_disable_commit_reveal;
pub mod migrate_fix_childkeys;
pub mod migrate_fix_is_network_member;
pub mod migrate_fix_liquidity_ticks;
pub mod migrate_fix_root_subnet_tao;
pub mod migrate_fix_root_tao_and_alpha_in;
pub mod migrate_identities_v2;
Expand Down
69 changes: 69 additions & 0 deletions pallets/subtensor/src/tests/coinbase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2934,6 +2934,75 @@ fn test_incentive_goes_to_hotkey_when_no_autostake_destination() {
});
}

// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_coinbase_liquidity_reserves --exact --show-output
#[test]
fn test_coinbase_liquidity_reserves() {
new_test_ext(1).execute_with(|| {
let owner_hotkey = U256::from(1001);
let owner_coldkey = U256::from(1002);
let coldkey = U256::from(1);

// add network
let netuid = add_dynamic_network(&owner_hotkey, &owner_coldkey);

// Setup reserves that will make amount push the liquidity limits
// let tao_reserve_before = TaoCurrency::from(2_000_000_000_000_000);
// let alpha_reserve_before = AlphaCurrency::from(1_700_000_000_000_000);
let tao_reserve_before = TaoCurrency::from(1_000_000_000_000_000);
let alpha_reserve_before = AlphaCurrency::from(1_000_000_000_000_000);
mock::setup_reserves(netuid, tao_reserve_before, alpha_reserve_before);

// Force the swap to initialize
SubtensorModule::swap_tao_for_alpha(
netuid,
TaoCurrency::ZERO,
1_000_000_000_000.into(),
false,
)
.unwrap();

// Calculate implied reserves before
let protocol_account_id = pallet_subtensor_swap::Pallet::<Test>::protocol_account_id();
let position_before = pallet_subtensor_swap::Positions::<Test>::get((
netuid,
protocol_account_id,
PositionId::from(1),
))
.unwrap();
let price_sqrt_before = pallet_subtensor_swap::AlphaSqrtPrice::<Test>::get(netuid);
let (tao_implied_before, _alpha_implied_before) =
position_before.to_token_amounts(price_sqrt_before).unwrap();

////////////////////////////////////////////
// Do emissions

// Set subnet ema price
SubnetMovingPrice::<Test>::insert(netuid, I96F32::from_num(1.0));

// Run the coinbase with the emission amount.
SubtensorModule::run_coinbase(U96F32::from_num(1_000_000_000));

// Calculate implied reserves after
let position_after = pallet_subtensor_swap::Positions::<Test>::get((
netuid,
protocol_account_id,
PositionId::from(1),
))
.unwrap();
let price_sqrt_after = pallet_subtensor_swap::AlphaSqrtPrice::<Test>::get(netuid);
let (tao_implied_after, _alpha_implied_after) =
position_after.to_token_amounts(price_sqrt_after).unwrap();

// Verify implied and realized reserve diffs match
let tao_reserve_after = SubnetTAO::<Test>::get(netuid);
assert_abs_diff_eq!(
tao_reserve_after - tao_reserve_before,
(tao_implied_after - tao_implied_before).into(),
epsilon = 1.into()
);
});
}

// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_zero_shares_zero_emission --exact --show-output --nocapture
#[test]
fn test_zero_shares_zero_emission() {
Expand Down
2 changes: 1 addition & 1 deletion pallets/subtensor/src/tests/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ parameter_types! {
pub const SwapProtocolId: PalletId = PalletId(*b"ten/swap");
pub const SwapMaxFeeRate: u16 = 10000; // 15.26%
pub const SwapMaxPositions: u32 = 100;
pub const SwapMinimumLiquidity: u64 = 1_000;
pub const SwapMinimumLiquidity: u128 = 1_000;
pub const SwapMinimumReserve: NonZeroU64 = NonZeroU64::new(100).unwrap();
}

Expand Down
4 changes: 2 additions & 2 deletions pallets/subtensor/src/tests/networks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2075,7 +2075,7 @@ fn massive_dissolve_refund_and_reregistration_flow_is_lossless_and_cleans_state(
"subnet {net:?} still exists"
);
assert!(
pallet_subtensor_swap::Ticks::<Test>::iter_prefix(net)
pallet_subtensor_swap::Ticks128::<Test>::iter_prefix(net)
.next()
.is_none(),
"ticks not cleared for net {net:?}"
Expand All @@ -2096,7 +2096,7 @@ fn massive_dissolve_refund_and_reregistration_flow_is_lossless_and_cleans_state(
"FeeGlobalAlpha nonzero for net {net:?}"
);
assert_eq!(
pallet_subtensor_swap::CurrentLiquidity::<Test>::get(net),
pallet_subtensor_swap::CurrentLiquidity128::<Test>::get(net),
0,
"CurrentLiquidity not zero for net {net:?}"
);
Expand Down
82 changes: 82 additions & 0 deletions pallets/subtensor/src/tests/staking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use frame_support::sp_runtime::DispatchError;
use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency};
use frame_system::RawOrigin;
use pallet_subtensor_swap::Call as SwapCall;
use pallet_subtensor_swap::position::PositionId;
use pallet_subtensor_swap::tick::TickIndex;
use safe_math::FixedExt;
use sp_core::{Get, H256, U256};
Expand Down Expand Up @@ -5577,6 +5578,87 @@ fn test_remove_root_updates_counters() {
});
}

// cargo test --package pallet-subtensor --lib -- tests::staking::test_add_stake_liquidity_reserves --exact --show-output
#[test]
fn test_add_stake_liquidity_reserves() {
new_test_ext(1).execute_with(|| {
let owner_hotkey = U256::from(1001);
let owner_coldkey = U256::from(1002);
let coldkey = U256::from(1);
let amount = TaoCurrency::from(10_000_000_000_000_000);

// add network
let netuid = add_dynamic_network(&owner_hotkey, &owner_coldkey);

// Give it some $$$ in his coldkey balance
SubtensorModule::add_balance_to_coldkey_account(&coldkey, amount.into());

// Setup reserves that will make amount push the liquidity limits
let tao_reserve_before = TaoCurrency::from(20_000_000_000_000);
let alpha_reserve_before = AlphaCurrency::from(1_700_000_000_000_000);
mock::setup_reserves(netuid, tao_reserve_before, alpha_reserve_before);

// Force the swap to initialize
SubtensorModule::swap_tao_for_alpha(
netuid,
TaoCurrency::ZERO,
1_000_000_000_000.into(),
false,
)
.unwrap();

// Calculate implied reserves before
let protocol_account_id = pallet_subtensor_swap::Pallet::<Test>::protocol_account_id();
let position_before = pallet_subtensor_swap::Positions::<Test>::get((
netuid,
protocol_account_id,
PositionId::from(1),
))
.unwrap();
let price_sqrt_before = pallet_subtensor_swap::AlphaSqrtPrice::<Test>::get(netuid);
let (tao_implied_before, _alpha_implied_before) =
position_before.to_token_amounts(price_sqrt_before).unwrap();

////////////////////////////////////////////
// Call add_stake extrinsic
assert_ok!(SubtensorModule::add_stake(
RuntimeOrigin::signed(coldkey),
owner_hotkey,
netuid,
amount
));

////////////////////////////////////////////
// Call remove_stake extrinsic for a small alpha amount
let unstake_amount = AlphaCurrency::from(100_000_000);
remove_stake_rate_limit_for_tests(&owner_hotkey, &coldkey, netuid);
assert_ok!(SubtensorModule::remove_stake(
RuntimeOrigin::signed(coldkey),
owner_hotkey,
netuid,
unstake_amount
));

// Calculate implied reserves after
let position_after = pallet_subtensor_swap::Positions::<Test>::get((
netuid,
protocol_account_id,
PositionId::from(1),
))
.unwrap();
let price_sqrt_after = pallet_subtensor_swap::AlphaSqrtPrice::<Test>::get(netuid);
let (tao_implied_after, _alpha_implied_after) =
position_after.to_token_amounts(price_sqrt_after).unwrap();

// Verify implied and realized reserve diffs match
let tao_reserve_after = SubnetTAO::<Test>::get(netuid);
assert_eq!(
tao_reserve_after - tao_reserve_before,
(tao_implied_after - tao_implied_before).into(),
);
});
}

// cargo test --package pallet-subtensor --lib -- tests::staking::test_staking_records_flow --exact --show-output
#[test]
fn test_staking_records_flow() {
Expand Down
9 changes: 9 additions & 0 deletions pallets/swap-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ pub trait SwapHandler {
fn dissolve_all_liquidity_providers(netuid: NetUid) -> DispatchResult;
fn toggle_user_liquidity(netuid: NetUid, enabled: bool);
fn clear_protocol_liquidity(netuid: NetUid) -> DispatchResult;

// Migrations
fn migrate_fix_liquidity_ticks(weight: &mut Weight);
fn migrate_fix_current_liquidity(weight: &mut Weight);
fn migrate_get_implied_reserves(
netuid: NetUid,
weight: &mut Weight,
) -> (TaoCurrency, AlphaCurrency, TaoCurrency, AlphaCurrency);
fn migrate_fix_protocol_liquidity(netuid: NetUid, weight: &mut Weight);
}

pub trait DefaultPriceLimit<PaidIn, PaidOut>
Expand Down
10 changes: 5 additions & 5 deletions pallets/swap/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use subtensor_runtime_common::NetUid;

use crate::{
pallet::{
AlphaSqrtPrice, Call, Config, CurrentLiquidity, CurrentTick, EnabledUserLiquidity, Pallet,
Positions, SwapV3Initialized,
AlphaSqrtPrice, Call, Config, CurrentLiquidity128, CurrentTick, EnabledUserLiquidity,
Pallet, Positions, SwapV3Initialized,
},
position::{Position, PositionId},
tick::TickIndex,
Expand All @@ -40,7 +40,7 @@ mod benchmarks {
SwapV3Initialized::<T>::insert(netuid, true);
AlphaSqrtPrice::<T>::insert(netuid, U64F64::from_num(1));
CurrentTick::<T>::insert(netuid, TickIndex::new(0).unwrap());
CurrentLiquidity::<T>::insert(netuid, T::MinimumLiquidity::get());
CurrentLiquidity128::<T>::insert(netuid, T::MinimumLiquidity::get());
}

let caller: T::AccountId = whitelisted_caller();
Expand All @@ -67,7 +67,7 @@ mod benchmarks {
SwapV3Initialized::<T>::insert(netuid, true);
AlphaSqrtPrice::<T>::insert(netuid, U64F64::from_num(1));
CurrentTick::<T>::insert(netuid, TickIndex::new(0).unwrap());
CurrentLiquidity::<T>::insert(netuid, T::MinimumLiquidity::get());
CurrentLiquidity128::<T>::insert(netuid, T::MinimumLiquidity::get());
}

let caller: T::AccountId = whitelisted_caller();
Expand Down Expand Up @@ -100,7 +100,7 @@ mod benchmarks {
SwapV3Initialized::<T>::insert(netuid, true);
AlphaSqrtPrice::<T>::insert(netuid, U64F64::from_num(1));
CurrentTick::<T>::insert(netuid, TickIndex::new(0).unwrap());
CurrentLiquidity::<T>::insert(netuid, T::MinimumLiquidity::get());
CurrentLiquidity128::<T>::insert(netuid, T::MinimumLiquidity::get());
}

let caller: T::AccountId = whitelisted_caller();
Expand Down
2 changes: 1 addition & 1 deletion pallets/swap/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ parameter_types! {
pub const SwapProtocolId: PalletId = PalletId(*b"ten/swap");
pub const MaxFeeRate: u16 = 10000; // 15.26%
pub const MaxPositions: u32 = 100;
pub const MinimumLiquidity: u64 = 1_000;
pub const MinimumLiquidity: u128 = 1_000;
pub const MinimumReserves: NonZeroU64 = NonZeroU64::new(1).unwrap();
}

Expand Down
Loading
Loading