Skip to content

Commit f3ccdf9

Browse files
authored
Merge pull request #1423 from opentensor/feat/burn-recycle
Add burn/recycle alpha extrinsics
2 parents 4853519 + dbd4a3a commit f3ccdf9

File tree

9 files changed

+467
-1
lines changed

9 files changed

+467
-1
lines changed

pallets/subtensor/src/benchmarks.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,5 +594,68 @@ batch_reveal_weights {
594594
version_keys
595595
)
596596

597+
benchmark_recycle_alpha {
598+
let caller: T::AccountId = whitelisted_caller::<AccountIdOf<T>>();
599+
let caller_origin = <T as frame_system::Config>::RuntimeOrigin::from(RawOrigin::Signed(caller.clone()));
600+
let netuid: u16 = 1;
601+
let tempo: u16 = 1;
602+
let seed: u32 = 1;
603+
604+
// Set up coldkey and hotkey
605+
let coldkey: T::AccountId = account("Test", 0, seed);
606+
let hotkey: T::AccountId = account("Alice", 0, seed);
607+
608+
// Initialize network
609+
Subtensor::<T>::init_new_network(netuid, tempo);
610+
Subtensor::<T>::set_network_registration_allowed(netuid, true);
611+
612+
// Register the neuron
613+
Subtensor::<T>::set_burn(netuid, 1);
614+
let amount_to_be_staked = 1000000u32.into();
615+
Subtensor::<T>::add_balance_to_coldkey_account(&coldkey.clone(), amount_to_be_staked);
616+
617+
assert_ok!(Subtensor::<T>::do_burned_registration(RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone()));
618+
619+
// Add alpha to the hotkey
620+
let alpha_amount: u64 = 1000000;
621+
TotalHotkeyAlpha::<T>::insert(&hotkey, netuid, alpha_amount);
622+
SubnetAlphaOut::<T>::insert(netuid, alpha_amount * 2);
623+
624+
// Verify the alpha has been added
625+
assert_eq!(TotalHotkeyAlpha::<T>::get(&hotkey, netuid), alpha_amount);
626+
627+
}: recycle_alpha(RawOrigin::Signed(coldkey), hotkey, alpha_amount, netuid)
628+
629+
benchmark_burn_alpha {
630+
let caller: T::AccountId = whitelisted_caller::<AccountIdOf<T>>();
631+
let caller_origin = <T as frame_system::Config>::RuntimeOrigin::from(RawOrigin::Signed(caller.clone()));
632+
let netuid = 1;
633+
let tempo = 1;
634+
let seed = 1;
635+
636+
// Set up coldkey and hotkey
637+
let coldkey: T::AccountId = account("Test", 0, seed);
638+
let hotkey: T::AccountId = account("Alice", 0, seed);
639+
640+
// Initialize network
641+
Subtensor::<T>::init_new_network(netuid, tempo);
642+
Subtensor::<T>::set_network_registration_allowed(netuid, true);
643+
644+
// Register the neuron
645+
Subtensor::<T>::set_burn(netuid, 1);
646+
let amount_to_be_staked = 1000000u32.into();
647+
Subtensor::<T>::add_balance_to_coldkey_account(&coldkey.clone(), amount_to_be_staked);
648+
649+
assert_ok!(Subtensor::<T>::do_burned_registration(RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone()));
650+
651+
// Add alpha to the hotkey
652+
let alpha_amount: u64 = 1000000;
653+
TotalHotkeyAlpha::<T>::insert(&hotkey, netuid, alpha_amount);
654+
SubnetAlphaOut::<T>::insert(netuid, alpha_amount * 2);
655+
656+
// Verify the alpha has been added
657+
assert_eq!(TotalHotkeyAlpha::<T>::get(&hotkey, netuid), alpha_amount);
658+
659+
}: burn_alpha(RawOrigin::Signed(coldkey), hotkey, alpha_amount, netuid)
597660

598661
}

