Skip to content

Commit 84d31f5

Browse files
authored
Merge pull request #578 from opentensor/release/9.10.0
Release/9.10.0
2 parents 31b77f1 + 6a7ea74 commit 84d31f5

File tree

21 files changed

+544
-179
lines changed

21 files changed

+544
-179
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# Changelog
22

3+
## 9.10.0 /2025-08-06
4+
* Sets default interval hours for subnets price to 4, bc of rate limiting. by @thewhaleking in https://github.com/opentensor/btcli/pull/568
5+
* Subnets Price --current + improvements by @thewhaleking in https://github.com/opentensor/btcli/pull/569
6+
* Reconfig Asyncio Runner by @thewhaleking in https://github.com/opentensor/btcli/pull/570
7+
* Show amount on `transfer --all` by @thewhaleking in https://github.com/opentensor/btcli/pull/571
8+
* Allows for typer>=0.16 and Click 8.2+ by @thewhaleking in https://github.com/opentensor/btcli/pull/572
9+
* BTCLI Config Updates by @thewhaleking in https://github.com/opentensor/btcli/pull/573
10+
* Added info about preinstalled macOS CPython by @thewhaleking in https://github.com/opentensor/btcli/pull/574
11+
* Click 8.2+/- compatibility by @thewhaleking in https://github.com/opentensor/btcli/pull/576
12+
* New command: `btcli w regen-hotkeypub` by @thewhaleking in https://github.com/opentensor/btcli/pull/575
13+
14+
**Full Changelog**: https://github.com/opentensor/btcli/compare/v9.9.0...v9.10.0
15+
316
## 9.9.0 /2025-07-28
417
* Feat/wallet verify by @ibraheem-abe in https://github.com/opentensor/btcli/pull/561
518
* Improved speed of query_all_identities and fetch_coldkey_hotkey_identities by @thewhaleking in https://github.com/opentensor/btcli/pull/560

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,15 @@ Installation steps are described below. For a full documentation on how to use `
3838

3939
## Install on macOS and Linux
4040

41-
You can install `btcli` on your local machine directly from source, PyPI, or Homebrew. **Make sure you verify your installation after you install**:
41+
You can install `btcli` on your local machine directly from source, PyPI, or Homebrew.
42+
**Make sure you verify your installation after you install**.
43+
44+
### For macOS users
45+
Note that the macOS preinstalled CPython installation is compiled with LibreSSL instead of OpenSSL. There are a number
46+
of issues with LibreSSL, and as such is not fully supported by the libraries used by btcli. Thus we highly recommend, if
47+
you are using a Mac, to first install Python from [Homebrew](https://brew.sh/). Additionally, the Rust FFI bindings
48+
[if installing from precompiled wheels (default)] require the Homebrew-installed OpenSSL pacakge. If you choose to use
49+
the preinstalled Python version from macOS, things may not work completely.
4250

4351

4452
### Install from [PyPI](https://pypi.org/project/bittensor/)

bittensor_cli/cli.py

Lines changed: 165 additions & 54 deletions
Large diffs are not rendered by default.

bittensor_cli/src/bittensor/extrinsics/registration.py

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
print_error,
4040
unlock_key,
4141
hex_to_bytes,
42+
get_hotkey_pub_ss58,
4243
)
4344

4445
if typing.TYPE_CHECKING:
@@ -490,7 +491,7 @@ async def register_extrinsic(
490491

491492
async def get_neuron_for_pubkey_and_subnet():
492493
uid = await subtensor.query(
493-
"SubtensorModule", "Uids", [netuid, wallet.hotkey.ss58_address]
494+
"SubtensorModule", "Uids", [netuid, get_hotkey_pub_ss58(wallet)]
494495
)
495496
if uid is None:
496497
return NeuronInfo.get_null_neuron()
@@ -525,7 +526,7 @@ async def get_neuron_for_pubkey_and_subnet():
525526
if not Confirm.ask(
526527
f"Continue Registration?\n"
527528
f" hotkey [{COLOR_PALETTE.G.HK}]({wallet.hotkey_str})[/{COLOR_PALETTE.G.HK}]:"
528-
f"\t[{COLOR_PALETTE.G.HK}]{wallet.hotkey.ss58_address}[/{COLOR_PALETTE.G.HK}]\n"
529+
f"\t[{COLOR_PALETTE.G.HK}]{get_hotkey_pub_ss58(wallet)}[/{COLOR_PALETTE.G.HK}]\n"
529530
f" coldkey [{COLOR_PALETTE.G.CK}]({wallet.name})[/{COLOR_PALETTE.G.CK}]:"
530531
f"\t[{COLOR_PALETTE.G.CK}]{wallet.coldkeypub.ss58_address}[/{COLOR_PALETTE.G.CK}]\n"
531532
f" network:\t\t[{COLOR_PALETTE.G.LINKS}]{subtensor.network}[/{COLOR_PALETTE.G.LINKS}]\n"
@@ -577,7 +578,7 @@ async def get_neuron_for_pubkey_and_subnet():
577578
if not pow_result:
578579
# might be registered already on this subnet
579580
is_registered = await is_hotkey_registered(
580-
subtensor, netuid=netuid, hotkey_ss58=wallet.hotkey.ss58_address
581+
subtensor, netuid=netuid, hotkey_ss58=get_hotkey_pub_ss58(wallet)
581582
)
582583
if is_registered:
583584
err_console.print(
@@ -598,7 +599,7 @@ async def get_neuron_for_pubkey_and_subnet():
598599
"block_number": pow_result.block_number,
599600
"nonce": pow_result.nonce,
600601
"work": [int(byte_) for byte_ in pow_result.seal],
601-
"hotkey": wallet.hotkey.ss58_address,
602+
"hotkey": get_hotkey_pub_ss58(wallet),
602603
"coldkey": wallet.coldkeypub.ss58_address,
603604
},
604605
)
@@ -639,7 +640,7 @@ async def get_neuron_for_pubkey_and_subnet():
639640
is_registered = await is_hotkey_registered(
640641
subtensor,
641642
netuid=netuid,
642-
hotkey_ss58=wallet.hotkey.ss58_address,
643+
hotkey_ss58=get_hotkey_pub_ss58(wallet),
643644
)
644645
if is_registered:
645646
console.print(
@@ -704,7 +705,7 @@ async def burned_register_extrinsic(
704705
spinner="aesthetic",
705706
) as status:
706707
my_uid = await subtensor.query(
707-
"SubtensorModule", "Uids", [netuid, wallet.hotkey.ss58_address]
708+
"SubtensorModule", "Uids", [netuid, get_hotkey_pub_ss58(wallet)]
708709
)
709710
block_hash = await subtensor.substrate.get_chain_head()
710711

@@ -751,7 +752,7 @@ async def burned_register_extrinsic(
751752
call_function="burned_register",
752753
call_params={
753754
"netuid": netuid,
754-
"hotkey": wallet.hotkey.ss58_address,
755+
"hotkey": get_hotkey_pub_ss58(wallet),
755756
},
756757
)
757758
success, err_msg = await subtensor.sign_and_send_extrinsic(
@@ -773,10 +774,10 @@ async def burned_register_extrinsic(
773774
reuse_block=False,
774775
),
775776
subtensor.get_netuids_for_hotkey(
776-
wallet.hotkey.ss58_address, block_hash=block_hash
777+
get_hotkey_pub_ss58(wallet), block_hash=block_hash
777778
),
778779
subtensor.query(
779-
"SubtensorModule", "Uids", [netuid, wallet.hotkey.ss58_address]
780+
"SubtensorModule", "Uids", [netuid, get_hotkey_pub_ss58(wallet)]
780781
),
781782
)
782783

@@ -1146,7 +1147,7 @@ async def _block_solver(
11461147

11471148
timeout = 0.15 if cuda else 0.15
11481149
while netuid == -1 or not await is_hotkey_registered(
1149-
subtensor, netuid, wallet.hotkey.ss58_address
1150+
subtensor, netuid, get_hotkey_pub_ss58(wallet)
11501151
):
11511152
# Wait until a solver finds a solution
11521153
try:
@@ -1755,37 +1756,39 @@ async def swap_hotkey_extrinsic(
17551756
:return: Success
17561757
"""
17571758
block_hash = await subtensor.substrate.get_chain_head()
1759+
hk_ss58 = get_hotkey_pub_ss58(wallet)
17581760
netuids_registered = await subtensor.get_netuids_for_hotkey(
1759-
wallet.hotkey.ss58_address, block_hash=block_hash
1761+
hk_ss58, block_hash=block_hash
17601762
)
17611763
netuids_registered_new_hotkey = await subtensor.get_netuids_for_hotkey(
1762-
new_wallet.hotkey.ss58_address, block_hash=block_hash
1764+
hk_ss58, block_hash=block_hash
17631765
)
17641766

17651767
if netuid is not None and netuid not in netuids_registered:
17661768
err_console.print(
1767-
f":cross_mark: [red]Failed[/red]: Original hotkey {wallet.hotkey.ss58_address} is not registered on subnet {netuid}"
1769+
f":cross_mark: [red]Failed[/red]: Original hotkey {hk_ss58} is not registered on subnet {netuid}"
17681770
)
17691771
return False
17701772

17711773
elif not len(netuids_registered) > 0:
17721774
err_console.print(
1773-
f"Original hotkey [dark_orange]{wallet.hotkey.ss58_address}[/dark_orange] is not registered on any subnet. "
1775+
f"Original hotkey [dark_orange]{hk_ss58}[/dark_orange] is not registered on any subnet. "
17741776
f"Please register and try again"
17751777
)
17761778
return False
17771779

1780+
new_hk_ss58 = get_hotkey_pub_ss58(new_wallet)
17781781
if netuid is not None:
17791782
if netuid in netuids_registered_new_hotkey:
17801783
err_console.print(
1781-
f":cross_mark: [red]Failed[/red]: New hotkey {new_wallet.hotkey.ss58_address} "
1784+
f":cross_mark: [red]Failed[/red]: New hotkey {new_hk_ss58} "
17821785
f"is already registered on subnet {netuid}"
17831786
)
17841787
return False
17851788
else:
17861789
if len(netuids_registered_new_hotkey) > 0:
17871790
err_console.print(
1788-
f":cross_mark: [red]Failed[/red]: New hotkey {new_wallet.hotkey.ss58_address} "
1791+
f":cross_mark: [red]Failed[/red]: New hotkey {new_hk_ss58} "
17891792
f"is already registered on subnet(s) {netuids_registered_new_hotkey}"
17901793
)
17911794
return False
@@ -1798,28 +1801,28 @@ async def swap_hotkey_extrinsic(
17981801
if netuid is not None:
17991802
confirm_message = (
18001803
f"Do you want to swap [dark_orange]{wallet.name}[/dark_orange] hotkey \n\t"
1801-
f"[dark_orange]{wallet.hotkey.ss58_address} ({wallet.hotkey_str})[/dark_orange] with hotkey \n\t"
1802-
f"[dark_orange]{new_wallet.hotkey.ss58_address} ({new_wallet.hotkey_str})[/dark_orange] on subnet {netuid}\n"
1804+
f"[dark_orange]{hk_ss58} ({wallet.hotkey_str})[/dark_orange] with hotkey \n\t"
1805+
f"[dark_orange]{new_hk_ss58} ({new_wallet.hotkey_str})[/dark_orange] on subnet {netuid}\n"
18031806
"This operation will cost [bold cyan]1 TAO (recycled)[/bold cyan]"
18041807
)
18051808
else:
18061809
confirm_message = (
18071810
f"Do you want to swap [dark_orange]{wallet.name}[/dark_orange] hotkey \n\t"
1808-
f"[dark_orange]{wallet.hotkey.ss58_address} ({wallet.hotkey_str})[/dark_orange] with hotkey \n\t"
1809-
f"[dark_orange]{new_wallet.hotkey.ss58_address} ({new_wallet.hotkey_str})[/dark_orange] on all subnets\n"
1811+
f"[dark_orange]{hk_ss58} ({wallet.hotkey_str})[/dark_orange] with hotkey \n\t"
1812+
f"[dark_orange]{new_hk_ss58} ({new_wallet.hotkey_str})[/dark_orange] on all subnets\n"
18101813
"This operation will cost [bold cyan]1 TAO (recycled)[/bold cyan]"
18111814
)
18121815

18131816
if not Confirm.ask(confirm_message):
18141817
return False
18151818
print_verbose(
1816-
f"Swapping {wallet.name}'s hotkey ({wallet.hotkey.ss58_address} - {wallet.hotkey_str}) with "
1817-
f"{new_wallet.name}'s hotkey ({new_wallet.hotkey.ss58_address} - {new_wallet.hotkey_str})"
1819+
f"Swapping {wallet.name}'s hotkey ({hk_ss58} - {wallet.hotkey_str}) with "
1820+
f"{new_wallet.name}'s hotkey ({new_hk_ss58} - {new_wallet.hotkey_str})"
18181821
)
18191822
with console.status(":satellite: Swapping hotkeys...", spinner="aesthetic"):
18201823
call_params = {
1821-
"hotkey": wallet.hotkey.ss58_address,
1822-
"new_hotkey": new_wallet.hotkey.ss58_address,
1824+
"hotkey": hk_ss58,
1825+
"new_hotkey": new_hk_ss58,
18231826
"netuid": netuid,
18241827
}
18251828

@@ -1832,7 +1835,8 @@ async def swap_hotkey_extrinsic(
18321835

18331836
if success:
18341837
console.print(
1835-
f"Hotkey {wallet.hotkey.ss58_address} ({wallet.hotkey_str}) swapped for new hotkey: {new_wallet.hotkey.ss58_address} ({new_wallet.hotkey_str})"
1838+
f"Hotkey {hk_ss58} ({wallet.hotkey_str}) swapped for new hotkey: "
1839+
f"{new_hk_ss58} ({new_wallet.hotkey_str})"
18361840
)
18371841
return True
18381842
else:

bittensor_cli/src/bittensor/extrinsics/root.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
print_verbose,
3838
format_error_message,
3939
unlock_key,
40+
get_hotkey_pub_ss58,
4041
)
4142

4243
if TYPE_CHECKING:
@@ -310,7 +311,7 @@ async def root_register_extrinsic(
310311

311312
print_verbose(f"Checking if hotkey ({wallet.hotkey_str}) is registered on root")
312313
is_registered = await is_hotkey_registered(
313-
subtensor, netuid=0, hotkey_ss58=wallet.hotkey.ss58_address
314+
subtensor, netuid=0, hotkey_ss58=get_hotkey_pub_ss58(wallet)
314315
)
315316
if is_registered:
316317
console.print(
@@ -322,7 +323,7 @@ async def root_register_extrinsic(
322323
call = await subtensor.substrate.compose_call(
323324
call_module="SubtensorModule",
324325
call_function="root_register",
325-
call_params={"hotkey": wallet.hotkey.ss58_address},
326+
call_params={"hotkey": get_hotkey_pub_ss58(wallet)},
326327
)
327328
success, err_msg = await subtensor.sign_and_send_extrinsic(
328329
call,
@@ -341,7 +342,7 @@ async def root_register_extrinsic(
341342
uid = await subtensor.query(
342343
module="SubtensorModule",
343344
storage_function="Uids",
344-
params=[0, wallet.hotkey.ss58_address],
345+
params=[0, get_hotkey_pub_ss58(wallet)],
345346
)
346347
if uid is not None:
347348
console.print(
@@ -391,7 +392,7 @@ async def _do_set_weights():
391392
"weights": weight_vals,
392393
"netuid": 0,
393394
"version_key": version_key,
394-
"hotkey": wallet.hotkey.ss58_address,
395+
"hotkey": get_hotkey_pub_ss58(wallet),
395396
},
396397
)
397398
# Period dictates how long the extrinsic will stay as part of waiting pool
@@ -415,7 +416,7 @@ async def _do_set_weights():
415416
return False, await response.error_message
416417

417418
my_uid = await subtensor.query(
418-
"SubtensorModule", "Uids", [0, wallet.hotkey.ss58_address]
419+
"SubtensorModule", "Uids", [0, get_hotkey_pub_ss58(wallet)]
419420
)
420421

421422
if my_uid is None:

bittensor_cli/src/bittensor/extrinsics/transfer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ async def do_transfer() -> tuple[bool, str, str]:
172172
if prompt:
173173
if not Confirm.ask(
174174
"Do you want to transfer:[bold white]\n"
175-
f" amount: [bright_cyan]{amount}[/bright_cyan]\n"
175+
f" amount: [bright_cyan]{amount if not transfer_all else account_balance}[/bright_cyan]\n"
176176
f" from: [light_goldenrod2]{wallet.name}[/light_goldenrod2] : "
177177
f"[bright_magenta]{wallet.coldkey.ss58_address}\n[/bright_magenta]"
178178
f" to: [bright_magenta]{destination}[/bright_magenta]\n for fee: [bright_cyan]{fee}[/bright_cyan]"

bittensor_cli/src/bittensor/subtensor_interface.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
validate_chain_endpoint,
4040
u16_normalized_float,
4141
U16_MAX,
42+
get_hotkey_pub_ss58,
4243
)
4344

4445
SubstrateClass = (
@@ -666,7 +667,7 @@ async def filter_netuids_by_registered_hotkeys(
666667
for sublist in await asyncio.gather(
667668
*[
668669
self.get_netuids_for_hotkey(
669-
wallet.hotkey.ss58_address,
670+
get_hotkey_pub_ss58(wallet),
670671
reuse_block=reuse_block,
671672
block_hash=block_hash,
672673
)

bittensor_cli/src/bittensor/utils.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ def get_hotkey_wallets_for_wallet(
275275
(exists := hotkey_for_name.hotkey_file.exists_on_device())
276276
and not hotkey_for_name.hotkey_file.is_encrypted()
277277
# and hotkey_for_name.coldkeypub.ss58_address
278-
and hotkey_for_name.hotkey.ss58_address
278+
and get_hotkey_pub_ss58(hotkey_for_name)
279279
):
280280
hotkey_wallets.append(hotkey_for_name)
281281
elif (
@@ -1431,3 +1431,15 @@ def blocks_to_duration(blocks: int) -> str:
14311431
results.append(f"{unit_count}{unit}")
14321432
# Return only the first two non-zero units
14331433
return " ".join(results[:2]) or "0s"
1434+
1435+
1436+
def get_hotkey_pub_ss58(wallet: Wallet) -> str:
1437+
"""
1438+
Helper fn to retrieve the hotkeypub ss58 of a wallet that may have been created before
1439+
bt-wallet 3.1.1 and thus not have a wallet hotkeypub. In this case, it will return the hotkey
1440+
SS58.
1441+
"""
1442+
try:
1443+
return wallet.hotkeypub.ss58_address
1444+
except KeyFileError:
1445+
return wallet.hotkey.ss58_address

bittensor_cli/src/commands/stake/add.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
print_verbose,
2121
unlock_key,
2222
json_console,
23+
get_hotkey_pub_ss58,
2324
)
2425
from bittensor_wallet import Wallet
2526

@@ -552,7 +553,7 @@ def _get_hotkeys_to_stake_to(
552553
# Stake to all hotkeys except excluded ones
553554
all_hotkeys_: list[Wallet] = get_hotkey_wallets_for_wallet(wallet=wallet)
554555
return [
555-
(wallet.hotkey_str, wallet.hotkey.ss58_address)
556+
(wallet.hotkey_str, get_hotkey_pub_ss58(wallet))
556557
for wallet in all_hotkeys_
557558
if wallet.hotkey_str not in (exclude_hotkeys or [])
558559
]
@@ -572,7 +573,7 @@ def _get_hotkeys_to_stake_to(
572573
name=wallet.name,
573574
hotkey=hotkey_ss58_or_hotkey_name,
574575
)
575-
hotkeys.append((wallet_.hotkey_str, wallet_.hotkey.ss58_address))
576+
hotkeys.append((wallet_.hotkey_str, get_hotkey_pub_ss58(wallet_)))
576577

577578
return hotkeys
578579

@@ -581,7 +582,7 @@ def _get_hotkeys_to_stake_to(
581582
f"Staking to hotkey: ({wallet.hotkey_str}) in wallet: ({wallet.name})"
582583
)
583584
assert wallet.hotkey is not None
584-
return [(None, wallet.hotkey.ss58_address)]
585+
return [(None, get_hotkey_pub_ss58(wallet))]
585586

586587

587588
def _define_stake_table(

0 commit comments

Comments
 (0)