@agentlayer.tech/wallet 0.1.0

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.
Files changed (96) hide show
  1. package/.openclaw/AGENTS.md +98 -0
  2. package/.openclaw/extensions/agent-wallet/README.md +127 -0
  3. package/.openclaw/extensions/agent-wallet/index.ts +1520 -0
  4. package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +184 -0
  5. package/.openclaw/extensions/agent-wallet/package.json +11 -0
  6. package/.openclaw/extensions/agent-wallet/skills/wallet-operator/SKILL.md +20 -0
  7. package/CHANGELOG.md +42 -0
  8. package/LICENSE +104 -0
  9. package/README.md +332 -0
  10. package/RELEASING.md +204 -0
  11. package/agent-wallet/.env.example +62 -0
  12. package/agent-wallet/AGENTS.md +129 -0
  13. package/agent-wallet/README.md +527 -0
  14. package/agent-wallet/agent_wallet/__init__.py +11 -0
  15. package/agent-wallet/agent_wallet/approval.py +161 -0
  16. package/agent-wallet/agent_wallet/bootstrap.py +178 -0
  17. package/agent-wallet/agent_wallet/btc_user_wallets.py +217 -0
  18. package/agent-wallet/agent_wallet/config.py +382 -0
  19. package/agent-wallet/agent_wallet/encrypted_storage.py +161 -0
  20. package/agent-wallet/agent_wallet/evm_user_wallets.py +370 -0
  21. package/agent-wallet/agent_wallet/exceptions.py +9 -0
  22. package/agent-wallet/agent_wallet/file_ops.py +34 -0
  23. package/agent-wallet/agent_wallet/http_client.py +25 -0
  24. package/agent-wallet/agent_wallet/models.py +66 -0
  25. package/agent-wallet/agent_wallet/nonce_registry.py +59 -0
  26. package/agent-wallet/agent_wallet/openclaw_adapter.py +5128 -0
  27. package/agent-wallet/agent_wallet/openclaw_cli.py +626 -0
  28. package/agent-wallet/agent_wallet/openclaw_runtime.py +272 -0
  29. package/agent-wallet/agent_wallet/plugin_bundle.py +42 -0
  30. package/agent-wallet/agent_wallet/providers/__init__.py +1 -0
  31. package/agent-wallet/agent_wallet/providers/bags.py +259 -0
  32. package/agent-wallet/agent_wallet/providers/evm_portfolio.py +470 -0
  33. package/agent-wallet/agent_wallet/providers/jupiter.py +567 -0
  34. package/agent-wallet/agent_wallet/providers/kamino.py +215 -0
  35. package/agent-wallet/agent_wallet/providers/lifi.py +277 -0
  36. package/agent-wallet/agent_wallet/providers/solana_rpc.py +470 -0
  37. package/agent-wallet/agent_wallet/providers/wdk_btc_local.py +114 -0
  38. package/agent-wallet/agent_wallet/providers/wdk_evm_local.py +205 -0
  39. package/agent-wallet/agent_wallet/sealed_keys.py +61 -0
  40. package/agent-wallet/agent_wallet/solana_stake.py +103 -0
  41. package/agent-wallet/agent_wallet/solana_tx.py +93 -0
  42. package/agent-wallet/agent_wallet/spending_limits.py +101 -0
  43. package/agent-wallet/agent_wallet/transaction_policy.py +518 -0
  44. package/agent-wallet/agent_wallet/user_wallets.py +355 -0
  45. package/agent-wallet/agent_wallet/validation.py +31 -0
  46. package/agent-wallet/agent_wallet/wallet_layer/__init__.py +1 -0
  47. package/agent-wallet/agent_wallet/wallet_layer/base.py +808 -0
  48. package/agent-wallet/agent_wallet/wallet_layer/base58.py +44 -0
  49. package/agent-wallet/agent_wallet/wallet_layer/factory.py +102 -0
  50. package/agent-wallet/agent_wallet/wallet_layer/solana.py +4252 -0
  51. package/agent-wallet/agent_wallet/wallet_layer/wdk_btc.py +272 -0
  52. package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +1628 -0
  53. package/agent-wallet/examples/bootstrap_wallet.py +21 -0
  54. package/agent-wallet/examples/openclaw_runtime_onboarding.py +28 -0
  55. package/agent-wallet/examples/openclaw_user_wallet_example.py +31 -0
  56. package/agent-wallet/examples/openclaw_wallet_adapter_example.py +33 -0
  57. package/agent-wallet/openclaw.plugin.json +138 -0
  58. package/agent-wallet/pyproject.toml +31 -0
  59. package/agent-wallet/scripts/bootstrap_openclaw_btc.py +278 -0
  60. package/agent-wallet/scripts/build_release_bundle.py +188 -0
  61. package/agent-wallet/scripts/finalize_openclaw_local_wallet_config.py +121 -0
  62. package/agent-wallet/scripts/install_agent_wallet.py +505 -0
  63. package/agent-wallet/scripts/install_openclaw_local_config.py +226 -0
  64. package/agent-wallet/scripts/install_openclaw_sealed_keys.py +105 -0
  65. package/agent-wallet/scripts/manage_openclaw_btc_wallet.py +244 -0
  66. package/agent-wallet/scripts/reveal_btc_seed.sh +130 -0
  67. package/agent-wallet/scripts/security_utils.py +37 -0
  68. package/agent-wallet/scripts/setup_btc_wallet.sh +146 -0
  69. package/agent-wallet/scripts/switch_openclaw_wallet_network.py +106 -0
  70. package/agent-wallet/skills/wallet-operator/SKILL.md +128 -0
  71. package/bin/openclaw-agent-wallet.mjs +487 -0
  72. package/install-from-github.sh +134 -0
  73. package/package.json +61 -0
  74. package/setup.sh +40 -0
  75. package/wdk-btc-wallet/README.md +325 -0
  76. package/wdk-btc-wallet/bootstrap.sh +22 -0
  77. package/wdk-btc-wallet/package-lock.json +1839 -0
  78. package/wdk-btc-wallet/package.json +18 -0
  79. package/wdk-btc-wallet/run-local.sh +21 -0
  80. package/wdk-btc-wallet/src/config.js +160 -0
  81. package/wdk-btc-wallet/src/json.js +35 -0
  82. package/wdk-btc-wallet/src/local_vault.js +432 -0
  83. package/wdk-btc-wallet/src/network_state.js +84 -0
  84. package/wdk-btc-wallet/src/server.js +257 -0
  85. package/wdk-btc-wallet/src/wdk_btc_wallet.js +332 -0
  86. package/wdk-evm-wallet/README.md +183 -0
  87. package/wdk-evm-wallet/bootstrap.sh +8 -0
  88. package/wdk-evm-wallet/package-lock.json +2340 -0
  89. package/wdk-evm-wallet/package.json +23 -0
  90. package/wdk-evm-wallet/run-local.sh +12 -0
  91. package/wdk-evm-wallet/src/config.js +274 -0
  92. package/wdk-evm-wallet/src/json.js +35 -0
  93. package/wdk-evm-wallet/src/local_vault.js +430 -0
  94. package/wdk-evm-wallet/src/network_state.js +92 -0
  95. package/wdk-evm-wallet/src/server.js +575 -0
  96. package/wdk-evm-wallet/src/wdk_evm_wallet.js +4981 -0