pallets/subtensor/src/macros/dispatches.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1909,5 +1909,55 @@ mod dispatches {
19091909

19101910
Ok(())
19111911
}
1912+
1913+
/// Recycles alpha from a cold/hot key pair, reducing AlphaOut on a subnet
1914+
///
1915+
/// # Arguments
1916+
/// * `origin` - The origin of the call (must be signed by the coldkey)
1917+
/// * `hotkey` - The hotkey account
1918+
/// * `amount` - The amount of alpha to recycle
1919+
/// * `netuid` - The subnet ID
1920+
///
1921+
/// # Events
1922+
/// Emits a `TokensRecycled` event on success.
1923+
#[pallet::call_index(101)]
1924+
#[pallet::weight((
1925+
Weight::from_parts(3_000_000, 0).saturating_add(T::DbWeight::get().reads_writes(3, 2)),
1926+
DispatchClass::Operational,
1927+
Pays::Yes
1928+
))]
1929+
pub fn recycle_alpha(
1930+
origin: T::RuntimeOrigin,
1931+
hotkey: T::AccountId,
1932+
amount: u64,
1933+
netuid: u16,
1934+
) -> DispatchResult {
1935+
Self::do_recycle_alpha(origin, hotkey, amount, netuid)
1936+
}
1937+
1938+
/// Burns alpha from a cold/hot key pair without reducing `AlphaOut`
1939+
///
1940+
/// # Arguments
1941+
/// * `origin` - The origin of the call (must be signed by the coldkey)
1942+
/// * `hotkey` - The hotkey account
1943+
/// * `amount` - The amount of alpha to burn
1944+
/// * `netuid` - The subnet ID
1945+
///
1946+
/// # Events
1947+
/// Emits a `TokensBurned` event on success.
1948+
#[pallet::call_index(102)]
1949+
#[pallet::weight((
1950+
Weight::from_parts(2_000_000, 0).saturating_add(T::DbWeight::get().reads_writes(2, 1)),
1951+
DispatchClass::Operational,
1952+
Pays::Yes
1953+
))]
1954+
pub fn burn_alpha(
1955+
origin: T::RuntimeOrigin,
1956+
hotkey: T::AccountId,
1957+
amount: u64,
1958+
netuid: u16,
1959+
) -> DispatchResult {
1960+
Self::do_burn_alpha(origin, hotkey, amount, netuid)
1961+
}
19121962
}
19131963
}

pallets/subtensor/src/macros/errors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,5 +195,7 @@ mod errors {
195195
ActivityCutoffTooLow,
196196
/// Call is disabled
197197
CallDisabled,
198+
/// Not enough AlphaOut on the subnet to recycle
199+
NotEnoughAlphaOutToRecycle,
198200
}
199201
}

pallets/subtensor/src/macros/events.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,5 +275,17 @@ mod events {
275275
/// Parameters:
276276
/// (netuid, new_hotkey)
277277
SubnetOwnerHotkeySet(u16, T::AccountId),
278+
279+
/// Alpha has been recycled, reducing AlphaOut on a subnet.
280+
///
281+
/// Parameters:
282+
/// (coldkey, hotkey, amount, subnet_id)
283+
AlphaRecycled(T::AccountId, T::AccountId, u64, u16),
284+
285+
/// Alpha have been burned without reducing AlphaOut.
286+
///
287+
/// Parameters:
288+
/// (coldkey, hotkey, amount, subnet_id)
289+
AlphaBurned(T::AccountId, T::AccountId, u64, u16),
278290
}
279291
}

