Skip to content

Commit a207d0b

Browse files
authored
Merge pull request #2008 from opentensor/auto_stake
Auto stake
2 parents 14024fd + 3ae481e commit a207d0b

File tree

5 files changed

+137
-5
lines changed

5 files changed

+137
-5
lines changed

pallets/subtensor/src/coinbase/run_coinbase.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -510,11 +510,12 @@ impl<T: Config> Pallet<T> {
510510
);
511511
continue;
512512
}
513-
514-
// Increase stake for miner.
513+
let destination: T::AccountId;
514+
let owner: T::AccountId = Owner::<T>::get(&hotkey);
515+
destination = AutoStakeDestination::<T>::get(&owner).unwrap_or(hotkey.clone());
515516
Self::increase_stake_for_hotkey_and_coldkey_on_subnet(
516-
&hotkey.clone(),
517-
&Owner::<T>::get(hotkey.clone()),
517+
&destination,
518+
&owner,
518519
netuid,
519520
incentive,
520521
);

pallets/subtensor/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,6 +1083,9 @@ pub mod pallet {
10831083
#[pallet::storage] // --- MAP ( cold ) --> Vec<hot> | Returns the vector of hotkeys controlled by this coldkey.
10841084
pub type OwnedHotkeys<T: Config> =
10851085
StorageMap<_, Blake2_128Concat, T::AccountId, Vec<T::AccountId>, ValueQuery>;
1086+
#[pallet::storage] // --- MAP ( cold ) --> hot | Returns the hotkey a coldkey will autostake to with mining rewards.
1087+
pub type AutoStakeDestination<T: Config> =
1088+
StorageMap<_, Blake2_128Concat, T::AccountId, T::AccountId, OptionQuery>;
10861089

10871090
#[pallet::storage] // --- DMAP ( cold ) --> (block_expected, new_coldkey) | Maps coldkey to the block to swap at and new coldkey.
10881091
pub type ColdkeySwapScheduled<T: Config> = StorageMap<

pallets/subtensor/src/macros/dispatches.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,7 @@ mod dispatches {
854854
/// Weight is calculated based on the number of database reads and writes.
855855
#[pallet::call_index(71)]
856856
#[pallet::weight((Weight::from_parts(161_700_000, 0)
857-
.saturating_add(T::DbWeight::get().reads(14))
857+
.saturating_add(T::DbWeight::get().reads(15_u64))
858858
.saturating_add(T::DbWeight::get().writes(9)), DispatchClass::Operational, Pays::No))]
859859
pub fn swap_coldkey(
860860
origin: OriginFor<T>,
@@ -2049,5 +2049,30 @@ mod dispatches {
20492049
commit_reveal_version,
20502050
)
20512051
}
2052+
2053+
/// Set the autostake destination hotkey for a coldkey.
2054+
///
2055+
/// The caller selects a hotkey where all future rewards
2056+
/// will be automatically staked.
2057+
///
2058+
/// # Args:
2059+
/// * `origin` - (<T as frame_system::Config>::Origin):
2060+
/// - The signature of the caller's coldkey.
2061+
///
2062+
/// * `hotkey` (T::AccountId):
2063+
/// - The hotkey account to designate as the autostake destination.
2064+
#[pallet::call_index(114)]
2065+
#[pallet::weight((Weight::from_parts(64_530_000, 0)
2066+
.saturating_add(T::DbWeight::get().reads(7_u64))
2067+
.saturating_add(T::DbWeight::get().writes(2)), DispatchClass::Normal, Pays::Yes))]
2068+
pub fn set_coldkey_auto_stake_hotkey(
2069+
origin: T::RuntimeOrigin,
2070+
hotkey: T::AccountId,
2071+
) -> DispatchResult {
2072+
let coldkey = ensure_signed(origin)?;
2073+
log::debug!("set_coldkey_auto_stake_hotkey( origin:{coldkey:?} hotkey:{hotkey:?} )");
2074+
AutoStakeDestination::<T>::insert(coldkey, hotkey.clone());
2075+
Ok(())
2076+
}
20522077
}
20532078
}

pallets/subtensor/src/swap/swap_coldkey.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,11 @@ impl<T: Config> Pallet<T> {
178178
weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2));
179179
}
180180

181+
if let Some(old_auto_stake_hotkey) = AutoStakeDestination::<T>::get(old_coldkey) {
182+
AutoStakeDestination::<T>::remove(old_coldkey);
183+
AutoStakeDestination::<T>::insert(new_coldkey, old_auto_stake_hotkey);
184+
}
185+
181186
// 4. Swap TotalColdkeyAlpha (DEPRECATED)
182187
// for netuid in Self::get_all_subnet_netuids() {
183188
// let old_alpha_stake: u64 = TotalColdkeyAlpha::<T>::get(old_coldkey, netuid);

