Describe the bug
do_terminate_lease (pallets/subtensor/src/subnets/leasing.rs:197-252) transfers subnet ownership to the beneficiary but does not repatriate the alpha stake (and lock state) that has accumulated on the lease's derived coldkey throughout the lease. The lease coldkey is blake2_256("leasing/coldkey", lease_id) - a deterministic hash with no preimage. The beneficiary proxy is removed at line 235, and the proxy allowlist never permitted stake-extraction calls. After termination, no extrinsic can ever be dispatched with Signed(lease.coldkey), so every fixed-end lease termination permanently strands the residual owner-cut alpha plus all Lock / HotkeyLock entries.
To Reproduce
- Register a leased network with
emissions_share < Percent::from_percent(100) and a finite end_block (via pallet_crowdloan::finalize -> pallet_subtensor::register_leased_network).
- Let the chain run through one or more
LeaseDividendsDistributionInterval cycles so owner emissions accrue. Each epoch:
- After
end_block, the beneficiary signs terminate_lease(lease_id, hotkey).
- Read
AlphaV2((lease.hotkey, lease.coldkey, netuid)), Lock((lease.coldkey, netuid, lease.hotkey)), HotkeyLock(netuid, lease.hotkey), Owner(lease.hotkey), OwnedHotkeys(lease.coldkey), StakingHotkeys(lease.coldkey).
Observed: all six storage rows survive termination unchanged. Beneficiary attempts (remove_stake, unlock_stake, transfer_stake, move_stake) cannot reach lease.coldkey's alpha - origin mismatch with the storage key, and the beneficiary cannot sign as lease.coldkey. Funds are unreachable.
Expected behavior
Before dec_providers(&lease.coldkey), repatriate the residual alpha and lock state to the beneficiary. The invariant total_coldkey_alpha_on_subnet(&lease.coldkey, netuid) == 0 must hold after termination. Equivalently: no AlphaV2, Lock, HotkeyLock, Owner, OwnedHotkeys, or StakingHotkeys rows may reference lease.coldkey once the proxy is removed.
Screenshots
No response
Environment
opentensor/subtensor main @ 6844ee37f0b8cb02baf9ff8d3ca4319cfb33f361, testnet @ e6a5f56cefeb96b9c63ea3ce6553a8e1066aaeb9
Additional context
Affected code (pallets/subtensor/src/subnets/leasing.rs:197-252) - the function transfers SubnetOwner / SubnetOwnerHotkey to the beneficiary, calls dec_providers on lease.coldkey / lease.hotkey, clears SubnetLeaseShares / AccumulatedLeaseDividends / SubnetLeases, and removes the beneficiary proxy. It never iterates or modifies:
AlphaV2((lease.hotkey, lease.coldkey, netuid)) - accumulated owner-cut residual.
Lock((lease.coldkey, netuid, lease.hotkey)) - per-coldkey lock state.
HotkeyLock(netuid, lease.hotkey) - aggregate lock state.
Owner(lease.hotkey) = lease.coldkey - hotkey-coldkey ownership pointer.
OwnedHotkeys(lease.coldkey), StakingHotkeys(lease.coldkey) - index entries.
Why the lease coldkey is unspendable:
lease_coldkey(lease_id) = blake2_256(("leasing/coldkey", lease_id)) (leasing.rs:352-356). No private key, no preimage attack possible.
ProxyType::SubnetLeaseBeneficiary allowlist (runtime/src/lib.rs:758-815) contains only start_call and ~20 sudo_set_* parameter-tuning calls. remove_stake, unlock_stake, transfer_stake, move_stake, unstake_all_alpha, claim_root are not in the allowlist - even before do_terminate_lease removes the proxy at line 235, the beneficiary had no path to extract stake from lease.coldkey.
Impact
- Every fixed-end lease termination permanently forfeits the cumulative
(1 - emissions_share) share of owner emissions accrued during the lease, plus registration-time floor-rounded refund dust. For multi-month leases at typical emission rates, this is the dominant share of subnet-owner emissions whenever emissions_share < 100%.
- The forfeited alpha is backed by TAO held in
SubnetTAO, so the corresponding pool TAO is unredeemable.
lease.coldkey is dec_providers'd while still owning non-zero alpha - AlphaV2 row references a coldkey that may fail system::Account existence assumptions elsewhere.
- Secondary:
HotkeyLock(netuid, lease.hotkey) keeps influencing subnet_king (pallets/subtensor/src/staking/lock.rs:396-412); the terminated lease's hotkey can keep winning king elections.
- This is the intended happy path - no malicious actor required; every fixed-end lease is affected.
Describe the bug
do_terminate_lease(pallets/subtensor/src/subnets/leasing.rs:197-252) transfers subnet ownership to the beneficiary but does not repatriate the alpha stake (and lock state) that has accumulated on the lease's derived coldkey throughout the lease. The lease coldkey isblake2_256("leasing/coldkey", lease_id)- a deterministic hash with no preimage. The beneficiary proxy is removed at line 235, and the proxy allowlist never permitted stake-extraction calls. After termination, no extrinsic can ever be dispatched withSigned(lease.coldkey), so every fixed-end lease termination permanently strands the residual owner-cut alpha plus allLock/HotkeyLockentries.To Reproduce
emissions_share < Percent::from_percent(100)and a finiteend_block(viapallet_crowdloan::finalize->pallet_subtensor::register_leased_network).LeaseDividendsDistributionIntervalcycles so owner emissions accrue. Each epoch:distribute_dividends_and_incentivescredits the fullowner_cutto(lease.hotkey, lease.coldkey, netuid)(run_coinbase.rs:582-587).distribute_leased_network_dividendssweeps onlyemissions_share * owner_cutto contributors+beneficiary (leasing.rs:258-350); the(1 - emissions_share) * owner_cutportion stays on(lease.hotkey, lease.coldkey, netuid).auto_lock_owner_cutinstalls/growsLock((lease.coldkey, netuid, lease.hotkey))(run_coinbase.rs:594->pallets/subtensor/src/staking/lock.rs:597-613).end_block, the beneficiary signsterminate_lease(lease_id, hotkey).AlphaV2((lease.hotkey, lease.coldkey, netuid)),Lock((lease.coldkey, netuid, lease.hotkey)),HotkeyLock(netuid, lease.hotkey),Owner(lease.hotkey),OwnedHotkeys(lease.coldkey),StakingHotkeys(lease.coldkey).Observed: all six storage rows survive termination unchanged. Beneficiary attempts (
remove_stake,unlock_stake,transfer_stake,move_stake) cannot reachlease.coldkey's alpha - origin mismatch with the storage key, and the beneficiary cannot sign aslease.coldkey. Funds are unreachable.Expected behavior
Before
dec_providers(&lease.coldkey), repatriate the residual alpha and lock state to the beneficiary. The invarianttotal_coldkey_alpha_on_subnet(&lease.coldkey, netuid) == 0must hold after termination. Equivalently: noAlphaV2,Lock,HotkeyLock,Owner,OwnedHotkeys, orStakingHotkeysrows may referencelease.coldkeyonce the proxy is removed.Screenshots
No response
Environment
opentensor/subtensor
main@6844ee37f0b8cb02baf9ff8d3ca4319cfb33f361,testnet@e6a5f56cefeb96b9c63ea3ce6553a8e1066aaeb9Additional context
Affected code (
pallets/subtensor/src/subnets/leasing.rs:197-252) - the function transfersSubnetOwner/SubnetOwnerHotkeyto the beneficiary, callsdec_providersonlease.coldkey/lease.hotkey, clearsSubnetLeaseShares/AccumulatedLeaseDividends/SubnetLeases, and removes the beneficiary proxy. It never iterates or modifies:AlphaV2((lease.hotkey, lease.coldkey, netuid))- accumulated owner-cut residual.Lock((lease.coldkey, netuid, lease.hotkey))- per-coldkey lock state.HotkeyLock(netuid, lease.hotkey)- aggregate lock state.Owner(lease.hotkey) = lease.coldkey- hotkey-coldkey ownership pointer.OwnedHotkeys(lease.coldkey),StakingHotkeys(lease.coldkey)- index entries.Why the lease coldkey is unspendable:
lease_coldkey(lease_id) = blake2_256(("leasing/coldkey", lease_id))(leasing.rs:352-356). No private key, no preimage attack possible.ProxyType::SubnetLeaseBeneficiaryallowlist (runtime/src/lib.rs:758-815) contains onlystart_calland ~20sudo_set_*parameter-tuning calls.remove_stake,unlock_stake,transfer_stake,move_stake,unstake_all_alpha,claim_rootare not in the allowlist - even beforedo_terminate_leaseremoves the proxy at line 235, the beneficiary had no path to extract stake fromlease.coldkey.Impact
(1 - emissions_share)share of owner emissions accrued during the lease, plus registration-time floor-rounded refund dust. For multi-month leases at typical emission rates, this is the dominant share of subnet-owner emissions wheneveremissions_share < 100%.SubnetTAO, so the corresponding pool TAO is unredeemable.lease.coldkeyisdec_providers'd while still owning non-zero alpha -AlphaV2row references a coldkey that may failsystem::Accountexistence assumptions elsewhere.HotkeyLock(netuid, lease.hotkey)keeps influencingsubnet_king(pallets/subtensor/src/staking/lock.rs:396-412); the terminated lease's hotkey can keep winning king elections.