pallets/subtensor/src/staking/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pub mod decrease_take;
55
pub mod helpers;
66
pub mod increase_take;
77
pub mod move_stake;
8+
pub mod recycle_alpha;
89
pub mod remove_stake;
910
pub mod set_children;
1011
pub mod stake_utils;
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
use super::*;
2+
use crate::{Error, system::ensure_signed};
3+
4+
impl<T: Config> Pallet<T> {
5+
/// Recycles alpha from a cold/hot key pair, reducing AlphaOut on a subnet
6+
///
7+
/// # Arguments
8+
///
9+
/// * `origin` - The origin of the call (must be signed by the coldkey)
10+
/// * `hotkey` - The hotkey account
11+
/// * `amount` - The amount of alpha to recycle
12+
/// * `netuid` - The subnet ID from which to reduce AlphaOut
13+
///
14+
/// # Returns
15+
///
16+
/// * `DispatchResult` - Success or error
17+
pub(crate) fn do_recycle_alpha(
18+
origin: T::RuntimeOrigin,
19+
hotkey: T::AccountId,
20+
amount: u64,
21+
netuid: u16,
22+
) -> DispatchResult {
23+
let coldkey = ensure_signed(origin)?;
24+
25+
ensure!(
26+
Self::if_subnet_exist(netuid),
27+
Error::<T>::SubNetworkDoesNotExist
28+
);
29+
30+
ensure!(
31+
Self::coldkey_owns_hotkey(&coldkey, &hotkey),
32+
Error::<T>::NonAssociatedColdKey
33+
);
34+
35+
ensure!(
36+
TotalHotkeyAlpha::<T>::get(&hotkey, netuid) >= amount,
37+
Error::<T>::NotEnoughStakeToWithdraw
38+
);
39+
40+
ensure!(
41+
SubnetAlphaOut::<T>::get(netuid) >= amount,
42+
Error::<T>::InsufficientLiquidity
43+
);
44+
45+
TotalHotkeyAlpha::<T>::mutate(&hotkey, netuid, |v| *v = v.saturating_sub(amount));
46+
SubnetAlphaOut::<T>::mutate(netuid, |total| {
47+
*total = total.saturating_sub(amount);
48+
});
49+
50+
Self::deposit_event(Event::AlphaRecycled(coldkey, hotkey, amount, netuid));
51+
52+
Ok(())
53+
}
54+
55+
/// Burns alpha from a cold/hot key pair without reducing AlphaOut
56+
///
57+
/// # Arguments
58+
///
59+
/// * `origin` - The origin of the call (must be signed by the coldkey)
60+
/// * `hotkey` - The hotkey account
61+
/// * `amount` - The "up to" amount of alpha to burn
62+
/// * `netuid` - The subnet ID
63+
///
64+
/// # Returns
65+
///
66+
/// * `DispatchResult` - Success or error
67+
pub(crate) fn do_burn_alpha(
68+
origin: T::RuntimeOrigin,
69+
hotkey: T::AccountId,
70+
amount: u64,
71+
netuid: u16,
72+
) -> DispatchResult {
73+
let coldkey = ensure_signed(origin)?;
74+
75+
ensure!(
76+
Self::if_subnet_exist(netuid),
77+
Error::<T>::SubNetworkDoesNotExist
78+
);
79+
80+
ensure!(
81+
Self::coldkey_owns_hotkey(&coldkey, &hotkey),
82+
Error::<T>::NonAssociatedColdKey
83+
);
84+
85+
ensure!(
86+
TotalHotkeyAlpha::<T>::get(&hotkey, netuid) >= amount,
87+
Error::<T>::NotEnoughStakeToWithdraw
88+
);
89+
90+
ensure!(
91+
SubnetAlphaOut::<T>::get(netuid) >= amount,
92+
Error::<T>::InsufficientLiquidity
93+
);
94+
95+
TotalHotkeyAlpha::<T>::mutate(&hotkey, netuid, |v| *v = v.saturating_sub(amount));
96+
97+
// Deposit event
98+
Self::deposit_event(Event::AlphaBurned(coldkey, hotkey, amount, netuid));
99+
100+
Ok(())
101+
}
102+
}

pallets/subtensor/src/tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod mock;
1111
mod move_stake;
1212
mod networks;
1313
mod neuron_info;
14+
mod recycle_alpha;
1415
mod registration;
1516
mod senate;
1617
mod serving;

0 commit comments

Comments
 (0)