use super::*; use frame_support::transactional; use substrate_fixed::types::U64F64; use subtensor_runtime_common::{AlphaBalance, NetUid, TaoBalance}; use subtensor_swap_interface::{Order, OrderSwapInterface, SwapHandler, SwapResult}; impl OrderSwapInterface for Pallet { #[transactional] fn buy_alpha( coldkey: &T::AccountId, hotkey: &T::AccountId, netuid: NetUid, tao_amount: TaoBalance, limit_price: TaoBalance, validate: bool, ) -> Result { ensure!(Self::if_subnet_exist(netuid), Error::::SubnetNotExists); Self::ensure_subtoken_enabled(netuid)?; if validate { ensure!( Self::hotkey_account_exists(hotkey), Error::::HotKeyAccountNotExists ); ensure!( tao_amount >= DefaultMinStake::::get(), Error::::AmountTooLow ); ensure!( Self::can_remove_balance_from_coldkey_account(coldkey, tao_amount), Error::::NotEnoughBalanceToStake ); } // `limit_price` is already in ×10⁹ scale (same as the `current_alpha_price` RPC // endpoint), which is also the scale the AMM uses for its price_limit argument. // Pass it directly without any scaling. u64::MAX means "no ceiling". let amm_limit = limit_price; // Stable subnets (mechanism_id != 1) are always 1:1 and never stop early. if SubnetMechanism::::get(netuid) == 1 { let sim_order = GetAlphaForTao::::with_amount(tao_amount); let sim: SwapResult = T::SwapInterface::swap(netuid.into(), sim_order, amm_limit, false, true)?; ensure!( sim.amount_paid_in.saturating_add(sim.fee_paid) >= tao_amount, Error::::SlippageTooHigh ); } let alpha_out = Self::stake_into_subnet(hotkey, coldkey, netuid, tao_amount, amm_limit, false)?; Ok(alpha_out) } #[transactional] fn sell_alpha( coldkey: &T::AccountId, hotkey: &T::AccountId, netuid: NetUid, alpha_amount: AlphaBalance, limit_price: TaoBalance, validate: bool, ) -> Result { ensure!(Self::if_subnet_exist(netuid), Error::::SubnetNotExists); Self::ensure_subtoken_enabled(netuid)?; if validate { Self::validate_remove_stake( coldkey, hotkey, netuid, alpha_amount, alpha_amount, false, )?; } // `limit_price` is already in ×10⁹ scale (same as the `current_alpha_price` RPC // endpoint), which is also the scale the AMM uses for its price_limit argument. // Pass it directly without any scaling. 0 means "no floor". let amm_limit = limit_price; // Stable subnets (mechanism_id != 1) are always 1:1 and never stop early. if SubnetMechanism::::get(netuid) == 1 { let sim_order = GetTaoForAlpha::::with_amount(alpha_amount); let sim: SwapResult = T::SwapInterface::swap(netuid.into(), sim_order, amm_limit, false, true)?; ensure!( sim.amount_paid_in.saturating_add(sim.fee_paid) >= alpha_amount, Error::::SlippageTooHigh ); } let tao_out = Self::unstake_from_subnet( hotkey, coldkey, coldkey, netuid, alpha_amount, amm_limit, false, )?; Ok(tao_out) } fn current_alpha_price(netuid: NetUid) -> U64F64 { T::SwapInterface::current_alpha_price(netuid) } fn transfer_tao(from: &T::AccountId, to: &T::AccountId, amount: TaoBalance) -> DispatchResult { Pallet::::transfer_tao(from, to, amount) } #[transactional] fn transfer_staked_alpha( from_coldkey: &T::AccountId, from_hotkey: &T::AccountId, to_coldkey: &T::AccountId, to_hotkey: &T::AccountId, netuid: NetUid, amount: AlphaBalance, validate_sender: bool, validate_receiver: bool, ) -> DispatchResult { ensure!(Self::if_subnet_exist(netuid), Error::::SubnetNotExists); Self::ensure_subtoken_enabled(netuid)?; if validate_sender { ensure!( Self::hotkey_account_exists(from_hotkey), Error::::HotKeyAccountNotExists ); ensure!(!amount.is_zero(), Error::::AmountTooLow); let tao_equiv = T::SwapInterface::current_alpha_price(netuid) .saturating_mul(U64F64::saturating_from_num(amount.to_u64())) .saturating_to_num::(); ensure!( TaoBalance::from(tao_equiv) >= DefaultMinStake::::get(), Error::::AmountTooLow ); Self::ensure_available_to_unstake(from_coldkey, netuid, amount)?; } if validate_receiver { ensure!( Self::hotkey_account_exists(to_hotkey), Error::::HotKeyAccountNotExists ); } let available = Self::get_stake_for_hotkey_and_coldkey_on_subnet(from_hotkey, from_coldkey, netuid); ensure!(available >= amount, Error::::NotEnoughStakeToWithdraw); Self::decrease_stake_for_hotkey_and_coldkey_on_subnet( from_hotkey, from_coldkey, netuid, amount, ); Self::increase_stake_for_hotkey_and_coldkey_on_subnet( to_hotkey, to_coldkey, netuid, amount, ); LastColdkeyHotkeyStakeBlock::::insert( to_coldkey, to_hotkey, Self::get_current_block_as_u64(), ); Ok(()) } fn register_pallet_hotkey(coldkey: &T::AccountId, hotkey: &T::AccountId) -> DispatchResult { Self::create_account_if_non_existent(coldkey, hotkey) } fn pallet_hotkey_registered(coldkey: &T::AccountId, hotkey: &T::AccountId) -> bool { Self::coldkey_owns_hotkey(coldkey, hotkey) } #[cfg(feature = "runtime-benchmarks")] fn set_up_netuid_for_benchmark(netuid: NetUid) { if !Self::if_subnet_exist(netuid) { Self::init_new_network(netuid, 100); } SubtokenEnabled::::insert(netuid, true); // Seed pool reserves so the AMM price is well-defined and swaps return non-zero. SubnetTAO::::insert(netuid, TaoBalance::from(1_000_000_000_000_u64)); SubnetAlphaIn::::insert(netuid, AlphaBalance::from(1_000_000_000_000_u64)); } #[cfg(feature = "runtime-benchmarks")] fn set_up_acc_for_benchmark(hotkey: &T::AccountId, coldkey: &T::AccountId) { let _ = Self::create_account_if_non_existent(coldkey, hotkey); let credit = Self::mint_tao(TaoBalance::from(1_000_000_000_000_u64)); let _ = Self::spend_tao(coldkey, credit, TaoBalance::from(1_000_000_000_000_u64)); } }