@agentlayer.tech/wallet 0.1.32 → 0.1.34

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 (36) hide show
  1. package/.openclaw/extensions/agent-wallet/dist/index.js +2 -59
  2. package/.openclaw/extensions/agent-wallet/index.ts +2 -59
  3. package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +1 -4
  4. package/.openclaw/extensions/agent-wallet/package.json +1 -1
  5. package/CHANGELOG.md +66 -0
  6. package/README.md +2 -5
  7. package/RELEASING.md +56 -29
  8. package/VERSION +1 -0
  9. package/agent-wallet/.env.example +0 -1
  10. package/agent-wallet/README.md +0 -8
  11. package/agent-wallet/agent_wallet/__init__.py +5 -0
  12. package/agent-wallet/agent_wallet/config.py +0 -1
  13. package/agent-wallet/agent_wallet/openclaw_adapter.py +25 -324
  14. package/agent-wallet/agent_wallet/openclaw_cli.py +0 -5
  15. package/agent-wallet/agent_wallet/providers/bags.py +1 -58
  16. package/agent-wallet/agent_wallet/providers/jupiter.py +1 -64
  17. package/agent-wallet/agent_wallet/update_check.py +191 -0
  18. package/agent-wallet/agent_wallet/wallet_layer/base.py +0 -44
  19. package/agent-wallet/agent_wallet/wallet_layer/solana.py +0 -236
  20. package/agent-wallet/openclaw.plugin.json +1 -5
  21. package/agent-wallet/pyproject.toml +1 -1
  22. package/agent-wallet/skills/wallet-operator/SKILL.md +2 -5
  23. package/bin/openclaw-agent-wallet.mjs +419 -33
  24. package/claude-code/plugins/agent-wallet/.claude-plugin/plugin.json +1 -1
  25. package/claude-code/plugins/agent-wallet/scripts/run_mcp.sh +14 -1
  26. package/codex/plugins/agent-wallet/.codex-plugin/plugin.json +1 -1
  27. package/codex/plugins/agent-wallet/scripts/run_mcp.sh +18 -0
  28. package/codex/plugins/agent-wallet/server.py +39 -5
  29. package/hermes/plugins/agent_wallet/plugin.yaml +1 -1
  30. package/package.json +5 -1
  31. package/scripts/check_release_version.mjs +50 -20
  32. package/scripts/version_targets.mjs +60 -0
  33. package/wdk-btc-wallet/package.json +1 -1
  34. package/wdk-evm-wallet/README.md +3 -3
  35. package/wdk-evm-wallet/package.json +1 -1
  36. package/wdk-evm-wallet/src/wdk_evm_wallet.js +17 -2
