Skip to content

Commit fa5a388

Browse files
committed
Use resulting average price formula for add-remove limit stake
1 parent c4b1bf5 commit fa5a388

File tree

3 files changed

+162
-202
lines changed

3 files changed

+162
-202
lines changed

pallets/subtensor/src/staking/add_stake.rs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
use super::*;
2-
use safe_math::*;
32
use sp_core::Get;
4-
use substrate_fixed::types::U96F32;
53

64
impl<T: Config> Pallet<T> {
75
/// ---- The implementation for the extrinsic add_stake: Adds stake to a hotkey account.
@@ -174,34 +172,39 @@ impl<T: Config> Pallet<T> {
174172
if alpha_in == 0 {
175173
return 0;
176174
}
177-
let alpha_in_float: U96F32 = U96F32::saturating_from_num(alpha_in);
175+
let alpha_in_u128 = alpha_in as u128;
178176

179177
// Corner case: SubnetTAO is zero. Staking can't happen, so max amount is zero.
180178
let tao_reserve = SubnetTAO::<T>::get(netuid);
181179
if tao_reserve == 0 {
182180
return 0;
183181
}
184-
let tao_reserve_float: U96F32 = U96F32::saturating_from_num(tao_reserve);
182+
let tao_reserve_u128 = tao_reserve as u128;
185183

186184
// Corner case: limit_price < current_price (price cannot decrease with staking)
187-
let limit_price_float: U96F32 = U96F32::saturating_from_num(limit_price)
188-
.checked_div(U96F32::saturating_from_num(1_000_000_000))
189-
.unwrap_or(U96F32::saturating_from_num(0));
190-
if limit_price_float < Self::get_alpha_price(netuid) {
185+
let tao = 1_000_000_000_u128;
186+
let limit_price_u128 = limit_price as u128;
187+
if (limit_price_u128
188+
< Self::get_alpha_price(netuid)
189+
.saturating_to_num::<u128>()
190+
.saturating_mul(tao))
191+
|| (limit_price == 0u64)
192+
{
191193
return 0;
192194
}
193195

194-
// Main case: return SQRT(limit_price * SubnetTAO * SubnetAlphaIn) - SubnetTAO
195-
// This is the positive solution of quare equation for finding additional TAO from
196-
// limit_price.
197-
let zero: U96F32 = U96F32::saturating_from_num(0.0);
198-
let epsilon: U96F32 = U96F32::saturating_from_num(0.1);
199-
let sqrt: U96F32 =
200-
checked_sqrt(limit_price_float.saturating_mul(tao_reserve_float), epsilon)
201-
.unwrap_or(zero)
202-
.saturating_mul(checked_sqrt(alpha_in_float, epsilon).unwrap_or(zero));
203-
204-
sqrt.saturating_sub(U96F32::saturating_from_num(tao_reserve_float))
205-
.saturating_to_num::<u64>()
196+
// Main case: return limit_price * SubnetAlphaIn - SubnetTAO
197+
// Non overflowing calculation: limit_price * alpha_in <= u64::MAX * u64::MAX <= u128::MAX
198+
// May overflow result, then it will be capped at u64::MAX, which is OK because that matches balance u64 size.
199+
let result = limit_price_u128
200+
.saturating_mul(alpha_in_u128)
201+
.checked_div(tao)
202+
.unwrap_or(0)
203+
.saturating_sub(tao_reserve_u128);
204+
if result < u64::MAX as u128 {
205+
result as u64
206+
} else {
207+
u64::MAX
208+
}
206209
}
207210
}

pallets/subtensor/src/staking/remove_stake.rs

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
use super::*;
2-
use safe_math::*;
32
use sp_core::Get;
4-
use substrate_fixed::types::U96F32;
53

64
impl<T: Config> Pallet<T> {
75
/// ---- The implementation for the extrinsic remove_stake: Removes stake from a hotkey account and adds it onto a coldkey.
@@ -343,14 +341,14 @@ impl<T: Config> Pallet<T> {
343341
if alpha_in == 0 {
344342
return 0;
345343
}
346-
let alpha_in_float: U96F32 = U96F32::saturating_from_num(alpha_in);
344+
let alpha_in_u128 = alpha_in as u128;
347345

348346
// Corner case: SubnetTAO is zero. Staking can't happen, so max amount is zero.
349347
let tao_reserve = SubnetTAO::<T>::get(netuid);
350348
if tao_reserve == 0 {
351349
return 0;
352350
}
353-
let tao_reserve_float: U96F32 = U96F32::saturating_from_num(tao_reserve);
351+
let tao_reserve_u128 = tao_reserve as u128;
354352

355353
// Corner case: limit_price == 0 (because there's division by limit price)
356354
// => can sell all
@@ -359,25 +357,32 @@ impl<T: Config> Pallet<T> {
359357
}
360358

361359
// Corner case: limit_price >= current_price (price cannot increase with unstaking)
362-
let limit_price_float: U96F32 = U96F32::saturating_from_num(limit_price)
363-
.checked_div(U96F32::saturating_from_num(1_000_000_000))
364-
.unwrap_or(U96F32::saturating_from_num(0));
365-
if limit_price_float >= Self::get_alpha_price(netuid) {
360+
// No overflows: alpha_price * tao <= u64::MAX * u64::MAX
361+
// Alpha price is U96F32 size, but it is calculated as u64/u64, so it never uses all 96 bits.
362+
let limit_price_u128 = limit_price as u128;
363+
let tao = 1_000_000_000_u128;
364+
if limit_price_u128
365+
>= tao_reserve_u128
366+
.saturating_mul(tao)
367+
.checked_div(alpha_in_u128)
368+
.unwrap_or(0)
369+
{
366370
return 0;
367371
}
368372

369-
// Main case: return SQRT(SubnetTAO * SubnetAlphaIn / limit_price) - SubnetAlphaIn
370-
// This is the positive solution of quare equation for finding Alpha amount from
371-
// limit_price.
372-
let zero: U96F32 = U96F32::saturating_from_num(0.0);
373-
let epsilon: U96F32 = U96F32::saturating_from_num(0.1);
374-
let sqrt: U96F32 = checked_sqrt(tao_reserve_float, epsilon)
375-
.unwrap_or(zero)
376-
.saturating_mul(
377-
checked_sqrt(alpha_in_float.safe_div(limit_price_float), epsilon).unwrap_or(zero),
378-
);
379-
380-
sqrt.saturating_sub(U96F32::saturating_from_num(alpha_in_float))
381-
.saturating_to_num::<u64>()
373+
// Main case: SubnetTAO / limit_price - SubnetAlphaIn
374+
// Non overflowing calculation: tao_reserve * tao <= u64::MAX * u64::MAX <= u128::MAX
375+
// May overflow result, then it will be capped at u64::MAX, which is OK because that matches Alpha u64 size.
376+
let result = tao_reserve_u128
377+
.saturating_mul(tao)
378+
.checked_div(limit_price_u128)
379+
.unwrap_or(0)
380+
.saturating_sub(alpha_in_u128);
381+
382+
if result < u64::MAX as u128 {
383+
result as u64
384+
} else {
385+
u64::MAX
386+
}
382387
}
383388
}

0 commit comments

Comments
 (0)