Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 18 additions & 0 deletions bittensor_cli/src/bittensor/subtensor_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -1581,3 +1581,21 @@ async def get_coldkey_swap_schedule_duration(
)

return result

async def get_subnet_price(
self,
netuid: int = None,
block_hash: Optional[str] = None,
) -> Balance:
if not block_hash:
block_hash = await self.substrate.get_chain_head()
current_sqrt_price = await self.substrate.query(
module="Swap",
storage_function="AlphaSqrtPrice",
params=[netuid],
block_hash=block_hash,
)

current_sqrt_price = fixed_to_float(current_sqrt_price)
current_price = current_sqrt_price * current_sqrt_price
return Balance.from_rao(int(current_price * 1e9))
68 changes: 41 additions & 27 deletions bittensor_cli/src/commands/stake/add.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,27 +307,36 @@ async def stake_extrinsic(
return False
remaining_wallet_balance -= amount_to_stake

stake_fee = await subtensor.get_stake_fee(
origin_hotkey_ss58=None,
origin_netuid=None,
origin_coldkey_ss58=wallet.coldkeypub.ss58_address,
destination_hotkey_ss58=hotkey[1],
destination_netuid=netuid,
destination_coldkey_ss58=wallet.coldkeypub.ss58_address,
amount=amount_to_stake.rao,
stake_fee, current_price = await asyncio.gather(
subtensor.get_stake_fee(
origin_hotkey_ss58=None,
origin_netuid=None,
origin_coldkey_ss58=wallet.coldkeypub.ss58_address,
destination_hotkey_ss58=hotkey[1],
destination_netuid=netuid,
destination_coldkey_ss58=wallet.coldkeypub.ss58_address,
amount=amount_to_stake.rao,
),
subtensor.get_subnet_price(netuid=netuid),
)

# Calculate slippage
try:
received_amount, slippage_pct, slippage_pct_float, rate = (
_calculate_slippage(subnet_info, amount_to_stake, stake_fee)
)
except ValueError:
return False

max_slippage = max(slippage_pct_float, max_slippage)

# Add rows for the table
# TODO: Update for V3, slippage calculation is significantly different in v3
# try:
# received_amount, slippage_pct, slippage_pct_float, rate = (
# _calculate_slippage(subnet_info, amount_to_stake, stake_fee)
# )
# except ValueError:
# return False
#
# max_slippage = max(slippage_pct_float, max_slippage)

# Temporary workaround - calculations without slippage
current_price_float = float(current_price.tao)
rate = 1. / current_price_float
received_amount = rate * amount_to_stake

# Add rows for the table
base_row = [
str(netuid), # netuid
f"{hotkey[1]}", # hotkey
Expand All @@ -336,16 +345,16 @@ async def stake_extrinsic(
+ f" {Balance.get_unit(netuid)}/{Balance.get_unit(0)} ", # rate
str(received_amount.set_unit(netuid)), # received
str(stake_fee), # fee
str(slippage_pct), # slippage
# str(slippage_pct), # slippage
]

# If we are staking safe, add price tolerance
if safe_staking:
if subnet_info.is_dynamic:
rate = amount_to_stake.rao / received_amount.rao
_rate_with_tolerance = rate * (
price_with_tolerance_float = current_price_float * (
1 + rate_tolerance
) # Rate only for display
)
_rate_with_tolerance = 1. / price_with_tolerance_float # Rate only for display
rate_with_tolerance = f"{_rate_with_tolerance:.4f}"
price_with_tolerance = Balance.from_tao(
_rate_with_tolerance
Expand Down Expand Up @@ -581,9 +590,10 @@ def _define_stake_table(
justify="center",
style=COLOR_PALETTE["STAKE"]["STAKE_AMOUNT"],
)
table.add_column(
"Slippage", justify="center", style=COLOR_PALETTE["STAKE"]["SLIPPAGE_PERCENT"]
)
# TODO: Uncomment when slippage is reimplemented for v3
# table.add_column(
# "Slippage", justify="center", style=COLOR_PALETTE["STAKE"]["SLIPPAGE_PERCENT"]
# )

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

safe_staking_description = """
- [bold white]Rate Tolerance[/bold white]: Maximum acceptable alpha rate. If the rate exceeds this tolerance, the transaction will be limited or rejected.
Expand All @@ -654,6 +664,9 @@ def _calculate_slippage(
- slippage_str: Formatted slippage percentage string
- slippage_float: Raw slippage percentage value
- rate: Exchange rate string

TODO: Update to v3. This method only works for protocol-liquidity-only
mode (user liquidity disabled)
"""
amount_after_fee = amount - stake_fee

Expand All @@ -670,6 +683,7 @@ def _calculate_slippage(
slippage_str = f"{slippage_pct_float:.4f} %"
rate = f"{(1 / subnet_info.price.tao or 1):.4f}"
else:
# TODO: Fix this. Slippage is always zero for static networks.
slippage_pct_float = (
100 * float(stake_fee.tao) / float(amount.tao) if amount.tao != 0 else 0
)
Expand Down
60 changes: 35 additions & 25 deletions bittensor_cli/src/commands/stake/remove.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,13 @@ async def unstake(
wallet.coldkeypub.ss58_address, block_hash=chain_head
),
)
all_sn_dynamic_info = {info.netuid: info for info in all_sn_dynamic_info_}
prices = await asyncio.gather(*[
subtensor.get_subnet_price(netuid=netuid) for _ in all_sn_dynamic_info_
])

for item, price in zip(all_sn_dynamic_info_, prices):
item.price = price
all_sn_dynamic_info = {info.netuid: info for info in all_sn_dynamic_info_}

if interactive:
try:
Expand Down Expand Up @@ -241,8 +247,8 @@ async def unstake(
str(subnet_info.price.tao)
+ f"({Balance.get_unit(0)}/{Balance.get_unit(netuid)})", # Rate
str(stake_fee), # Fee
str(received_amount), # Received Amount
slippage_pct, # Slippage Percent
# str(received_amount), # Received Amount
# slippage_pct, # Slippage Percent
]

# Additional fields for safe unstaking
Expand Down Expand Up @@ -443,16 +449,16 @@ async def unstake_all(
justify="center",
style=COLOR_PALETTE["STAKE"]["STAKE_AMOUNT"],
)
table.add_column(
f"Received ({Balance.unit})",
justify="center",
style=COLOR_PALETTE["POOLS"]["TAO_EQUIV"],
)
table.add_column(
"Slippage",
justify="center",
style=COLOR_PALETTE["STAKE"]["SLIPPAGE_PERCENT"],
)
# table.add_column(
# f"Received ({Balance.unit})",
# justify="center",
# style=COLOR_PALETTE["POOLS"]["TAO_EQUIV"],
# )
# table.add_column(
# "Slippage",
# justify="center",
# style=COLOR_PALETTE["STAKE"]["SLIPPAGE_PERCENT"],
# )

# Calculate slippage and total received
max_slippage = 0.0
Expand Down Expand Up @@ -490,8 +496,8 @@ async def unstake_all(
str(float(subnet_info.price))
+ f"({Balance.get_unit(0)}/{Balance.get_unit(stake.netuid)})",
str(stake_fee),
str(received_amount),
slippage_pct,
# str(received_amount),
# slippage_pct,
)
console.print(table)
if max_slippage > 5:
Expand Down Expand Up @@ -863,6 +869,9 @@ def _calculate_slippage(
- received_amount: Balance after slippage deduction
- slippage_pct: Formatted string of slippage percentage
- slippage_pct_float: Float value of slippage percentage

TODO: Update to v3. This method only works for protocol-liquidity-only
mode (user liquidity disabled)
"""
received_amount, _, _ = subnet_info.alpha_to_tao_with_slippage(amount)
received_amount -= stake_fee
Expand All @@ -884,6 +893,7 @@ def _calculate_slippage(
)
slippage_pct = f"{slippage_pct_float:.4f} %"
else:
# TODO: Fix this. Slippage is always zero for static networks.
# Root will only have fee-based slippage
slippage_pct_float = (
100 * float(stake_fee.tao) / float(amount.tao) if amount.tao != 0 else 0
Expand Down Expand Up @@ -993,7 +1003,7 @@ async def _unstake_selection(
table.add_column("Symbol", style=COLOR_PALETTE["GENERAL"]["SYMBOL"])
table.add_column("Stake Amount", style=COLOR_PALETTE["STAKE"]["STAKE_AMOUNT"])
table.add_column(
f"[bold white]RATE ({Balance.get_unit(0)}_in/{Balance.get_unit(1)}_in)",
f"[bold white]Rate ({Balance.get_unit(0)}/{Balance.get_unit(1)})",
style=COLOR_PALETTE["POOLS"]["RATE"],
justify="left",
)
Expand Down Expand Up @@ -1255,15 +1265,15 @@ def _create_unstake_table(
justify="center",
style=COLOR_PALETTE["STAKE"]["STAKE_AMOUNT"],
)
table.add_column(
f"Received ({Balance.get_unit(0)})",
justify="center",
style=COLOR_PALETTE["POOLS"]["TAO_EQUIV"],
footer=str(total_received_amount),
)
table.add_column(
"Slippage", justify="center", style=COLOR_PALETTE["STAKE"]["SLIPPAGE_PERCENT"]
)
# table.add_column(
# f"Received ({Balance.get_unit(0)})",
# justify="center",
# style=COLOR_PALETTE["POOLS"]["TAO_EQUIV"],
# footer=str(total_received_amount),
# )
# table.add_column(
# "Slippage", justify="center", style=COLOR_PALETTE["STAKE"]["SLIPPAGE_PERCENT"]
# )
if safe_staking:
table.add_column(
f"Rate with tolerance: [blue]({rate_tolerance * 100}%)[/blue]",
Expand Down
Loading