Skip to content

Commit 25ad35a

Browse files
authored
Merge pull request #399 from opentensor/feat/swap-coldkey
Feat/swap coldkey
2 parents 3a49a95 + f295a96 commit 25ad35a

File tree

4 files changed

+486
-8
lines changed

4 files changed

+486
-8
lines changed

bittensor_cli/cli.py

Lines changed: 173 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,17 @@ class Options:
109109
"--wallet.hotkey",
110110
help="Hotkey of the wallet",
111111
)
112+
wallet_ss58_address = typer.Option(
113+
None,
114+
"--wallet-name",
115+
"--name",
116+
"--wallet_name",
117+
"--wallet.name",
118+
"--address",
119+
"--ss58",
120+
"--ss58-address",
121+
help="SS58 address or wallet name to check. Leave empty to be prompted.",
122+
)
112123
wallet_hotkey_ss58 = typer.Option(
113124
None,
114125
"--hotkey",
@@ -684,6 +695,12 @@ def __init__(self):
684695
self.wallet_app.command(
685696
"swap-hotkey", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"]
686697
)(self.wallet_swap_hotkey)
698+
self.wallet_app.command(
699+
"swap-coldkey", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"]
700+
)(self.wallet_swap_coldkey)
701+
self.wallet_app.command(
702+
"swap-check", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"]
703+
)(self.wallet_check_ck_swap)
687704
self.wallet_app.command(
688705
"regen-coldkey", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"]
689706
)(self.wallet_regen_coldkey)
@@ -2306,28 +2323,92 @@ def wallet_new_coldkey(
23062323

23072324
def wallet_check_ck_swap(
23082325
self,
2309-
wallet_name: Optional[str] = Options.wallet_name,
2326+
wallet_ss58_address: Optional[str] = Options.wallet_ss58_address,
23102327
wallet_path: Optional[str] = Options.wallet_path,
23112328
wallet_hotkey: Optional[str] = Options.wallet_hotkey,
2329+
scheduled_block: Optional[int] = typer.Option(
2330+
None,
2331+
"--block",
2332+
help="Block number where the swap was scheduled",
2333+
),
2334+
show_all: bool = typer.Option(
2335+
False,
2336+
"--all",
2337+
"-a",
2338+
help="Show all pending coldkey swaps",
2339+
),
23122340
network: Optional[list[str]] = Options.network,
23132341
quiet: bool = Options.quiet,
23142342
verbose: bool = Options.verbose,
23152343
):
23162344
"""
2317-
Check the status of your scheduled coldkey swap.
2345+
Check the status of scheduled coldkey swaps.
23182346
23192347
USAGE
23202348
2321-
Users should provide the old coldkey wallet to check the swap status.
2349+
This command can be used in three ways:
2350+
1. Show all pending swaps (--all)
2351+
2. Check status of a specific wallet's swap or SS58 address
2352+
3. Check detailed swap status with block number (--block)
23222353
2323-
EXAMPLE
2354+
EXAMPLES
2355+
2356+
Show all pending swaps:
2357+
[green]$[/green] btcli wallet swap-check --all
23242358
2325-
[green]$[/green] btcli wallet check_coldkey_swap
2359+
Check specific wallet's swap:
2360+
[green]$[/green] btcli wallet swap-check --wallet-name my_wallet
2361+
2362+
Check swap using SS58 address:
2363+
[green]$[/green] btcli wallet swap-check --ss58 5DkQ4...
2364+
2365+
Check swap details with block number:
2366+
[green]$[/green] btcli wallet swap-check --wallet-name my_wallet --block 12345
23262367
"""
23272368
self.verbosity_handler(quiet, verbose)
2328-
wallet = self.wallet_ask(wallet_name, wallet_path, wallet_hotkey)
23292369
self.initialize_chain(network)
2330-
return self._run_command(wallets.check_coldkey_swap(wallet, self.subtensor))
2370+
2371+
if show_all:
2372+
return self._run_command(
2373+
wallets.check_swap_status(self.subtensor, None, None)
2374+
)
2375+
2376+
if not wallet_ss58_address:
2377+
wallet_ss58_address = Prompt.ask(
2378+
"Enter [blue]wallet name[/blue] or [blue]SS58 address[/blue] [dim](leave blank to show all pending swaps)[/dim]"
2379+
)
2380+
if not wallet_ss58_address:
2381+
return self._run_command(
2382+
wallets.check_swap_status(self.subtensor, None, None)
2383+
)
2384+
2385+
if is_valid_ss58_address(wallet_ss58_address):
2386+
ss58_address = wallet_ss58_address
2387+
else:
2388+
wallet = self.wallet_ask(
2389+
wallet_ss58_address,
2390+
wallet_path,
2391+
wallet_hotkey,
2392+
ask_for=[WO.NAME, WO.PATH],
2393+
validate=WV.WALLET,
2394+
)
2395+
ss58_address = wallet.coldkeypub.ss58_address
2396+
2397+
if not scheduled_block:
2398+
block_input = Prompt.ask(
2399+
"[blue]Enter the block number[/blue] where the swap was scheduled [dim](optional, press enter to skip)[/dim]",
2400+
default="",
2401+
)
2402+
if block_input:
2403+
try:
2404+
scheduled_block = int(block_input)
2405+
except ValueError:
2406+
print_error("Invalid block number")
2407+
raise typer.Exit()
2408+
2409+
return self._run_command(
2410+
wallets.check_swap_status(self.subtensor, ss58_address, scheduled_block)
2411+
)
23312412

23322413
def wallet_create_wallet(
23332414
self,
@@ -2762,6 +2843,91 @@ def wallet_sign(
27622843

27632844
return self._run_command(wallets.sign(wallet, message, use_hotkey))
27642845

2846+
def wallet_swap_coldkey(
2847+
self,
2848+
wallet_name: Optional[str] = Options.wallet_name,
2849+
wallet_path: Optional[str] = Options.wallet_path,
2850+
wallet_hotkey: Optional[str] = Options.wallet_hotkey,
2851+
new_wallet_or_ss58: Optional[str] = typer.Option(
2852+
None,
2853+
"--new-coldkey",
2854+
"--new-coldkey-ss58",
2855+
"--new-wallet",
2856+
"--new",
2857+
help="SS58 address of the new coldkey that will replace the current one.",
2858+
),
2859+
network: Optional[list[str]] = Options.network,
2860+
quiet: bool = Options.quiet,
2861+
verbose: bool = Options.verbose,
2862+
force_swap: bool = typer.Option(
2863+
False,
2864+
"--force",
2865+
"-f",
2866+
"--force-swap",
2867+
help="Force the swap even if the new coldkey is already scheduled for a swap.",
2868+
),
2869+
):
2870+
"""
2871+
Schedule a coldkey swap for a wallet.
2872+
2873+
This command allows you to schedule a coldkey swap for a wallet. You can either provide a new wallet name, or SS58 address.
2874+
2875+
EXAMPLES
2876+
2877+
[green]$[/green] btcli wallet schedule-coldkey-swap --new-wallet my_new_wallet
2878+
2879+
[green]$[/green] btcli wallet schedule-coldkey-swap --new-coldkey-ss58 5Dk...X3q
2880+
"""
2881+
self.verbosity_handler(quiet, verbose)
2882+
2883+
if not wallet_name:
2884+
wallet_name = Prompt.ask(
2885+
"Enter the [blue]wallet name[/blue] which you want to swap the coldkey for",
2886+
default=self.config.get("wallet_name") or defaults.wallet.name,
2887+
)
2888+
wallet = self.wallet_ask(
2889+
wallet_name,
2890+
wallet_path,
2891+
wallet_hotkey,
2892+
ask_for=[WO.NAME],
2893+
validate=WV.WALLET,
2894+
)
2895+
console.print(
2896+
f"\nWallet selected to swap the [blue]coldkey[/blue] from: \n"
2897+
f"[dark_sea_green3]{wallet}[/dark_sea_green3]\n"
2898+
)
2899+
2900+
if not new_wallet_or_ss58:
2901+
new_wallet_or_ss58 = Prompt.ask(
2902+
"Enter the [blue]new wallet name[/blue] or [blue]SS58 address[/blue] of the new coldkey",
2903+
)
2904+
2905+
if is_valid_ss58_address(new_wallet_or_ss58):
2906+
new_wallet_coldkey_ss58 = new_wallet_or_ss58
2907+
else:
2908+
new_wallet_name = new_wallet_or_ss58
2909+
new_wallet = self.wallet_ask(
2910+
new_wallet_name,
2911+
wallet_path,
2912+
wallet_hotkey,
2913+
ask_for=[WO.NAME],
2914+
validate=WV.WALLET,
2915+
)
2916+
console.print(
2917+
f"\nNew wallet to swap the [blue]coldkey[/blue] to: \n"
2918+
f"[dark_sea_green3]{new_wallet}[/dark_sea_green3]\n"
2919+
)
2920+
new_wallet_coldkey_ss58 = new_wallet.coldkeypub.ss58_address
2921+
2922+
return self._run_command(
2923+
wallets.schedule_coldkey_swap(
2924+
wallet=wallet,
2925+
subtensor=self.initialize_chain(network),
2926+
new_coldkey_ss58=new_wallet_coldkey_ss58,
2927+
force_swap=force_swap,
2928+
)
2929+
)
2930+
27652931
def stake_list(
27662932
self,
27672933
network: Optional[list[str]] = Options.network,

bittensor_cli/src/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ class Constants:
3333
"latent-lite": latent_lite_entrypoint,
3434
"subvortex": subvortex_entrypoint,
3535
}
36+
genesis_block_hash_map = {
37+
"finney": "0x2f0555cc76fc2840a25a6ea3b9637146806f1f44b090c175ffde2a7e5ab36c03",
38+
"test": "0x8f9cf856bf558a14440e75569c9e58594757048d7b3a84b5d25f6bd978263105",
39+
}
3640
delegates_detail_url = "https://raw.githubusercontent.com/opentensor/bittensor-delegates/main/public/delegates.json"
3741

3842

bittensor_cli/src/bittensor/subtensor_interface.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,3 +1501,53 @@ async def get_stake_fee(
15011501
)
15021502

15031503
return Balance.from_rao(result)
1504+
1505+
async def get_scheduled_coldkey_swap(
1506+
self,
1507+
block_hash: Optional[str] = None,
1508+
reuse_block: bool = False,
1509+
) -> Optional[list[str]]:
1510+
"""
1511+
Queries the chain to fetch the list of coldkeys that are scheduled for a swap.
1512+
1513+
:param block_hash: Block hash at which to perform query.
1514+
:param reuse_block: Whether to reuse the last-used block hash.
1515+
1516+
:return: A list of SS58 addresses of the coldkeys that are scheduled for a coldkey swap.
1517+
"""
1518+
result = await self.substrate.query_map(
1519+
module="SubtensorModule",
1520+
storage_function="ColdkeySwapScheduled",
1521+
block_hash=block_hash,
1522+
reuse_block_hash=reuse_block,
1523+
)
1524+
1525+
keys_pending_swap = []
1526+
async for ss58, _ in result:
1527+
keys_pending_swap.append(decode_account_id(ss58))
1528+
return keys_pending_swap
1529+
1530+
async def get_coldkey_swap_schedule_duration(
1531+
self,
1532+
block_hash: Optional[str] = None,
1533+
reuse_block: bool = False,
1534+
) -> int:
1535+
"""
1536+
Retrieves the duration (in blocks) required for a coldkey swap to be executed.
1537+
1538+
Args:
1539+
block_hash: The hash of the blockchain block number for the query.
1540+
reuse_block: Whether to reuse the last-used blockchain block hash.
1541+
1542+
Returns:
1543+
int: The number of blocks required for the coldkey swap schedule duration.
1544+
"""
1545+
result = await self.query(
1546+
module="SubtensorModule",
1547+
storage_function="ColdkeySwapScheduleDuration",
1548+
params=[],
1549+
block_hash=block_hash,
1550+
reuse_block_hash=reuse_block,
1551+
)
1552+
1553+
return result

0 commit comments

Comments
 (0)