Skip to content
Open
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
12 changes: 11 additions & 1 deletion bittensor_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -866,7 +866,7 @@ def __init__(self):
self.subnet_mechanisms_app = typer.Typer(epilog=_epilog)
self.weights_app = typer.Typer(epilog=_epilog)
self.view_app = typer.Typer(epilog=_epilog)
self.liquidity_app = typer.Typer(epilog=_epilog)
self.liquidity_app = typer.Typer(epilog=_epilog, hidden=True)
self.crowd_app = typer.Typer(epilog=_epilog)
self.utils_app = typer.Typer(epilog=_epilog)
self.axon_app = typer.Typer(epilog=_epilog)
Expand Down Expand Up @@ -8557,6 +8557,9 @@ def liquidity_add(
json_output: bool = Options.json_output,
):
"""Add liquidity to the swap (as a combination of TAO + Alpha)."""
console.print_error("User liquidity is currently disabled on Bittensor.")
raise typer.Exit()

self.verbosity_handler(quiet, verbose, json_output, prompt, decline)
proxy = self.is_valid_proxy_name_or_ss58(proxy, announce_only)
if not netuid:
Expand Down Expand Up @@ -8634,6 +8637,9 @@ def liquidity_list(
json_output: bool = Options.json_output,
):
"""Displays liquidity positions in given subnet."""
console.print_error("User liquidity is currently disabled on Bittensor.")
raise typer.Exit()

self.verbosity_handler(quiet, verbose, json_output, prompt=False)
if not netuid:
netuid = IntPrompt.ask(
Expand Down Expand Up @@ -8687,6 +8693,8 @@ def liquidity_remove(
):
"""Remove liquidity from the swap (as a combination of TAO + Alpha)."""

console.print_error("User liquidity is currently disabled on Bittensor.")
raise typer.Exit()
self.verbosity_handler(quiet, verbose, json_output, prompt, decline)
proxy = self.is_valid_proxy_name_or_ss58(proxy, announce_only)
if all_liquidity_ids and position_id:
Expand Down Expand Up @@ -8763,6 +8771,8 @@ def liquidity_modify(
json_output: bool = Options.json_output,
):
"""Modifies the liquidity position for the given subnet."""
console.print_error("User liquidity is currently disabled on Bittensor.")
raise typer.Exit()
self.verbosity_handler(quiet, verbose, json_output, prompt, decline)
proxy = self.is_valid_proxy_name_or_ss58(proxy, announce_only)
if not netuid:
Expand Down
98 changes: 16 additions & 82 deletions bittensor_cli/src/bittensor/chain_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -800,88 +800,6 @@ def tao_to_alpha(self, tao: Balance) -> Balance:
def alpha_to_tao(self, alpha: Balance) -> Balance:
return Balance.from_tao(alpha.tao * self.price.tao)

def tao_to_alpha_with_slippage(
self, tao: Balance
) -> tuple[Balance, Balance, float]:
"""
Returns an estimate of how much Alpha a staker would receive if they stake their tao using the current pool
state.

Args:
tao: Amount of TAO to stake.
Returns:
Tuple of balances where the first part is the amount of Alpha received, and the
second part (slippage) is the difference between the estimated amount and ideal
amount as if there was no slippage
"""
if self.is_dynamic:
new_tao_in = self.tao_in + tao
if new_tao_in == 0:
return tao, Balance.from_rao(0)
new_alpha_in = self.k / new_tao_in

# Amount of alpha given to the staker
alpha_returned = Balance.from_rao(
self.alpha_in.rao - new_alpha_in.rao
).set_unit(self.netuid)

# Ideal conversion as if there is no slippage, just price
alpha_ideal = self.tao_to_alpha(tao)

if alpha_ideal.tao > alpha_returned.tao:
slippage = Balance.from_tao(
alpha_ideal.tao - alpha_returned.tao
).set_unit(self.netuid)
else:
slippage = Balance.from_tao(0)
else:
alpha_returned = tao.set_unit(self.netuid)
slippage = Balance.from_tao(0)

slippage_pct_float = (
100 * float(slippage) / float(slippage + alpha_returned)
if slippage + alpha_returned != 0
else 0
)
return alpha_returned, slippage, slippage_pct_float

def alpha_to_tao_with_slippage(
self, alpha: Balance
) -> tuple[Balance, Balance, float]:
"""
Returns an estimate of how much TAO a staker would receive if they unstake their alpha using the current pool
state.

Args:
alpha: Amount of Alpha to stake.
Returns:
Tuple of balances where the first part is the amount of TAO received, and the
second part (slippage) is the difference between the estimated amount and ideal
amount as if there was no slippage
"""
if self.is_dynamic:
new_alpha_in = self.alpha_in + alpha
new_tao_reserve = self.k / new_alpha_in
# Amount of TAO given to the unstaker
tao_returned = Balance.from_rao(self.tao_in - new_tao_reserve)

# Ideal conversion as if there is no slippage, just price
tao_ideal = self.alpha_to_tao(alpha)

if tao_ideal > tao_returned:
slippage = Balance.from_tao(tao_ideal.tao - tao_returned.tao)
else:
slippage = Balance.from_tao(0)
else:
tao_returned = alpha.set_unit(0)
slippage = Balance.from_tao(0)
slippage_pct_float = (
100 * float(slippage) / float(slippage + tao_returned)
if slippage + tao_returned != 0
else 0
)
return tao_returned, slippage, slippage_pct_float


@dataclass
class ColdkeySwapAnnouncementInfo(InfoBase):
Expand Down Expand Up @@ -1218,6 +1136,8 @@ class SimSwapResult:
alpha_amount: Balance
tao_fee: Balance
alpha_fee: Balance
tao_slippage: Balance
alpha_slippage: Balance

@classmethod
def from_dict(cls, d: dict, netuid: int) -> "SimSwapResult":
Expand All @@ -1226,8 +1146,22 @@ def from_dict(cls, d: dict, netuid: int) -> "SimSwapResult":
alpha_amount=Balance.from_rao(d["alpha_amount"]).set_unit(netuid),
tao_fee=Balance.from_rao(d["tao_fee"]).set_unit(0),
alpha_fee=Balance.from_rao(d["alpha_fee"]).set_unit(netuid),
tao_slippage=Balance.from_rao(d["tao_slippage"]).set_unit(0),
alpha_slippage=Balance.from_rao(d["alpha_slippage"]).set_unit(netuid),
)

