code/pallets/limit-orders/src/lib.rs

lib.rs

1,300 lines · 57,473 bytes · 19a6485969RawGitHub
#![cfg_attr(not(feature = "std"), no_std)]

extern crate alloc;

pub use pallet::*;

#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub(crate) mod migrations;
#[cfg(test)]
mod tests;
pub mod weights;

type MigrationKeyMaxLen = frame_support::traits::ConstU32<128>;

use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
use frame_support::{BoundedVec, traits::ConstU32};
use scale_info::TypeInfo;
use sp_core::H256;
use sp_runtime::{
    AccountId32, MultiSignature, Perbill,
    traits::{ConstBool, Verify},
};
use substrate_fixed::types::U64F64;
use subtensor_macros::freeze_struct;
use subtensor_runtime_common::{AlphaBalance, NetUid, TaoBalance, Token};
use subtensor_swap_interface::OrderSwapInterface;

// ── Data structures ──────────────────────────────────────────────────────────

/// Internal direction of a net pool trade. Used only for `GroupExecutionSummary`
/// and pool-swap bookkeeping; not part of the public order payload.
#[derive(
    Encode, Decode, DecodeWithMemTracking, TypeInfo, MaxEncodedLen, Clone, PartialEq, Eq, Debug,
)]
pub enum OrderSide {
    Buy,
    Sell,
}

/// The user-facing order type. Each variant encodes both the execution action
/// (buy alpha / sell alpha) and the price-trigger direction.
///
/// | Variant      | Action | Triggers when       |
/// |--------------|--------|---------------------|
/// | `LimitBuy`   | Buy    | price ≤ limit_price |
/// | `TakeProfit` | Sell   | price ≥ limit_price |
/// | `StopLoss`   | Sell   | price ≤ limit_price |
#[derive(
    Encode, Decode, DecodeWithMemTracking, TypeInfo, MaxEncodedLen, Clone, PartialEq, Eq, Debug,
)]
pub enum OrderType {
    LimitBuy,
    TakeProfit,
    StopLoss,
}

impl OrderType {
    /// `true` if this order results in buying alpha (staking into subnet).
    pub fn is_buy(&self) -> bool {
        matches!(self, OrderType::LimitBuy)
    }
}

/// The canonical order payload that users sign off-chain.
/// Only its H256 hash is stored on-chain; the full struct is submitted by the
/// admin at execution time (or by the user at cancellation time).
#[allow(clippy::multiple_bound_locations)] // bounds on AccountId required by FRAME derives
#[freeze_struct("27c7eedb92261456")]
#[derive(
    Encode, Decode, DecodeWithMemTracking, TypeInfo, MaxEncodedLen, Clone, PartialEq, Eq, Debug,
)]
pub struct Order<AccountId: Encode + Decode + TypeInfo + MaxEncodedLen + Clone> {
    /// The coldkey that authorised this order (pays TAO for buys; owns the
    /// staked alpha for sells).
    pub signer: AccountId,
    /// The hotkey to stake to (buy) or unstake from (sell).
    pub hotkey: AccountId,
    /// Target subnet.
    pub netuid: NetUid,
    /// Order type (LimitBuy, TakeProfit, or StopLoss).
    pub order_type: OrderType,
    /// Input amount: TAO (raw) for Buy, alpha (raw) for Sell.
    pub amount: u64,
    /// Price threshold in ×10⁹ scale (same as the `current_alpha_price` RPC endpoint).
    /// A value of `1_000_000_000` represents a price of 1.0 TAO/alpha.
    /// Sub-unity prices (e.g. 0.5 TAO/alpha) are expressed as `500_000_000`.
    /// Buy: maximum acceptable price.  Sell: minimum acceptable price.
    /// `u64::MAX` means no ceiling (buy at any price); `0` means no floor (sell at any price).
    pub limit_price: u64,
    /// Unix timestamp in milliseconds after which this order must not be executed.
    pub expiry: u64,
    /// Fee rate applied to this order's TAO amount (input for buys, output for sells).
    pub fee_rate: Perbill,
    /// Account that receives the fee collected from this order.
    pub fee_recipient: AccountId,
    /// Accounts authorized to relay this order. When set, only an account present
    /// in this list may submit the execution transaction. Supports up to 10 relayers.
    pub relayer: Option<BoundedVec<AccountId, ConstU32<10>>>,
    /// Maximum slippage tolerance in parts per billion applied to `limit_price`
    /// at execution time. `None` = no protection (execute at market).
    /// - Buy:  effective price ceiling = `limit_price + limit_price * max_slippage`
    /// - Sell: effective price floor   = `limit_price - limit_price * max_slippage`
    pub max_slippage: Option<Perbill>,
    /// EVM-compatible chain ID that this order is bound to.
    /// Prevents replay of testnet-signed orders on mainnet and vice versa.
    pub chain_id: u64,
    /// Wether partial fills are enabled
    pub partial_fills_enabled: bool,
}

/// Versioned wrapper around an order payload.
///
/// Adding a new variant in the future (e.g. `V2`) lets the pallet accept orders
/// signed against either schema simultaneously, preventing old signed orders from
/// being invalidated by a schema upgrade.
#[derive(
    Encode, Decode, DecodeWithMemTracking, TypeInfo, MaxEncodedLen, Clone, PartialEq, Eq, Debug,
)]
pub enum VersionedOrder<AccountId: Encode + Decode + TypeInfo + MaxEncodedLen + Clone> {
    V1(Order<AccountId>),
}

impl<AccountId: Encode + Decode + TypeInfo + MaxEncodedLen + Clone> VersionedOrder<AccountId> {
    /// Returns a reference to the inner order regardless of version.
    pub fn inner(&self) -> &Order<AccountId> {
        match self {
            VersionedOrder::V1(order) => order,
        }
    }
}

/// The envelope the admin submits on-chain: the versioned order payload plus
/// the user's signature over the SCALE-encoded `VersionedOrder`.
///
/// Signature verification is performed against `order.inner().signer` (the AccountId)
/// directly. Only sr25519 signatures are accepted; ed25519 and ecdsa variants
/// of `MultiSignature` are rejected at validation time.
#[freeze_struct("9dd5a8ac812dc504")]
#[derive(
    Encode, Decode, DecodeWithMemTracking, TypeInfo, MaxEncodedLen, Clone, PartialEq, Eq, Debug,
)]
pub struct SignedOrder<AccountId: Encode + Decode + TypeInfo + MaxEncodedLen + Clone> {
    pub order: VersionedOrder<AccountId>,
    /// Sr25519 signature over `SCALE_ENCODE(VersionedOrder)`.
    pub signature: MultiSignature,
    /// Whether we want a partial fill for this order
    pub partial_fill: Option<u64>,
}

