bittensor-cli 8.2.0rc12__py3-none-any.whl → 8.2.0rc14__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
bittensor_cli/__init__.py CHANGED
@@ -18,6 +18,6 @@
18
18
  from .cli import CLIManager
19
19
 
20
20
 
21
- __version__ = "8.2.0rc12"
21
+ __version__ = "8.2.0rc14"
22
22
 
23
23
  __all__ = ["CLIManager", "__version__"]
bittensor_cli/cli.py CHANGED
@@ -29,9 +29,10 @@ from bittensor_cli.src.bittensor.balances import Balance
29
29
  from bittensor_cli.src.bittensor.async_substrate_interface import (
30
30
  SubstrateRequestException,
31
31
  )
32
- from bittensor_cli.src.commands import subnets, sudo, wallets
32
+ from bittensor_cli.src.commands import sudo, wallets
33
33
  from bittensor_cli.src.commands import weights as weights_cmds
34
- from bittensor_cli.src.commands.stake import children_hotkeys, stake
34
+ from bittensor_cli.src.commands.subnets import price, subnets
35
+ from bittensor_cli.src.commands.stake import children_hotkeys, stake, move
35
36
  from bittensor_cli.src.bittensor.subtensor_interface import SubtensorInterface
36
37
  from bittensor_cli.src.bittensor.chain_data import SubnetHyperparameters
37
38
  from bittensor_cli.src.bittensor.utils import (
@@ -41,13 +42,14 @@ from bittensor_cli.src.bittensor.utils import (
41
42
  is_valid_ss58_address,
42
43
  print_error,
43
44
  validate_chain_endpoint,
44
- retry_prompt,
45
45
  validate_netuid,
46
46
  is_rao_network,
47
47
  get_effective_network,
48
48
  prompt_for_identity,
49
49
  validate_uri,
50
50
  prompt_for_subnet_identity,
51
+ print_linux_dependency_message,
52
+ is_linux,
51
53
  )
52
54
  from typing_extensions import Annotated
53
55
  from textwrap import dedent
@@ -62,7 +64,7 @@ except ImportError:
62
64
  pass
63
65
 
64
66
 
65
- __version__ = "8.2.0rc12"
67
+ __version__ = "8.2.0rc14"
66
68
 
67
69
 
68
70
  _core_version = re.match(r"^\d+\.\d+\.\d+", __version__).group(0)
@@ -685,8 +687,14 @@ class CLIManager:
685
687
  "list", rich_help_panel=HELP_PANELS["STAKE"]["STAKE_MGMT"]
686
688
  )(self.stake_list)
687
689
  self.stake_app.command(
688
- "move", rich_help_panel=HELP_PANELS["STAKE"]["STAKE_MGMT"]
690
+ "move", rich_help_panel=HELP_PANELS["STAKE"]["MOVEMENT"]
689
691
  )(self.stake_move)
692
+ self.stake_app.command(
693
+ "transfer", rich_help_panel=HELP_PANELS["STAKE"]["MOVEMENT"]
694
+ )(self.stake_transfer)
695
+ self.stake_app.command(
696
+ "swap", rich_help_panel=HELP_PANELS["STAKE"]["MOVEMENT"]
697
+ )(self.stake_swap)
690
698
 
691
699
  # stake-children commands
692
700
  children_app = typer.Typer()
@@ -754,7 +762,7 @@ class CLIManager:
754
762
  "show", rich_help_panel=HELP_PANELS["SUBNETS"]["INFO"]
755
763
  )(self.subnets_show)
756
764
  self.subnets_app.command(
757
- "price", rich_help_panel=HELP_PANELS["SUBNETS"]["INFO"], hidden=True
765
+ "price", rich_help_panel=HELP_PANELS["SUBNETS"]["INFO"]
758
766
  )(self.subnets_price)
759
767
 
760
768
  # weights commands
@@ -2926,14 +2934,18 @@ class CLIManager:
2926
2934
 
