@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.
- package/.openclaw/AGENTS.md +98 -0
- package/.openclaw/extensions/agent-wallet/README.md +127 -0
- package/.openclaw/extensions/agent-wallet/index.ts +1520 -0
- package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +184 -0
- package/.openclaw/extensions/agent-wallet/package.json +11 -0
- package/.openclaw/extensions/agent-wallet/skills/wallet-operator/SKILL.md +20 -0
- package/CHANGELOG.md +42 -0
- package/LICENSE +104 -0
- package/README.md +332 -0
- package/RELEASING.md +204 -0
- package/agent-wallet/.env.example +62 -0
- package/agent-wallet/AGENTS.md +129 -0
- package/agent-wallet/README.md +527 -0
- package/agent-wallet/agent_wallet/__init__.py +11 -0
- package/agent-wallet/agent_wallet/approval.py +161 -0
- package/agent-wallet/agent_wallet/bootstrap.py +178 -0
- package/agent-wallet/agent_wallet/btc_user_wallets.py +217 -0
- package/agent-wallet/agent_wallet/config.py +382 -0
- package/agent-wallet/agent_wallet/encrypted_storage.py +161 -0
- package/agent-wallet/agent_wallet/evm_user_wallets.py +370 -0
- package/agent-wallet/agent_wallet/exceptions.py +9 -0
- package/agent-wallet/agent_wallet/file_ops.py +34 -0
- package/agent-wallet/agent_wallet/http_client.py +25 -0
- package/agent-wallet/agent_wallet/models.py +66 -0
- package/agent-wallet/agent_wallet/nonce_registry.py +59 -0
- package/agent-wallet/agent_wallet/openclaw_adapter.py +5128 -0
- package/agent-wallet/agent_wallet/openclaw_cli.py +626 -0
- package/agent-wallet/agent_wallet/openclaw_runtime.py +272 -0
- package/agent-wallet/agent_wallet/plugin_bundle.py +42 -0
- package/agent-wallet/agent_wallet/providers/__init__.py +1 -0
- package/agent-wallet/agent_wallet/providers/bags.py +259 -0
- package/agent-wallet/agent_wallet/providers/evm_portfolio.py +470 -0
- package/agent-wallet/agent_wallet/providers/jupiter.py +567 -0
- package/agent-wallet/agent_wallet/providers/kamino.py +215 -0
- package/agent-wallet/agent_wallet/providers/lifi.py +277 -0
- package/agent-wallet/agent_wallet/providers/solana_rpc.py +470 -0
- package/agent-wallet/agent_wallet/providers/wdk_btc_local.py +114 -0
- package/agent-wallet/agent_wallet/providers/wdk_evm_local.py +205 -0
- package/agent-wallet/agent_wallet/sealed_keys.py +61 -0
- package/agent-wallet/agent_wallet/solana_stake.py +103 -0
- package/agent-wallet/agent_wallet/solana_tx.py +93 -0
- package/agent-wallet/agent_wallet/spending_limits.py +101 -0
- package/agent-wallet/agent_wallet/transaction_policy.py +518 -0
- package/agent-wallet/agent_wallet/user_wallets.py +355 -0
- package/agent-wallet/agent_wallet/validation.py +31 -0
- package/agent-wallet/agent_wallet/wallet_layer/__init__.py +1 -0
- package/agent-wallet/agent_wallet/wallet_layer/base.py +808 -0
- package/agent-wallet/agent_wallet/wallet_layer/base58.py +44 -0
- package/agent-wallet/agent_wallet/wallet_layer/factory.py +102 -0
- package/agent-wallet/agent_wallet/wallet_layer/solana.py +4252 -0
- package/agent-wallet/agent_wallet/wallet_layer/wdk_btc.py +272 -0
- package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +1628 -0
- package/agent-wallet/examples/bootstrap_wallet.py +21 -0
- package/agent-wallet/examples/openclaw_runtime_onboarding.py +28 -0
- package/agent-wallet/examples/openclaw_user_wallet_example.py +31 -0
- package/agent-wallet/examples/openclaw_wallet_adapter_example.py +33 -0
- package/agent-wallet/openclaw.plugin.json +138 -0
- package/agent-wallet/pyproject.toml +31 -0
- package/agent-wallet/scripts/bootstrap_openclaw_btc.py +278 -0
- package/agent-wallet/scripts/build_release_bundle.py +188 -0
- package/agent-wallet/scripts/finalize_openclaw_local_wallet_config.py +121 -0
- package/agent-wallet/scripts/install_agent_wallet.py +505 -0
- package/agent-wallet/scripts/install_openclaw_local_config.py +226 -0
- package/agent-wallet/scripts/install_openclaw_sealed_keys.py +105 -0
- package/agent-wallet/scripts/manage_openclaw_btc_wallet.py +244 -0
- package/agent-wallet/scripts/reveal_btc_seed.sh +130 -0
- package/agent-wallet/scripts/security_utils.py +37 -0
- package/agent-wallet/scripts/setup_btc_wallet.sh +146 -0
- package/agent-wallet/scripts/switch_openclaw_wallet_network.py +106 -0
- package/agent-wallet/skills/wallet-operator/SKILL.md +128 -0
- package/bin/openclaw-agent-wallet.mjs +487 -0
- package/install-from-github.sh +134 -0
- package/package.json +61 -0
- package/setup.sh +40 -0
- package/wdk-btc-wallet/README.md +325 -0
- package/wdk-btc-wallet/bootstrap.sh +22 -0
- package/wdk-btc-wallet/package-lock.json +1839 -0
- package/wdk-btc-wallet/package.json +18 -0
- package/wdk-btc-wallet/run-local.sh +21 -0
- package/wdk-btc-wallet/src/config.js +160 -0
- package/wdk-btc-wallet/src/json.js +35 -0
- package/wdk-btc-wallet/src/local_vault.js +432 -0
- package/wdk-btc-wallet/src/network_state.js +84 -0
- package/wdk-btc-wallet/src/server.js +257 -0
- package/wdk-btc-wallet/src/wdk_btc_wallet.js +332 -0
- package/wdk-evm-wallet/README.md +183 -0
- package/wdk-evm-wallet/bootstrap.sh +8 -0
- package/wdk-evm-wallet/package-lock.json +2340 -0
- package/wdk-evm-wallet/package.json +23 -0
- package/wdk-evm-wallet/run-local.sh +12 -0
- package/wdk-evm-wallet/src/config.js +274 -0
- package/wdk-evm-wallet/src/json.js +35 -0
- package/wdk-evm-wallet/src/local_vault.js +430 -0
- package/wdk-evm-wallet/src/network_state.js +92 -0
- package/wdk-evm-wallet/src/server.js +575 -0
- 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.
|