Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
fbef78a
add stake before check validator_permit
May 20, 2025
52c149b
Merge branch 'master' into fix/roman/e2e_root_set_weights
basfroman May 20, 2025
a473b73
ruff
May 20, 2025
83c5133
Merge remote-tracking branch 'origin/fix/roman/e2e_root_set_weights' …
May 20, 2025
4112a85
Merge pull request #2884 from opentensor/fix/roman/e2e_root_set_weights
basfroman May 20, 2025
9649cc5
improve `add_stake_extrinsic` (avoid Balance warnings)
May 20, 2025
688e2d7
improve `unstake_extrinsic`, `unstake_multiple_extrinsic` (add `unsta…
May 20, 2025
33a32e7
update calls in subtensors
May 20, 2025
5feede0
fix unit tests
May 20, 2025
7177985
improve docstrings, fix private function usage
May 20, 2025
ff6fe2e
fix one more unit test
May 20, 2025
343cf4c
add defaults from local env
May 20, 2025
b28d153
replace network
May 20, 2025
671a570
Merge pull request #2886 from opentensor/feat/roman/add-local-env-for…
basfroman May 20, 2025
d2dde76
Merge branch 'staging' into feat/roman/staking-unstaking-issue
basfroman May 20, 2025
f5a659f
improve error message
May 21, 2025
b997985
fix tests
May 21, 2025
10872b5
dynamic link in test
May 21, 2025
d4c8a16
oops
May 21, 2025
2937152
Merge pull request #2888 from opentensor/feat/roman/improve-error-mes…
basfroman May 21, 2025
dccc84f
Merge branch 'staging' into feat/roman/staking-unstaking-issue
basfroman May 21, 2025
6c6689c
Merge pull request #2885 from opentensor/feat/roman/staking-unstaking…
basfroman May 21, 2025
5a799c1
sign_with="hotkey" to `publish_metadata`
May 21, 2025
f82317f
improve unit test
May 21, 2025
655524d
Merge pull request #2890 from opentensor/fix/roman/fix-publish-metadata
basfroman May 21, 2025
75aaa92
bumps version and changelog
ibraheem-abe May 22, 2025
fb51b48
Merge pull request #2891 from opentensor/changelog/962
ibraheem-abe May 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
# Changelog

## 9.5.0 /2025-05-15
## 9.6.1 /2025-05-22

## What's Changed
* Release/9.6.0 by @ibraheem-abe in https://github.com/opentensor/bittensor/pull/2882
* Add stake before check `validator_permit` by @basfroman in https://github.com/opentensor/bittensor/pull/2884
* Add defaults for endpoint and network from local env by @basfroman in https://github.com/opentensor/bittensor/pull/2886
* Improve error message by @basfroman in https://github.com/opentensor/bittensor/pull/2888
* Make `unstake` and `unstake_multiple` for all Alphas more clear by @basfroman in https://github.com/opentensor/bittensor/pull/2885
* fix publish metadata by @basfroman in https://github.com/opentensor/bittensor/pull/2890

**Full Changelog**: https://github.com/opentensor/bittensor/compare/v9.6.0...v9.6.1

## 9.6.0 /2025-05-15

* Add manual way to show the size of virtual environments in the PR by @basfroman in https://github.com/opentensor/bittensor/pull/2875
* Improve `Monitor SDK Requirements Size` workflow by @basfroman in https://github.com/opentensor/bittensor/pull/2878
Expand Down
47 changes: 28 additions & 19 deletions bittensor/core/async_subtensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3119,6 +3119,9 @@ async def wait_for_block(self, block: Optional[int] = None):
bool: True if the target block was reached, False if timeout occurred.

Example:
import bittensor as bt
subtensor = bt.Subtensor()

await subtensor.wait_for_block() # Waits for next block
await subtensor.wait_for_block(block=1234) # Waits for a specific block
"""
Expand Down Expand Up @@ -3380,27 +3383,27 @@ async def add_stake(
period: Optional[int] = None,
) -> bool:
"""
Adds the specified amount of stake to a neuron identified by the hotkey ``SS58`` address.
Staking is a fundamental process in the Bittensor network that enables neurons to participate actively and earn
incentives.
Adds a stake from the specified wallet to the neuron identified by the SS58 address of its hotkey in specified subnet.
Staking is a fundamental process in the Bittensor network that enables neurons to participate actively and earn incentives.

Args:
wallet (bittensor_wallet.Wallet): The wallet to be used for staking.
hotkey_ss58 (Optional[str]): The ``SS58`` address of the hotkey associated with the neuron.
netuid: subnet UID
amount (Balance): The amount of TAO to stake.
wait_for_inclusion (bool): Waits for the transaction to be included in a block.
wait_for_finalization (bool): Waits for the transaction to be finalized on the blockchain.
safe_staking (bool): If true, enables price safety checks to protect against fluctuating prices. The stake
will only execute if the price change doesn't exceed the rate tolerance. Default is False.
allow_partial_stake (bool): If true and safe_staking is enabled, allows partial staking when
the full amount would exceed the price threshold. If false, the entire stake fails if it would
exceed the threshold. Default is False.
rate_tolerance (float): The maximum allowed price change ratio when staking. For example,
0.005 = 0.5% maximum price increase. Only used when safe_staking is True. Default is 0.005.
period (Optional[int]): The number of blocks during which the transaction will remain valid after it's
submitted. If the transaction is not included in a block within that number of blocks, it will expire
and be rejected. You can think of it as an expiration date for the transaction.
wallet: The wallet to be used for staking.
hotkey_ss58: The SS58 address of the hotkey associated with the neuron to which you intend to delegate your
stake. If not specified, the wallet's hotkey will be used. Defaults to ``None``.
netuid: The unique identifier of the subnet to which the neuron belongs.
amount: The amount of TAO to stake.
wait_for_inclusion: Waits for the transaction to be included in a block. Defaults to ``True``.
wait_for_finalization: Waits for the transaction to be finalized on the blockchain. Defaults to ``False``.
safe_staking: If true, enables price safety checks to protect against fluctuating prices. The stake will
only execute if the price change doesn't exceed the rate tolerance. Default is ``False``.
allow_partial_stake: If true and safe_staking is enabled, allows partial staking when the full amount would
exceed the price tolerance. If false, the entire stake fails if it would exceed the tolerance.
Default is ``False``.
rate_tolerance: The maximum allowed price change ratio when staking. For example,
0.005 = 0.5% maximum price increase. Only used when safe_staking is True. Default is ``0.005``.
period: The number of blocks during which the transaction will remain valid after it's submitted. If the
transaction is not included in a block within that number of blocks, it will expire and be rejected. You
can think of it as an expiration date for the transaction. Defaults to ``None``.

Returns:
bool: ``True`` if the staking is successful, False otherwise.
Expand Down Expand Up @@ -4428,6 +4431,7 @@ async def unstake(
allow_partial_stake: bool = False,
rate_tolerance: float = 0.005,
period: Optional[int] = None,
unstake_all: bool = False,
) -> bool:
"""
Removes a specified amount of stake from a single hotkey account. This function is critical for adjusting
Expand All @@ -4451,6 +4455,7 @@ async def unstake(
period (Optional[int]): The number of blocks during which the transaction will remain valid after it's submitted. If
the transaction is not included in a block within that number of blocks, it will expire and be rejected.
You can think of it as an expiration date for the transaction.
unstake_all: If true, unstakes all tokens. Default is ``False``. If `True` amount is ignored.

Returns:
bool: ``True`` if the unstaking process is successful, False otherwise.
Expand All @@ -4471,6 +4476,7 @@ async def unstake(
allow_partial_stake=allow_partial_stake,
rate_tolerance=rate_tolerance,
period=period,
unstake_all=unstake_all,
)

async def unstake_multiple(
Expand All @@ -4482,6 +4488,7 @@ async def unstake_multiple(
wait_for_inclusion: bool = True,
wait_for_finalization: bool = False,
period: Optional[int] = None,
unstake_all: bool = False,
) -> bool:
"""
Performs batch unstaking from multiple hotkey accounts, allowing a neuron to reduce its staked amounts
Expand All @@ -4499,6 +4506,7 @@ async def unstake_multiple(
period (Optional[int]): The number of blocks during which the transaction will remain valid after it's submitted. If
the transaction is not included in a block within that number of blocks, it will expire and be rejected.
You can think of it as an expiration date for the transaction.
unstake_all: If true, unstakes all tokens. Default is ``False``. If `True` amounts are ignored.

Returns:
bool: ``True`` if the batch unstaking is successful, False otherwise.
Expand All @@ -4515,6 +4523,7 @@ async def unstake_multiple(
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
period=period,
unstake_all=unstake_all,
)


Expand Down
1 change: 1 addition & 0 deletions bittensor/core/extrinsics/asyncex/serving.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ async def publish_metadata(
success, message = await subtensor.sign_and_send_extrinsic(
call=call,
wallet=wallet,
sign_with="hotkey",
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
period=period,
Expand Down
25 changes: 13 additions & 12 deletions bittensor/core/extrinsics/asyncex/staking.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,27 @@ async def add_stake_extrinsic(
period: Optional[int] = None,
) -> bool:
"""
Adds the specified amount of stake to passed hotkey `uid`.
Adds a stake from the specified wallet to the neuron identified by the SS58 address of its hotkey in specified subnet.
Staking is a fundamental process in the Bittensor network that enables neurons to participate actively and earn incentives.

Arguments:
subtensor: the initialized SubtensorInterface object to use
subtensor: Subtensor instance with the connection to the chain.
wallet: Bittensor wallet object.
old_balance: the balance prior to the staking
hotkey_ss58: The `ss58` address of the hotkey account to stake to defaults to the wallet's hotkey.
netuid: The netuid of the stake to be added
amount: Amount to stake as Bittensor balance, `None` if staking all.
hotkey_ss58: The `ss58` address of the hotkey account to stake to default to the wallet's hotkey. If not
specified, the wallet's hotkey will be used. Defaults to ``None``.
netuid: The unique identifier of the subnet to which the neuron belongs.
amount: Amount to stake as Bittensor balance in TAO always, `None` if staking all. Defaults is ``None``.
wait_for_inclusion: If set, waits for the extrinsic to enter a block before returning `True`, or returns
`False` if the extrinsic fails to enter the block within the timeout.
`False` if the extrinsic fails to enter the block within the timeout. Defaults to ``True``.
wait_for_finalization: If set, waits for the extrinsic to be finalized on the chain before returning `True`,
or returns `False` if the extrinsic fails to be finalized within the timeout.
safe_staking: If set, uses safe staking logic
allow_partial_stake: If set, allows partial stake
rate_tolerance: The rate tolerance for safe staking
or returns `False` if the extrinsic fails to be finalized within the timeout. Defaults to ``False``.
safe_staking: If True, enables price safety checks. Default is ``False``.
allow_partial_stake: If True, allows partial unstaking if price tolerance exceeded. Default is ``False``.
rate_tolerance: Maximum allowed price increase percentage (0.005 = 0.5%). Default is ``0.005``.
period: The number of blocks during which the transaction will remain valid after it's submitted. If
the transaction is not included in a block within that number of blocks, it will expire and be rejected.
You can think of it as an expiration date for the transaction.
You can think of it as an expiration date for the transaction. Defaults to ``None``.

Returns:
success: Flag is `True` if extrinsic was finalized or included in the block. If we did not wait for
Expand Down Expand Up @@ -93,7 +95,6 @@ async def add_stake_extrinsic(
)
else:
staking_balance = amount
staking_balance.set_unit(netuid)

# Leave existential balance to keep key alive.
if staking_balance > old_balance - existential_deposit:
Expand Down
10 changes: 10 additions & 0 deletions bittensor/core/extrinsics/asyncex/unstaking.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ async def unstake_extrinsic(
allow_partial_stake: bool = False,
rate_tolerance: float = 0.005,
period: Optional[int] = None,
unstake_all: bool = False,
) -> bool:
"""Removes stake into the wallet coldkey from the specified hotkey ``uid``.

Expand All @@ -45,11 +46,15 @@ async def unstake_extrinsic(
period (Optional[int]): The number of blocks during which the transaction will remain valid after it's submitted.
If the transaction is not included in a block within that number of blocks, it will expire and be rejected.
You can think of it as an expiration date for the transaction.
unstake_all: If true, unstakes all tokens. Default is ``False``.

Returns:
success (bool): Flag is ``True`` if extrinsic was finalized or included in the block. If we did not wait for
finalization / inclusion, the response is ``True``.
"""
if amount and unstake_all:
raise ValueError("Cannot specify both `amount` and `unstake_all`.")

# Decrypt keys,
if not (unlock := unlock_key(wallet)).success:
logging.error(unlock.message)
Expand Down Expand Up @@ -204,6 +209,7 @@ async def unstake_multiple_extrinsic(
wait_for_inclusion: bool = True,
wait_for_finalization: bool = False,
period: Optional[int] = None,
unstake_all: bool = False,
) -> bool:
"""Removes stake from each ``hotkey_ss58`` in the list, using each amount, to a common coldkey.

Expand All @@ -220,11 +226,15 @@ async def unstake_multiple_extrinsic(
period (Optional[int]): The number of blocks during which the transaction will remain valid after it's submitted.
If the transaction is not included in a block within that number of blocks, it will expire and be rejected.
You can think of it as an expiration date for the transaction.
unstake_all: If true, unstakes all tokens. Default is ``False``.

Returns:
success (bool): Flag is ``True`` if extrinsic was finalized or included in the block. Flag is ``True`` if any
wallet was unstaked. If we did not wait for finalization / inclusion, the response is ``True``.
"""
if amounts and unstake_all:
raise ValueError("Cannot specify both `amounts` and `unstake_all`.")

if not isinstance(hotkey_ss58s, list) or not all(
isinstance(hotkey_ss58, str) for hotkey_ss58 in hotkey_ss58s
):
Expand Down
1 change: 1 addition & 0 deletions bittensor/core/extrinsics/serving.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ def publish_metadata(
success, message = subtensor.sign_and_send_extrinsic(
call=call,
wallet=wallet,
sign_with="hotkey",
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
period=period,
Expand Down
29 changes: 14 additions & 15 deletions bittensor/core/extrinsics/staking.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,26 @@ def add_stake_extrinsic(
period: Optional[int] = None,
) -> bool:
"""
Adds the specified amount of stake to passed hotkey `uid`.
Adds a stake from the specified wallet to the neuron identified by the SS58 address of its hotkey in specified subnet.
Staking is a fundamental process in the Bittensor network that enables neurons to participate actively and earn incentives.

Arguments:
subtensor: the Subtensor object to use
subtensor: Subtensor instance with the connection to the chain.
wallet: Bittensor wallet object.
hotkey_ss58: The `ss58` address of the hotkey account to stake to default to the wallet's hotkey.
netuid (Optional[int]): Subnet unique ID.
amount: Amount to stake as Bittensor balance, `None` if staking all.
hotkey_ss58: The `ss58` address of the hotkey account to stake to default to the wallet's hotkey. If not
specified, the wallet's hotkey will be used. Defaults to ``None``.
netuid: The unique identifier of the subnet to which the neuron belongs.
amount: Amount to stake as Bittensor balance in TAO always, `None` if staking all. Defaults is ``None``.
wait_for_inclusion: If set, waits for the extrinsic to enter a block before returning `True`, or returns
`False` if the extrinsic fails to enter the block within the timeout.
`False` if the extrinsic fails to enter the block within the timeout. Defaults to ``True``.
wait_for_finalization: If set, waits for the extrinsic to be finalized on the chain before returning `True`,
or returns `False` if the extrinsic fails to be finalized within the timeout.
safe_staking (bool): If true, enables price safety checks
allow_partial_stake (bool): If true, allows partial unstaking if price tolerance exceeded
rate_tolerance (float): Maximum allowed price increase percentage (0.005 = 0.5%)
or returns `False` if the extrinsic fails to be finalized within the timeout. Defaults to ``False``.
safe_staking: If True, enables price safety checks. Default is ``False``.
allow_partial_stake: If True, allows partial unstaking if price tolerance exceeded. Default is ``False``.
rate_tolerance: Maximum allowed price increase percentage (0.005 = 0.5%). Default is ``0.005``.
period: The number of blocks during which the transaction will remain valid after it's submitted. If
the transaction is not included in a block within that number of blocks, it will expire and be rejected.
You can think of it as an expiration date for the transaction.
You can think of it as an expiration date for the transaction. Defaults to ``None``.

Returns:
success: Flag is `True` if extrinsic was finalized or included in the block. If we did not wait for
Expand Down Expand Up @@ -87,14 +89,11 @@ def add_stake_extrinsic(
)
else:
staking_balance = amount
staking_balance.set_unit(netuid)

# Leave existential balance to keep key alive.
if staking_balance > old_balance - existential_deposit:
# If we are staking all, we need to leave at least the existential deposit.
staking_balance = old_balance - existential_deposit
else:
staking_balance = staking_balance

# Check enough to stake.
if staking_balance > old_balance:
Expand Down Expand Up @@ -200,7 +199,7 @@ def add_stake_extrinsic(

except SubstrateRequestException as error:
logging.error(
f":cross_mark: [red]Add Stake Error: {format_error_message((error))}[/red]"
f":cross_mark: [red]Add Stake Error: {format_error_message(error)}[/red]"
)
return False

Expand Down
9 changes: 9 additions & 0 deletions bittensor/core/extrinsics/unstaking.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def unstake_extrinsic(
allow_partial_stake: bool = False,
rate_tolerance: float = 0.005,
period: Optional[int] = None,
unstake_all: bool = False,
) -> bool:
"""Removes stake into the wallet coldkey from the specified hotkey ``uid``.

Expand All @@ -44,11 +45,15 @@ def unstake_extrinsic(
period (Optional[int]): The number of blocks during which the transaction will remain valid after it's submitted.
If the transaction is not included in a block within that number of blocks, it will expire and be rejected.
You can think of it as an expiration date for the transaction.
unstake_all: If true, unstakes all tokens. Default is ``False``.

Returns:
success (bool): Flag is ``True`` if extrinsic was finalized or included in the block. If we did not wait for
finalization / inclusion, the response is ``True``.
"""
if amount and unstake_all:
raise ValueError("Cannot specify both `amount` and `unstake_all`.")

# Decrypt keys,
if not (unlock := unlock_key(wallet)).success:
logging.error(unlock.message)
Expand Down Expand Up @@ -201,6 +206,7 @@ def unstake_multiple_extrinsic(
wait_for_inclusion: bool = True,
wait_for_finalization: bool = False,
period: Optional[int] = None,
unstake_all: bool = False,
) -> bool:
"""Removes stake from each ``hotkey_ss58`` in the list, using each amount, to a common coldkey.

Expand All @@ -217,11 +223,14 @@ def unstake_multiple_extrinsic(
period (Optional[int]): The number of blocks during which the transaction will remain valid after it's submitted.
If the transaction is not included in a block within that number of blocks, it will expire and be rejected.
You can think of it as an expiration date for the transaction.
unstake_all: If true, unstakes all tokens. Default is ``False``.

Returns:
success (bool): Flag is ``True`` if extrinsic was finalized or included in the block. Flag is ``True`` if any
wallet was unstaked. If we did not wait for finalization / inclusion, the response is ``True``.
"""
if amounts and unstake_all:
raise ValueError("Cannot specify both `amounts` and `unstake_all`.")

if not isinstance(hotkey_ss58s, list) or not all(
isinstance(hotkey_ss58, str) for hotkey_ss58 in hotkey_ss58s
Expand Down
Loading
Loading