@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,188 @@
1
+ """Build a release bundle tarball for the OpenClaw wallet/plugin runtime."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import io
7
+ import json
8
+ import subprocess
9
+ import tarfile
10
+ from datetime import datetime, timezone
11
+ from pathlib import Path, PurePosixPath
12
+
13
+ DEFAULT_BUNDLE_PREFIX = "openclaw-agent-wallet-bundle"
14
+ INCLUDED_ROOT_FILES = [
15
+ ".env.example",
16
+ ".gitignore",
17
+ "AGENTS.md",
18
+ "CHANGELOG.md",
19
+ "LICENSE",
20
+ "README.md",
21
+ "RELEASING.md",
22
+ "install-from-github.sh",
23
+ "requirements.txt",
24
+ "setup.sh",
25
+ ]
26
+ INCLUDED_TOP_LEVEL_DIRS = [
27
+ ".openclaw",
28
+ "agent-a2a-gateway",
29
+ "agent-wallet",
30
+ "wdk-btc-wallet",
31
+ "wdk-evm-wallet",
32
+ ]
33
+ EXCLUDED_EXACT_RELATIVE_PATHS = {
34
+ ".openclaw/extensions-local",
35
+ ".openclaw/openclaw.local.example.json",
36
+ }
37
+ EXCLUDED_DIR_NAMES = {
38
+ ".git",
39
+ ".venv",
40
+ ".pytest_cache",
41
+ ".ruff_cache",
42
+ "extensions-local",
43
+ "graphify-out",
44
+ "__pycache__",
45
+ "dist",
46
+ "node_modules",
47
+ }
48
+ EXCLUDED_FILE_NAMES = {
49
+ ".DS_Store",
50
+ }
51
+ EXCLUDED_SUFFIXES = {
52
+ ".pyc",
53
+ ".pyo",
54
+ }
55
+
56
+
57
+ def _repo_root() -> Path:
58
+ return Path(__file__).resolve().parents[2]
59
+
60
+
61
+ def _default_output_dir() -> Path:
62
+ return _repo_root() / "dist"
63
+
64
+
65
+ def _git_version(root: Path) -> str:
66
+ try:
67
+ result = subprocess.run(
68
+ ["git", "-C", str(root), "describe", "--tags", "--always", "--dirty"],
69
+ capture_output=True,
70
+ text=True,
71
+ check=True,
72
+ )
73
+ version = result.stdout.strip()
74
+ if version:
75
+ return version.replace("/", "-")
76
+ except Exception:
77
+ pass
78
+ return datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
79
+
80
+
81
+ def _bundle_root_name(version: str) -> str:
82
+ return f"{DEFAULT_BUNDLE_PREFIX}-{version}"
83
+
84
+
85
+ def _should_skip(path: Path, source_root: Path) -> bool:
86
+ relative = path.relative_to(source_root)
87
+ relative_text = relative.as_posix()
88
+ if relative_text in EXCLUDED_EXACT_RELATIVE_PATHS:
89
+ return True
90
+ for part in relative.parts:
91
+ if part in EXCLUDED_DIR_NAMES:
92
+ return True
93
+ if path.name in EXCLUDED_FILE_NAMES:
94
+ return True
95
+ return any(path.name.endswith(suffix) for suffix in EXCLUDED_SUFFIXES)
96
+
97
+
98
+ def _iter_paths(base_path: Path, source_root: Path) -> list[Path]:
99
+ if not base_path.exists():
100
+ return []
101
+ if base_path.is_file():
102
+ return [] if _should_skip(base_path, source_root) else [base_path]
103
+
104
+ collected: list[Path] = []
105
+ for path in sorted(base_path.rglob("*")):
106
+ if _should_skip(path, source_root):
107
+ continue
108
+ collected.append(path)
109
+ return collected
110
+
111
+
112
+ def _normalize_tar_name(bundle_root: str, source_root: Path, path: Path) -> str:
113
+ relative = PurePosixPath(path.relative_to(source_root).as_posix())
114
+ return str(PurePosixPath(bundle_root) / relative)
115
+
116
+
117
+ def _build_manifest(source_root: Path, version: str, bundle_root: str) -> bytes:
118
+ payload = {
119
+ "bundle_prefix": DEFAULT_BUNDLE_PREFIX,
120
+ "bundle_root": bundle_root,
121
+ "version": version,
122
+ "generated_at": datetime.now(timezone.utc).isoformat(),
123
+ "source_root": str(source_root),
124
+ "included_root_files": INCLUDED_ROOT_FILES,
125
+ "included_top_level_dirs": INCLUDED_TOP_LEVEL_DIRS,
126
+ "excluded_dir_names": sorted(EXCLUDED_DIR_NAMES),
127
+ "excluded_file_names": sorted(EXCLUDED_FILE_NAMES),
128
+ "excluded_suffixes": sorted(EXCLUDED_SUFFIXES),
129
+ "excluded_exact_relative_paths": sorted(EXCLUDED_EXACT_RELATIVE_PATHS),
130
+ }
131
+ return (json.dumps(payload, indent=2) + "\n").encode("utf-8")
132
+
133
+
134
+ def build_parser() -> argparse.ArgumentParser:
135
+ parser = argparse.ArgumentParser(description=__doc__)
136
+ parser.add_argument("--source-root", default=str(_repo_root()))
137
+ parser.add_argument("--output-dir", default=str(_default_output_dir()))
138
+ parser.add_argument("--output-file", default="")
139
+ parser.add_argument("--version", default="")
140
+ parser.add_argument("--bundle-root", default="")
141
+ return parser
142
+
143
+
144
+ def main() -> None:
145
+ args = build_parser().parse_args()
146
+ source_root = Path(args.source_root).expanduser().resolve()
147
+ output_dir = Path(args.output_dir).expanduser().resolve()
148
+ version = args.version.strip() or _git_version(source_root)
149
+ bundle_root = args.bundle_root.strip() or _bundle_root_name(version)
150
+ output_dir.mkdir(parents=True, exist_ok=True)
151
+ output_path = (
152
+ Path(args.output_file).expanduser().resolve()
153
+ if args.output_file.strip()
154
+ else output_dir / f"{bundle_root}.tar.gz"
155
+ )
156
+
157
+ included_paths: list[Path] = []
158
+ for relative in INCLUDED_ROOT_FILES + INCLUDED_TOP_LEVEL_DIRS:
159
+ included_paths.extend(_iter_paths(source_root / relative, source_root))
160
+
161
+ manifest_bytes = _build_manifest(source_root, version, bundle_root)
162
+ with tarfile.open(output_path, "w:gz") as archive:
163
+ for path in included_paths:
164
+ archive.add(path, arcname=_normalize_tar_name(bundle_root, source_root, path), recursive=False)
165
+
166
+ manifest_info = tarfile.TarInfo(name=f"{bundle_root}/bundle-manifest.json")
167
+ manifest_info.size = len(manifest_bytes)
168
+ manifest_info.mtime = int(datetime.now(timezone.utc).timestamp())
169
+ archive.addfile(manifest_info, io.BytesIO(manifest_bytes))
170
+
171
+ print(
172
+ json.dumps(
173
+ {
174
+ "ok": True,
175
+ "source_root": str(source_root),
176
+ "output_path": str(output_path),
177
+ "bundle_root": bundle_root,
178
+ "version": version,
179
+ "included_root_files": INCLUDED_ROOT_FILES,
180
+ "included_top_level_dirs": INCLUDED_TOP_LEVEL_DIRS,
181
+ },
182
+ indent=2,
183
+ )
184
+ )
185
+
186
+
187
+ if __name__ == "__main__":
188
+ main()
@@ -0,0 +1,121 @@
1
+ """Finalize an OpenClaw agent-wallet config with a persistent master key."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ import os
8
+ import secrets
9
+ import sys
10
+ from datetime import datetime, timezone
11
+ from pathlib import Path
12
+
13
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
14
+
15
+ from agent_wallet.file_ops import atomic_write_text, chmod_if_exists
16
+ from agent_wallet.sealed_keys import resolve_sealed_keys_path, seal_keys, unseal_keys
17
+ from agent_wallet.user_wallets import resolve_user_wallet_path, rotate_user_wallet_encryption
18
+ from security_utils import write_redacted_backup
19
+
20
+
21
+ def _default_config_path() -> Path:
22
+ return Path(os.path.expanduser("~/.openclaw/openclaw.json"))
23
+
24
+
25
+ def build_parser() -> argparse.ArgumentParser:
26
+ parser = argparse.ArgumentParser(description=__doc__)
27
+ parser.add_argument("--config-path", default=str(_default_config_path()))
28
+ parser.add_argument("--plugin-id", default="agent-wallet")
29
+ parser.add_argument("--user-id")
30
+ parser.add_argument("--network")
31
+ parser.add_argument(
32
+ "--current-master-key",
33
+ default="",
34
+ help="Deprecated insecure path. Use AGENT_WALLET_CURRENT_MASTER_KEY env instead.",
35
+ )
36
+ parser.add_argument(
37
+ "--new-master-key",
38
+ default="",
39
+ help="Deprecated insecure path. Use AGENT_WALLET_NEW_MASTER_KEY env instead.",
40
+ )
41
+ return parser
42
+
43
+
44
+ def main() -> None:
45
+ args = build_parser().parse_args()
46
+ config_path = Path(args.config_path).expanduser()
47
+ data = json.loads(config_path.read_text(encoding="utf-8"))
48
+ plugin_config = data["plugins"]["entries"][args.plugin_id]["config"]
49
+
50
+ backup_path = config_path.with_name(
51
+ f"{config_path.name}.bak.agent-wallet-finalize.{datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%SZ')}"
52
+ )
53
+ write_redacted_backup(backup_path, data)
54
+
55
+ existing_master_key = str(plugin_config.get("masterKey") or "").strip()
56
+ if existing_master_key:
57
+ raise SystemExit(
58
+ "masterKey stored in config is no longer supported. Remove it and keep runtime secrets in sealed_keys.json."
59
+ )
60
+
61
+ boot_key = os.getenv("AGENT_WALLET_BOOT_KEY", "").strip()
62
+ if not boot_key:
63
+ raise SystemExit("AGENT_WALLET_BOOT_KEY is required.")
64
+
65
+ sealed_keys_path = resolve_sealed_keys_path()
66
+ sealed_secrets = unseal_keys(boot_key) if sealed_keys_path.exists() else {}
67
+ current_master_key = args.current_master_key.strip() or os.getenv("AGENT_WALLET_CURRENT_MASTER_KEY", "").strip()
68
+ if not current_master_key:
69
+ current_master_key = str(sealed_secrets.get("master_key") or "").strip()
70
+ new_master_key_arg = args.new_master_key.strip() or os.getenv("AGENT_WALLET_NEW_MASTER_KEY", "").strip()
71
+ if args.current_master_key.strip() or args.new_master_key.strip():
72
+ raise SystemExit(
73
+ "Passing master keys via command-line arguments is insecure. Use AGENT_WALLET_CURRENT_MASTER_KEY / AGENT_WALLET_NEW_MASTER_KEY environment variables instead."
74
+ )
75
+
76
+ user_id = args.user_id or str(plugin_config.get("userId") or "").strip()
77
+ if not user_id:
78
+ raise SystemExit("user_id is required either as an argument or in plugin config.")
79
+
80
+ network = args.network or str(plugin_config.get("network") or "mainnet").strip() or "mainnet"
81
+ wallet_path = resolve_user_wallet_path(user_id, network=network)
82
+ new_master_key = new_master_key_arg or secrets.token_hex(32)
83
+
84
+ rotated_wallet = False
85
+ if wallet_path.exists():
86
+ if not current_master_key:
87
+ raise SystemExit(
88
+ "AGENT_WALLET_CURRENT_MASTER_KEY is required to rotate an existing encrypted user wallet."
89
+ )
90
+ rotate_user_wallet_encryption(
91
+ user_id,
92
+ network=network,
93
+ current_master_key=current_master_key,
94
+ new_master_key=new_master_key,
95
+ )
96
+ rotated_wallet = True
97
+
98
+ plugin_config.pop("masterKey", None)
99
+ atomic_write_text(config_path, json.dumps(data, indent=2) + "\n", mode=0o600)
100
+ chmod_if_exists(config_path, 0o600)
101
+ seal_keys(boot_key, {**sealed_secrets, "master_key": new_master_key})
102
+
103
+ print(
104
+ json.dumps(
105
+ {
106
+ "ok": True,
107
+ "config_path": str(config_path),
108
+ "backup_path": str(backup_path),
109
+ "master_key_present": True,
110
+ "rotated_wallet": rotated_wallet,
111
+ "user_id": user_id,
112
+ "network": network,
113
+ "sealed_keys_path": str(resolve_sealed_keys_path()),
114
+ },
115
+ indent=2,
116
+ )
117
+ )
118
+
119
+
120
+ if __name__ == "__main__":
121
+ main()