#[derive(
    Encode, Decode, DecodeWithMemTracking, TypeInfo, MaxEncodedLen, Clone, PartialEq, Eq, Debug,
)]
pub enum OrderStatus {
    /// The order was successfully executed.
    Fulfilled,
    /// The order was partially filled, with the amount already fulfilled in the enum
    PartiallyFilled(u64),
    /// The user registered a cancellation intent before execution.
    Cancelled,
}

/// Classified, fee-adjusted entry produced by `validate_and_classify`.
/// Used in every in-memory batch pipeline step; never stored on-chain.
#[derive(Debug, PartialEq)]
pub(crate) struct OrderEntry<AccountId> {
    pub(crate) order_id: H256,
    pub(crate) signer: AccountId,
    pub(crate) hotkey: AccountId,
    pub(crate) side: OrderType,
    /// Actual input amount being processed this execution (partial or full, before fee).
    pub(crate) gross: u64,
    /// Full order amount as signed by the user. Used to determine terminal status.
    pub(crate) order_amount: u64,
    /// Net input amount (after fee).
    /// For buys: `gross - fee_rate * gross`. For sells: equals `gross` (fee on TAO output).
    pub(crate) net: u64,
    /// Per-order fee rate.
    pub(crate) fee_rate: Perbill,
    /// Per-order fee recipient.
    pub(crate) fee_recipient: AccountId,
    /// Effective price limit passed to the pool swap.
    /// For buys: ceiling (max TAO per alpha the pool may charge).
    /// For sells: floor (min TAO per alpha the pool must return).
    /// Derived from `limit_price` and `max_slippage` during classification.
    pub(crate) effective_swap_limit: u64,
    /// Present when this execution covers only part of the order.
    pub(crate) partial_fill: Option<u64>,
}

// ── Pallet ───────────────────────────────────────────────────────────────────

#[frame_support::pallet]
#[allow(clippy::expect_used)]
pub mod pallet {
    use super::*;
    use crate::weights::WeightInfo as _;
    use frame_support::{
        PalletId,
        pallet_prelude::*,
        traits::{Get, UnixTime},
        transactional,
    };
    use frame_system::pallet_prelude::*;
    use sp_runtime::traits::AccountIdConversion;
    use sp_std::collections::btree_set::BTreeSet;
    use sp_std::vec::Vec;

    #[pallet::pallet]
    pub struct Pallet<T>(_);

    #[pallet::config]
    pub trait Config: frame_system::Config<AccountId = AccountId32> {
        /// Full swap + balance execution interface (see [`OrderSwapInterface`]).
        type SwapInterface: OrderSwapInterface<Self::AccountId>;

        /// Time provider for expiry checks.
        type TimeProvider: UnixTime;

        /// Maximum number of orders in a single `execute_orders` call.
        /// Should equal `floor(max_block_weight / per_order_weight)`.
        #[pallet::constant]
        type MaxOrdersPerBatch: Get<u32>;

        /// PalletId used to derive the intermediary account for batch execution.
        ///
        /// The derived account temporarily holds pooled TAO and staked alpha
        /// during `execute_batched_orders` before distributing to order signers.
        #[pallet::constant]
        type PalletId: Get<PalletId>;

        /// Hotkey registered in each subnet that the pallet's intermediary
        /// account stakes to/from during batch execution.
        ///
        /// This must be a hotkey registered on every subnet the pallet may
        /// operate on. Operators should register a dedicated hotkey and set
        /// this in the runtime configuration.
        #[pallet::constant]
        type PalletHotkey: Get<Self::AccountId>;

        /// Weight information for the pallet's extrinsics.
        type WeightInfo: crate::weights::WeightInfo;

        /// EVM-compatible chain ID used to bind orders to a specific chain.
        /// Wire to `pallet_evm_chain_id` in the runtime via `ConfigurableChainId`.
        type ChainId: Get<u64>;
    }

    // ── Storage ───────────────────────────────────────────────────────────────

    /// Tracks the on-chain status of a known `OrderId`.
    /// Absent ⇒ never seen (still executable if valid).
    /// Present ⇒ Fulfilled or Cancelled (both are terminal).
    #[pallet::storage]
    pub type Orders<T: Config> = StorageMap<_, Blake2_128Concat, H256, OrderStatus, OptionQuery>;

    /// Switch to enable/disable the pallet.
    /// Defaults to `false` so bare node deployments are safe; genesis sets it to `true`.
    #[pallet::storage]
    pub type LimitOrdersEnabled<T: Config> = StorageValue<_, bool, ValueQuery, ConstBool<false>>;

    /// Tracks which named migrations have already been applied.
    /// Keyed by a short migration name; value is always `true`.
    #[pallet::storage]
    pub type HasMigrationRun<T: Config> =
        StorageMap<_, Identity, BoundedVec<u8, MigrationKeyMaxLen>, bool, ValueQuery>;

    // ── Events ────────────────────────────────────────────────────────────────

    #[pallet::event]
    #[pallet::generate_deposit(pub(super) fn deposit_event)]
    pub enum Event<T: Config> {
        /// A limit order was successfully executed.
        OrderExecuted {
            order_id: H256,
            signer: T::AccountId,
            netuid: NetUid,
            order_type: OrderType,
            /// Input amount: TAO (raw) for Buy orders, alpha (raw) for Sell orders.
            amount_in: u64,
            /// Output amount: alpha (raw) received for Buy orders, TAO (raw) received for Sell orders (after fee).
            amount_out: u64,
        },
        /// An order was skipped during execution.
        OrderSkipped {
            order_id: H256,
            reason: sp_runtime::DispatchError,
        },
        /// A user registered a cancellation intent for their order.
        OrderCancelled {
            order_id: H256,
            signer: T::AccountId,
        },
        /// Summary emitted once per `execute_batched_orders` call.
        GroupExecutionSummary {
            /// The subnet all orders in this batch belong to.
            netuid: NetUid,
            /// Direction of the net pool trade (Buy = net TAO into pool).
            net_side: OrderSide,
            /// Net amount sent to the pool (TAO for Buy, alpha for Sell).
            /// Zero when buys and sells perfectly offset each other.
            net_amount: u64,
            /// Tokens received back from the pool.
            /// Zero when `net_amount` is zero.
            actual_out: u64,
            /// Number of orders that were successfully executed.
            executed_count: u32,
        },
        /// Root has either enabled(true) or disabled(false) the pallet
        LimitOrdersPalletStatusChanged { enabled: bool },
    }

