|
1 | | -from typing import Optional, TYPE_CHECKING |
2 | | - |
3 | | -import rich.prompt |
4 | | -from rich.table import Table |
5 | | - |
6 | | -from bittensor_cli.src.bittensor.chain_data import DelegateInfoLite |
7 | | -from bittensor_cli.src.bittensor.utils import console |
8 | | - |
9 | | -if TYPE_CHECKING: |
10 | | - from bittensor_cli.src.bittensor.subtensor_interface import SubtensorInterface |
11 | | - |
12 | | - |
13 | | -async def select_delegate(subtensor: "SubtensorInterface", netuid: int): |
14 | | - # Get a list of delegates and sort them by total stake in descending order |
15 | | - delegates: list[DelegateInfoLite] = ( |
16 | | - await subtensor.get_delegates_by_netuid_light(netuid) |
17 | | - ).sort(key=lambda x: x.total_stake, reverse=True) |
18 | | - |
19 | | - # Get registered delegates details. |
20 | | - registered_delegate_info = await subtensor.get_delegate_identities() |
21 | | - |
22 | | - # Create a table to display delegate information |
23 | | - table = Table( |
24 | | - show_header=True, |
25 | | - header_style="bold", |
26 | | - border_style="rgb(7,54,66)", |
27 | | - style="rgb(0,43,54)", |
28 | | - ) |
29 | | - |
30 | | - # Add columns to the table with specific styles |
31 | | - table.add_column("Index", style="rgb(253,246,227)", no_wrap=True) |
32 | | - table.add_column("Delegate Name", no_wrap=True) |
33 | | - table.add_column("Hotkey SS58", style="rgb(211,54,130)", no_wrap=True) |
34 | | - table.add_column("Owner SS58", style="rgb(133,153,0)", no_wrap=True) |
35 | | - table.add_column("Take", style="rgb(181,137,0)", no_wrap=True) |
36 | | - table.add_column( |
37 | | - "Total Stake", style="rgb(38,139,210)", no_wrap=True, justify="right" |
38 | | - ) |
39 | | - table.add_column( |
40 | | - "Owner Stake", style="rgb(220,50,47)", no_wrap=True, justify="right" |
41 | | - ) |
42 | | - # table.add_column("Return per 1000", style="rgb(108,113,196)", no_wrap=True, justify="right") |
43 | | - # table.add_column("Total Daily Return", style="rgb(42,161,152)", no_wrap=True, justify="right") |
44 | | - |
45 | | - # List to store visible delegates |
46 | | - visible_delegates = [] |
47 | | - |
48 | | - def get_user_input() -> str: |
49 | | - return rich.prompt.Prompt.ask( |
50 | | - 'Press Enter to scroll, enter a number (1-N) to select, or type "h" for help: ', |
51 | | - choices=["", "h"] + [str(x) for x in range(1, len(delegates) - 1)], |
52 | | - show_choices=True, |
53 | | - ) |
54 | | - |
55 | | - # TODO: Add pagination to handle large number of delegates more efficiently |
56 | | - # Iterate through delegates and display their information |
57 | | - |
58 | | - def loop_selections() -> Optional[int]: |
59 | | - idx = 0 |
60 | | - selected_idx = None |
61 | | - while idx < len(delegates): |
62 | | - if idx < len(delegates): |
63 | | - delegate = delegates[idx] |
64 | | - |
65 | | - # Add delegate to visible list |
66 | | - visible_delegates.append(delegate) |
67 | | - |
68 | | - # Add a row to the table with delegate information |
69 | | - table.add_row( |
70 | | - str(idx), |
71 | | - registered_delegate_info[delegate.hotkey_ss58].name |
72 | | - if delegate.hotkey_ss58 in registered_delegate_info |
73 | | - else "", |
74 | | - delegate.hotkey_ss58[:5] |
75 | | - + "..." |
76 | | - + delegate.hotkey_ss58[-5:], # Show truncated hotkey |
77 | | - delegate.owner_ss58[:5] |
78 | | - + "..." |
79 | | - + delegate.owner_ss58[-5:], # Show truncated owner address |
80 | | - f"{delegate.take:.6f}", |
81 | | - f"τ{delegate.total_stake.tao:,.4f}", |
82 | | - f"τ{delegate.owner_stake.tao:,.4f}", |
83 | | - # f"τ{delegate.return_per_1000.tao:,.4f}", |
84 | | - # f"τ{delegate.total_daily_return.tao:,.4f}", |
85 | | - ) |
86 | | - |
87 | | - # Clear console and print updated table |
88 | | - console.clear() |
89 | | - console.print(table) |
90 | | - |
91 | | - # Prompt user for input |
92 | | - user_input: str = get_user_input() |
93 | | - |
94 | | - # Add a help option to display information about each column |
95 | | - if user_input == "h": |
96 | | - console.print("\nColumn Information:") |
97 | | - console.print( |
98 | | - "[rgb(253,246,227)]Index:[/rgb(253,246,227)] Position in the list of delegates" |
99 | | - ) |
100 | | - console.print( |
101 | | - "[rgb(211,54,130)]Hotkey SS58:[/rgb(211,54,130)] Truncated public key of the delegate's hotkey" |
102 | | - ) |
103 | | - console.print( |
104 | | - "[rgb(133,153,0)]Owner SS58:[/rgb(133,153,0)] Truncated public key of the delegate's owner" |
105 | | - ) |
106 | | - console.print( |
107 | | - "[rgb(181,137,0)]Take:[/rgb(181,137,0)] Percentage of rewards the delegate takes" |
108 | | - ) |
109 | | - console.print( |
110 | | - "[rgb(38,139,210)]Total Stake:[/rgb(38,139,210)] Total amount staked to this delegate" |
111 | | - ) |
112 | | - console.print( |
113 | | - "[rgb(220,50,47)]Owner Stake:[/rgb(220,50,47)] Amount staked by the delegate owner" |
114 | | - ) |
115 | | - console.print( |
116 | | - "[rgb(108,113,196)]Return per 1000:[/rgb(108,113,196)] Estimated return for 1000 Tao staked" |
117 | | - ) |
118 | | - console.print( |
119 | | - "[rgb(42,161,152)]Total Daily Return:[/rgb(42,161,152)] Estimated total daily return for all stake" |
120 | | - ) |
121 | | - user_input = get_user_input() |
122 | | - |
123 | | - # If user presses Enter, continue to next delegate |
124 | | - if user_input and user_input != "h": |
125 | | - selected_idx = int(user_input) |
126 | | - break |
127 | | - |
128 | | - if idx < len(delegates): |
129 | | - idx += 1 |
130 | | - |
131 | | - return selected_idx |
132 | | - |
133 | | - # TODO( const ): uncomment for check |
134 | | - # Add a confirmation step before returning the selected delegate |
135 | | - # console.print(f"\nSelected delegate: [rgb(211,54,130)]{visible_delegates[selected_idx].hotkey_ss58}[/rgb(211,54,130)]") |
136 | | - # console.print(f"Take: [rgb(181,137,0)]{visible_delegates[selected_idx].take:.6f}[/rgb(181,137,0)]") |
137 | | - # console.print(f"Total Stake: [rgb(38,139,210)]{visible_delegates[selected_idx].total_stake}[/rgb(38,139,210)]") |
138 | | - |
139 | | - # confirmation = Prompt.ask("Do you want to proceed with this delegate? (y/n)") |
140 | | - # if confirmation.lower() != 'yes' and confirmation.lower() != 'y': |
141 | | - # return select_delegate( subtensor, netuid ) |
142 | | - |
143 | | - # Return the selected delegate |
144 | | - while True: |
145 | | - selected_idx_ = loop_selections() |
146 | | - if selected_idx_ is None: |
147 | | - if not rich.prompt.Confirm.ask( |
148 | | - "You've reached the end of the list. You must make a selection. Loop through again?" |
149 | | - ): |
150 | | - raise IndexError |
151 | | - else: |
152 | | - continue |
153 | | - else: |
154 | | - return delegates[selected_idx_] |
0 commit comments