Skip to content

Commit a6e7b49

Browse files
authored
Merge pull request #1215 from opentensor/fix/validate_limit_txs
Fix/validate limit txs
2 parents 86fdc36 + 2395e74 commit a6e7b49

File tree

2 files changed

+157
-1
lines changed

2 files changed

+157
-1
lines changed

pallets/subtensor/src/lib.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1783,7 +1783,7 @@ where
17831783
}
17841784
Some(Call::commit_crv3_weights { netuid, .. }) => {
17851785
if Self::check_weights_min_stake(who, *netuid) {
1786-
let priority: u64 = Self::get_priority_set_weights(who, *netuid);
1786+
let priority: u64 = Pallet::<T>::get_priority_set_weights(who, *netuid);
17871787
Ok(ValidTransaction {
17881788
priority,
17891789
longevity: 1,
@@ -1811,6 +1811,26 @@ where
18111811
false,
18121812
))
18131813
}
1814+
Some(Call::add_stake_limit {
1815+
hotkey,
1816+
netuid,
1817+
amount_staked,
1818+
limit_price,
1819+
allow_partial,
1820+
}) => {
1821+
// Calcaulate the maximum amount that can be executed with price limit
1822+
let max_amount = Pallet::<T>::get_max_amount_add(*netuid, *limit_price);
1823+
1824+
// Fully validate the user input
1825+
Self::result_to_validity(Pallet::<T>::validate_add_stake(
1826+
who,
1827+
hotkey,
1828+
*netuid,
1829+
*amount_staked,
1830+
max_amount,
1831+
*allow_partial,
1832+
))
1833+
}
18141834
Some(Call::remove_stake {
18151835
hotkey,
18161836
netuid,
@@ -1826,6 +1846,26 @@ where
18261846
false,
18271847
))
18281848
}
1849+
Some(Call::remove_stake_limit {
1850+
hotkey,
1851+
netuid,
1852+
amount_unstaked,
1853+
limit_price,
1854+
allow_partial,
1855+
}) => {
1856+
// Calcaulate the maximum amount that can be executed with price limit
1857+
let max_amount = Pallet::<T>::get_max_amount_remove(*netuid, *limit_price);
1858+
1859+
// Fully validate the user input
1860+
Self::result_to_validity(Pallet::<T>::validate_remove_stake(
1861+
who,
1862+
hotkey,
1863+
*netuid,
1864+
*amount_unstaked,
1865+
max_amount,
1866+
*allow_partial,
1867+
))
1868+
}
18291869
Some(Call::move_stake {
18301870
origin_hotkey,
18311871
destination_hotkey,

pallets/subtensor/src/tests/staking.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2206,6 +2206,122 @@ fn test_stake_below_min_validate() {
22062206
});
22072207
}
22082208

