code/runtime/src/mldsa_order_tests.rs
//! Real balance, subnet reserve and alpha-share rollback for account-approved orders.
use super::*;
use frame_support::{assert_noop, assert_ok, traits::Get};
use pallet_limit_orders::{AuthorizedOrder, Order, OrderAuthorization, OrderType, VersionedOrder};
use sp_runtime::{Perbill, traits::AccountIdConversion};
use subtensor_runtime_common::AlphaBalance;
// PROTECTED_REGRESSION: batch price failure reverts real assets approvals and nonces; changes require explicit human approval.
#[test]
fn batch_price_failure_reverts_real_assets_approvals_and_nonces() {
// Two buyers split an odd alpha amount. Their one-unit rounding loss must
// not exceed the zero-slippage ceiling, even with a perfectly offset batch.
mldsa::with_profiles(|| {
let netuid = NetUid::from(42u16);
SubtensorModule::init_new_network(netuid, 100);
pallet_subtensor::SubnetMechanism::<Runtime>::insert(netuid, 1);
pallet_subtensor::SubtokenEnabled::<Runtime>::insert(netuid, true);
pallet_subtensor::SubnetTAO::<Runtime>::insert(netuid, TaoBalance::new(2_000_000_000_000));
pallet_subtensor::SubnetAlphaIn::<Runtime>::insert(
netuid,
AlphaBalance::new(1_000_000_000_000),
);
pallet_subtensor_swap::SwapBalancer::<Runtime>::remove(netuid);
assert_eq!(
Swap::current_price(netuid),
substrate_fixed::types::U64F64::from_num(2)
);
let accounts = [91, 92, 93].map(|seed| AccountId::from(pair(seed).public()));
let intermediary: AccountId = LimitOrdersPalletId::get().into_account_truncating();
for account in &accounts {
assert_ok!(SubtensorModule::create_account_if_non_existent(
account, account
));
let _ = Balances::make_free_balance_be(account, TaoBalance::new(10_000_000_000));
}
assert_ok!(SubtensorModule::create_account_if_non_existent(
&intermediary,
&LimitOrdersPalletHotkey::get()
));
let _ = Balances::make_free_balance_be(&intermediary, TaoBalance::new(1_000_000_000));
SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
&accounts[2],
&accounts[2],
netuid,
AlphaBalance::new(3_000_000_001),
);
pallet_limit_orders::LimitOrdersEnabled::<Runtime>::put(true);
for slippage in [0, 1] {
let nonce = 7u64.saturating_add(slippage as u64);
let mut batch = Vec::new();
for (index, owner) in accounts.iter().enumerate() {
let order = VersionedOrder::V1(Order {
signer: owner.clone(),
hotkey: owner.clone(),
netuid,
order_type: if index == 2 {
OrderType::StopLoss
} else {
OrderType::LimitBuy
},
amount: 3_000_000_001,
limit_price: 2_000_000_000,
expiry: u64::MAX,
fee_rate: Perbill::zero(),
fee_recipient: intermediary.clone(),
relayer: None,
max_slippage: Some(Perbill::from_percent(slippage)),
chain_id: ConfigurableChainId::get(),
partial_fills_enabled: false,
});
assert_ok!(LimitOrders::authorize_order(
RuntimeOrigin::signed(owner.clone()),
order.clone().with_nonce(nonce).unwrap()
));
batch.push(AuthorizedOrder {
order,
nonce,
partial_fill: None,
authorization: OrderAuthorization::AccountApproved,
});
}
let batch = unified_orders(batch.try_into().unwrap());
if slippage == 0 {
// The failure occurs during payout, after real TAO and alpha
// collection. assert_noop compares the complete storage root.
assert_noop!(
LimitOrders::execute_batched_orders(
RuntimeOrigin::signed(accounts[0].clone()),
netuid,
batch
),
pallet_limit_orders::Error::<Runtime>::PriceConditionNotMet
);
for owner in &accounts {
assert!(LimitOrders::approved_order(owner, nonce).is_some());
assert_eq!(
Balances::free_balance(owner),
TaoBalance::new(10_000_000_000)
);
}
assert_eq!(
SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
&accounts[2],
&accounts[2],
netuid
),
AlphaBalance::new(3_000_000_001)
);
} else {
// With new explicitly approved rounding tolerance, the same
// accounts can settle successfully.
assert_ok!(LimitOrders::execute_batched_orders(
RuntimeOrigin::signed(accounts[0].clone()),
netuid,
batch
));
}
}
});
}
fn orders(
owner: &AccountId,
recipient: &AccountId,
netuid: NetUid,
) -> frame_support::BoundedVec<AuthorizedOrder, pallet_limit_orders::MaxAuthorizedOrders> {
(0..2)
.map(|nonce| {
let order = VersionedOrder::V1(Order {
signer: owner.clone(),
hotkey: owner.clone(),
netuid,
order_type: OrderType::LimitBuy,
amount: 1_000_000_000,
limit_price: u64::MAX,
expiry: u64::MAX,
fee_rate: Perbill::from_percent(1),
fee_recipient: recipient.clone(),
relayer: None,
max_slippage: None,
chain_id: ConfigurableChainId::get(),
partial_fills_enabled: false,
});
AuthorizedOrder {
nonce,
order,
partial_fill: None,
authorization: OrderAuthorization::AccountApproved,
}
})
.collect::<Vec<_>>()
.try_into()
.unwrap()
}
#[test]
fn all_post_quantum_profiles_approve_and_cancel_orders_without_additional_deposits() {
for profile in 4..=9 {
mldsa::with_profiles(|| {
System::set_block_number(1);
hashed_auth::TestVerificationWeight::set(Weight::from_parts(10_000_000, 0));
let (owner, sign): (AccountId, Box<dyn Fn(RuntimeCall) -> UncheckedExtrinsic>) =
match profile {
4 => (mldsa::register(81), Box::new(|call| mldsa::sign(81, call))),
5 => {
let wallet = mldsa::stateless::Wallet::new(81);
let _ = Balances::make_free_balance_be(
&wallet.account,
TaoBalance::new(1_000_000_000_000),
);
(
wallet.account.clone(),
Box::new(move |call| wallet.sign(call)),
)
}
_ => {
let wallet = falcon::Wallet::new(81, profile);
wallet.prepare();
(
wallet.account.clone(),
Box::new(move |call| wallet.sign(call)),
)
}
};
pallet_limit_orders::LimitOrdersEnabled::<Runtime>::put(true);
let signed = orders(&owner, &owner, NetUid::from(42u16))[0].clone();
let order = signed.order.with_nonce(signed.nonce).unwrap();
let reserved = Balances::reserved_balance(&owner);
let initial_nonce = System::account_nonce(&owner);
assert_ok!(
Executive::apply_extrinsic(sign(RuntimeCall::LimitOrders(
pallet_limit_orders::Call::authorize_order {
order: order.clone()
},
)))
.unwrap()
);
assert!(pallet_limit_orders::ApprovedOrders::<Runtime>::contains_key(&owner));
assert_ok!(
Executive::apply_extrinsic(sign(RuntimeCall::LimitOrders(
pallet_limit_orders::Call::cancel_order { order },
)))
.unwrap()
);
assert_eq!(
LimitOrders::approved_order(&owner, signed.nonce)
.unwrap()
.status,
Some(pallet_limit_orders::OrderStatus::Cancelled)
);
assert_eq!(Balances::reserved_balance(&owner), reserved);
assert_eq!(System::account_nonce(&owner), initial_nonce + 2);
let registered = pallet_hashed_accounts::MlDsaAccounts::<Runtime>::get(&owner);
if [4, 6, 8].contains(&profile) {
assert_eq!(registered.unwrap().generation, 2);
} else {
assert!(registered.is_none());
}
});
}
}
#[test]
fn restricted_proxy_cannot_create_deferred_order_spending_authority() {
use alloc::boxed::Box;
use frame_support::traits::InstanceFilter;
for protected in [false, true] {
for proxy_type in [
ProxyType::NonTransfer,
ProxyType::NonFungible,
ProxyType::NonCritical,
] {
mldsa::with_profiles(|| {
System::set_block_number(1);
let accounts = [85, 86, 87].map(|identity| {
if protected {
mldsa::register(identity)
} else {
let account = AccountId::from(pair(identity).public());
let _ = Balances::make_free_balance_be(
&account,
TaoBalance::new(1_000_000_000_000),
);
account
}
});
let [owner, delegate, bridge] = accounts;
assert_ok!(Proxy::add_proxy_delegate(
&owner,
delegate.clone(),
proxy_type,
0
));
assert_ok!(Proxy::add_proxy_delegate(
&bridge,
delegate.clone(),
proxy_type,
0
));
assert_ok!(Proxy::add_proxy_delegate(
&owner,
bridge.clone(),
ProxyType::Any,
0
));
let netuid = NetUid::from(42u16);
SubtensorModule::init_new_network(netuid, 100);
pallet_subtensor::SubnetMechanism::<Runtime>::insert(netuid, 0);
pallet_subtensor::SubtokenEnabled::<Runtime>::insert(netuid, true);
pallet_subtensor::SubnetTAO::<Runtime>::insert(
netuid,
TaoBalance::new(1_000_000_000_000),
);
pallet_subtensor::SubnetAlphaIn::<Runtime>::insert(
netuid,
AlphaBalance::new(1_000_000_000_000),
);
assert_ok!(SubtensorModule::create_account_if_non_existent(
&owner, &owner
));
pallet_limit_orders::LimitOrdersEnabled::<Runtime>::put(true);
let signed = orders(&owner, &delegate, netuid)[0].clone();
let approval =
RuntimeCall::LimitOrders(pallet_limit_orders::Call::authorize_order {
order: signed.order.clone().with_nonce(signed.nonce).unwrap(),
});
// Every restricted grant denies creation, even those that may
// relay an order already authorized by its owner.
for grant in (0..=u8::MAX).filter_map(|i| ProxyType::try_from(i).ok()) {
assert_eq!(grant.filter(&approval), grant == ProxyType::Any);
}
let balances = [&owner, &delegate].map(Balances::free_balance);
let reserve = pallet_subtensor::SubnetTAO::<Runtime>::get(netuid);
let alpha = pallet_subtensor::SubnetAlphaIn::<Runtime>::get(netuid);
let calls = [
(owner.clone(), approval.clone()),
(
owner.clone(),
RuntimeCall::Utility(pallet_utility::Call::batch_all {
calls: vec![approval.clone()],
}),
),
(
bridge.clone(),
RuntimeCall::Proxy(pallet_proxy::Call::proxy {
real: owner.clone().into(),
force_proxy_type: Some(ProxyType::Any),
call: Box::new(approval.clone()),
}),
),
];
for (real, call) in calls {
assert_ok!(Proxy::proxy(
RuntimeOrigin::signed(delegate.clone()),
real.into(),
Some(proxy_type),
Box::new(call)
));
assert_eq!(
pallet_proxy::LastCallResult::<Runtime>::get(&owner),
Some(Err(frame_system::Error::<Runtime>::CallFiltered.into()))
);
assert!(!pallet_limit_orders::ApprovedOrders::<Runtime>::contains_key(&owner));
assert!(LimitOrders::approved_order(&owner, signed.nonce).is_none());
assert_noop!(
LimitOrders::execute_orders(
RuntimeOrigin::signed(delegate.clone()),
unified_orders(vec![signed.clone()].try_into().unwrap()),
true
),
pallet_limit_orders::Error::<Runtime>::OrderNotApproved
);
assert_eq!([&owner, &delegate].map(Balances::free_balance), balances);
assert_eq!(pallet_subtensor::SubnetTAO::<Runtime>::get(netuid), reserve);
assert_eq!(
pallet_subtensor::SubnetAlphaIn::<Runtime>::get(netuid),
alpha
);
assert_eq!(
SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
&owner, &owner, netuid
),
AlphaBalance::ZERO
);
}
// Full authority still approves the identical terms, and the
// same relayer/order fixture reaches real economic execution.
assert_ok!(Proxy::proxy(
RuntimeOrigin::signed(bridge),
owner.clone().into(),
Some(ProxyType::Any),
Box::new(approval)
));
assert!(pallet_limit_orders::ApprovedOrders::<Runtime>::contains_key(&owner));
assert_ok!(LimitOrders::execute_orders(
RuntimeOrigin::signed(delegate.clone()),
unified_orders(vec![signed].try_into().unwrap()),
true
));
assert_eq!(
Balances::free_balance(&owner),
balances[0].saturating_sub(TaoBalance::new(1_000_000_000))
);
assert_eq!(
Balances::free_balance(&delegate),
balances[1].saturating_add(TaoBalance::new(10_000_000))
);
assert!(
SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
&owner, &owner, netuid
) > AlphaBalance::ZERO
);
});
}
}
}
fn unified_orders(
orders: frame_support::BoundedVec<AuthorizedOrder, pallet_limit_orders::MaxAuthorizedOrders>,
) -> frame_support::BoundedVec<
pallet_limit_orders::SignedOrder<AccountId>,
<Runtime as pallet_limit_orders::Config>::MaxOrdersPerBatch,
> {
orders
.into_iter()
.map(|signed| signed.try_into().unwrap())
.collect::<Vec<_>>()
.try_into()
.unwrap()
}
#[test]
fn balance_reaping_removes_approvals_without_locking_an_existential_balance() {
mldsa::with_profiles(|| {
System::set_block_number(1);
pallet_limit_orders::LimitOrdersEnabled::<Runtime>::put(true);
let owner = AccountId::from(pair(231).public());
let recipient = AccountId::from(pair(232).public());
let funding = TaoBalance::new(1_000_000_000);
let _ = Balances::make_free_balance_be(&owner, funding);
let signed = orders(&owner, &recipient, NetUid::from(42u16))[0].clone();
let reserved = Balances::reserved_balance(&owner);
let providers = System::providers(&owner);
for nonce in 0..8 {
assert_ok!(LimitOrders::authorize_order(
RuntimeOrigin::signed(owner.clone()),
signed.order.clone().with_nonce(nonce).unwrap()
));
}
assert_eq!(Balances::reserved_balance(&owner), reserved);
assert_eq!(System::providers(&owner), providers);
assert_ok!(Balances::transfer_allow_death(
RuntimeOrigin::signed(owner.clone()),
recipient.clone().into(),
funding
));
assert!(!frame_system::Account::<Runtime>::contains_key(&owner));
assert!(!pallet_limit_orders::ApprovedOrders::<Runtime>::contains_key(&owner));
let _ = Balances::make_free_balance_be(&owner, funding);
assert_noop!(
LimitOrders::execute_orders(
RuntimeOrigin::signed(recipient),
unified_orders(vec![signed].try_into().unwrap()),
true
),
pallet_limit_orders::Error::<Runtime>::OrderNotApproved
);
});
}
// PROTECTED_REGRESSION: derived protection requires cancelling classical proxy orders; changes require explicit human approval.
#[test]
fn derived_protection_requires_cancelling_classical_proxy_orders() {
mldsa::with_profiles(|| {
let parent = mldsa::register(240);
let descriptor =
pallet_hashed_accounts::DerivedDescriptor::Derivative { parent, index: 240 };
let owner = descriptor.account_id();
let delegate = AccountId::from(pair(241).public());
let netuid = NetUid::from(42u16);
let _ = Balances::make_free_balance_be(&owner, TaoBalance::new(1_000_000_000_000));
assert_ok!(Proxy::add_proxy(
RuntimeOrigin::signed(owner.clone()),
delegate.clone().into(),
ProxyType::Any,
0
));
pallet_limit_orders::LimitOrdersEnabled::<Runtime>::put(true);
let signed = orders(&owner, &delegate, netuid)[0].clone();
let approve = RuntimeCall::LimitOrders(pallet_limit_orders::Call::authorize_order {
order: signed.order.clone().with_nonce(signed.nonce).unwrap(),
});
assert_ok!(Proxy::proxy(
RuntimeOrigin::signed(delegate.clone()),
owner.clone().into(),
Some(ProxyType::Any),
Box::new(approve)
));
assert_eq!(
pallet_proxy::LastCallResult::<Runtime>::get(&owner),
Some(Ok(()))
);
assert!(LimitOrders::approved_order(&owner, signed.nonce).is_some());
assert_ok!(Proxy::remove_proxy(
RuntimeOrigin::signed(owner.clone()),
delegate.clone().into(),
ProxyType::Any,
0
));
assert_noop!(
HashedAccounts::register_derived(
RuntimeOrigin::signed(owner.clone()),
descriptor.clone()
),
sp_runtime::DispatchError::Other("MlDsaPendingOrderApproval")
);
assert!(!HashedAccounts::is_protected(&owner));
assert!(LimitOrders::approved_order(&owner, signed.nonce).is_some());
assert_ok!(LimitOrders::cancel_order(
RuntimeOrigin::signed(owner.clone()),
signed.order.clone().with_nonce(signed.nonce).unwrap()
));
assert_ok!(HashedAccounts::register_derived(
RuntimeOrigin::signed(owner.clone()),
descriptor
));
assert!(HashedAccounts::is_protected(&owner));
SubtensorModule::init_new_network(netuid, 100);
pallet_subtensor::SubnetMechanism::<Runtime>::insert(netuid, 0);
pallet_subtensor::SubtokenEnabled::<Runtime>::insert(netuid, true);
pallet_subtensor::SubnetTAO::<Runtime>::insert(netuid, TaoBalance::new(1_000_000_000_000));
pallet_subtensor::SubnetAlphaIn::<Runtime>::insert(
netuid,
AlphaBalance::new(1_000_000_000_000),
);
assert_ok!(SubtensorModule::create_account_if_non_existent(
&owner, &owner
));
let before = Balances::free_balance(&owner);
assert_noop!(
LimitOrders::execute_orders(
RuntimeOrigin::signed(delegate),
unified_orders(vec![signed].try_into().unwrap()),
true
),
pallet_limit_orders::Error::<Runtime>::OrderCancelled
);
assert_eq!(Balances::free_balance(&owner), before);
});
}