    // ── Errors ────────────────────────────────────────────────────────────────

    #[pallet::error]
    pub enum Error<T> {
        /// The provided signature does not match the order payload and signer.
        InvalidSignature,
        /// The order has already been Fulfilled or Cancelled.
        OrderAlreadyProcessed,
        /// Order has been cancelled
        OrderCancelled,
        /// The order's expiry timestamp is in the past.
        OrderExpired,
        /// The current market price does not satisfy the order's limit price.
        PriceConditionNotMet,
        /// Caller is not the order signer (required for cancellation).
        Unauthorized,
        /// The pool swap returned zero output for a non-zero input.
        SwapReturnedZero,
        /// Root netuid (0) is not allowed for limit orders.
        RootNetUidNotAllowed,
        /// An order in the batch targets a different netuid than the batch netuid parameter.
        OrderNetUidMismatch,
        /// Limit orders are disabled
        LimitOrdersDisabled,
        /// Relayer not the same as specified in the order
        RelayerMissMatch,
        /// Partial fills not enabled for this order
        PartialFillsNotEnabled,
        /// Incorrect partial fill amount provided
        IncorrectPartialFillAmount,
        /// A relayer must be set on the order when using partial fills
        RelayerRequiredForPartialFill,
        /// The order's chain_id does not match the current chain.
        ChainIdMismatch,
        /// The pallet hotkey has not been registered to the pallet account.
        /// Call on_runtime_upgrade or wait for genesis to complete registration
        /// before enabling the pallet.
        PalletHotkeyNotRegistered,
        /// A TAO -> alpha conversion overflowed the fixed-point range.
        ArithmeticOverflow,
        /// The same order appears more than once in a single batch.
        DuplicateOrderInBatch,
        /// An order's pro-rata share in the batch rounded down to zero. The whole
        /// batch is rejected so the order's input is never consumed without
        /// delivering any output (conservation), and the order stays retryable in a
        /// differently-composed batch.
        ZeroShareInBatch,
    }

    // ── Hooks ─────────────────────────────────────────────────────────────────

    // ── Genesis ───────────────────────────────────────────────────────────────

    #[pallet::genesis_config]
    #[derive(frame_support::DefaultNoBound)]
    pub struct GenesisConfig<T: Config> {
        #[serde(skip)]
        pub _phantom: core::marker::PhantomData<T>,
    }