@property
def tao_slippage_pct(self) -> float:
"""Slippage percentage for alpha->tao swaps."""
ideal = self.tao_amount.tao + self.tao_slippage.tao
return (100.0 * self.tao_slippage.tao / ideal) if ideal > 0 else 0.0

@property
def alpha_slippage_pct(self) -> float:
"""Slippage percentage for tao->alpha swaps."""
ideal = self.alpha_amount.tao + self.alpha_slippage.tao
return (100.0 * self.alpha_slippage.tao / ideal) if ideal > 0 else 0.0


@dataclass
class CrowdloanData(InfoBase):
Expand Down
94 changes: 50 additions & 44 deletions bittensor_cli/src/bittensor/subtensor_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,40 +444,52 @@ async def get_total_stake_for_coldkey(

:return: {address: Balance objects}
"""
sub_stakes, dynamic_info = await asyncio.gather(
sub_stakes, price_map = await asyncio.gather(
self.get_stake_for_coldkeys(list(ss58_addresses), block_hash=block_hash),
# Token pricing info
self.all_subnets(block_hash=block_hash),
self.get_subnet_prices(block_hash=block_hash),
)

results = {}
results: dict[str, tuple[Balance, Balance]] = {}
dynamic_stakes: list[tuple[str, "StakeInfo"]] = []

for ss58, stake_info_list in sub_stakes.items():
total_tao_value = Balance(0)
total_swapped_tao_value = Balance(0)
total_tao_value, total_swapped_tao_value = Balance(0), Balance(0)
for sub_stake in stake_info_list:
if sub_stake.stake.rao == 0:
continue
netuid = sub_stake.netuid
pool = dynamic_info[netuid]

alpha_value = Balance.from_rao(int(sub_stake.stake.rao)).set_unit(
netuid
netuid = sub_stake.netuid
price = price_map[netuid]
ideal_tao = Balance.from_tao(sub_stake.stake.tao * price.tao).set_unit(
0
)
total_tao_value += ideal_tao

# Without slippage
tao_value = pool.alpha_to_tao(alpha_value)
total_tao_value += tao_value

# With slippage
if netuid == 0:
swapped_tao_value = tao_value
total_swapped_tao_value += ideal_tao
else:
swapped_tao_value, _, _ = pool.alpha_to_tao_with_slippage(
sub_stake.stake
)
total_swapped_tao_value += swapped_tao_value
dynamic_stakes.append((ss58, sub_stake))

results[ss58] = (total_tao_value, total_swapped_tao_value)

if dynamic_stakes:
sim_results = await asyncio.gather(
*[
self.sim_swap(
origin_netuid=sub_stake.netuid,
destination_netuid=0,
amount=sub_stake.stake.rao,
block_hash=block_hash,
)
for _, sub_stake in dynamic_stakes
]
)

for (ss58, sub_stake), sim_result in zip(dynamic_stakes, sim_results):
total_tao_value, total_swapped_tao_value = results[ss58]
total_swapped_tao_value += sim_result.tao_amount
results[ss58] = (total_tao_value, total_swapped_tao_value)

return results

async def get_total_stake_for_hotkey(
Expand Down Expand Up @@ -1654,7 +1666,7 @@ async def all_subnets(self, block_hash: Optional[str] = None) -> list[DynamicInf
"get_all_dynamic_info",
block_hash=block_hash,
),
self.get_subnet_prices(block_hash=block_hash, page_size=129),
self.get_subnet_prices(block_hash=block_hash),
)
sns: list[DynamicInfo] = DynamicInfo.list_from_any(result)
for sn in sns:
Expand Down Expand Up @@ -1782,6 +1794,7 @@ async def sim_swap(
)
secondary_fee = (result.tao_fee / sn_price.tao).set_unit(origin_netuid)
result.alpha_fee = result.alpha_fee + secondary_fee
result.tao_slippage = intermediate_result.tao_slippage
return result
elif origin_netuid > 0:
# dynamic to tao
Expand Down Expand Up @@ -2523,43 +2536,36 @@ async def get_subnet_price(

:return: The current Alpha price in TAO units for the specified subnet.
"""
# TODO update this to use the runtime call SwapRuntimeAPI.current_alpha_price
current_sqrt_price = await self.query(
module="Swap",
storage_function="AlphaSqrtPrice",
params=[netuid],
if netuid == 0:
return Balance.from_tao(1.0)

current_price = await self.query_runtime_api(
"SwapRuntimeApi",
"current_alpha_price",
params={"netuid": 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))
return Balance.from_rao(current_price)

async def get_subnet_prices(
self, block_hash: Optional[str] = None, page_size: int = 100
self, block_hash: Optional[str] = None
) -> dict[int, Balance]:
"""
Gets the current Alpha prices in TAO for all subnets.

:param block_hash: The hash of the block to retrieve prices from.
:param page_size: The page size for batch queries (default: 100).

:return: A dictionary mapping netuid to the current Alpha price in TAO units.
"""
query = await self.substrate.query_map(
module="Swap",
storage_function="AlphaSqrtPrice",
page_size=page_size,
all_prices = await self.query_runtime_api(
"SwapRuntimeApi",
"current_alpha_price_all",
block_hash=block_hash,
)

map_ = {}
async for netuid_, current_sqrt_price in query:
current_sqrt_price_ = fixed_to_float(current_sqrt_price.value)
current_price = current_sqrt_price_**2
map_[netuid_] = Balance.from_rao(int(current_price * 1e9))

return map_
result = {}
for entry in all_prices:
result[entry["netuid"]] = Balance.from_rao(entry["price"])
return result

async def get_all_subnet_ema_tao_inflow(
self,
Expand Down
Loading
Loading