Skip to content

Commit 35363e2

Browse files
committed
Check-in
1 parent ea0b035 commit 35363e2

File tree

2 files changed

+173
-3
lines changed

2 files changed

+173
-3
lines changed

bittensor_cli/src/bittensor/subtensor_interface.py

+38
Original file line numberDiff line numberDiff line change
@@ -1205,3 +1205,41 @@ async def multi_get_stake_for_coldkey_and_hotkey_on_netuid(
12051205
)
12061206
results[hotkey_ss58][netuid] = value
12071207
return results
1208+
1209+
async def get_stake_info_for_coldkeys(
1210+
self, coldkey_ss58_list: list[str], block_hash: Optional[str] = None
1211+
) -> Optional[dict[str, list[StakeInfo]]]:
1212+
"""
1213+
Retrieves stake information for a list of coldkeys. This function aggregates stake data for multiple
1214+
accounts, providing a collective view of their stakes and delegations.
1215+
1216+
Args:
1217+
coldkey_ss58_list: A list of SS58 addresses of the accounts' coldkeys.
1218+
block_hash: The blockchain block number for the query.
1219+
1220+
Returns:
1221+
A dictionary mapping each coldkey to a list of its StakeInfo objects.
1222+
1223+
This function is useful for analyzing the stake distribution and delegation patterns of multiple
1224+
accounts simultaneously, offering a broader perspective on network participation and investment strategies.
1225+
"""
1226+
encoded_coldkeys = [
1227+
ss58_to_vec_u8(coldkey_ss58) for coldkey_ss58 in coldkey_ss58_list
1228+
]
1229+
1230+
hex_bytes_result = await self.query_runtime_api(
1231+
runtime_api="StakeInfoRuntimeApi",
1232+
method="get_stake_info_for_coldkeys",
1233+
params=encoded_coldkeys,
1234+
block_hash=block_hash,
1235+
)
1236+
1237+
if hex_bytes_result is None:
1238+
return None
1239+
1240+
if hex_bytes_result.startswith("0x"):
1241+
bytes_result = bytes.fromhex(hex_bytes_result[2:])
1242+
else:
1243+
bytes_result = bytes.fromhex(hex_bytes_result)
1244+
1245+
return StakeInfo.list_of_tuple_from_vec_u8(bytes_result) # type: ignore

bittensor_cli/src/commands/stake/stake.py