    #[pallet::genesis_build]
    impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
        fn build(&self) {
            let _ = T::SwapInterface::register_pallet_hotkey(
                &Pallet::<T>::pallet_account(),
                &T::PalletHotkey::get(),
            );
            // Enable the pallet on all networks that start from this genesis.
            // The storage default is `false` (safe for bare upgrades); genesis
            // explicitly opts new chains in.
            LimitOrdersEnabled::<T>::set(true);
        }
    }

    // ── Hooks ─────────────────────────────────────────────────────────────────

    #[pallet::hooks]
    impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
        fn on_runtime_upgrade() -> frame_support::weights::Weight {
            let mut weight = frame_support::weights::Weight::from_parts(0, 0);

            weight = weight.saturating_add(migrations::migrate_register_pallet_hotkey::<T>());

            weight
        }
    }

    // ── Extrinsics ────────────────────────────────────────────────────────────

    #[pallet::call]
    impl<T: Config> Pallet<T> {
        /// Execute a batch of signed limit orders. Admin-gated.
        ///
        /// The `should_fail` flag controls how individual order failures are
        /// handled:
        ///
        /// - When `false` (best-effort): orders whose price condition is not yet
        ///   met are silently skipped so that a single stale order cannot block
        ///   the rest of the batch. Orders that fail for any other reason
        ///   (expired, bad signature, etc.) are also skipped; the admin is
        ///   expected to filter these off-chain.
        /// - When `true` (all-or-nothing): the first order failure aborts the
        ///   whole batch by returning the underlying error, reverting any orders
        ///   already executed in this call.
        #[pallet::call_index(0)]
        #[pallet::weight(T::WeightInfo::execute_orders(orders.len() as u32))]
        pub fn execute_orders(
            origin: OriginFor<T>,
            orders: BoundedVec<SignedOrder<T::AccountId>, T::MaxOrdersPerBatch>,
            should_fail: bool,
        ) -> DispatchResult {
            let relayer = ensure_signed(origin)?;
            ensure!(
                LimitOrdersEnabled::<T>::get(),
                Error::<T>::LimitOrdersDisabled
            );

            for signed_order in orders {
                let order_id = Self::derive_order_id(&signed_order.order);
                if let Err(reason) = Self::try_execute_order(signed_order, order_id, &relayer) {
                    if should_fail {
                        // All-or-nothing: abort the batch, reverting prior orders.
                        return Err(reason);
                    }
                    // Best-effort: individual order failures do not revert the batch.
                    Self::deposit_event(Event::OrderSkipped { order_id, reason });
                }
            }

            Ok(())
        }

        /// Execute a batch of signed limit orders for a single subnet using
        /// aggregated (netted) pool interaction.
        ///
        /// Unlike `execute_orders`, which hits the pool once per order, this
        /// extrinsic:
        ///
        /// 1. Validates all orders (bad signature / expired / already processed /
        ///    price-not-met orders are skipped and emit `OrderSkipped`).
        /// 2. Fetches the current price once.
        /// 3. Aggregates all valid buy inputs (TAO) and sell inputs (alpha).
        /// 4. Nets the two sides: only the residual amount touches the pool in
        ///    a single swap, minimising price impact.
        /// 5. Distributes outputs pro-rata:
        ///    - Dominant-side orders split the pool output proportionally to
        ///      their individual net amounts.
        ///    - Offset-side orders are filled internally at the current price
        ///      (no pool interaction for them).
        /// 6. Collects protocol fees (TAO for buy orders, alpha → TAO for sell
        ///    orders) and routes them to `FeeCollector`.
        ///
        /// All orders in the batch must target `netuid`. Orders for a different
        /// subnet are skipped.
        #[pallet::call_index(1)]
        #[pallet::weight(T::WeightInfo::execute_batched_orders(orders.len() as u32))]
        pub fn execute_batched_orders(
            origin: OriginFor<T>,
            netuid: NetUid,
            orders: BoundedVec<SignedOrder<T::AccountId>, T::MaxOrdersPerBatch>,
        ) -> DispatchResult {
            let relayer = ensure_signed(origin)?;
            ensure!(
                LimitOrdersEnabled::<T>::get(),
                Error::<T>::LimitOrdersDisabled
            );

            Self::do_execute_batched_orders(netuid, orders, relayer)
        }

        /// Register a cancellation intent for an order.
        ///
        /// Must be called by the order's signer. The full `Order` payload is
        /// provided so the pallet can derive the `OrderId`. Once marked
        /// Cancelled, the order can never be executed.
        #[pallet::call_index(2)]
        #[pallet::weight(T::WeightInfo::cancel_order())]
        pub fn cancel_order(
            origin: OriginFor<T>,
            order: VersionedOrder<T::AccountId>,
        ) -> DispatchResult {
            let who = ensure_signed(origin)?;
            ensure!(order.inner().signer == who, Error::<T>::Unauthorized);

            let order_id = Self::derive_order_id(&order);

            ensure!(
                Orders::<T>::get(order_id).is_none(),
                Error::<T>::OrderAlreadyProcessed
            );

            Orders::<T>::insert(order_id, OrderStatus::Cancelled);
            Self::deposit_event(Event::OrderCancelled {
                order_id,
                signer: who,
            });

            Ok(())
        }

        /// Set a status for the limit orders pallet
        ///
        /// Must be called by root
        /// It allows disabling or enabling the pallet
        /// true means enabling, false means disabling
        #[pallet::call_index(3)]
        #[pallet::weight(T::WeightInfo::set_pallet_status())]
        pub fn set_pallet_status(origin: OriginFor<T>, enabled: bool) -> DispatchResult {
            ensure_root(origin)?;

            if enabled {
                ensure!(
                    T::SwapInterface::pallet_hotkey_registered(
                        &Self::pallet_account(),
                        &T::PalletHotkey::get(),
                    ),
                    Error::<T>::PalletHotkeyNotRegistered
                );
            }

            LimitOrdersEnabled::<T>::set(enabled);

            Self::deposit_event(Event::LimitOrdersPalletStatusChanged { enabled });

            Ok(())
        }
    }

    // ── Internal helpers ──────────────────────────────────────────────────────

    impl<T: Config> Pallet<T> {
        /// Compute the effective price limit passed to the pool swap.
        ///
        /// - `None` slippage → no constraint: `u64::MAX` for buys (no ceiling),
        ///   `0` for sells (no floor).
        /// - `Some(p)` → widens `limit_price` by the slippage fraction:
        ///   - Buy:  ceiling = `limit_price + limit_price * p`  (saturating)
        ///   - Sell: floor   = `limit_price - limit_price * p`  (saturating)
        pub(crate) fn compute_effective_swap_limit(
            is_buy: bool,
            limit_price: u64,
            max_slippage: Option<Perbill>,
        ) -> u64 {
            match max_slippage {
                None => {
                    if is_buy {
                        u64::MAX
                    } else {
                        0
                    }
                }
                Some(slippage) => {
                    let delta = slippage.mul_floor(limit_price);
                    if is_buy {
                        limit_price.saturating_add(delta)
                    } else {
                        limit_price.saturating_sub(delta)
                    }
                }
            }
        }

        /// Derive the on-chain `OrderId` as blake2_256 over the SCALE-encoded order.
        pub fn derive_order_id(order: &VersionedOrder<T::AccountId>) -> H256 {
            H256(sp_core::hashing::blake2_256(&order.encode()))
        }

        /// Account derived from the pallet's `PalletId`.
        pub(crate) fn pallet_account() -> T::AccountId {
            T::PalletId::get().into_account_truncating()
        }

        /// Transfer `fee_tao` from `signer` to `recipient`.
        /// Returns an error if the transfer fails, causing the surrounding operation to revert.
        /// Does nothing when `fee_tao` is zero.
        fn forward_fee(
            signer: &T::AccountId,
            recipient: &T::AccountId,
            fee_tao: TaoBalance,
        ) -> DispatchResult {
            if fee_tao.is_zero() {
                return Ok(());
            }
            T::SwapInterface::transfer_tao(signer, recipient, fee_tao)
        }

        /// Validates all execution preconditions for a signed order.
        /// Checks that the order's netuid is not root (0), that the signature is valid,
        /// the order has not been processed, is not expired, and the price condition is met.
        /// The batch netuid match (order.netuid == batch netuid) is checked separately by callers.
        pub(crate) fn is_order_valid(
            signed_order: &SignedOrder<T::AccountId>,
            order_id: H256,
            now_ms: u64,
            current_price: U64F64,
            relayer: &T::AccountId,
        ) -> DispatchResult {
            let order = signed_order.order.inner();
            ensure!(!order.netuid.is_root(), Error::<T>::RootNetUidNotAllowed);
            ensure!(
                order.chain_id == T::ChainId::get(),
                Error::<T>::ChainIdMismatch
            );
            ensure!(
                matches!(signed_order.signature, MultiSignature::Sr25519(_))
                    && signed_order
                        .signature
                        .verify(signed_order.order.encode().as_slice(), &order.signer),
                Error::<T>::InvalidSignature
            );
            let order_status = Orders::<T>::get(order_id);
            ensure!(
                order_status != Some(OrderStatus::Fulfilled),
                Error::<T>::OrderAlreadyProcessed
            );
            ensure!(
                order_status != Some(OrderStatus::Cancelled),
                Error::<T>::OrderCancelled
            );
            ensure!(now_ms <= order.expiry, Error::<T>::OrderExpired);
            // Scale current_price to ×10⁹ to match the limit_price field, which is
            // expressed in the same ×10⁹ scale as the `current_alpha_price` RPC endpoint.
            // This allows sub-unity prices (e.g. 0.5 TAO/alpha = 500_000_000) to be
            // represented and compared correctly.
            let scaled_price = current_price
                .saturating_mul(U64F64::from_num(1_000_000_000u64))
                .saturating_to_num::<u64>();
            ensure!(
                match order.order_type {
                    OrderType::TakeProfit => scaled_price >= order.limit_price,
                    OrderType::StopLoss | OrderType::LimitBuy => scaled_price <= order.limit_price,
                },
                Error::<T>::PriceConditionNotMet
            );
            if let Some(forced_relayers) = order.relayer.as_ref() {
                ensure!(
                    forced_relayers.contains(relayer),
                    Error::<T>::RelayerMissMatch
                );
            }
            if let Some(partial_fill) = signed_order.partial_fill {
                ensure!(
                    order.relayer.is_some(),
                    Error::<T>::RelayerRequiredForPartialFill
                );
                ensure!(
                    order.partial_fills_enabled,
                    Error::<T>::PartialFillsNotEnabled
                );
                let max_fill =
                    if let Some(OrderStatus::PartiallyFilled(already_filled)) = order_status {
                        order.amount.saturating_sub(already_filled)
                    } else {
                        order.amount
                    };
                ensure!(
                    partial_fill > 0 && partial_fill <= max_fill,
                    Error::<T>::IncorrectPartialFillAmount
                );
            } else {
                // `partial_fill == None` means a one-shot full execution of `order.amount`
                // (see `compute_order_status`, which returns `Fulfilled` for `None`). This is
                // only valid for an order that has not been filled yet. Against an order that is
                // already `PartiallyFilled(n)` the cumulative-fill cap above is skipped, so the
                // execution path would re-run the full `order.amount` on top of the `n` already
                // filled — over-debiting the signer and breaking the `sum(fills) <= order.amount`
                // conservation invariant. Reject it: the remaining amount must be completed with an
                // explicit `partial_fill = Some(order.amount - n)`.
                ensure!(
                    !matches!(order_status, Some(OrderStatus::PartiallyFilled(_))),
                    Error::<T>::IncorrectPartialFillAmount
                );
            }
            Ok(())
        }

        /// Compute the new `OrderStatus` to write after filling `fill_amount` of an order.
        ///
        /// Reads the current on-chain status to find any already-filled amount, adds
        /// `fill_amount`, and returns `Fulfilled` when the total reaches `order_amount`.
        /// Pass `None` for `fill_amount` when the order is being fully executed in one shot.
        pub(crate) fn compute_order_status(
            order_id: H256,
            fill_amount: Option<u64>,
            order_amount: u64,
        ) -> OrderStatus {
            let Some(fill) = fill_amount else {
                return OrderStatus::Fulfilled;
            };
            let already_filled =
                if let Some(OrderStatus::PartiallyFilled(n)) = Orders::<T>::get(order_id) {
                    n
                } else {
                    0
                };
            let new_total = already_filled.saturating_add(fill);
            if new_total >= order_amount {
                OrderStatus::Fulfilled
            } else {
                OrderStatus::PartiallyFilled(new_total)
            }
        }

        /// Attempt to execute one signed order. Returns an error on any
        /// validation or execution failure without panicking.
        ///
        /// `#[transactional]` makes the whole body a single storage layer: the
        /// swap (`buy_alpha`/`sell_alpha`, themselves transactional), the fee
        /// transfer, and the `Orders::insert` either all commit together or all
        /// roll back together.
        #[transactional]
        fn try_execute_order(
            signed_order: SignedOrder<T::AccountId>,
            order_id: H256,
            relayer: &T::AccountId,
        ) -> DispatchResult {
            let order = signed_order.order.inner();
            let now_ms = T::TimeProvider::now().as_millis() as u64;
            let current_price = T::SwapInterface::current_alpha_price(order.netuid);

            Self::is_order_valid(&signed_order, order_id, now_ms, current_price, relayer)?;

            let effective_swap_limit = Self::compute_effective_swap_limit(
                order.order_type.is_buy(),
                order.limit_price,
                order.max_slippage,
            );

            // Execute the swap, taking the order's fee from the input (buys) or output (sells).
            // `effective_swap_limit` enforces slippage protection: for buys it caps the price
            // ceiling; for sells it sets a minimum floor.  When `max_slippage` is None the
            // limit is u64::MAX (buys) or 0 (sells), matching previous market-order behaviour.
            let (amount_in, amount_out) = if order.order_type.is_buy() {
                // partial fill validations have passed, it is safe here to do this
                let tao_in = TaoBalance::from(signed_order.partial_fill.unwrap_or(order.amount));
                // Deduct fee from TAO input before swapping.
                let fee_tao = TaoBalance::from(order.fee_rate.mul_floor(tao_in.to_u64()));
                let tao_after_fee = tao_in.saturating_sub(fee_tao);

                let alpha_out = T::SwapInterface::buy_alpha(
                    &order.signer,
                    &order.hotkey,
                    order.netuid,
                    tao_after_fee,
                    TaoBalance::from(effective_swap_limit),
                    true,
                )?;

                // Forward the fee TAO to the order's fee recipient.
                Self::forward_fee(&order.signer, &order.fee_recipient, fee_tao)?;
                (tao_after_fee.to_u64(), alpha_out.to_u64())
            } else {
                // partial fill validations have passed, it is safe here to do this
                let alpha_in =
                    AlphaBalance::from(signed_order.partial_fill.unwrap_or(order.amount));

                // Sell the full alpha amount; fee is taken from the TAO output.
                let tao_out = T::SwapInterface::sell_alpha(
                    &order.signer,
                    &order.hotkey,
                    order.netuid,
                    alpha_in,
                    TaoBalance::from(effective_swap_limit),
                    true,
                )?;

                // Deduct fee from TAO output and forward to the order's fee recipient.
                let fee_tao = TaoBalance::from(order.fee_rate.mul_floor(tao_out.to_u64()));
                Self::forward_fee(&order.signer, &order.fee_recipient, fee_tao)?;
                (alpha_in.to_u64(), tao_out.saturating_sub(fee_tao).to_u64())
            };

            // Mark as fulfilled or partially filled and emit event.
            let status =
                Self::compute_order_status(order_id, signed_order.partial_fill, order.amount);
            Orders::<T>::insert(order_id, status);
            Self::deposit_event(Event::OrderExecuted {
                order_id,
                signer: order.signer.clone(),
                netuid: order.netuid,
                order_type: order.order_type.clone(),
                amount_in,
                amount_out,
            });

            Ok(())
        }

        /// Thin orchestrator for `execute_batched_orders`.
        ///
        /// All-or-nothing: any `Err` returned here (e.g. a `ZeroShareInBatch` rejection
        /// during distribution) rolls back the whole batch — including the up-front
        /// `collect_assets` debits and the pool swap — via FRAME's default per-dispatch
        /// storage layer, so no signer is left debited without receiving output.
        fn do_execute_batched_orders(
            netuid: NetUid,
            orders: BoundedVec<SignedOrder<T::AccountId>, T::MaxOrdersPerBatch>,
            relayer: T::AccountId,
        ) -> DispatchResult {
            ensure!(!netuid.is_root(), Error::<T>::RootNetUidNotAllowed);

            let now_ms = T::TimeProvider::now().as_millis() as u64;
            let current_price = T::SwapInterface::current_alpha_price(netuid);

            // Validate all orders; any invalid order causes the entire batch to fail.
            let (valid_buys, valid_sells) =
                Self::validate_and_classify(netuid, &orders, now_ms, current_price, relayer)?;

            let executed_count = valid_buys.len().saturating_add(valid_sells.len()) as u32;
            if executed_count == 0 {
                return Ok(());
            }

            let total_buy_net: u128 = valid_buys.iter().map(|e| e.net as u128).sum();
            let total_sell_net: u128 = valid_sells.iter().map(|e| e.net as u128).sum();
            let total_sell_tao_equiv: u128 = Self::alpha_to_tao(total_sell_net, current_price);

            let pallet_acct = Self::pallet_account();
            let pallet_hotkey = T::PalletHotkey::get();

            // Pull all input assets into the pallet intermediary before touching the pool.
            Self::collect_assets(
                &valid_buys,
                &valid_sells,
                &pallet_acct,
                &pallet_hotkey,
                netuid,
            )?;

            // Derive the tightest slippage constraint from the dominant side:
            // buy-dominant → min of all buy ceilings; sell-dominant → max of all sell floors.
            let pool_price_limit = if total_buy_net >= total_sell_tao_equiv {
                valid_buys
                    .iter()
                    .map(|e| e.effective_swap_limit)
                    .min()
                    .unwrap_or(u64::MAX)
            } else {
                valid_sells
                    .iter()
                    .map(|e| e.effective_swap_limit)
                    .max()
                    .unwrap_or(0)
            };

            // Execute a single pool swap for the residual (buy TAO minus sell TAO-equiv, or vice versa).
            let (net_side, actual_out) = Self::net_pool_swap(
                total_buy_net,
                total_sell_net,
                total_sell_tao_equiv,
                current_price,
                &pallet_acct,
                &pallet_hotkey,
                netuid,
                pool_price_limit,
            )?;

            // Give every buyer their pro-rata share of (pool alpha output + offset sell alpha).
            Self::distribute_alpha_pro_rata(
                &valid_buys,
                actual_out,
                total_buy_net,
                total_sell_net,
                &net_side,
                current_price,
                &pallet_acct,
                &pallet_hotkey,
                netuid,
            )?;

            // Give every seller their pro-rata share of (pool TAO output + offset buy TAO),
            // deducting per-order fees from each payout; returns accumulated sell fees by recipient.
            let sell_fees = Self::distribute_tao_pro_rata(
                &valid_sells,
                actual_out,
                total_buy_net,
                total_sell_tao_equiv,
                &net_side,
                current_price,
                &pallet_acct,
                netuid,
            )?;

            // Merge buy and sell fees by recipient and transfer once per unique recipient.
            Self::collect_fees(&valid_buys, sell_fees, &pallet_acct)?;

            let net_amount = Self::net_amount_for_event(
                &net_side,
                total_buy_net,
                total_sell_net,
                total_sell_tao_equiv,
                current_price,
            )?;
            Self::deposit_event(Event::GroupExecutionSummary {
                netuid,
                net_side,
                net_amount,
                actual_out: actual_out as u64,
                executed_count,
            });

            Ok(())
        }

        /// Validate every order against `netuid`, signature, expiry, and price.
        /// Valid orders are split into two BoundedVecs by side.
        /// Each entry is `(order_id, signer, hotkey, gross, net, fee)`.
        ///
        /// Returns an error immediately if any order fails validation (wrong netuid,
        /// invalid signature, expired, already processed, or price condition not met).
        pub(crate) fn validate_and_classify(
            netuid: NetUid,
            orders: &BoundedVec<SignedOrder<T::AccountId>, T::MaxOrdersPerBatch>,
            now_ms: u64,
            current_price: U64F64,
            relayer: T::AccountId,
        ) -> Result<
            (
                BoundedVec<OrderEntry<T::AccountId>, T::MaxOrdersPerBatch>,
                BoundedVec<OrderEntry<T::AccountId>, T::MaxOrdersPerBatch>,
            ),
            DispatchError,
        > {
            let mut buys = BoundedVec::new();
            let mut sells = BoundedVec::new();

            // Track which order_ids we have already seen in this batch. A repeated
            // order_id is never legitimate within a single batch.
            let mut seen_order_ids: BTreeSet<H256> = BTreeSet::new();

            for signed_order in orders.iter() {
                let order_id = Self::derive_order_id(&signed_order.order);

                // Hard-fail on the first duplicate order_id in the batch (covers both
                // buys and sells). BTreeSet::insert returns false if already present.
                ensure!(
                    seen_order_ids.insert(order_id),
                    Error::<T>::DuplicateOrderInBatch
                );

                let order = signed_order.order.inner();

                // Hard-fail if the order targets a different subnet than the batch netuid.
                ensure!(order.netuid == netuid, Error::<T>::OrderNetUidMismatch);

                // Hard-fail on any per-order validation error (signature, expiry, price, root).
                Self::is_order_valid(signed_order, order_id, now_ms, current_price, &relayer)?;

                let amount_in = signed_order.partial_fill.unwrap_or(order.amount);
                let net = if order.order_type.is_buy() {
                    // Buy: fee on TAO input — net is the amount that reaches the pool.
                    amount_in.saturating_sub(order.fee_rate.mul_floor(amount_in))
                } else {
                    // Sell: fee on TAO output — full alpha enters the pool; the fee is
                    // deducted from the TAO payout later in `distribute_tao_pro_rata`.
                    amount_in
                };

                let effective_swap_limit = Self::compute_effective_swap_limit(
                    order.order_type.is_buy(),
                    order.limit_price,
                    order.max_slippage,
                );

                let entry = OrderEntry {
                    order_id,
                    signer: order.signer.clone(),
                    hotkey: order.hotkey.clone(),
                    side: order.order_type.clone(),
                    gross: amount_in,
                    order_amount: order.amount,
                    net,
                    fee_rate: order.fee_rate,
                    fee_recipient: order.fee_recipient.clone(),
                    effective_swap_limit,
                    partial_fill: signed_order.partial_fill,
                };

                // try_push cannot fail: both vecs share the same bound as `orders`.
                if entry.side.is_buy() {
                    let _ = buys.try_push(entry);
                } else {
                    let _ = sells.try_push(entry);
                }
            }

            Ok((buys, sells))
        }

        /// Pull gross TAO from each buyer and gross staked alpha from each seller
        /// into the pallet intermediary account, bypassing the pool.
        fn collect_assets(
            buys: &BoundedVec<OrderEntry<T::AccountId>, T::MaxOrdersPerBatch>,
            sells: &BoundedVec<OrderEntry<T::AccountId>, T::MaxOrdersPerBatch>,
            pallet_acct: &T::AccountId,
            pallet_hotkey: &T::AccountId,
            netuid: NetUid,
        ) -> DispatchResult {
            for e in buys.iter() {
                T::SwapInterface::transfer_tao(&e.signer, pallet_acct, TaoBalance::from(e.gross))?;
            }
            for e in sells.iter() {
                T::SwapInterface::transfer_staked_alpha(
                    &e.signer,
                    &e.hotkey,
                    pallet_acct,
                    pallet_hotkey,
                    netuid,
                    AlphaBalance::from(e.gross),
                    true,  // validate_sender: check user's rate limit, subnet, min stake
                    false, // set_receiver_limit: do not rate-limit the pallet intermediary
                )?;
            }
            Ok(())
        }

        /// Execute a single pool swap for the net (residual) amount.
        /// Returns `(net_side, actual_out)` where `actual_out` is in the output
        /// token units (alpha for Buy, TAO for Sell).
        ///
        /// `price_limit` encodes the tightest slippage constraint across all dominant-side
        /// orders: a ceiling for buy-dominant swaps, a floor for sell-dominant swaps.
        #[allow(clippy::too_many_arguments)]
        fn net_pool_swap(
            total_buy_net: u128,
            total_sell_net: u128,
            total_sell_tao_equiv: u128,
            current_price: U64F64,
            pallet_acct: &T::AccountId,
            pallet_hotkey: &T::AccountId,
            netuid: NetUid,
            price_limit: u64,
        ) -> Result<(OrderSide, u128), DispatchError> {
            if total_buy_net >= total_sell_tao_equiv {
                let net_tao = (total_buy_net.saturating_sub(total_sell_tao_equiv)) as u64;
                let actual_alpha = if net_tao > 0 {
                    let out = T::SwapInterface::buy_alpha(
                        pallet_acct,
                        pallet_hotkey,
                        netuid,
                        TaoBalance::from(net_tao),
                        TaoBalance::from(price_limit),
                        false,
                    )?
                    .to_u64() as u128;
                    ensure!(out > 0, Error::<T>::SwapReturnedZero);
                    out
                } else {
                    0u128
                };
                Ok((OrderSide::Buy, actual_alpha))
            } else {
                let total_buy_alpha_equiv = Self::tao_to_alpha(total_buy_net, current_price)?;
                let net_alpha = (total_sell_net.saturating_sub(total_buy_alpha_equiv)) as u64;
                let actual_tao = if net_alpha > 0 {
                    let out = T::SwapInterface::sell_alpha(
                        pallet_acct,
                        pallet_hotkey,
                        netuid,
                        AlphaBalance::from(net_alpha),
                        TaoBalance::from(price_limit),
                        false,
                    )?
                    .to_u64() as u128;
                    ensure!(out > 0, Error::<T>::SwapReturnedZero);
                    out
                } else {
                    0u128
                };
                Ok((OrderSide::Sell, actual_tao))
            }
        }

        /// Distribute alpha pro-rata to ALL buyers and mark their orders fulfilled.
        ///
        /// - Buy-dominant: total alpha = pool output + sell-side alpha (passed through).
        /// - Sell-dominant: total alpha = buy-side TAO converted at `current_price`.
        #[allow(clippy::too_many_arguments)]
        pub(crate) fn distribute_alpha_pro_rata(
            buys: &BoundedVec<OrderEntry<T::AccountId>, T::MaxOrdersPerBatch>,
            actual_out: u128,
            total_buy_net: u128,
            total_sell_net: u128,
            net_side: &OrderSide,
            current_price: U64F64,
            pallet_acct: &T::AccountId,
            pallet_hotkey: &T::AccountId,
            netuid: NetUid,
        ) -> DispatchResult {
            let total_alpha: u128 = match net_side {
                OrderSide::Buy => actual_out.saturating_add(total_sell_net),
                OrderSide::Sell => Self::tao_to_alpha(total_buy_net, current_price)?,
            };

            for e in buys.iter() {
                let share: u64 = if total_buy_net > 0 {
                    total_alpha
                        .saturating_mul(e.net as u128)
                        .checked_div(total_buy_net)
                        .unwrap_or(0) as u64
                } else {
                    0
                };
                // A floored-to-zero share means this buyer's input was already collected
                // by `collect_assets` but the pool/offset alpha cannot pay them even one
                // unit. Hard-fail the whole batch (FRAME's per-dispatch storage layer rolls
                // back `collect_assets` and the pool swap) rather than silently skipping the
                // transfer while still marking the order terminal — which would consume the
                // signer's TAO for zero alpha and permanently close the order.
                ensure!(share > 0, Error::<T>::ZeroShareInBatch);
                T::SwapInterface::transfer_staked_alpha(
                    pallet_acct,
                    pallet_hotkey,
                    &e.signer,
                    &e.hotkey,
                    netuid,
                    AlphaBalance::from(share),
                    false, // validate_sender: skip — pallet intermediary needs no validation
                    true,  // set_receiver_limit: rate-limit the buyer after they receive stake
                )?;
                let status = Self::compute_order_status(e.order_id, e.partial_fill, e.order_amount);
                Orders::<T>::insert(e.order_id, status);
                Self::deposit_event(Event::OrderExecuted {
                    order_id: e.order_id,
                    signer: e.signer.clone(),
                    netuid,
                    order_type: e.side.clone(),
                    amount_in: e.gross,
                    amount_out: share,
                });
            }
            Ok(())
        }

        /// Distribute TAO pro-rata to ALL sellers and mark their orders fulfilled.
        ///
        /// - Sell-dominant: total TAO = pool output + buy-side TAO (passed through).
        /// - Buy-dominant: each seller receives their alpha valued at `current_price`.
        ///
        /// Fee on TAO output: `ppb(share)` is withheld from each seller's payout and
        /// left in the pallet account. Returns the total sell-side fee TAO accumulated.
        #[allow(clippy::too_many_arguments)]
        pub(crate) fn distribute_tao_pro_rata(
            sells: &BoundedVec<OrderEntry<T::AccountId>, T::MaxOrdersPerBatch>,
            actual_out: u128,
            total_buy_net: u128,
            total_sell_tao_equiv: u128,
            net_side: &OrderSide,
            current_price: U64F64,
            pallet_acct: &T::AccountId,
            netuid: NetUid,
        ) -> Result<Vec<(T::AccountId, u64)>, DispatchError> {
            let total_tao: u128 = match net_side {
                OrderSide::Sell => actual_out.saturating_add(total_buy_net),
                OrderSide::Buy => total_sell_tao_equiv,
            };

            // Accumulate sell-side fees by recipient (one entry per unique recipient).
            let mut sell_fees: Vec<(T::AccountId, u64)> = Vec::new();

            for e in sells.iter() {
                let sell_tao_equiv = Self::alpha_to_tao(e.net as u128, current_price);
                let gross_share: u64 = if total_sell_tao_equiv > 0 {
                    total_tao
                        .saturating_mul(sell_tao_equiv)
                        .checked_div(total_sell_tao_equiv)
                        .unwrap_or(0) as u64
                } else {
                    0u64
                };
                let fee = e.fee_rate.mul_floor(gross_share);
                let net_share = gross_share.saturating_sub(fee);

                // A floored-to-zero payout means this seller's alpha was already collected
                // by `collect_assets` but the pool/offset TAO cannot pay them even one unit
                // (after fee). Hard-fail the whole batch (rolled back by the dispatch storage
                // layer) rather than no-op the transfer while still marking the order terminal,
                // which would consume the seller's alpha for zero TAO and close the order.
                ensure!(net_share > 0, Error::<T>::ZeroShareInBatch);

                if fee > 0 {
                    if let Some(entry) = sell_fees.iter_mut().find(|(r, _)| r == &e.fee_recipient) {
                        entry.1 = entry.1.saturating_add(fee);
                    } else {
                        sell_fees.push((e.fee_recipient.clone(), fee));
                    }
                }

                T::SwapInterface::transfer_tao(
                    pallet_acct,
                    &e.signer,
                    TaoBalance::from(net_share),
                )?;
                let status = Self::compute_order_status(e.order_id, e.partial_fill, e.order_amount);
                Orders::<T>::insert(e.order_id, status);
                Self::deposit_event(Event::OrderExecuted {
                    order_id: e.order_id,
                    signer: e.signer.clone(),
                    netuid,
                    order_type: e.side.clone(),
                    amount_in: e.gross,
                    amount_out: net_share,
                });
            }
            Ok(sell_fees)
        }

        /// Forward accumulated fees to their respective recipients.
        ///
        /// Merges buy-side fees (withheld from TAO input) and sell-side fees
        /// (withheld from TAO output, passed in as `sell_fees`) by recipient,
        /// then performs one TAO transfer per unique `fee_recipient`.
        /// All transfers are best-effort and do not revert the batch on failure.
        pub(crate) fn collect_fees(
            buys: &BoundedVec<OrderEntry<T::AccountId>, T::MaxOrdersPerBatch>,
            sell_fees: Vec<(T::AccountId, u64)>,
            pallet_acct: &T::AccountId,
        ) -> DispatchResult {
            // Start with sell fees; fold in buy fees.
            // Buy fee was already computed in `validate_and_classify` as `gross - net`,
            // so we recover it here without recomputing.
            let mut fees: Vec<(T::AccountId, u64)> = sell_fees;
            for e in buys.iter() {
                let fee = e.gross.saturating_sub(e.net);
                if fee > 0 {
                    if let Some(entry) = fees.iter_mut().find(|(r, _)| r == &e.fee_recipient) {
                        entry.1 = entry.1.saturating_add(fee);
                    } else {
                        fees.push((e.fee_recipient.clone(), fee));
                    }
                }
            }

            // One transfer per unique fee recipient.
            for (recipient, amount) in fees {
                Self::forward_fee(pallet_acct, &recipient, TaoBalance::from(amount))?;
            }

            // TODO: sweep rounding dust and any emissions accrued on the pallet account.
            // Pro-rata integer division leaves small alpha residuals in (pallet_account,
            // pallet_hotkey) after each batch.  Over time these accumulate and, if an
            // emission epoch fires while the dust is present, the pallet earns emissions
            // it never distributes.  Fix: add `staked_alpha(coldkey, hotkey, netuid) ->
            // AlphaBalance` to `OrderSwapInterface`, then sell the full remaining balance
            // here and forward the TAO to `FeeCollector`.
            Ok(())
        }

        /// Compute the net amount field for the `GroupExecutionSummary` event.
        pub(crate) fn net_amount_for_event(
            net_side: &OrderSide,
            total_buy_net: u128,
            total_sell_net: u128,
            total_sell_tao_equiv: u128,
            current_price: U64F64,
        ) -> Result<u64, DispatchError> {
            match net_side {
                OrderSide::Buy => Ok((total_buy_net.saturating_sub(total_sell_tao_equiv)) as u64),
                OrderSide::Sell => {
                    let buy_alpha_equiv = Self::tao_to_alpha(total_buy_net, current_price)? as u64;
                    Ok((total_sell_net as u64).saturating_sub(buy_alpha_equiv))
                }
            }
        }

        /// Convert a TAO amount to alpha at `price` (TAO/alpha).
        ///
        /// A zero `price` yields `Ok(0)` (no alpha is purchasable). A genuine
        /// fixed-point overflow returns `Err(ArithmeticOverflow)` so the caller
        /// aborts the batch.
        fn tao_to_alpha(tao: u128, price: U64F64) -> Result<u128, DispatchError> {
            if price == U64F64::from_num(0u32) {
                return Ok(0u128);
            }
            U64F64::saturating_from_num(tao)
                .checked_div(price)
                .map(|alpha| alpha.saturating_to_num::<u128>())
                .ok_or(Error::<T>::ArithmeticOverflow.into())
        }

        /// Convert an alpha amount to TAO at `price` (TAO/alpha).
        fn alpha_to_tao(alpha: u128, price: U64F64) -> u128 {
            price
                .saturating_mul(U64F64::saturating_from_num(alpha))
                .saturating_to_num::<u128>()
        }
    }
}