@@ -0,0 +1,37 @@
1
+ """Helpers for avoiding secret leakage in config patch scripts."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import copy
6
+ import json
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ from agent_wallet.file_ops import atomic_write_text, chmod_if_exists
11
+
12
+ SENSITIVE_PLUGIN_KEYS = {"masterKey", "privateKey", "approvalSecret"}
13
+
14
+
15
+ def scrub_plugin_secrets(data: dict[str, Any]) -> dict[str, Any]:
16
+ clone = copy.deepcopy(data)
17
+ plugins = clone.get("plugins")
18
+ if not isinstance(plugins, dict):
19
+ return clone
20
+ entries = plugins.get("entries")
21
+ if not isinstance(entries, dict):
22
+ return clone
23
+ for entry in entries.values():
24
+ if not isinstance(entry, dict):
25
+ continue
26
+ config = entry.get("config")
27
+ if not isinstance(config, dict):
28
+ continue
29
+ for key in SENSITIVE_PLUGIN_KEYS:
30
+ if key in config:
31
+ config[key] = "[REDACTED]"
32
+ return clone
33
+
34
+
35
+ def write_redacted_backup(path: Path, data: dict[str, Any]) -> None:
36
+ atomic_write_text(path, json.dumps(scrub_plugin_secrets(data), indent=2) + "\n", mode=0o600)
37
+ chmod_if_exists(path, 0o600)
@@ -0,0 +1,146 @@
1
+ #!/bin/sh
2
+ set -eu
3
+
4
+ SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
5
+ PACKAGE_ROOT=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)
6
+
7
+ resolve_python_bin() {
8
+ if [ -n "${OPENCLAW_AGENT_WALLET_PYTHON:-}" ] && [ -x "${OPENCLAW_AGENT_WALLET_PYTHON}" ]; then
9
+ printf "%s" "${OPENCLAW_AGENT_WALLET_PYTHON}"
10
+ return 0
11
+ fi
12
+
13
+ if [ -x "/tmp/agent-wallet-venv/bin/python" ]; then
14
+ printf "%s" "/tmp/agent-wallet-venv/bin/python"
15
+ return 0
16
+ fi
17
+
18
+ if [ -x "$PACKAGE_ROOT/.venv/bin/python" ]; then
19
+ printf "%s" "$PACKAGE_ROOT/.venv/bin/python"
20
+ return 0
21
+ fi
22
+
23
+ if command -v python3 >/dev/null 2>&1; then
24
+ command -v python3
25
+ return 0
26
+ fi
27
+
28
+ command -v python
29
+ }
30
+
31
+ PYTHON_BIN=$(resolve_python_bin)
32
+ export OPENCLAW_AGENT_WALLET_PYTHON="$PYTHON_BIN"
33
+
34
+ has_flag() {
35
+ flag=$1
36
+ shift
37
+ for arg in "$@"; do
38
+ case "$arg" in
39
+ "$flag"|"$flag"=*)
40
+ return 0
41
+ ;;
42
+ esac
43
+ done
44
+ return 1
45
+ }
46
+
47
+ prompt_with_default() {
48
+ label=$1
49
+ default_value=$2
50
+ if [ -t 0 ]; then
51
+ printf "%s [%s]: " "$label" "$default_value" >&2
52
+ read -r value
53
+ if [ -z "${value:-}" ]; then
54
+ printf "%s" "$default_value"
55
+ else
56
+ printf "%s" "$value"
57
+ fi
58
+ return 0
59
+ fi
60
+ printf "%s" "$default_value"
61
+ }
62
+
63
+ normalize_network_value() {
64
+ case $(printf "%s" "$1" | tr '[:upper:]' '[:lower:]') in
65
+ 1|mainnet|bitcoin)
66
+ printf "mainnet"
67
+ ;;
68
+ 2|testnet)
69
+ printf "testnet"
70
+ ;;
71
+ 3|regtest)
72
+ printf "regtest"
73
+ ;;
74
+ *)
75
+ return 1
76
+ ;;
77
+ esac
78
+ }
79
+
80
+ prompt_network_choice() {
81
+ default_value=$1
82
+ if ! [ -t 0 ]; then
83
+ printf "%s" "$default_value"
84
+ return 0
85
+ fi
86
+
87
+ case "$default_value" in
88
+ mainnet|bitcoin) default_hint="1" ;;
89
+ testnet) default_hint="2" ;;
90
+ regtest) default_hint="3" ;;
91
+ *) default_hint="1" ;;
92
+ esac
93
+
94
+ while true; do
95
+ printf "BTC network:\n" >&2
96
+ printf " 1) mainnet\n" >&2
97
+ printf " 2) testnet\n" >&2
98
+ printf " 3) regtest\n" >&2
99
+ printf "Choose network [%s]: " "$default_hint" >&2
100
+ read -r choice
101
+ if [ -z "${choice:-}" ]; then
102
+ choice=$default_hint
103
+ fi
104
+ if network=$(normalize_network_value "$choice"); then
105
+ printf "%s" "$network"
106
+ return 0
107
+ fi
108
+ printf "Invalid choice. Enter 1, 2, 3, mainnet, testnet, or regtest.\n" >&2
109
+ done
110
+ }
111
+
112
+ DEFAULT_USER_ID=${OPENCLAW_BTC_USER_ID:-${USER:-openclaw-user}-local}
113
+ DEFAULT_NETWORK=${OPENCLAW_BTC_NETWORK:-mainnet}
114
+ DEFAULT_SERVICE_URL=${OPENCLAW_BTC_SERVICE_URL:-http://127.0.0.1:8080}
115
+
116
+ if ! has_flag --user-id "$@"; then
117
+ USER_ID=$(prompt_with_default "OpenClaw user id" "$DEFAULT_USER_ID")
118
+ set -- "$@" --user-id "$USER_ID"
119
+ fi
120
+
121
+ if ! has_flag --network "$@"; then
122
+ NETWORK=$(prompt_network_choice "$DEFAULT_NETWORK")
123
+ set -- "$@" --network "$NETWORK"
124
+ fi
125
+
126
+ if ! has_flag --service-url "$@"; then
127
+ set -- "$@" --service-url "$DEFAULT_SERVICE_URL"
128
+ fi
129
+
130
+ if ! has_flag --config-path "$@" && [ -n "${OPENCLAW_BTC_CONFIG_PATH:-}" ]; then
131
+ set -- "$@" --config-path "$OPENCLAW_BTC_CONFIG_PATH"
132
+ fi
133
+
134
+ if ! has_flag --wdk-wallet-root "$@" && [ -n "${OPENCLAW_BTC_WDK_WALLET_ROOT:-}" ]; then
135
+ set -- "$@" --wdk-wallet-root "$OPENCLAW_BTC_WDK_WALLET_ROOT"
136
+ fi
137
+
138
+ if ! has_flag --python-bin "$@"; then
139
+ set -- "$@" --python-bin "$PYTHON_BIN"
140
+ fi
141
+
142
+ if ! has_flag --package-root "$@"; then
143
+ set -- "$@" --package-root "$PACKAGE_ROOT"
144
+ fi
145
+
146
+ exec "$PYTHON_BIN" "$SCRIPT_DIR/bootstrap_openclaw_btc.py" "$@"
@@ -0,0 +1,106 @@
1
+ """Switch the configured OpenClaw agent-wallet network safely."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ import os
8
+ from datetime import datetime, timezone
9
+ from pathlib import Path
10
+
11
+ from agent_wallet.file_ops import atomic_write_text, chmod_if_exists
12
+ from security_utils import write_redacted_backup
13
+
14
+
15
+ def _default_config_path() -> Path:
16
+ return Path(os.path.expanduser("~/.openclaw/openclaw.json"))
17
+
18
+
19
+ def build_parser() -> argparse.ArgumentParser:
20
+ parser = argparse.ArgumentParser(description=__doc__)
21
+ parser.add_argument("--config-path", default=str(_default_config_path()))
22
+ parser.add_argument("--plugin-id", default="agent-wallet")
23
+ parser.add_argument("--network", required=True, choices=["mainnet", "devnet", "testnet"])
24
+ parser.add_argument("--rpc-url", default="")
25
+ parser.add_argument("--rpc-urls", default="")
26
+ parser.add_argument("--sign-only", action=argparse.BooleanOptionalAction, default=None)
27
+ parser.add_argument("--show-only", action=argparse.BooleanOptionalAction, default=False)
28
+ return parser
29
+
30
+
31
+ def _normalize_user_id(user_id: str) -> str:
32
+ import hashlib
33
+ import re
34
+
35
+ cleaned = re.sub(r"[^a-zA-Z0-9._-]+", "-", user_id.strip())
36
+ cleaned = cleaned.strip("-._")
37
+ if not cleaned:
38
+ cleaned = "user"
39
+ digest = hashlib.sha256(user_id.encode("utf-8")).hexdigest()[:12]
40
+ return f"{cleaned[:48]}-{digest}"
41
+
42
+
43
+ def _resolve_wallet_path(openclaw_home: Path, user_id: str, network: str) -> Path:
44
+ return openclaw_home / "users" / _normalize_user_id(user_id) / "wallets" / f"solana-{network}-agent.json"
45
+
46
+
47
+ def main() -> None:
48
+ args = build_parser().parse_args()
49
+ config_path = Path(args.config_path).expanduser()
50
+ data = json.loads(config_path.read_text(encoding="utf-8"))
51
+
52
+ plugin_entry = data["plugins"]["entries"][args.plugin_id]
53
+ plugin_config = plugin_entry.setdefault("config", {})
54
+ user_id = str(plugin_config.get("userId") or os.getenv("USER") or "openclaw-main").strip()
55
+ openclaw_home = Path(
56
+ str(plugin_config.get("openclawHome") or os.getenv("OPENCLAW_HOME") or "~/.openclaw")
57
+ ).expanduser()
58
+
59
+ wallet_path = _resolve_wallet_path(openclaw_home, user_id, args.network)
60
+ pin_path = wallet_path.with_suffix(f"{wallet_path.suffix}.pin.json")
61
+
62
+ result = {
63
+ "ok": True,
64
+ "config_path": str(config_path),
65
+ "plugin_id": args.plugin_id,
66
+ "user_id": user_id,
67
+ "selected_network": args.network,
68
+ "wallet_path": str(wallet_path),
69
+ "wallet_exists": wallet_path.exists(),
70
+ "wallet_pin_exists": pin_path.exists(),
71
+ "rpc_url": args.rpc_url.strip() or str(plugin_config.get("rpcUrl") or ""),
72
+ "rpc_urls": plugin_config.get("rpcUrls") or [],
73
+ "sign_only": plugin_config.get("signOnly"),
74
+ "show_only": args.show_only,
75
+ }
76
+
77
+ if args.show_only:
78
+ print(json.dumps(result, indent=2))
79
+ return
80
+
81
+ backup_path = config_path.with_name(
82
+ f"{config_path.name}.bak.agent-wallet-switch.{datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%SZ')}"
83
+ )
84
+ write_redacted_backup(backup_path, data)
85
+
86
+ plugin_config["network"] = args.network
87
+ if args.rpc_url.strip():
88
+ plugin_config["rpcUrl"] = args.rpc_url.strip()
89
+ else:
90
+ plugin_config.pop("rpcUrl", None)
91
+ if args.rpc_urls.strip():
92
+ plugin_config["rpcUrls"] = [item.strip() for item in args.rpc_urls.split(",") if item.strip()]
93
+ if args.sign_only is not None:
94
+ plugin_config["signOnly"] = args.sign_only
95
+
96
+ atomic_write_text(config_path, json.dumps(data, indent=2) + "\n", mode=0o600)
97
+ chmod_if_exists(config_path, 0o600)
98
+
99
+ result["backup_path"] = str(backup_path)
100
+ result["sign_only"] = plugin_config.get("signOnly")
101
+ result["rpc_urls"] = plugin_config.get("rpcUrls") or []
102
+ print(json.dumps(result, indent=2))
103
+
104
+
105
+ if __name__ == "__main__":
106
+ main()
@@ -0,0 +1,128 @@
1
+ ---
2
+ name: wallet-operator
3
+ description: Use when operating OpenClaw wallet tools: balances, transfers, swaps, LI.FI cross-chain swaps, Jupiter swaps, Velora EVM swaps, BTC transfers, staking, Jupiter Earn, Kamino lending, Bags claims/launches, and wallet execution safety.
4
+ ---
5
+
6
+ # Wallet Operator
7
+
8
+ Use this skill before calling OpenClaw wallet tools. It is the routing guide for wallet commands, providers, units, and approval flow.
9
+
10
+ ## Core Rules
11
+
12
+ 1. Start with `get_wallet_capabilities` when the active chain, signing support, or available tools are unclear.
13
+ 2. Use `get_wallet_address` before asking for deposits or confirming a recipient/source wallet.
14
+ 3. Use `get_wallet_balance` before spending, swapping, bridging, staking, lending, or claiming.
15
+ 4. Use `preview` first for every write action. Use `prepare` only after explicit user intent. Use `execute` only with a host-issued `approval_token`.
16
+ 5. `prepare` returns an execution plan only; it must not return signed transaction bytes.
17
+ 6. On mainnet, `execute` requires approval that includes explicit mainnet confirmation.
18
+ 7. If backend is `sign_only`, do not execute; use `prepare` and state that nothing was broadcast.
19
+ 8. Never claim a transfer, swap, bridge, stake, claim, deposit, borrow, repay, or withdrawal happened unless the tool result says it was broadcast/confirmed.
20
+ 9. Do not use Mayan. Direct Mayan paths were removed. Cross-chain swaps must go through LI.FI with Mayan denied.
21
+
22
+ ## Provider Map
23
+
24
+ - Solana same-chain swap: `swap_solana_tokens` via Jupiter.
25
+ - EVM same-chain swap: `swap_evm_tokens` via Velora, ERC-20 to ERC-20 on `ethereum` or `base`.
26
+ - Cross-chain Solana -> EVM: `swap_solana_lifi_cross_chain_tokens` via LI.FI.
27
+ - Cross-chain EVM -> EVM/Solana: `swap_evm_lifi_cross_chain_tokens` via LI.FI.
28
+ - SOL/SPL transfers: `transfer_sol`, `transfer_spl_token`.
29
+ - EVM transfers: `transfer_evm_native`, `transfer_evm_token`.
30
+ - BTC transfer: `transfer_btc`.
31
+ - Solana staking: `stake_sol_native`, `deactivate_solana_stake`, `withdraw_solana_stake`.
32
+ - Jupiter Earn: `jupiter_earn_deposit`, `jupiter_earn_withdraw`.
33
+ - Kamino: `kamino_lend_deposit`, `kamino_lend_withdraw`, `kamino_lend_borrow`, `kamino_lend_repay`.
34
+ - Bags: `claim_bags_fees`, `launch_bags_token`.
35
+
36
+ ## Common Token IDs
37
+
38
+ - Native SOL for LI.FI: `sol`, `native`, or `11111111111111111111111111111111`.
39
+ - Native SOL mint for Jupiter swaps: `So11111111111111111111111111111111111111112`.
40
+ - Native ETH for LI.FI EVM destinations/sources: `eth`, `native`, or `0x0000000000000000000000000000000000000000`.
41
+ - EVM token addresses should be lowercase when possible. Checksummed addresses are accepted in current code and normalized for LI.FI.
42
+ - Solana USDC mint: `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`.
43
+ - Base USDC: `0x833589fcd6edb6e08f4c7c32d4f71b54bda02913`.
44
+ - LI.FI chain IDs: Ethereum `1`, Base `8453`, Solana `1151111081099710`.
45
+
46
+ ## Read Commands
47
+
48
+ - `get_wallet_capabilities`: available chain, backend, send/sign support.
49
+ - `get_wallet_address`: active wallet address.
50
+ - `get_wallet_balance`: primary balance/portfolio summary. For EVM USD total, use `total_value_usd` from this result.
51
+ - `get_wallet_portfolio`: Solana portfolio holdings.
52
+ - `get_solana_token_prices`: prices by Solana mint.
53
+ - `get_lifi_supported_chains`: supported LI.FI subset.
54
+ - `get_lifi_quote`: read-only LI.FI quote/status surface; use when user asks for indicative cross-chain quote outside the write flow.
55
+ - `get_lifi_transfer_status`: check LI.FI bridge status after a cross-chain source transaction.
56
+ - `get_evm_network`: active EVM network and supported EVM swap networks.
57
+ - `get_evm_token_balance`: ERC-20 balance by `token_address`, optional `network`.
58
+ - `get_evm_token_metadata`: ERC-20 metadata by `token_address`, optional `network`.
59
+ - `get_evm_fee_rates`: EVM fee suggestions.
60
+ - `get_evm_transaction_receipt`: EVM receipt by `tx_hash`.
61
+ - `get_btc_transfer_history`, `get_btc_fee_rates`, `get_btc_max_spendable`: BTC read helpers.
62
+
63
+ ## Transfer Commands
64
+
65
+ - SOL transfer: `transfer_sol`
66
+ - Params: `recipient`, `amount` in SOL UI units, `mode`, `purpose`, optional `user_intent`, `approval_token`.
67
+ - SPL transfer: `transfer_spl_token`
68
+ - Params: `recipient`, `mint`, `amount` in UI units, optional `decimals`, `mode`, `purpose`.
69
+ - EVM native transfer: `transfer_evm_native`
70
+ - Params: `recipient`, `amount_wei` raw wei string, `mode`, `purpose`, optional `network`.
71
+ - EVM ERC-20 transfer: `transfer_evm_token`
72
+ - Params: `token_address`, `recipient`, `amount_raw` base-unit string, `mode`, `purpose`, optional `network`.
73
+ - BTC transfer: `transfer_btc`
74
+ - Params: `recipient`, `amount_sats`, optional `fee_rate`, `confirmation_target`, `mode`, `purpose`.
75
+
76
+ ## Swap Commands
77
+
78
+ - Solana same-chain Jupiter swap: `swap_solana_tokens`
79
+ - Params: `input_mint`, `output_mint`, `amount` in UI units, optional `slippage_bps`, `mode`, `purpose`.
80
+ - Use for SOL<->SPL or SPL<->SPL on Solana. Do not use LI.FI for Solana-only swaps.
81
+ - EVM same-chain Velora swap: `swap_evm_tokens`
82
+ - Params: `token_in`, `token_out`, `amount_in_raw` base-unit string, `mode`, `purpose`, optional `network`.
83
+ - Current intended path is ERC-20 to ERC-20 on `ethereum` or `base`.
84
+ - EVM swap quote only: `get_evm_swap_quote`
85
+ - Params: `token_in`, `token_out`, `amount_in_raw`, optional `network`.
86
+
87
+ ## Cross-Chain Commands
88
+
89
+ - Solana -> Ethereum/Base: `swap_solana_lifi_cross_chain_tokens`
90
+ - Source must be Solana mainnet.
91
+ - Params: `input_token`, `destination_chain` (`ethereum`, `base`, `1`, `8453`), `output_token`, `destination_address`, `amount_in_raw`, optional `slippage`, bridge lists, `mode`, `purpose`.
92
+ - Example SOL -> Base native ETH: `input_token=sol`, `destination_chain=base`, `output_token=native`, `amount_in_raw` in lamports.
93
+ - Execute confirms the Solana source tx. Use `get_lifi_transfer_status` to track final destination-chain completion.
94
+ - Ethereum/Base -> Ethereum/Base/Solana: `swap_evm_lifi_cross_chain_tokens`
95
+ - Source network is selected by active EVM network or optional `network`.
96
+ - Params: `token_in`, `destination_chain` (`ethereum`, `base`, `solana`, `1`, `8453`, `1151111081099710`), `output_token`, `destination_address`, `amount_in_raw`, optional `slippage`, bridge lists, `mode`, `purpose`, optional `network`.
97
+ - Native EVM input can be `native`, `eth`, or zero address.
98
+ - Solana output token should be a Solana mint such as USDC mint.
99
+
100
+ ## Staking And DeFi Commands
101
+
102
+ - `stake_sol_native`: `vote_account`, `amount` in SOL, `mode`, `purpose`.
103
+ - `deactivate_solana_stake`: `stake_account`, `mode`, `purpose`.
104
+ - `withdraw_solana_stake`: `stake_account`, `amount` in SOL, optional `recipient`, `mode`, `purpose`.
105
+ - Before Jupiter Earn writes, use `get_jupiter_earn_tokens`, `get_jupiter_earn_positions`, and `get_jupiter_earn_earnings`.
106
+ - `jupiter_earn_deposit`: `asset` mint, `amount_raw`, `mode`, `purpose`.
107
+ - `jupiter_earn_withdraw`: `asset` mint, `amount_raw`, `mode`, `purpose`.
108
+ - Before Kamino writes, use `get_kamino_lend_markets`, `get_kamino_lend_market_reserves`, `get_kamino_lend_user_obligations`, and `get_kamino_lend_user_rewards`.
109
+ - Kamino write params: `market`, `reserve`, `amount_ui` decimal string, `mode`, `purpose`.
110
+ - Bags reads: `get_bags_claimable_positions`, `get_bags_fee_analytics`.
111
+ - `claim_bags_fees`: `token_mint`, `mode`, `purpose`.
112
+ - `launch_bags_token`: `name`, `symbol`, `description`, `base_mint`, `claimers`, `basis_points`, `initial_buy_sol`, `mode`, `purpose`; optional socials/image/config type.
113
+ - `close_empty_token_accounts`: `limit`, `mode` (`preview` or `execute`), `purpose`.
114
+ - `request_devnet_airdrop`: `amount`; only outside mainnet.
115
+
116
+ ## Approval Flow Template
117
+
118
+ 1. Call the write tool with `mode=preview` and a concrete `purpose`.
119
+ 2. Show the user the important fields: chain, token, amount, destination, provider, estimated output/minimum output, fees, and route/tool when present.
120
+ 3. For `prepare`, call same tool with `mode=prepare`, same params, `user_intent=true`.
121
+ 4. For `execute`, use the same semantic params and pass the `approval_token`. Do not mutate amount, token, destination, network, slippage, or minimum output between preview and execute.
122
+ 5. For cross-chain swaps, after execute, offer `get_lifi_transfer_status` using the source tx hash and bridge/tool if returned.
123
+
124
+ ## Disabled Or Avoided Paths
125
+
126
+ - Do not call Jupiter Portfolio tools if they are not listed by `get_wallet_capabilities`; they may be temporarily disabled.
127
+ - Do not invent generic calldata, arbitrary contract calls, token approvals, or non-listed bridge providers.
128
+ - If a requested tool is absent from `list_tools` or capabilities, say the wallet runtime does not expose it.