Skip to content

Commit 8a92e50

Browse files
authored
Merge pull request #528 from opentensor/release/9.8.1
Release/9.8.1
2 parents 5ec5499 + c1cac5c commit 8a92e50

File tree

11 files changed

+245
-243
lines changed

11 files changed

+245
-243
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.8.1/2025-07-08
4+
5+
## What's Changed
6+
* Fixed broken type annotation. by @thewhaleking in https://github.com/opentensor/btcli/pull/523
7+
* Update/slippage price calcs by @ibraheem-abe in https://github.com/opentensor/btcli/pull/526
8+
* Partially fix slippage display by @gztensor in https://github.com/opentensor/btcli/pull/524
9+
* stake add: netuid 0 by @thewhaleking in https://github.com/opentensor/btcli/pull/525
10+
11+
## New Contributors
12+
* @gztensor made their first contribution in https://github.com/opentensor/btcli/pull/524
13+
14+
**Full Changelog**: https://github.com/opentensor/btcli/compare/v9.8.0...v9.8.1
15+
316
## 9.8.0/2025-07-07
417

518
## What's Changed

bittensor_cli/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3352,7 +3352,7 @@ def stake_add(
33523352
)
33533353
else:
33543354
netuid_ = get_optional_netuid(None, all_netuids)
3355-
netuids = [netuid_] if netuid_ else None
3355+
netuids = [netuid_] if netuid_ is not None else None
33563356
if netuids:
33573357
for netuid_ in netuids:
33583358
# ensure no negative netuids make it into our list

bittensor_cli/src/bittensor/subtensor_interface.py

