diff --git a/kaleido_cli/commands/node.py b/kaleido_cli/commands/node.py index 23040ae..6c78cfe 100644 --- a/kaleido_cli/commands/node.py +++ b/kaleido_cli/commands/node.py @@ -17,6 +17,12 @@ DEFAULT_INDEXER_URL, DEFAULT_NETWORK, DEFAULT_PROXY_ENDPOINT, + DEFAULT_REGTEST_BITCOIND_RPC_HOST, + DEFAULT_REGTEST_BITCOIND_RPC_PASSWORD, + DEFAULT_REGTEST_BITCOIND_RPC_PORT, + DEFAULT_REGTEST_BITCOIND_RPC_USERNAME, + DEFAULT_REGTEST_INDEXER_URL, + DEFAULT_REGTEST_PROXY_ENDPOINT, ) from kaleido_cli.context import get_client, state from kaleido_cli.docker_manager import ( @@ -105,6 +111,22 @@ def _resolve_name(name: str | None) -> str: raise typer.Exit(1) +def _prompt_unlock_service_profile() -> str: + while True: + raw = typer.prompt( + "Bitcoin services profile: [S]ignet defaults, [R]egtest defaults, [C]ustom", + default="S", + ) + choice = raw.strip().lower() + if choice in {"s", "signet", "mutinynet", "signetcustom"}: + return "signet" + if choice in {"r", "regtest"}: + return "regtest" + if choice in {"c", "custom", "o", "other"}: + return "custom" + print_error("Choose S for signet, R for regtest, or C for custom.") + + # --------------------------------------------------------------------------- # Environment management # --------------------------------------------------------------------------- @@ -558,8 +580,14 @@ async def _node_init(password: str, mnemonic: str | None) -> None: "unlock", epilog=( "[bold]Examples[/bold]\n\n" - " Simple unlock (uses Kaleidoswap mutinynet defaults):\n" + " Simple unlock (choose signet, regtest, or custom services):\n" " [cyan]kaleido node unlock[/cyan]\n\n" + " Non-interactive signet defaults:\n" + " [cyan]kaleido --agent node unlock --password mysecret[/cyan]\n\n" + " Regtest defaults:\n" + " [cyan]kaleido node unlock --bitcoind-user user --bitcoind-pass password \\\n" + " --bitcoind-host regtest-bitcoind.rgbtools.org --bitcoind-port 80 \\\n" + " --indexer-url electrum.rgbtools.org:50041[/cyan]\n\n" " Override bitcoind credentials:\n" " [cyan]kaleido node unlock --bitcoind-user alice --bitcoind-pass hunter2[/cyan]\n\n" " Full custom override:\n" @@ -630,10 +658,22 @@ def node_unlock( resolved_password = typer.prompt("Wallet password", hide_input=True) if is_interactive(): - use_defaults = typer.confirm( - "Use default Kaleidoswap mutinynet services (bitcoind, indexer, proxy)?", default=True - ) - if not use_defaults: + profile = _prompt_unlock_service_profile() + if profile == "signet": + bitcoind_user = DEFAULT_BITCOIND_RPC_USERNAME + bitcoind_pass = DEFAULT_BITCOIND_RPC_PASSWORD + bitcoind_host = DEFAULT_BITCOIND_RPC_HOST + bitcoind_port = DEFAULT_BITCOIND_RPC_PORT + indexer_url = DEFAULT_INDEXER_URL + proxy_endpoint = DEFAULT_PROXY_ENDPOINT + elif profile == "regtest": + bitcoind_user = DEFAULT_REGTEST_BITCOIND_RPC_USERNAME + bitcoind_pass = DEFAULT_REGTEST_BITCOIND_RPC_PASSWORD + bitcoind_host = DEFAULT_REGTEST_BITCOIND_RPC_HOST + bitcoind_port = DEFAULT_REGTEST_BITCOIND_RPC_PORT + indexer_url = DEFAULT_REGTEST_INDEXER_URL + proxy_endpoint = DEFAULT_REGTEST_PROXY_ENDPOINT + else: bitcoind_user = typer.prompt("bitcoind RPC username", default=bitcoind_user) bitcoind_pass = typer.prompt( "bitcoind RPC password", default=bitcoind_pass, hide_input=True @@ -642,13 +682,6 @@ def node_unlock( bitcoind_port = typer.prompt("bitcoind RPC port", default=bitcoind_port, type=int) indexer_url = typer.prompt("Electrs indexer URL", default=indexer_url) proxy_endpoint = typer.prompt("RGB proxy endpoint", default=proxy_endpoint) - else: - bitcoind_user = DEFAULT_BITCOIND_RPC_USERNAME - bitcoind_pass = DEFAULT_BITCOIND_RPC_PASSWORD - bitcoind_host = DEFAULT_BITCOIND_RPC_HOST - bitcoind_port = DEFAULT_BITCOIND_RPC_PORT - indexer_url = DEFAULT_INDEXER_URL - proxy_endpoint = DEFAULT_PROXY_ENDPOINT raw = typer.prompt("[OPTIONAL] Lightning announce alias (Enter to skip)", default="") if raw.strip(): announce_alias = raw.strip() diff --git a/kaleido_cli/config.py b/kaleido_cli/config.py index e60d973..8a91018 100644 --- a/kaleido_cli/config.py +++ b/kaleido_cli/config.py @@ -23,6 +23,13 @@ DEFAULT_INDEXER_URL = "electrum.signet.kaleidoswap.com:60601" DEFAULT_PROXY_ENDPOINT = "rpcs://proxy.iriswallet.com/0.2/json-rpc" +DEFAULT_REGTEST_BITCOIND_RPC_USERNAME = "user" +DEFAULT_REGTEST_BITCOIND_RPC_PASSWORD = "password" +DEFAULT_REGTEST_BITCOIND_RPC_HOST = "regtest-bitcoind.rgbtools.org" +DEFAULT_REGTEST_BITCOIND_RPC_PORT = 80 +DEFAULT_REGTEST_INDEXER_URL = "electrum.rgbtools.org:50041" +DEFAULT_REGTEST_PROXY_ENDPOINT = "rpcs://proxy.iriswallet.com/0.2/json-rpc" + def normalize_network_name(network: str) -> str: """Normalize friendly CLI aliases to the network value expected by RLN.""" diff --git a/tests/conftest.py b/tests/conftest.py index 37d53c8..cc0a247 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -98,6 +98,7 @@ def mock_client(mocker): rln.list_transactions = AsyncMock() rln.estimate_fee = AsyncMock() rln.shutdown = AsyncMock() + rln.unlock_wallet = AsyncMock() rln.backup = AsyncMock() rln.restore = AsyncMock() rln.change_password = AsyncMock() diff --git a/tests/test_cmd_node.py b/tests/test_cmd_node.py new file mode 100644 index 0000000..bbeb0bc --- /dev/null +++ b/tests/test_cmd_node.py @@ -0,0 +1,88 @@ +"""Tests for `kaleido node` CLI commands.""" + +from __future__ import annotations + +from kaleido_cli.app import app +from kaleido_cli.config import ( + DEFAULT_BITCOIND_RPC_HOST, + DEFAULT_BITCOIND_RPC_PASSWORD, + DEFAULT_BITCOIND_RPC_PORT, + DEFAULT_BITCOIND_RPC_USERNAME, + DEFAULT_INDEXER_URL, + DEFAULT_PROXY_ENDPOINT, + DEFAULT_REGTEST_BITCOIND_RPC_HOST, + DEFAULT_REGTEST_BITCOIND_RPC_PASSWORD, + DEFAULT_REGTEST_BITCOIND_RPC_PORT, + DEFAULT_REGTEST_BITCOIND_RPC_USERNAME, + DEFAULT_REGTEST_INDEXER_URL, + DEFAULT_REGTEST_PROXY_ENDPOINT, +) + + +def _unlock_request(mock_client): + return mock_client.rln.unlock_wallet.await_args.args[0] + + +def test_node_unlock_interactive_signet_defaults(runner, mocker, mock_client): + mocker.patch("kaleido_cli.commands.node.is_interactive", return_value=True) + + result = runner.invoke(app, ["node", "unlock"], input="walletpw\ns\n\n\n") + + assert result.exit_code == 0 + req = _unlock_request(mock_client) + assert req.password == "walletpw" + assert req.bitcoind_rpc_username == DEFAULT_BITCOIND_RPC_USERNAME + assert req.bitcoind_rpc_password == DEFAULT_BITCOIND_RPC_PASSWORD + assert req.bitcoind_rpc_host == DEFAULT_BITCOIND_RPC_HOST + assert req.bitcoind_rpc_port == DEFAULT_BITCOIND_RPC_PORT + assert req.indexer_url == DEFAULT_INDEXER_URL + assert req.proxy_endpoint == DEFAULT_PROXY_ENDPOINT + + +def test_node_unlock_interactive_regtest_defaults(runner, mocker, mock_client): + mocker.patch("kaleido_cli.commands.node.is_interactive", return_value=True) + + result = runner.invoke(app, ["node", "unlock"], input="walletpw\nr\n\n\n") + + assert result.exit_code == 0 + req = _unlock_request(mock_client) + assert req.password == "walletpw" + assert req.bitcoind_rpc_username == DEFAULT_REGTEST_BITCOIND_RPC_USERNAME + assert req.bitcoind_rpc_password == DEFAULT_REGTEST_BITCOIND_RPC_PASSWORD + assert req.bitcoind_rpc_host == DEFAULT_REGTEST_BITCOIND_RPC_HOST + assert req.bitcoind_rpc_port == DEFAULT_REGTEST_BITCOIND_RPC_PORT + assert req.indexer_url == DEFAULT_REGTEST_INDEXER_URL + assert req.proxy_endpoint == DEFAULT_REGTEST_PROXY_ENDPOINT + + +def test_node_unlock_interactive_custom_services(runner, mocker, mock_client): + mocker.patch("kaleido_cli.commands.node.is_interactive", return_value=True) + + result = runner.invoke( + app, + ["node", "unlock"], + input=( + "walletpw\n" + "c\n" + "alice\n" + "secret\n" + "127.0.0.1\n" + "18443\n" + "tcp://127.0.0.1:50001\n" + "rpc://127.0.0.1:3000/json-rpc\n" + "alias\n" + "127.0.0.1:9735\n" + ), + ) + + assert result.exit_code == 0 + req = _unlock_request(mock_client) + assert req.password == "walletpw" + assert req.bitcoind_rpc_username == "alice" + assert req.bitcoind_rpc_password == "secret" + assert req.bitcoind_rpc_host == "127.0.0.1" + assert req.bitcoind_rpc_port == 18443 + assert req.indexer_url == "tcp://127.0.0.1:50001" + assert req.proxy_endpoint == "rpc://127.0.0.1:3000/json-rpc" + assert req.announce_alias == "alias" + assert req.announce_addresses == ["127.0.0.1:9735"]