2927
2935
  def stake_move(
2928
2936
  self,
2929
- network=Options.network,
2937
+ network: Optional[list[str]] = Options.network,
2930
2938
  wallet_name=Options.wallet_name,
2931
2939
  wallet_path=Options.wallet_path,
2932
2940
  wallet_hotkey=Options.wallet_hotkey,
2933
- origin_netuid: int = typer.Option(help="Origin netuid", prompt=True),
2934
- destination_netuid: int = typer.Option(help="Destination netuid", prompt=True),
2941
+ origin_netuid: Optional[int] = typer.Option(
2942
+ None, "--origin-netuid", help="Origin netuid"
2943
+ ),
2944
+ destination_netuid: Optional[int] = typer.Option(
2945
+ None, "--dest-netuid", help="Destination netuid"
2946
+ ),
2935
2947
  destination_hotkey: Optional[str] = typer.Option(
2936
- None, help="Destination hotkey", prompt=False
2948
+ None, "--dest-ss58", "--dest", help="Destination hotkey", prompt=False
2937
2949
  ),
2938
2950
  amount: float = typer.Option(
2939
2951
  None,
@@ -2947,43 +2959,346 @@ class CLIManager:
2947
2959
  prompt: bool = Options.prompt,
2948
2960
  ):
2949
2961
  """
2950
- Move Staked TAO to a hotkey from one subnet to another.
2962
+ Move staked TAO between hotkeys while keeping the same coldkey ownership.
2963
+
2964
+ This command allows you to:
2965
+ - Move stake from one hotkey to another hotkey
2966
+ - Move stake between different subnets
2967
+ - Keep the same coldkey ownership
2968
+
2969
+ You can specify:
2970
+ - The origin subnet (--origin-netuid)
2971
+ - The destination subnet (--dest-netuid)
2972
+ - The destination hotkey (--dest-hotkey)
2973
+ - The amount to move (--amount)
2951
2974
 
2952
- THe move commands converts the origin subnet's dTao to Tao, and then converts Tao to destination subnet's dTao.
2975
+ If no arguments are provided, an interactive selection menu will be shown.
2953
2976
 
2954
2977
  EXAMPLE
2955
2978
 
2956
2979
  [green]$[/green] btcli stake move
2957
2980
  """
2958
- # TODO: Improve logic of moving stake (dest hotkey)
2959
- ask_for = (
2960
- [WO.NAME, WO.PATH] if destination_hotkey else [WO.NAME, WO.HOTKEY, WO.PATH]
2981
+ console.print(
2982
+ "[dim]This command moves stake from one hotkey to another hotkey while keeping the same coldkey.[/dim]"
2961
2983
  )
2962
- validate = WV.WALLET if destination_hotkey else WV.WALLET_AND_HOTKEY
2984
+ if not destination_hotkey:
2985
+ dest_wallet_or_ss58 = Prompt.ask(
2986
+ "Enter the [blue]destination wallet[/blue] where destination hotkey is located or [blue]ss58 address[/blue]"
2987
+ )
2988
+ if is_valid_ss58_address(dest_wallet_or_ss58):
2989
+ destination_hotkey = dest_wallet_or_ss58
2990
+ else:
2991
+ dest_wallet = self.wallet_ask(
2992
+ dest_wallet_or_ss58,
2993
+ wallet_path,
2994
+ None,
2995
+ ask_for=[WO.NAME, WO.PATH],
2996
+ validate=WV.WALLET,
2997
+ )
2998
+ destination_hotkey = Prompt.ask(
2999
+ "Enter the [blue]destination hotkey[/blue] name",
3000
+ default=dest_wallet.hotkey_str,
3001
+ )
3002
+ destination_wallet = self.wallet_ask(
3003
+ dest_wallet_or_ss58,
3004
+ wallet_path,
3005
+ destination_hotkey,
3006
+ ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
3007
+ validate=WV.WALLET_AND_HOTKEY,
3008
+ )
3009
+ destination_hotkey = destination_wallet.hotkey.ss58_address
3010
+ else:
3011
+ if is_valid_ss58_address(destination_hotkey):
3012
+ destination_hotkey = destination_hotkey
3013
+ else:
3014
+ print_error(
3015
+ "Invalid destination hotkey ss58 address. Please enter a valid ss58 address or wallet name."
3016
+ )
3017
+ raise typer.Exit()
2963
3018
 
3019
+ if not wallet_name:
3020
+ wallet_name = Prompt.ask(
3021
+ "Enter the [blue]origin wallet name[/blue]",
3022
+ default=self.config.get("wallet_name") or defaults.wallet.name,
3023
+ )
2964
3024
  wallet = self.wallet_ask(
2965
- wallet_name,
2966
- wallet_path,
2967
- wallet_hotkey,
2968
- ask_for=ask_for,
2969
- validate=validate,
3025
+ wallet_name, wallet_path, wallet_hotkey, ask_for=[WO.NAME, WO.PATH]
2970
3026
  )
2971
- if not destination_hotkey:
2972
- destination_hotkey = wallet.hotkey.ss58_address
3027
+
3028
+ interactive_selection = False
3029
+ if not wallet_hotkey:
3030
+ origin_hotkey = Prompt.ask(
3031
+ "Enter the [blue]origin hotkey[/blue] name or "
3032
+ "[blue]ss58 address[/blue] where the stake will be moved from "
3033
+ "[dim](or Press Enter to view existing stakes)[/dim]"
3034
+ )
3035
+ if origin_hotkey == "":
3036
+ interactive_selection = True
3037
+
3038
+ elif is_valid_ss58_address(origin_hotkey):
3039
+ origin_hotkey = origin_hotkey
3040
+ else:
3041
+ wallet = self.wallet_ask(
3042
+ wallet_name,
3043
+ wallet_path,
3044
+ origin_hotkey,
3045
+ ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
3046
+ validate=WV.WALLET_AND_HOTKEY,
3047
+ )
3048
+ origin_hotkey = wallet.hotkey.ss58_address
3049
+ else:
3050
+ wallet = self.wallet_ask(
3051
+ wallet_name,
3052
+ wallet_path,
3053
+ wallet_hotkey,
3054
+ ask_for=[],
3055
+ validate=WV.WALLET_AND_HOTKEY,
3056
+ )
3057
+ origin_hotkey = wallet.hotkey.ss58_address
3058
+
3059
+ if not interactive_selection:
3060
+ if not origin_netuid:
3061
+ origin_netuid = IntPrompt.ask(
3062
+ "Enter the [blue]origin subnet[/blue] (netuid) to move stake from"
3063
+ )
3064
+
3065
+ if not destination_netuid:
3066
+ destination_netuid = IntPrompt.ask(
3067
+ "Enter the [blue]destination subnet[/blue] (netuid) to move stake to"
3068
+ )
2973
3069
 
2974
3070
  return self._run_command(
2975
- stake.move_stake(
3071
+ move.move_stake(
2976
3072
  subtensor=self.initialize_chain(network),
2977
3073
  wallet=wallet,
2978
3074
  origin_netuid=origin_netuid,
3075
+ origin_hotkey=origin_hotkey,
2979
3076
  destination_netuid=destination_netuid,
2980
3077
  destination_hotkey=destination_hotkey,
2981
3078
  amount=amount,
2982
3079
  stake_all=stake_all,
3080
+ interactive_selection=interactive_selection,
2983
3081
  prompt=prompt,
2984
3082
  )
2985
3083
  )
2986
3084
 
3085
+ def stake_transfer(
3086
+ self,
3087
+ network: Optional[list[str]] = Options.network,
3088
+ wallet_name: Optional[str] = Options.wallet_name,
3089
+ wallet_path: Optional[str] = Options.wallet_path,
3090
+ wallet_hotkey: Optional[str] = Options.wallet_hotkey,
3091
+ origin_netuid: Optional[int] = typer.Option(
3092
+ None,
3093
+ "--origin-netuid",
3094
+ help="The netuid to transfer stake from",
3095
+ ),
3096
+ dest_netuid: Optional[int] = typer.Option(
3097
+ None,
3098
+ "--dest-netuid",
3099
+ help="The netuid to transfer stake to",
3100
+ ),
3101
+ dest_ss58: Optional[str] = typer.Option(
3102
+ None,
3103
+ "--dest-ss58",
3104
+ "--dest",
3105
+ "--dest-coldkey",
3106
+ help="The destination wallet name or SS58 address to transfer stake to",
3107
+ ),
3108
+ amount: float = typer.Option(
3109
+ None,
3110
+ "--amount",
3111
+ "-a",
3112
+ help="Amount of stake to transfer",
3113
+ ),
3114
+ prompt: bool = Options.prompt,
3115
+ quiet: bool = Options.quiet,
3116
+ verbose: bool = Options.verbose,
3117
+ ):
3118
+ """
3119
+ Transfer stake between coldkeys while keeping the same hotkey ownership.
3120
+
3121
+ This command allows you to:
3122
+ - Transfer stake from one coldkey to another coldkey
3123
+ - Keep the same hotkey ownership
3124
+ - Transfer stake between different subnets
3125
+
3126
+ You can specify:
3127
+ - The origin subnet (--origin-netuid)
3128
+ - The destination subnet (--dest-netuid)
3129
+ - The destination wallet/address (--dest)
3130
+ - The amount to transfer (--amount)
3131
+
3132
+ If no arguments are provided, an interactive selection menu will be shown.
3133
+
3134
+ EXAMPLE
3135
+
3136
+ Transfer 100 TAO from subnet 1 to subnet 2:
3137
+ [green]$[/green] btcli stake transfer --origin-netuid 1 --dest-netuid 2 --dest wallet2 --amount 100
3138
+
3139
+ Using SS58 address:
3140
+ [green]$[/green] btcli stake transfer --origin-netuid 1 --dest-netuid 2 --dest 5FrLxJsyJ5x9n2rmxFwosFraxFCKcXZDngEP9H7qjkKgHLcK --amount 100
3141
+ """
3142
+ console.print(
3143
+ "[dim]This command transfers stake from one coldkey to another while keeping the same hotkey.[/dim]"
3144
+ )
3145
+ self.verbosity_handler(quiet, verbose)
3146
+
3147
+ wallet = self.wallet_ask(
3148
+ wallet_name,
3149
+ wallet_path,
3150
+ wallet_hotkey,
3151
+ ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
3152
+ validate=WV.WALLET_AND_HOTKEY,
3153
+ )
3154
+
3155
+ if not dest_ss58:
3156
+ dest_ss58 = Prompt.ask(
3157
+ "Enter the [blue]destination wallet name[/blue] or [blue]coldkey SS58 address[/blue]"
3158
+ )
3159
+
3160
+ if is_valid_ss58_address(dest_ss58):
3161
+ dest_ss58 = dest_ss58
3162
+ else:
3163
+ dest_wallet = self.wallet_ask(
3164
+ dest_ss58,
3165
+ wallet_path,
3166
+ None,
3167
+ ask_for=[WO.NAME, WO.PATH],
3168
+ validate=WV.WALLET,
3169
+ )
3170
+ dest_ss58 = dest_wallet.coldkeypub.ss58_address
3171
+
3172
+ interactive_selection = False
3173
+ if origin_netuid is None and dest_netuid is None and not amount:
3174
+ interactive_selection = True
3175
+ else:
3176
+ if origin_netuid is None:
3177
+ origin_netuid = IntPrompt.ask(
3178
+ "Enter the [blue]origin subnet[/blue] (netuid)"
3179
+ )
3180
+ if not amount:
3181
+ amount = FloatPrompt.ask("Enter the [blue]amount[/blue] to transfer")
3182
+
3183
+ if dest_netuid is None:
3184
+ dest_netuid = IntPrompt.ask(
3185
+ "Enter the [blue]destination subnet[/blue] (netuid)"
3186
+ )
3187
+
3188
+ return self._run_command(
3189
+ move.transfer_stake(
3190
+ wallet=wallet,
3191
+ subtensor=self.initialize_chain(network),
3192
+ origin_netuid=origin_netuid,
3193
+ dest_netuid=dest_netuid,
3194
+ dest_coldkey_ss58=dest_ss58,
3195
+ amount=amount,
3196
+ interactive_selection=interactive_selection,
3197
+ prompt=prompt,
3198
+ )
3199
+ )
3200
+
3201
+ def stake_swap(
3202
+ self,
3203
+ network: Optional[list[str]] = Options.network,
3204
+ wallet_name: Optional[str] = Options.wallet_name,
3205
+ wallet_path: Optional[str] = Options.wallet_path,
3206
+ wallet_hotkey: Optional[str] = Options.wallet_hotkey,
3207
+ origin_netuid: Optional[int] = typer.Option(
3208
+ None,
3209
+ "--origin-netuid",
3210
+ "-o",
3211
+ "--origin",
3212
+ help="The netuid to swap stake from",
3213
+ ),
3214
+ dest_netuid: Optional[int] = typer.Option(
3215
+ None,
3216
+ "--dest-netuid",
3217
+ "-d",
3218
+ "--dest",
3219
+ help="The netuid to swap stake to",
3220
+ ),
3221
+ amount: float = typer.Option(
3222
+ None,
3223
+ "--amount",
3224
+ "-a",
3225
+ help="Amount of stake to swap",
3226
+ ),
3227
+ swap_all: bool = typer.Option(
3228
+ False,
3229
+ "--swap-all",
3230
+ "--all",
3231
+ help="Swap all available stake",
3232
+ ),
3233
+ prompt: bool = Options.prompt,
3234
+ wait_for_inclusion: bool = Options.wait_for_inclusion,
3235
+ wait_for_finalization: bool = Options.wait_for_finalization,
3236
+ quiet: bool = Options.quiet,
3237
+ verbose: bool = Options.verbose,
3238
+ ):
3239
+ """
3240
+ Swap stake between different subnets while keeping the same coldkey-hotkey pair ownership.
3241
+
3242
+ This command allows you to:
3243
+ - Move stake from one subnet to another subnet
3244
+ - Keep the same coldkey ownership
3245
+ - Keep the same hotkey ownership
3246
+
3247
+ You can specify:
3248
+ - The origin subnet (--origin-netuid)
3249
+ - The destination subnet (--dest-netuid)
3250
+ - The amount to swap (--amount)
3251
+
3252
+ If no arguments are provided, an interactive selection menu will be shown.
3253
+
3254
+ EXAMPLE
3255
+
3256
+ Swap 100 TAO from subnet 1 to subnet 2:
3257
+ [green]$[/green] btcli stake swap --wallet-name default --wallet-hotkey default --origin-netuid 1 --dest-netuid 2 --amount 100
3258
+ """
3259
+ console.print(
3260
+ "[dim]This command moves stake from one subnet to another subnet while keeping the same coldkey-hotkey pair.[/dim]"
3261
+ )
3262
+ self.verbosity_handler(quiet, verbose)
3263
+
3264
+ wallet = self.wallet_ask(
3265
+ wallet_name,
3266
+ wallet_path,
3267
+ wallet_hotkey,
3268
+ ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
3269
+ validate=WV.WALLET_AND_HOTKEY,
3270
+ )
3271
+
3272
+ interactive_selection = False
3273
+ if origin_netuid is None and dest_netuid is None and not amount:
3274
+ interactive_selection = True
3275
+ else:
3276
+ if origin_netuid is None:
3277
+ origin_netuid = IntPrompt.ask(
3278
+ "Enter the [blue]origin subnet[/blue] (netuid)"
3279
+ )
3280
+ if dest_netuid is None:
3281
+ dest_netuid = IntPrompt.ask(
3282
+ "Enter the [blue]destination subnet[/blue] (netuid)"
3283
+ )
3284
+ if not amount and not swap_all:
3285
+ amount = FloatPrompt.ask("Enter the [blue]amount[/blue] to swap")
3286
+
3287
+ return self._run_command(
3288
+ move.swap_stake(
3289
+ wallet=wallet,
3290
+ subtensor=self.initialize_chain(network),
3291
+ origin_netuid=origin_netuid,
3292
+ destination_netuid=dest_netuid,
3293
+ amount=amount,
3294
+ swap_all=swap_all,
3295
+ interactive_selection=interactive_selection,
3296
+ prompt=prompt,
3297
+ wait_for_inclusion=wait_for_inclusion,
3298
+ wait_for_finalization=wait_for_finalization,
3299
+ )
3300
+ )
3301
+
2987
3302
  def stake_get_children(
2988
3303
  self,
2989
3304
  wallet_name: Optional[str] = Options.wallet_name,
@@ -3561,23 +3876,88 @@ class CLIManager:
3561
3876
  def subnets_price(
3562
3877
  self,
3563
3878
  network: Optional[list[str]] = Options.network,
3564
- netuid: int = Options.netuid,
3879
+ netuids: str = typer.Option(
3880
+ None,
3881
+ "--netuids",
3882
+ "--netuid",
3883
+ "-n",
3884
+ help="Netuid(s) to show the price for.",
3885
+ ),
3565
3886
  interval_hours: int = typer.Option(
3566
3887
  24,
3567
3888
  "--interval-hours",
3568
3889
  "--interval",
3569
3890
  help="The number of hours to show the historical price for.",
3570
3891
  ),
3892
+ all_netuids: bool = typer.Option(
3893
+ False,
3894
+ "--all-netuids",
3895
+ "--all",
3896
+ help="Show the price for all subnets.",
3897
+ ),
3898
+ log_scale: bool = typer.Option(
3899
+ False,
3900
+ "--log-scale",
3901
+ "--log",
3902
+ help="Show the price in log scale.",
3903
+ ),
3904
+ html_output: bool = Options.html_output,
3571
3905
  ):
3572
3906
  """
3573
3907
  Shows the historical price of a subnet for the past 24 hours.
3574
3908
 
3909
+ This command displays the historical price of a subnet for the past 24 hours.
3910
+ If the `--all` flag is used, the command will display the price for all subnets in html format.
3911
+ If the `--html` flag is used, the command will display the price in an HTML chart.
3912
+ If the `--log-scale` flag is used, the command will display the price in log scale.
3913
+ If no html flag is used, the command will display the price in the cli.
3914
+
3575
3915
  EXAMPLE
3576
3916
 
3577
3917
  [green]$[/green] btcli subnets price --netuid 1
3918
+ [green]$[/green] btcli subnets price --netuid 1 --html --log
3919
+ [green]$[/green] btcli subnets price --all --html
3920
+ [green]$[/green] btcli subnets price --netuids 1,2,3,4 --html
3578
3921
  """
3922
+ if netuids:
3923
+ netuids = parse_to_list(
3924
+ netuids,
3925
+ int,
3926
+ "Netuids must be a comma-separated list of ints, e.g., `--netuids 1,2,3,4`.",
3927
+ )
3928
+ if all_netuids and netuids:
3929
+ print_error("Cannot specify both --netuid and --all-netuids")
3930
+ raise typer.Exit()
3931
+
3932
+ if not netuids and not all_netuids:
3933
+ netuids = Prompt.ask(
3934
+ "Enter the [blue]netuid(s)[/blue] to view the price of in comma-separated format [dim](or Press Enter to view all subnets)[/dim]",
3935
+ )
3936
+ if not netuids:
3937
+ all_netuids = True
3938
+ html_output = True
3939
+ else:
3940
+ netuids = parse_to_list(
3941
+ netuids,
3942
+ int,
3943
+ "Netuids must be a comma-separated list of ints, e.g., `--netuids 1,2,3,4`.",
3944
+ )
3945
+
3946
+ if all_netuids:
3947
+ html_output = True
3948
+
3949
+ if html_output and is_linux():
3950
+ print_linux_dependency_message()
3951
+
3579
3952
  return self._run_command(
3580
- subnets.price(self.initialize_chain(network), netuid, interval_hours)
3953
+ price.price(
3954
+ self.initialize_chain(network),
3955
+ netuids,
3956
+ all_netuids,
3957
+ interval_hours,
3958
+ html_output,
3959
+ log_scale,
3960
+ )
3581
3961
  )
3582
3962
 
3583
3963
  def subnets_show(
@@ -869,6 +869,7 @@ HELP_PANELS = {
869
869
  "STAKE": {
870
870
  "STAKE_MGMT": "Stake Management",
871
871
  "CHILD": "Child Hotkeys",
872
+ "MOVEMENT": "Stake Movement",
872
873
  },
873
874
  "SUDO": {
874
875
  "CONFIG": "Subnet Configuration",
@@ -17,7 +17,7 @@
17
17
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18
18
  # DEALINGS IN THE SOFTWARE.
19
19
 
20
- from typing import Union
20
+ from typing import Union, TypedDict
21
21
  from bittensor_cli.src import UNITS
22
22
 
23
23
 
@@ -301,3 +301,31 @@ class Balance:
301
301
  self.unit = Balance.get_unit(netuid)
302
302
  self.rao_unit = Balance.get_unit(netuid)
303
303
  return self
304
+
305
+
306
+ class FixedPoint(TypedDict):
307
+ """
308
+ Represents a fixed point ``U64F64`` number.
309
+ Where ``bits`` is a U128 representation of the fixed point number.
310
+
311
+ This matches the type of the Alpha shares.
312
+ """
313
+
314
+ bits: int
315
+
316
+
317
+ def fixed_to_float(fixed: FixedPoint) -> float:
318
+ # Currently this is stored as a U64F64
319
+ # which is 64 bits of integer and 64 bits of fractional
320
+ uint_bits = 64
321
+ frac_bits = 64
322
+
323
+ data: int = fixed["bits"]
324
+
325
+ # Shift bits to extract integer part (assuming 64 bits for integer part)
326
+ integer_part = data >> frac_bits
327
+ fractional_part = data & (2**frac_bits - 1)
328
+
329
+ frac_float = fractional_part / (2**frac_bits)
330
+
331
+ return integer_part + frac_float
@@ -1035,7 +1035,13 @@ class DynamicInfo:
1035
1035
  else:
1036
1036
  alpha_returned = tao.set_unit(self.netuid)
1037
1037
  slippage = Balance.from_tao(0)
1038
- return alpha_returned, slippage
1038
+
1039
+ slippage_pct_float = (
1040
+ 100 * float(slippage) / float(slippage + alpha_returned)
1041
+ if slippage + alpha_returned != 0
1042
+ else 0
1043
+ )
1044
+ return alpha_returned, slippage, slippage_pct_float
1039
1045
 
1040
1046
  def alpha_to_tao_with_slippage(self, alpha: Balance) -> tuple[Balance, Balance]:
1041
1047
  """
@@ -1063,7 +1069,12 @@ class DynamicInfo:
1063
1069
  else:
1064
1070
  tao_returned = alpha.set_unit(0)
1065
1071
  slippage = Balance.from_tao(0)
1066
- return tao_returned, slippage
1072
+ slippage_pct_float = (
1073
+ 100 * float(slippage) / float(slippage + tao_returned)
1074
+ if slippage + tao_returned != 0
1075
+ else 0
1076
+ )
1077
+ return tao_returned, slippage, slippage_pct_float
1067
1078
 
1068
1079
 
1069
1080
  @dataclass