@@ -0,0 +1,191 @@
1
+ """Non-blocking "a newer version is available" check for the agent wallet.
2
+
3
+ Distribution is the npm package ``@agentlayer.tech/wallet``; a new release is a
4
+ new npm publish. This module compares the installed version against the latest
5
+ version published on the npm registry and decides whether to surface a notice.
6
+
7
+ Design constraints (must all hold):
8
+
9
+ * **Never block startup.** The network refresh runs in a daemon thread and only
10
+ updates a cache file for the *next* start. The synchronous notice decision
11
+ reads that cache and returns instantly without touching the network.
12
+ * **At most once per usage cycle.** The notice is injected into the MCP server
13
+ ``instructions`` string, which a client reads exactly once per session.
14
+ * **At most once per day per version across sessions.** A cached
15
+ ``last_shown_*`` record throttles repeats to :data:`NAG_INTERVAL_SECONDS`.
16
+ * **Fail-open.** Any error (offline, timeout, malformed cache) results in no
17
+ notice and no exception — the wallet keeps working.
18
+ * **Opt-out.** Set ``AGENT_WALLET_DISABLE_UPDATE_CHECK=1`` to disable entirely.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import json
24
+ import os
25
+ import threading
26
+ import time
27
+ from pathlib import Path
28
+ from typing import Callable
29
+
30
+ from .config import resolve_openclaw_home
31
+
32
+ PACKAGE_NAME = "@agentlayer.tech/wallet"
33
+ # URL-encoded scoped package name for the npm registry endpoint.
34
+ _REGISTRY_URL = "https://registry.npmjs.org/@agentlayer.tech%2Fwallet/latest"
35
+
36
+ CACHE_TTL_SECONDS = 24 * 3600
37
+ NAG_INTERVAL_SECONDS = 24 * 3600
38
+ NET_TIMEOUT_SECONDS = 1.5
39
+
40
+ ENV_DISABLE = "AGENT_WALLET_DISABLE_UPDATE_CHECK"
41
+
42
+
43
+ def installed_version() -> str:
44
+ """Return the installed agent-wallet version."""
45
+ from . import __version__
46
+
47
+ return __version__
48
+
49
+
50
+ def is_disabled(env: dict | None = None) -> bool:
51
+ """Return True when the update check is opted out via environment."""
52
+ env = os.environ if env is None else env
53
+ return str(env.get(ENV_DISABLE, "")).strip().lower() in {"1", "true", "yes", "on"}
54
+
55
+
56
+ def cache_path() -> Path:
57
+ """Location of the shared update-check cache file."""
58
+ return resolve_openclaw_home() / "agent-wallet-runtime" / "update-check.json"
59
+
60
+
61
+ def _read_cache() -> dict:
62
+ try:
63
+ return json.loads(cache_path().read_text(encoding="utf-8"))
64
+ except Exception:
65
+ return {}
66
+
67
+
68
+ def _write_cache(data: dict) -> None:
69
+ try:
70
+ path = cache_path()
71
+ path.parent.mkdir(parents=True, exist_ok=True)
72
+ tmp = path.with_suffix(".json.tmp")
73
+ tmp.write_text(json.dumps(data), encoding="utf-8")
74
+ tmp.replace(path)
75
+ except Exception:
76
+ # Cache is best-effort; never let a write failure surface.
77
+ pass
78
+
79
+
80
+ def _parse_semver(value: str) -> tuple[int, ...]:
81
+ parts: list[int] = []
82
+ for chunk in str(value).strip().split("."):
83
+ num = ""
84
+ for ch in chunk:
85
+ if ch.isdigit():
86
+ num += ch
87
+ else:
88
+ break
89
+ parts.append(int(num) if num else 0)
90
+ return tuple(parts)
91
+
92
+
93
+ def _is_newer(latest: str, current: str) -> bool:
94
+ try:
95
+ return _parse_semver(latest) > _parse_semver(current)
96
+ except Exception:
97
+ return False
98
+
99
+
100
+ def pending_notice(
101
+ *,
102
+ mark_shown: bool,
103
+ current: str | None = None,
104
+ now: float | None = None,
105
+ ) -> str | None:
106
+ """Return a human-readable notice when a newer version should be surfaced.
107
+
108
+ Reads only the cache (no network, instant). Returns ``None`` when disabled,
109
+ when no newer version is known, or when the same version was already shown
110
+ within :data:`NAG_INTERVAL_SECONDS`. When ``mark_shown`` is True and a notice
111
+ is returned, the "last shown" record is persisted to throttle later sessions.
112
+ """
113
+ if is_disabled():
114
+ return None
115
+ current = installed_version() if current is None else current
116
+ now = time.time() if now is None else now
117
+
118
+ cache = _read_cache()
119
+ latest = cache.get("latest_version")
120
+ if not latest or not _is_newer(str(latest), current):
121
+ return None
122
+
123
+ if (
124
+ cache.get("last_shown_version") == latest
125
+ and isinstance(cache.get("last_shown_at"), (int, float))
126
+ and now - cache["last_shown_at"] < NAG_INTERVAL_SECONDS
127
+ ):
128
+ return None
129
+
130
+ if mark_shown:
131
+ cache["last_shown_version"] = latest
132
+ cache["last_shown_at"] = now
133
+ _write_cache(cache)
134
+
135
+ return (
136
+ f"newer agent-wallet version {latest} is available (you have {current}). "
137
+ f"Update with: npx {PACKAGE_NAME} update --yes"
138
+ )
139
+
140
+
141
+ def _fetch_latest_version() -> str | None:
142
+ """Fetch the latest published version from the npm registry (blocking)."""
143
+ import httpx
144
+
145
+ resp = httpx.get(_REGISTRY_URL, timeout=NET_TIMEOUT_SECONDS)
146
+ resp.raise_for_status()
147
+ version = resp.json().get("version")
148
+ return str(version) if version else None
149
+
150
+
151
+ def _refresh_now(
152
+ fetcher: Callable[[], str | None] | None = None,
153
+ now: float | None = None,
154
+ ) -> None:
155
+ """Refresh the cached latest version if stale. Synchronous, fail-open."""
156
+ if is_disabled():
157
+ return
158
+ now = time.time() if now is None else now
159
+ cache = _read_cache()
160
+ checked_at = cache.get("checked_at")
161
+ if isinstance(checked_at, (int, float)) and now - checked_at < CACHE_TTL_SECONDS:
162
+ return # cache fresh enough; skip network
163
+ fetcher = _fetch_latest_version if fetcher is None else fetcher
164
+ try:
165
+ latest = fetcher()
166
+ except Exception:
167
+ return # fail-open: leave cache untouched
168
+ if not latest:
169
+ return
170
+ cache["latest_version"] = str(latest)
171
+ cache["checked_at"] = now
172
+ _write_cache(cache)
173
+
174
+
175
+ def maybe_refresh_in_background(
176
+ fetcher: Callable[[], str | None] | None = None,
177
+ ) -> threading.Thread | None:
178
+ """Start a daemon thread to refresh the cache without blocking the caller.
179
+
180
+ Returns the started thread (for tests) or ``None`` when disabled.
181
+ """
182
+ if is_disabled():
183
+ return None
184
+ thread = threading.Thread(
185
+ target=_refresh_now,
186
+ kwargs={"fetcher": fetcher},
187
+ name="agent-wallet-update-check",
188
+ daemon=True,
189
+ )
190
+ thread.start()
191
+ return thread
@@ -357,19 +357,6 @@ class AgentWalletBackend(ABC):
357
357
  async def get_stake_account(self, stake_account: str) -> dict[str, Any]:
358
358
  raise WalletBackendError(f"{self.name} does not support stake account lookup.")
359
359
 
360
- async def get_jupiter_portfolio(
361
- self,
362
- address: str | None = None,
363
- platforms: list[str] | None = None,
364
- ) -> dict[str, Any]:
365
- raise WalletBackendError(f"{self.name} does not support Jupiter portfolio lookup.")
366
-
367
- async def get_jupiter_portfolio_platforms(self) -> dict[str, Any]:
368
- raise WalletBackendError(f"{self.name} does not support Jupiter portfolio platforms.")
369
-
370
- async def get_jupiter_staked_jup(self, address: str | None = None) -> dict[str, Any]:
371
- raise WalletBackendError(f"{self.name} does not support Jupiter staked JUP lookup.")
372
-
373
360
  async def get_flash_trade_markets(
374
361
  self,
375
362
  pool_name: str | None = None,
@@ -804,37 +791,6 @@ class AgentWalletBackend(ABC):
804
791
  }
805
792
  return result
806
793
 
807
- async def get_bags_claimable_positions(
808
- self,
809
- wallet: str | None = None,
810
- ) -> dict[str, Any]:
811
- raise WalletBackendError(f"{self.name} does not support Bags claimable positions lookup.")
812
-
813
- async def get_bags_fee_analytics(
814
- self,
815
- token_mint: str,
816
- *,
817
- include_claim_events: bool = False,
818
- mode: str = "offset",
819
- limit: int | None = None,
820
- offset: int | None = None,
821
- from_ts: int | None = None,
822
- to_ts: int | None = None,
823
- ) -> dict[str, Any]:
824
- raise WalletBackendError(f"{self.name} does not support Bags fee analytics lookup.")
825
-
826
- async def preview_bags_fee_claim(self, token_mint: str) -> dict[str, Any]:
827
- raise WalletBackendError(f"{self.name} does not support Bags fee claim previews.")
828
-
829
- async def execute_bags_fee_claim(self, token_mint: str) -> dict[str, Any]:
830
- raise WalletBackendError(f"{self.name} does not support Bags fee claims.")
831
-
832
- async def execute_bags_fee_claim_from_preview(
833
- self,
834
- preview: dict[str, Any],
835
- ) -> dict[str, Any]:
836
- return await self.execute_bags_fee_claim(str(preview["token_mint"]))
837
-
838
794
  async def preview_bags_token_launch(
839
795
  self,
840
796
  *,
@@ -993,79 +993,6 @@ class SolanaWalletBackend(AgentWalletBackend):
993
993
  "source": "lifi",
994
994
  }
995
995
 
996
- async def get_bags_claimable_positions(
997
- self,
998
- wallet: str | None = None,
999
- ) -> dict[str, Any]:
1000
- self._require_mainnet_bags("Bags fee claims")
1001
- wallet_address = wallet or self.address
1002
- if not wallet_address:
1003
- raise WalletBackendError("A wallet address is required for Bags claimable positions.")
1004
- wallet_address = validate_solana_address(wallet_address)
1005
- raw = await bags.fetch_claimable_positions(wallet_address)
1006
- positions = self._bags_claim_positions_list(raw)
1007
- return {
1008
- "chain": "solana",
1009
- "network": self.network,
1010
- "wallet": wallet_address,
1011
- "position_count": len(positions),
1012
- "positions": positions,
1013
- "raw": raw,
1014
- "source": "bags",
1015
- }
1016
-
1017
- async def get_bags_fee_analytics(
1018
- self,
1019
- token_mint: str,
1020
- *,
1021
- include_claim_events: bool = False,
1022
- mode: str = "offset",
1023
- limit: int | None = None,
1024
- offset: int | None = None,
1025
- from_ts: int | None = None,
1026
- to_ts: int | None = None,
1027
- ) -> dict[str, Any]:
1028
- self._require_mainnet_bags("Bags fee analytics")
1029
- normalized_mint = validate_solana_mint(token_mint)
1030
- if mode not in {"offset", "time"}:
1031
- raise WalletBackendError("mode must be 'offset' or 'time'.")
1032
- if limit is not None and limit <= 0:
1033
- raise WalletBackendError("limit must be greater than zero when provided.")
1034
- if offset is not None and offset < 0:
1035
- raise WalletBackendError("offset must be greater than or equal to zero when provided.")
1036
- if from_ts is not None and from_ts < 0:
1037
- raise WalletBackendError("from_ts must be greater than or equal to zero.")
1038
- if to_ts is not None and to_ts < 0:
1039
- raise WalletBackendError("to_ts must be greater than or equal to zero.")
1040
-
1041
- tasks = [
1042
- bags.fetch_lifetime_fees(normalized_mint),
1043
- bags.fetch_claim_stats(normalized_mint),
1044
- ]
1045
- if include_claim_events:
1046
- tasks.append(
1047
- bags.fetch_claim_events(
1048
- token_mint=normalized_mint,
1049
- mode=mode,
1050
- limit=limit,
1051
- offset=offset,
1052
- from_ts=from_ts,
1053
- to_ts=to_ts,
1054
- )
1055
- )
1056
- results = await asyncio.gather(*tasks)
1057
- claim_events = results[2] if include_claim_events else None
1058
- return {
1059
- "chain": "solana",
1060
- "network": self.network,
1061
- "token_mint": normalized_mint,
1062
- "lifetime_fees": results[0],
1063
- "claim_stats": results[1],
1064
- "claim_events": claim_events,
1065
- "include_claim_events": include_claim_events,
1066
- "source": "bags",
1067
- }
1068
-
1069
996
  async def get_staking_validators(
1070
997
  self,
1071
998
  limit: int = 20,
@@ -1262,16 +1189,6 @@ class SolanaWalletBackend(AgentWalletBackend):
1262
1189
  raise WalletBackendError("basis_points must sum to exactly 10000.")
1263
1190
  return normalized
1264
1191
 
1265
- def _bags_claim_positions_list(self, payload: Any) -> list[dict[str, Any]]:
1266
- if isinstance(payload, list):
1267
- return [item for item in payload if isinstance(item, dict)]
1268
- if isinstance(payload, dict):
1269
- for key in ("positions", "claimablePositions", "items", "data"):
1270
- value = payload.get(key)
1271
- if isinstance(value, list):
1272
- return [item for item in value if isinstance(item, dict)]
1273
- return []
1274
-
1275
1192
  def _bags_decode_serialized_transaction_bytes(self, serialized_transaction: str) -> bytes:
1276
1193
  serialized = str(serialized_transaction).strip()
1277
1194
  if not serialized:
@@ -1533,75 +1450,6 @@ class SolanaWalletBackend(AgentWalletBackend):
1533
1450
  if self.network != "mainnet":
1534
1451
  raise WalletBackendError(f"{feature} is only enabled for Solana mainnet.")
1535
1452
 
1536
- async def get_jupiter_portfolio_platforms(self) -> dict[str, Any]:
1537
- self._require_mainnet_jupiter("Jupiter portfolio")
1538
- data = await jupiter.fetch_portfolio_platforms()
1539
- platforms = data.get("platforms")
1540
- if not isinstance(platforms, list):
1541
- platforms = data.get("data") if isinstance(data.get("data"), list) else []
1542
- return {
1543
- "chain": "solana",
1544
- "network": self.network,
1545
- "platform_count": len(platforms),
1546
- "platforms": platforms,
1547
- "raw": data,
1548
- "source": "jupiter-portfolio",
1549
- }
1550
-
1551
- async def get_jupiter_portfolio(
1552
- self,
1553
- address: str | None = None,
1554
- platforms: list[str] | None = None,
1555
- ) -> dict[str, Any]:
1556
- self._require_mainnet_jupiter("Jupiter portfolio")
1557
- wallet_address = address or self.address
1558
- if not wallet_address:
1559
- raise WalletBackendError(
1560
- "No Solana wallet address configured. Set SOLANA_AGENT_PUBLIC_KEY or a signer."
1561
- )
1562
- wallet_address = validate_solana_address(wallet_address)
1563
- platform_filter: list[str] | None = None
1564
- if platforms is not None:
1565
- platform_filter = []
1566
- for platform in platforms:
1567
- if not isinstance(platform, str) or not platform.strip():
1568
- raise WalletBackendError("Each platform must be a non-empty string.")
1569
- platform_filter.append(platform.strip())
1570
- data = await jupiter.fetch_portfolio_positions(
1571
- address=wallet_address,
1572
- platforms=platform_filter,
1573
- )
1574
- positions = data.get("positions")
1575
- if not isinstance(positions, list):
1576
- positions = data.get("data") if isinstance(data.get("data"), list) else []
1577
- return {
1578
- "chain": "solana",
1579
- "network": self.network,
1580
- "address": wallet_address,
1581
- "platforms": platform_filter or [],
1582
- "position_count": len(positions),
1583
- "positions": positions,
1584
- "raw": data,
1585
- "source": "jupiter-portfolio",
1586
- }
1587
-
1588
- async def get_jupiter_staked_jup(self, address: str | None = None) -> dict[str, Any]:
1589
- self._require_mainnet_jupiter("Jupiter staked JUP")
1590
- wallet_address = address or self.address
1591
- if not wallet_address:
1592
- raise WalletBackendError(
1593
- "No Solana wallet address configured. Set SOLANA_AGENT_PUBLIC_KEY or a signer."
1594
- )
1595
- wallet_address = validate_solana_address(wallet_address)
1596
- data = await jupiter.fetch_staked_jup(address=wallet_address)
1597
- return {
1598
- "chain": "solana",
1599
- "network": self.network,
1600
- "address": wallet_address,
1601
- "raw": data,
1602
- "source": "jupiter-portfolio",
1603
- }
1604
-
1605
1453
  async def get_flash_trade_markets(
1606
1454
  self,
1607
1455
  pool_name: str | None = None,
@@ -4599,90 +4447,6 @@ class SolanaWalletBackend(AgentWalletBackend):
4599
4447
  "source": "solana-rpc",
4600
4448
  }
4601
4449
 
4602
- async def preview_bags_fee_claim(self, token_mint: str) -> dict[str, Any]:
4603
- self._require_mainnet_bags("Bags fee claims")
4604
- owner = await self.get_address()
4605
- if not owner:
4606
- raise WalletBackendError(
4607
- "No Solana wallet address configured. Set SOLANA_AGENT_PUBLIC_KEY or a signer."
4608
- )
4609
- normalized_mint = validate_solana_mint(token_mint)
4610
- positions_payload = await self.get_bags_claimable_positions(owner)
4611
- positions = [
4612
- item
4613
- for item in positions_payload["positions"]
4614
- if str(item.get("tokenMint") or item.get("token_mint") or "").strip() == normalized_mint
4615
- ]
4616
- return {
4617
- "chain": "solana",
4618
- "network": self.network,
4619
- "mode": "preview",
4620
- "asset_type": "bags-fee-claim",
4621
- "owner": owner,
4622
- "fee_claimer": owner,
4623
- "token_mint": normalized_mint,
4624
- "claimable_position_count": len(positions),
4625
- "claimable_positions": positions,
4626
- "sign_only": self.sign_only,
4627
- "can_send": self.get_capabilities().can_send_transaction,
4628
- "source": "bags",
4629
- }
4630
-
4631
- async def execute_bags_fee_claim(
4632
- self,
4633
- token_mint: str,
4634
- ) -> dict[str, Any]:
4635
- preview = await self.preview_bags_fee_claim(token_mint)
4636
- return await self.execute_bags_fee_claim_from_preview(preview)
4637
-
4638
- async def execute_bags_fee_claim_from_preview(
4639
- self,
4640
- preview: dict[str, Any],
4641
- ) -> dict[str, Any]:
4642
- if not self.signer:
4643
- raise WalletBackendError("Solana signer is not configured.")
4644
- owner = await self.get_address()
4645
- if not owner:
4646
- raise WalletBackendError(
4647
- "No Solana wallet address configured. Set SOLANA_AGENT_PUBLIC_KEY or a signer."
4648
- )
4649
- if str(preview.get("asset_type") or "").strip().lower() != "bags-fee-claim":
4650
- raise WalletBackendError("preview payload is not a Bags fee claim preview.")
4651
- if str(preview.get("network") or self.network).strip().lower() != self.network:
4652
- raise WalletBackendError("preview payload network does not match the wallet backend.")
4653
- if str(preview.get("owner") or owner) != owner:
4654
- raise WalletBackendError("preview payload owner does not match the connected wallet.")
4655
- if int(preview.get("claimable_position_count") or 0) <= 0:
4656
- raise WalletBackendError("No claimable Bags fee positions were found for this token.")
4657
-
4658
- token_mint = validate_solana_mint(str(preview.get("token_mint") or ""))
4659
- claim_payload = await bags.build_claim_transactions(
4660
- {
4661
- "feeClaimer": owner,
4662
- "tokenMint": token_mint,
4663
- }
4664
- )
4665
- transactions = self._bags_extract_transaction_base64s(claim_payload)
4666
- prepared = await self._prepare_bags_transactions(
4667
- transaction_base64s=transactions,
4668
- token_mint=token_mint,
4669
- action="Bags fee claim",
4670
- owner=owner,
4671
- asset_type="bags-fee-claim",
4672
- extra={
4673
- "fee_claimer": owner,
4674
- "claimable_position_count": int(preview.get("claimable_position_count") or 0),
4675
- "claimable_positions": preview.get("claimable_positions"),
4676
- "claim_response": claim_payload,
4677
- },
4678
- )
4679
- result = await self._execute_prepared_bags_transactions(prepared)
4680
- result["fee_claimer"] = owner
4681
- result["claimable_position_count"] = int(preview.get("claimable_position_count") or 0)
4682
- result["claimable_positions"] = preview.get("claimable_positions")
4683
- result["claim_response"] = claim_payload
4684
- return result
4685
-
4686
4450
  async def preview_bags_token_launch(
4687
4451
  self,
4688
4452
  *,
@@ -2,7 +2,7 @@
2
2
  "id": "agent-wallet",
3
3
  "name": "Agent Wallet",
4
4
  "description": "Plugin-friendly wallet backend for OpenClaw agents with safe wallet tools and runtime instructions across Solana, local BTC, and local EVM.",
5
- "version": "0.1.0",
5
+ "version": "0.1.34",
6
6
  "skills": ["skills/wallet-operator"],
7
7
  "configSchema": {
8
8
  "type": "object",
@@ -113,10 +113,6 @@
113
113
  "type": "string",
114
114
  "description": "Optional Jupiter Price API base URL for token price lookup."
115
115
  },
116
- "jupiterPortfolioBaseUrl": {
117
- "type": "string",
118
- "description": "Optional Jupiter Portfolio API base URL for Jupiter-specific positions and staking data."
119
- },
120
116
  "jupiterApiKey": {
121
117
  "type": "string",
122
118
  "description": "Optional Jupiter API key if your deployment uses a keyed endpoint."
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "openclaw-agent-wallet"
7
- version = "0.1.32"
7
+ version = "0.1.34"
8
8
  description = "Plugin-friendly wallet backend for OpenClaw agents"
9
9
  requires-python = ">=3.10"
10
10
  dependencies = [
@@ -1,6 +1,6 @@
1
1
  ---
2
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, Kamino lending, Bags claims/launches, and wallet execution safety.
3
+ description: Use when operating OpenClaw wallet tools: balances, transfers, swaps, LI.FI cross-chain swaps, Jupiter swaps, Velora EVM swaps, BTC transfers, staking, Kamino lending, Bags launches, and wallet execution safety.
4
4
  ---
5
5
 
6
6
  # Wallet Operator
@@ -30,7 +30,7 @@ Use this skill before calling OpenClaw wallet tools. It is the routing guide for
30
30
  - BTC transfer: `transfer_btc`.
31
31
  - Solana staking: `stake_sol_native`, `deactivate_solana_stake`, `withdraw_solana_stake`.
32
32
  - Kamino: `kamino_lend_deposit`, `kamino_lend_withdraw`, `kamino_lend_borrow`, `kamino_lend_repay`.
33
- - Bags: `claim_bags_fees`, `launch_bags_token`.
33
+ - Bags: `launch_bags_token`.
34
34
 
35
35
  ## Common Token IDs
36
36
 
@@ -108,8 +108,6 @@ Use this skill before calling OpenClaw wallet tools. It is the routing guide for
108
108
  - `withdraw_solana_stake`: `stake_account`, `amount` in SOL, optional `recipient`, `mode`, `purpose`.
109
109
  - Before Kamino writes, use `get_kamino_lend_markets`, `get_kamino_lend_market_reserves`, `get_kamino_lend_user_obligations`, and `get_kamino_lend_user_rewards`.
110
110
  - Kamino write params: `market`, `reserve`, `amount_ui` decimal string, `mode`, `purpose`.
111
- - Bags reads: `get_bags_claimable_positions`, `get_bags_fee_analytics`.
112
- - `claim_bags_fees`: `token_mint`, `mode`, `purpose`.
113
111
  - `launch_bags_token`: `name`, `symbol`, `description`, `base_mint`, `claimers`, `basis_points`, `initial_buy_sol`, `mode`, `purpose`; optional socials/image/config type.
114
112
  - `close_empty_token_accounts`: `limit`, `mode` (`preview` or `execute`), `purpose`.
115
113
 
@@ -123,6 +121,5 @@ Use this skill before calling OpenClaw wallet tools. It is the routing guide for
123
121
 
124
122
  ## Disabled Or Avoided Paths
125
123
 
126
- - Do not call Jupiter Portfolio tools if they are not listed by `get_wallet_capabilities`; they may be temporarily disabled.
127
124
  - Do not invent generic calldata, arbitrary contract calls, token approvals, or non-listed bridge providers.
128
125
  - If a requested tool is absent from `list_tools` or capabilities, say the wallet runtime does not expose it.