Lines changed: 78 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,23 +1423,40 @@ async def get_stake_for_coldkeys(
14231423
return stake_info_map if stake_info_map else None
14241424

14251425
async def all_subnets(self, block_hash: Optional[str] = None) -> list[DynamicInfo]:
1426-
result = await self.query_runtime_api(
1427-
"SubnetInfoRuntimeApi",
1428-
"get_all_dynamic_info",
1429-
block_hash=block_hash,
1426+
result, prices = await asyncio.gather(
1427+
self.query_runtime_api(
1428+
"SubnetInfoRuntimeApi",
1429+
"get_all_dynamic_info",
1430+
block_hash=block_hash,
1431+
),
1432+
self.get_subnet_prices(block_hash=block_hash, page_size=129),
14301433
)
1431-
return DynamicInfo.list_from_any(result)
1434+
sns: list[DynamicInfo] = DynamicInfo.list_from_any(result)
1435+
for sn in sns:
1436+
if sn.netuid == 0:
1437+
sn.price = Balance.from_tao(1.0)
1438+
else:
1439+
try:
1440+
sn.price = prices[sn.netuid]
1441+
except KeyError:
1442+
sn.price = sn.tao_in / sn.alpha_in
1443+
return sns
14321444

14331445
async def subnet(
14341446
self, netuid: int, block_hash: Optional[str] = None
14351447
) -> "DynamicInfo":
1436-
result = await self.query_runtime_api(
1437-
"SubnetInfoRuntimeApi",
1438-
"get_dynamic_info",
1439-
params=[netuid],
1440-
block_hash=block_hash,
1448+
result, price = await asyncio.gather(
1449+
self.query_runtime_api(
1450+
"SubnetInfoRuntimeApi",
1451+
"get_dynamic_info",
1452+
params=[netuid],
1453+
block_hash=block_hash,
1454+
),
1455+
self.get_subnet_price(netuid=netuid, block_hash=block_hash),
14411456
)
1442-
return DynamicInfo.from_any(result)
1457+
subnet_ = DynamicInfo.from_any(result)
1458+
subnet_.price = price
1459+
return subnet_
14431460

14441461
async def get_owned_hotkeys(
14451462
self,
@@ -1581,3 +1598,53 @@ async def get_coldkey_swap_schedule_duration(
15811598
)
15821599

15831600
return result
1601+
1602+
async def get_subnet_price(
1603+
self,
1604+
netuid: int = None,
1605+
block_hash: Optional[str] = None,
1606+
) -> Balance:
1607+
"""
1608+
Gets the current Alpha price in TAO for a specific subnet.
1609+
1610+
:param netuid: The unique identifier of the subnet.
1611+
:param block_hash: The hash of the block to retrieve the price from.
1612+
1613+
:return: The current Alpha price in TAO units for the specified subnet.
1614+
"""
1615+
current_sqrt_price = await self.query(
1616+
module="Swap",
1617+
storage_function="AlphaSqrtPrice",
1618+
params=[netuid],
1619+
block_hash=block_hash,
1620+
)
1621+
1622+
current_sqrt_price = fixed_to_float(current_sqrt_price)
1623+
current_price = current_sqrt_price * current_sqrt_price
1624+
return Balance.from_rao(int(current_price * 1e9))
1625+
1626+
async def get_subnet_prices(
1627+
self, block_hash: Optional[str] = None, page_size: int = 100
1628+
) -> dict[int, Balance]:
1629+
"""
1630+
Gets the current Alpha prices in TAO for all subnets.
1631+
1632+
:param block_hash: The hash of the block to retrieve prices from.
1633+
:param page_size: The page size for batch queries (default: 100).
1634+
1635+
:return: A dictionary mapping netuid to the current Alpha price in TAO units.
1636+
"""
1637+
query = await self.substrate.query_map(
1638+
module="Swap",
1639+
storage_function="AlphaSqrtPrice",
1640+
page_size=page_size,
1641+
block_hash=block_hash,
1642+
)
1643+
1644+
map_ = {}
1645+
async for netuid_, current_sqrt_price in query:
1646+
current_sqrt_price_ = fixed_to_float(current_sqrt_price.value)
1647+
current_price = current_sqrt_price_**2
1648+
map_[netuid_] = Balance.from_rao(int(current_price * 1e9))
1649+
1650+
return map_

bittensor_cli/src/commands/stake/add.py

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -245,12 +245,12 @@ async def stake_extrinsic(
245245
# Get subnet data and stake information for coldkey
246246
chain_head = await subtensor.substrate.get_chain_head()
247247
_all_subnets, _stake_info, current_wallet_balance = await asyncio.gather(
248-
subtensor.all_subnets(),
248+
subtensor.all_subnets(block_hash=chain_head),
249249
subtensor.get_stake_for_coldkey(
250250
coldkey_ss58=wallet.coldkeypub.ss58_address,
251251
block_hash=chain_head,
252252
),
253-
subtensor.get_balance(wallet.coldkeypub.ss58_address),
253+
subtensor.get_balance(wallet.coldkeypub.ss58_address, block_hash=chain_head),
254254
)
255255
all_subnets = {di.netuid: di for di in _all_subnets}
256256

@@ -307,6 +307,7 @@ async def stake_extrinsic(
307307
return False
308308
remaining_wallet_balance -= amount_to_stake
309309

310+
# TODO this should be asyncio gathered before the for loop
310311
stake_fee = await subtensor.get_stake_fee(
311312
origin_hotkey_ss58=None,
312313
origin_netuid=None,
@@ -318,14 +319,20 @@ async def stake_extrinsic(
318319
)
319320

320321
# Calculate slippage
321-
try:
322-
received_amount, slippage_pct, slippage_pct_float, rate = (
323-
_calculate_slippage(subnet_info, amount_to_stake, stake_fee)
324-
)
325-
except ValueError:
326-
return False
327-
328-
max_slippage = max(slippage_pct_float, max_slippage)
322+
# TODO: Update for V3, slippage calculation is significantly different in v3
323+
# try:
324+
# received_amount, slippage_pct, slippage_pct_float, rate = (
325+
# _calculate_slippage(subnet_info, amount_to_stake, stake_fee)
326+
# )
327+
# except ValueError:
328+
# return False
329+
#
330+
# max_slippage = max(slippage_pct_float, max_slippage)
331+
332+
# Temporary workaround - calculations without slippage
333+
current_price_float = float(subnet_info.price.tao)
334+
rate = 1.0 / current_price_float
335+
received_amount = rate * amount_to_stake
329336

330337
# Add rows for the table
331338
base_row = [
@@ -336,19 +343,19 @@ async def stake_extrinsic(
336343
+ f" {Balance.get_unit(netuid)}/{Balance.get_unit(0)} ", # rate
337344
str(received_amount.set_unit(netuid)), # received
338345
str(stake_fee), # fee
339-
str(slippage_pct), # slippage
346+
# str(slippage_pct), # slippage
340347
]
341348

342349
# If we are staking safe, add price tolerance
343350
if safe_staking:
344351
if subnet_info.is_dynamic:
345-
rate = amount_to_stake.rao / received_amount.rao
346-
_rate_with_tolerance = rate * (
347-
1 + rate_tolerance
352+
price_with_tolerance = current_price_float * (1 + rate_tolerance)
353+
_rate_with_tolerance = (
354+
1.0 / price_with_tolerance
348355
) # Rate only for display
349356
rate_with_tolerance = f"{_rate_with_tolerance:.4f}"
350357
price_with_tolerance = Balance.from_tao(
351-
_rate_with_tolerance
358+
price_with_tolerance
352359
).rao # Actual price to pass to extrinsic
353360
else:
354361
rate_with_tolerance = "1"
@@ -581,9 +588,10 @@ def _define_stake_table(
581588
justify="center",
582589
style=COLOR_PALETTE["STAKE"]["STAKE_AMOUNT"],
583590
)
584-
table.add_column(
585-
"Slippage", justify="center", style=COLOR_PALETTE["STAKE"]["SLIPPAGE_PERCENT"]
586-
)
591+
# TODO: Uncomment when slippage is reimplemented for v3
592+
# table.add_column(
593+
# "Slippage", justify="center", style=COLOR_PALETTE["STAKE"]["SLIPPAGE_PERCENT"]
594+
# )
587595

588596
if safe_staking:
589597
table.add_column(
@@ -628,8 +636,8 @@ def _print_table_and_slippage(table: Table, max_slippage: float, safe_staking: b
628636
- [bold white]Hotkey[/bold white]: The ss58 address of the hotkey you are staking to.
629637
- [bold white]Amount[/bold white]: The TAO you are staking into this subnet onto this hotkey.
630638
- [bold white]Rate[/bold white]: The rate of exchange between your TAO and the subnet's stake.
631-
- [bold white]Received[/bold white]: The amount of stake you will receive on this subnet after slippage.
632-
- [bold white]Slippage[/bold white]: The slippage percentage of the stake operation. (0% if the subnet is not dynamic i.e. root)."""
639+
- [bold white]Received[/bold white]: The amount of stake you will receive on this subnet after slippage."""
640+
# - [bold white]Slippage[/bold white]: The slippage percentage of the stake operation. (0% if the subnet is not dynamic i.e. root)."""
633641

634642
safe_staking_description = """
635643
- [bold white]Rate Tolerance[/bold white]: Maximum acceptable alpha rate. If the rate exceeds this tolerance, the transaction will be limited or rejected.
@@ -654,6 +662,9 @@ def _calculate_slippage(
654662
- slippage_str: Formatted slippage percentage string
655663
- slippage_float: Raw slippage percentage value
656664
- rate: Exchange rate string
665+
666+
TODO: Update to v3. This method only works for protocol-liquidity-only
667+
mode (user liquidity disabled)
657668
"""
658669
amount_after_fee = amount - stake_fee
659670

@@ -670,6 +681,7 @@ def _calculate_slippage(
670681
slippage_str = f"{slippage_pct_float:.4f} %"
671682
rate = f"{(1 / subnet_info.price.tao or 1):.4f}"
672683
else:
684+
# TODO: Fix this. Slippage is always zero for static networks.
673685
slippage_pct_float = (
674686
100 * float(stake_fee.tao) / float(amount.tao) if amount.tao != 0 else 0
675687
)

0 commit comments

Comments
 (0)