pallets/subtensor/src/tests/coinbase.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2749,3 +2749,101 @@ fn test_coinbase_v3_liquidity_update() {
27492749
assert!(liquidity_before < liquidity_after);
27502750
});
27512751
}
2752+
2753+
#[test]
2754+
fn test_incentive_is_autostaked_to_owner_destination() {
2755+
new_test_ext(1).execute_with(|| {
2756+
let subnet_owner_ck = U256::from(0);
2757+
let subnet_owner_hk = U256::from(1);
2758+
2759+
let miner_ck = U256::from(10);
2760+
let miner_hk = U256::from(11);
2761+
let dest_hk = U256::from(12);
2762+
2763+
Owner::<Test>::insert(miner_hk, miner_ck);
2764+
Owner::<Test>::insert(dest_hk, miner_ck);
2765+
OwnedHotkeys::<Test>::insert(miner_ck, vec![miner_hk, dest_hk]);
2766+
2767+
let netuid = add_dynamic_network(&subnet_owner_hk, &subnet_owner_ck);
2768+
2769+
Uids::<Test>::insert(netuid, miner_hk, 1);
2770+
Uids::<Test>::insert(netuid, dest_hk, 2);
2771+
2772+
// Set autostake destination for the miner's coldkey
2773+
AutoStakeDestination::<Test>::insert(miner_ck, dest_hk);
2774+
2775+
assert_eq!(
2776+
SubtensorModule::get_stake_for_hotkey_on_subnet(&miner_hk, netuid),
2777+
0.into()
2778+
);
2779+
assert_eq!(
2780+
SubtensorModule::get_stake_for_hotkey_on_subnet(&dest_hk, netuid),
2781+
0.into()
2782+
);
2783+
2784+
// Distribute an incentive to the miner hotkey
2785+
let mut incentives: BTreeMap<U256, AlphaCurrency> = BTreeMap::new();
2786+
let incentive: AlphaCurrency = 10_000_000u64.into();
2787+
incentives.insert(miner_hk, incentive);
2788+
2789+
SubtensorModule::distribute_dividends_and_incentives(
2790+
netuid,
2791+
AlphaCurrency::ZERO, // owner_cut
2792+
incentives,
2793+
BTreeMap::new(), // alpha_dividends
2794+
BTreeMap::new(), // tao_dividends
2795+
);
2796+
2797+
// Expect the stake to land on the destination hotkey (not the original miner hotkey)
2798+
assert_eq!(
2799+
SubtensorModule::get_stake_for_hotkey_on_subnet(&miner_hk, netuid),
2800+
0.into()
2801+
);
2802+
assert_eq!(
2803+
SubtensorModule::get_stake_for_hotkey_on_subnet(&dest_hk, netuid),
2804+
incentive
2805+
);
2806+
});
2807+
}
2808+
2809+
#[test]
2810+
fn test_incentive_goes_to_hotkey_when_no_autostake_destination() {
2811+
new_test_ext(1).execute_with(|| {
2812+
let subnet_owner_ck = U256::from(0);
2813+
let subnet_owner_hk = U256::from(1);
2814+
2815+
let miner_ck = U256::from(20);
2816+
let miner_hk = U256::from(21);
2817+
2818+
Owner::<Test>::insert(miner_hk, miner_ck);
2819+
OwnedHotkeys::<Test>::insert(miner_ck, vec![miner_hk]);
2820+
2821+
let netuid = add_dynamic_network(&subnet_owner_hk, &subnet_owner_ck);
2822+
2823+
Uids::<Test>::insert(netuid, miner_hk, 1);
2824+
2825+
assert_eq!(
2826+
SubtensorModule::get_stake_for_hotkey_on_subnet(&miner_hk, netuid),
2827+
0.into()
2828+
);
2829+
2830+
// Distribute an incentive to the miner hotkey
2831+
let mut incentives: BTreeMap<U256, AlphaCurrency> = BTreeMap::new();
2832+
let incentive: AlphaCurrency = 5_000_000u64.into();
2833+
incentives.insert(miner_hk, incentive);
2834+
2835+
SubtensorModule::distribute_dividends_and_incentives(
2836+
netuid,
2837+
AlphaCurrency::ZERO, // owner_cut
2838+
incentives,
2839+
BTreeMap::new(), // alpha_dividends
2840+
BTreeMap::new(), // tao_dividends
2841+
);
2842+
2843+
// With no autostake destination, the incentive should be staked to the original hotkey
2844+
assert_eq!(
2845+
SubtensorModule::get_stake_for_hotkey_on_subnet(&miner_hk, netuid),
2846+
incentive
2847+
);
2848+
});
2849+
}

0 commit comments

Comments
 (0)