@@ -24,8 +24,7 @@ use frame_system::pallet_prelude::*;
2424use sp_core:: blake2_256;
2525use sp_runtime:: { Percent , traits:: TrailingZeroInput } ;
2626use substrate_fixed:: types:: U64F64 ;
27- use subtensor_runtime_common:: { AlphaCurrency , NetUid , TaoCurrency } ;
28- use subtensor_swap_interface:: SwapHandler ;
27+ use subtensor_runtime_common:: { AlphaCurrency , NetUid } ;
2928
3029pub type LeaseId = u32 ;
3130
@@ -130,6 +129,9 @@ impl<T: Config> Pallet<T> {
130129 ) ;
131130 SubnetUidToLeaseId :: < T > :: insert ( netuid, lease_id) ;
132131
132+ // The lease take should be 0% to allow all contributors to receive dividends entirely.
133+ Self :: delegate_hotkey ( & lease_hotkey, 0 ) ;
134+
133135 // Get all the contributions to the crowdloan except for the beneficiary
134136 // because its share will be computed as the dividends are distributed
135137 let contributions = pallet_crowdloan:: Contributions :: < T > :: iter_prefix ( crowdloan_id)
@@ -249,9 +251,8 @@ impl<T: Config> Pallet<T> {
249251
250252 /// Hook used when the subnet owner's cut is distributed to split the amount into dividends
251253 /// for the contributors and the beneficiary in shares relative to their initial contributions.
252- ///
253- /// It will ensure the subnet has enough alpha in its liquidity pool before swapping it to tao to be distributed,
254- /// and if not enough liquidity is available, it will accumulate the dividends for later distribution.
254+ /// It accumulates dividends to be distributed later when the interval for distribution is reached.
255+ /// Distribution is made in alpha and stake to the contributor coldkey and lease hotkey.
255256 pub fn distribute_leased_network_dividends ( lease_id : LeaseId , owner_cut_alpha : AlphaCurrency ) {
256257 // Ensure the lease exists
257258 let Some ( lease) = SubnetLeases :: < T > :: get ( lease_id) else {
@@ -290,55 +291,48 @@ impl<T: Config> Pallet<T> {
290291 return ;
291292 }
292293
293- // Ensure there is enough liquidity to unstake the contributors cut
294- if let Err ( err) = Self :: validate_remove_stake (
295- & lease. coldkey ,
296- & lease. hotkey ,
297- lease. netuid ,
298- total_contributors_cut_alpha,
299- total_contributors_cut_alpha,
300- false ,
301- ) {
302- log:: debug!( "Couldn't distributing dividends for lease {lease_id}: {err:?}" ) ;
303- AccumulatedLeaseDividends :: < T > :: set ( lease_id, total_contributors_cut_alpha) ;
304- return ;
305- }
306-
307- // Unstake the contributors cut from the subnet as tao to the lease coldkey
308- let tao_unstaked = match Self :: unstake_from_subnet (
309- & lease. hotkey ,
310- & lease. coldkey ,
311- lease. netuid ,
312- total_contributors_cut_alpha,
313- T :: SwapInterface :: min_price ( ) ,
314- false ,
315- ) {
316- Ok ( tao_unstaked) => tao_unstaked,
317- Err ( err) => {
318- log:: debug!( "Couldn't distributing dividends for lease {lease_id}: {err:?}" ) ;
319- AccumulatedLeaseDividends :: < T > :: set ( lease_id, total_contributors_cut_alpha) ;
320- return ;
294+ // We use a storage layer to ensure the distribution is atomic.
295+ if let Err ( err) = frame_support:: storage:: with_storage_layer ( || {
296+ let mut alpha_distributed = AlphaCurrency :: ZERO ;
297+
298+ // Distribute the contributors cut to the contributors and accumulate the alpha
299+ // distributed so far to obtain how much alpha is left to distribute to the beneficiary
300+ for ( contributor, share) in SubnetLeaseShares :: < T > :: iter_prefix ( lease_id) {
301+ let alpha_for_contributor = share
302+ . saturating_mul ( U64F64 :: from ( total_contributors_cut_alpha. to_u64 ( ) ) )
303+ . ceil ( )
304+ . saturating_to_num :: < u64 > ( ) ;
305+ Self :: transfer_stake_within_subnet (
306+ & lease. coldkey ,
307+ & lease. hotkey ,
308+ & contributor,
309+ & lease. hotkey ,
310+ lease. netuid ,
311+ alpha_for_contributor. into ( ) ,
312+ ) ?;
313+ alpha_distributed = alpha_distributed. saturating_add ( alpha_for_contributor. into ( ) ) ;
321314 }
322- } ;
323315
324- // Distribute the contributors cut to the contributors and accumulate the tao
325- // distributed so far to obtain how much tao is left to distribute to the beneficiary
326- let mut tao_distributed = TaoCurrency :: ZERO ;
327- for ( contributor , share ) in SubnetLeaseShares :: < T > :: iter_prefix ( lease_id ) {
328- let tao_for_contributor = share
329- . saturating_mul ( U64F64 :: from ( tao_unstaked . to_u64 ( ) ) )
330- . floor ( )
331- . saturating_to_num :: < u64 > ( ) ;
332- Self :: add_balance_to_coldkey_account ( & contributor , tao_for_contributor ) ;
333- tao_distributed = tao_distributed . saturating_add ( tao_for_contributor . into ( ) ) ;
334- }
316+ // Distribute the leftover alpha to the beneficiary
317+ let beneficiary_cut_alpha =
318+ total_contributors_cut_alpha . saturating_sub ( alpha_distributed ) ;
319+ Self :: transfer_stake_within_subnet (
320+ & lease . coldkey ,
321+ & lease . hotkey ,
322+ & lease . beneficiary ,
323+ & lease . hotkey ,
324+ lease . netuid ,
325+ beneficiary_cut_alpha . into ( ) ,
326+ ) ? ;
335327
336- // Distribute the leftover tao to the beneficiary
337- let beneficiary_cut_tao = tao_unstaked. saturating_sub ( tao_distributed) ;
338- Self :: add_balance_to_coldkey_account ( & lease. beneficiary , beneficiary_cut_tao. into ( ) ) ;
328+ // Reset the accumulated dividends
329+ AccumulatedLeaseDividends :: < T > :: insert ( lease_id, AlphaCurrency :: ZERO ) ;
339330
340- // Reset the accumulated dividends
341- AccumulatedLeaseDividends :: < T > :: insert ( lease_id, AlphaCurrency :: ZERO ) ;
331+ Ok :: < ( ) , DispatchError > ( ( ) )
332+ } ) {
333+ log:: debug!( "Couldn't distributing dividends for lease {lease_id}: {err:?}" ) ;
334+ AccumulatedLeaseDividends :: < T > :: set ( lease_id, total_contributors_cut_alpha) ;
335+ } ;
342336 }
343337
344338 fn lease_coldkey ( lease_id : LeaseId ) -> Result < T :: AccountId , DispatchError > {
0 commit comments