2209+
// cargo test --package pallet-subtensor --lib -- tests::staking::test_add_stake_limit_validate --exact --show-output
2210+
#[test]
2211+
fn test_add_stake_limit_validate() {
2212+
// Testing the signed extension validate function
2213+
// correctly filters the `add_stake` transaction.
2214+
2215+
new_test_ext(0).execute_with(|| {
2216+
let hotkey = U256::from(533453);
2217+
let coldkey = U256::from(55453);
2218+
let amount = 300_000_000_000;
2219+
2220+
// add network
2221+
let netuid: u16 = add_dynamic_network(&hotkey, &coldkey);
2222+
2223+
// Force-set alpha in and tao reserve to make price equal 1.5
2224+
let tao_reserve: U96F32 = U96F32::from_num(150_000_000_000_u64);
2225+
let alpha_in: U96F32 = U96F32::from_num(100_000_000_000_u64);
2226+
SubnetTAO::<Test>::insert(netuid, tao_reserve.to_num::<u64>());
2227+
SubnetAlphaIn::<Test>::insert(netuid, alpha_in.to_num::<u64>());
2228+
let current_price: U96F32 = U96F32::from_num(SubtensorModule::get_alpha_price(netuid));
2229+
assert_eq!(current_price, U96F32::from_num(1.5));
2230+
2231+
// Give it some $$$ in his coldkey balance
2232+
SubtensorModule::add_balance_to_coldkey_account(&coldkey, amount);
2233+
2234+
// Setup limit price so that it doesn't peak above 4x of current price
2235+
// The amount that can be executed at this price is 150 TAO only
2236+
// Alpha produced will be equal to 50 = 100 - 150*100/300
2237+
let limit_price = 6_000_000_000;
2238+
2239+
// Add stake limit call
2240+
let call = RuntimeCall::SubtensorModule(SubtensorCall::add_stake_limit {
2241+
hotkey,
2242+
netuid,
2243+
amount_staked: amount,
2244+
limit_price,
2245+
allow_partial: false,
2246+
});
2247+
2248+
let info: crate::DispatchInfo =
2249+
crate::DispatchInfoOf::<<Test as frame_system::Config>::RuntimeCall>::default();
2250+
2251+
let extension = crate::SubtensorSignedExtension::<Test>::new();
2252+
// Submit to the signed extension validate function
2253+
let result_no_stake = extension.validate(&coldkey, &call.clone(), &info, 10);
2254+
2255+
// Should fail due to slippage
2256+
assert_err!(
2257+
result_no_stake,
2258+
crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(
2259+
CustomTransactionError::SlippageTooHigh.into()
2260+
))
2261+
);
2262+
});
2263+
}
2264+
2265+
// cargo test --package pallet-subtensor --lib -- tests::staking::test_remove_stake_limit_validate --exact --show-output
2266+
#[test]
2267+
fn test_remove_stake_limit_validate() {
2268+
// Testing the signed extension validate function
2269+
// correctly filters the `add_stake` transaction.
2270+
2271+
new_test_ext(0).execute_with(|| {
2272+
let hotkey = U256::from(533453);
2273+
let coldkey = U256::from(55453);
2274+
let stake_amount = 300_000_000_000;
2275+
let unstake_amount = 150_000_000_000;
2276+
2277+
// add network
2278+
let netuid: u16 = add_dynamic_network(&hotkey, &coldkey);
2279+
2280+
// Give the neuron some stake to remove
2281+
SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
2282+
&hotkey,
2283+
&coldkey,
2284+
netuid,
2285+
stake_amount,
2286+
);
2287+
2288+
// Forse-set alpha in and tao reserve to make price equal 1.5
2289+
let tao_reserve: U96F32 = U96F32::from_num(150_000_000_000_u64);
2290+
let alpha_in: U96F32 = U96F32::from_num(100_000_000_000_u64);
2291+
SubnetTAO::<Test>::insert(netuid, tao_reserve.to_num::<u64>());
2292+
SubnetAlphaIn::<Test>::insert(netuid, alpha_in.to_num::<u64>());
2293+
let current_price: U96F32 = U96F32::from_num(SubtensorModule::get_alpha_price(netuid));
2294+
assert_eq!(current_price, U96F32::from_num(1.5));
2295+
2296+
// Setup limit price so that it doesn't drop by more than 10% from current price
2297+
let limit_price = 1_350_000_000;
2298+
2299+
// Remove stake limit call
2300+
let call = RuntimeCall::SubtensorModule(SubtensorCall::remove_stake_limit {
2301+
hotkey,
2302+
netuid,
2303+
amount_unstaked: unstake_amount,
2304+
limit_price,
2305+
allow_partial: false,
2306+
});
2307+
2308+
let info: crate::DispatchInfo =
2309+
crate::DispatchInfoOf::<<Test as frame_system::Config>::RuntimeCall>::default();
2310+
2311+
let extension = crate::SubtensorSignedExtension::<Test>::new();
2312+
// Submit to the signed extension validate function
2313+
let result_no_stake = extension.validate(&coldkey, &call.clone(), &info, 10);
2314+
2315+
// Should fail due to slippage
2316+
assert_err!(
2317+
result_no_stake,
2318+
crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom(
2319+
CustomTransactionError::SlippageTooHigh.into()
2320+
))
2321+
);
2322+
});
2323+
}
2324+
22092325
#[test]
22102326
fn test_stake_overflow() {
22112327
new_test_ext(1).execute_with(|| {

0 commit comments

Comments
 (0)