+135-3
Original file line numberDiff line numberDiff line change
@@ -1597,9 +1597,9 @@ async def unstake(
15971597

15981598

15991599
async def stake_list(wallet: Wallet, subtensor: "SubtensorInterface"):
1600-
substakes = subtensor.get_stake_info_for_coldkeys(
1600+
sub_stakes = (await subtensor.get_stake_info_for_coldkeys(
16011601
coldkey_ss58_list=[wallet.coldkeypub.ss58_address]
1602-
)[wallet.coldkeypub.ss58_address]
1602+
))[wallet.coldkeypub.ss58_address]
16031603

16041604
# Get registered delegates details.
16051605
registered_delegate_info = await subtensor.get_delegate_identities()
@@ -1616,10 +1616,142 @@ async def stake_list(wallet: Wallet, subtensor: "SubtensorInterface"):
16161616
# Iterate over substakes and aggregate them by hotkey.
16171617
hotkeys_to_substakes: dict[str, list[StakeInfo]] = {}
16181618

1619-
for substake in substakes:
1619+
for substake in sub_stakes:
16201620
hotkey = substake.hotkey_ss58
16211621
if substake.stake.rao == 0:
16221622
continue
16231623
if hotkey not in hotkeys_to_substakes:
16241624
hotkeys_to_substakes[hotkey] = []
16251625
hotkeys_to_substakes[hotkey].append(substake)
1626+
1627+
def table_substakes(hotkey: str, substakes: list[StakeInfo]):
1628+
# Create table structure.
1629+
name = registered_delegate_info[
1630+
hotkey].name + f" ({hotkey})" if hotkey in registered_delegate_info else hotkey
1631+
rows = []
1632+
total_global_tao = Balance(0)
1633+
total_tao_value = Balance(0)
1634+
for substake in substakes:
1635+
netuid = substake.netuid
1636+
pool = dynamic_info[netuid]
1637+
symbol = f"{bittensor.Balance.get_unit(netuid)}"
1638+
price = "{:.4f}{}".format(pool.price.__float__(),
1639+
f" τ/{Balance.get_unit(netuid)}\u200E") if pool.is_dynamic else (
1640+
f" 1.0000 τ/{symbol} ")
1641+
alpha_value = Balance.from_rao(int(substake.stake.rao)).set_unit(netuid)
1642+
locked_value = Balance.from_rao(int(substake.locked.rao)).set_unit(netuid)
1643+
tao_value = pool.alpha_to_tao(alpha_value)
1644+
total_tao_value += tao_value
1645+
swapped_tao_value, slippage = pool.alpha_to_tao_with_slippage(substake.stake)
1646+
if pool.is_dynamic:
1647+
slippage_percentage = 100 * float(slippage) / float(
1648+
slippage + swapped_tao_value) if slippage + swapped_tao_value != 0 else 0
1649+
slippage_percentage = f"[dark_red]{slippage_percentage:.3f}%[/dark_red]"
1650+
else:
1651+
slippage_percentage = '0.000%'
1652+
tao_locked = pool.tao_in
1653+
issuance = pool.alpha_out if pool.is_dynamic else tao_locked
1654+
per_block_emission = substake.emission.tao / ((emission_drain_tempo / pool.tempo) * pool.tempo)
1655+
if alpha_value.tao > 0.00009:
1656+
if issuance.tao != 0:
1657+
alpha_ownership = "{:.4f}".format((alpha_value.tao / issuance.tao) * 100)
1658+
tao_ownership = bittensor.Balance.from_tao((alpha_value.tao / issuance.tao) * tao_locked.tao)
1659+
total_global_tao += tao_ownership
1660+
else:
1661+
alpha_ownership = "0.0000"
1662+
tao_ownership = "0.0000"
1663+
rows.append([
1664+
str(netuid), # Number
1665+
symbol, # Symbol
1666+
# f"[medium_purple]{tao_ownership}[/medium_purple] ([light_salmon3]{ alpha_ownership }[/light_salmon3][white]%[/white])", # Tao ownership.
1667+
f"[medium_purple]{tao_ownership}[/medium_purple]", # Tao ownership.
1668+
# f"[dark_sea_green]{ alpha_value }", # Alpha value
1669+
f"{substake.stake.tao:,.4f} {symbol}",
1670+
f"{pool.price.tao:.4f} τ/{symbol}",
1671+
f"[light_slate_blue]{tao_value}[/light_slate_blue]", # Tao equiv
1672+
f"[cadet_blue]{swapped_tao_value}[/cadet_blue] ({slippage_percentage})", # Swap amount.
1673+
# f"[light_salmon3]{ alpha_ownership }%[/light_salmon3]", # Ownership.
1674+
f"[bold cadet_blue]YES[/bold cadet_blue]" if substake.is_registered else f"[dark_red]NO[/dark_red]",
1675+
# Registered.
1676+
str(bittensor.Balance.from_tao(per_block_emission).set_unit(
1677+
netuid)) if substake.is_registered else "[dark_red]N/A[/dark_red]", # emission per block.
1678+
f"[light_slate_blue]{locked_value}[/light_slate_blue]", # Locked value
1679+
])
1680+
# table = Table(show_footer=True, pad_edge=False, box=None, expand=False, title=f"{name}")
1681+
table = Table(
1682+
title=f"[white]hotkey:[/white] [light_salmon3]{name}[/light_salmon3]\n",
1683+
width=bittensor.__console__.width - 5,
1684+
safe_box=True,
1685+
padding=(0, 1),
1686+
collapse_padding=False,
1687+
pad_edge=True,
1688+
expand=True,
1689+
show_header=True,
1690+
show_footer=True,
1691+
show_edge=False,
1692+
show_lines=False,
1693+
leading=0,
1694+
style="none",
1695+
row_styles=None,
1696+
header_style="bold",
1697+
footer_style="bold",
1698+
border_style="rgb(7,54,66)",
1699+
title_style="bold magenta",
1700+
title_justify="center",
1701+
highlight=False,
1702+
)
1703+
table.add_column("[white]Netuid", footer_style="overline white", style="grey89")
1704+
table.add_column("[white]Symbol", footer_style="white", style="light_goldenrod1", justify="right",
1705+
width=5,
1706+
no_wrap=True)
1707+
table.add_column(f"[white]TAO({Balance.unit})", style="aquamarine3", justify="right",
1708+
footer=f"{total_global_tao}")
1709+
table.add_column(f"[white]Stake({Balance.get_unit(1)})", footer_style="overline white",
1710+
style="green", justify="right")
1711+
table.add_column(f"[white]Rate({Balance.unit}/{Balance.get_unit(1)})",
1712+
footer_style="white", style="light_goldenrod2", justify="center")
1713+
table.add_column(
1714+
f"[white]Value({bittensor.Balance.get_unit(1)} x {Balance.unit}/{Balance.get_unit(1)})",
1715+
footer_style="overline white", style="blue", justify="right", footer=f"{total_tao_value}")
1716+
table.add_column(f"[white]Swap({Balance.get_unit(1)}) -> {Balance.unit}",
1717+
footer_style="overline white", style="white", justify="right")
1718+
# table.add_column(f"[white]Control({bittensor.Balance.get_unit(1)})", style="aquamarine3", justify="right")
1719+
table.add_column("[white]Registered", style="red", justify="right")
1720+
table.add_column(f"[white]Emission({Balance.get_unit(1)}/block)", style="aquamarine3",
1721+
justify="right")
1722+
table.add_column(f"[white]Locked({Balance.get_unit(1)})", footer_style="overline white",
1723+
style="green", justify="right")
1724+
for row in rows:
1725+
table.add_row(*row)
1726+
console.print(table)
1727+
return total_global_tao, total_tao_value
1728+
1729+
# Iterate over each hotkey and make a table
1730+
all_hotkeys_total_global_tao = Balance(0)
1731+
all_hotkeys_total_tao_value = Balance(0)
1732+
for hotkey in hotkeys_to_substakes.keys():
1733+
stake, value = table_substakes(hotkey, hotkeys_to_substakes[hotkey])
1734+
all_hotkeys_total_global_tao += stake
1735+
all_hotkeys_total_tao_value += value
1736+
1737+
console.print("\n\n")
1738+
console.print(
1739+
f"Wallet:\n Coldkey SS58: [bold dark_green]{cli.config.coldkey_address}[/bold dark_green]\n Free Balance: [aquamarine3]{balance}[/aquamarine3]\n Total TAO ({bittensor.Balance.unit}): [aquamarine3]{all_hotkeys_total_global_tao}[/aquamarine3]\n Total Value ({bittensor.Balance.unit}): [aquamarine3]{all_hotkeys_total_tao_value}[/aquamarine3]")
1740+
console.print(
1741+
"""
1742+
[bold white]Description[/bold white]:
1743+
Each table displays information about your coldkey's staking accounts with a hotkey.
1744+
The header of the table displays the hotkey and the footer displays the total stake and total value of all your staking accounts.
1745+
The columns of the table are as follows:
1746+
- [bold white]Netuid[/bold white]: The unique identifier for the subnet (its index).
1747+
- [bold white]Symbol[/bold white]: The symbol representing the subnet stake's unit.
1748+
- [bold white]TAO[/bold white]: The hotkey's TAO balance on this subnet. This is this hotkey's proportion of total TAO staked into the subnet divided by the hotkey's share of outstanding stake.
1749+
- [bold white]Stake[/bold white]: The hotkey's stake balance in subnets staking unit.
1750+
- [bold white]Rate[/bold white]: The rate of exchange between the subnet's staking unit and the subnet's TAO.
1751+
- [bold white]Value[/bold white]: The price of the hotkey's stake in TAO computed via the exchange rate.
1752+
- [bold white]Swap[/bold white]: The amount of TAO received when unstaking all of the hotkey's stake (with slippage).
1753+
- [bold white]Registered[/bold white]: Whether the hotkey is registered on this subnet.
1754+
- [bold white]Emission[/bold white]: If registered, the emission (in stake) attained by this hotkey on this subnet per block.
1755+
- [bold white]Locked[/bold white]: The total amount of stake locked (not able to be unstaked).
1756+
"""
1757+
)

0 commit comments

Comments
 (0)