@agentlayer.tech/wallet 0.1.9 → 0.1.11

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/CHANGELOG.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ - Added an optional Hermes Agent bridge plugin under `hermes/plugins/agent_wallet`
6
+ that forwards into the existing Python wallet CLI instead of duplicating
7
+ OpenClaw wallet tools or policy.
8
+ - Added `wallet hermes install --yes` and `AGENT_WALLET_BOOT_KEY_FILE` support
9
+ for smoother Hermes onboarding without manual `.env` editing.
5
10
  - Replaced the repo license with `PolyForm Small Business 1.0.0`.
6
11
  - Clarified in `README.md` that individuals can audit, fork, run, and modify
7
12
  the code for themselves, and that company use follows the PolyForm small
package/README.md CHANGED
@@ -1,13 +1,16 @@
1
1
  ![AgentLayer](logo+name.png)
2
-
3
2
  # AgentLayer
4
3
 
4
+ ```bash
5
+ npx @agentlayer.tech/wallet install --yes
6
+ ```
5
7
  AgentLayer is a beta local-first wallet and finance stack for agents.
6
8
 
7
9
  The repository includes:
8
10
 
9
11
  - `agent-wallet/` - the main wallet backend for AgentLayer
10
12
  - `.openclaw/` - the local AgentLayer bridge layer
13
+ - `hermes/` - optional Hermes Agent plugin bridge for the same wallet backend
11
14
  - `wdk-btc-wallet/` - the local Bitcoin wallet service
12
15
  - `wdk-evm-wallet/` - the local EVM wallet service
13
16
  - `provider-gateway/` - shared provider access for Solana RPC, Bags, and related finance reads
@@ -33,12 +36,6 @@ System prerequisites:
33
36
  - `node`
34
37
  - `npm`
35
38
 
36
- Install from the latest GitHub release bundle:
37
-
38
- ```bash
39
- curl -fsSL https://raw.githubusercontent.com/lopushok9/Agent-Layer/main/install-from-github.sh | sh
40
- ```
41
-
42
39
  Install through npm:
43
40
 
44
41
  ```bash
@@ -66,6 +63,7 @@ Useful npm CLI commands:
66
63
  ```bash
67
64
  wallet status
68
65
  wallet doctor
66
+ wallet hermes install --yes
69
67
  wallet update --yes
70
68
  wallet rollback
71
69
  ```
@@ -143,9 +141,25 @@ Without those secrets, the installer still lays down the runtime and installs de
143
141
  }
144
142
  ```
145
143
 
144
+ ## Connect Hermes Agent
145
+
146
+ OpenClaw remains the primary local environment, but the repo also ships an optional Hermes Agent bridge at:
147
+
148
+ ```bash
149
+ hermes/plugins/agent_wallet
150
+ ```
151
+
152
+ It exposes only two Hermes tools: `agent_wallet_tools` for discovery and `agent_wallet_invoke` for forwarding a single call into the existing Python wallet CLI. Install it by symlinking the plugin directory into Hermes:
153
+
154
+ ```bash
155
+ npx @agentlayer.tech/wallet hermes install --yes
156
+ ```
157
+
158
+ That command installs the Hermes plugin, runs `hermes plugins enable agent-wallet`, writes non-secret runtime paths into `~/.hermes/.env`, and points Hermes at a local boot-key file. Secrets stay in the existing protected OpenClaw runtime paths, especially `~/.openclaw/sealed_keys.json`; do not put wallet secrets into Hermes tool config.
159
+
146
160
  ## What you get after install
147
161
 
148
- If you install from GitHub release, the bundle is extracted under:
162
+ If you install through npm, the runtime is extracted under:
149
163
 
150
164
  ```bash
151
165
  ~/.openclaw/agent-wallet-runtime/current
@@ -159,6 +173,7 @@ The installer then does the following:
159
173
  - creates a minimal `~/.openclaw/openclaw.json` if one does not exist
160
174
  - if the required secrets are already present, writes or updates `~/.openclaw/sealed_keys.json`
161
175
  - if the required secrets are already present, patches `~/.openclaw/openclaw.json` to load the `agent-wallet` extension and point it at the installed runtime
176
+ - `wallet hermes install --yes` additionally connects Hermes Agent to the same runtime without copying wallet tools or policy
162
177
 
163
178
  When the installer reaches the final config step, the default plugin config is:
164
179
 
package/RELEASING.md CHANGED
@@ -1,217 +1,216 @@
1
1
  # Releasing
2
2
 
3
- ## npm installer package
4
-
5
- The production installer is published as:
3
+ This repo publishes the npm installer as:
6
4
 
7
5
  ```text
8
6
  @agentlayer.tech/wallet
9
7
  ```
10
8
 
11
- Expected user install path:
9
+ The public install command is:
12
10
 
13
11
  ```bash
14
12
  npx @agentlayer.tech/wallet install --yes
15
13
  ```
16
14
 
17
- The npm package ships source and installer scripts only. It must not ship local
18
- state such as `node_modules/`, `.venv/`, `__pycache__/`, wallet files, or
19
- OpenClaw secrets.
15
+ ## When npm Publishes
20
16
 
21
- Before publishing a tag, verify locally:
17
+ Normal commits and pushes do not publish new npm versions. They only run the
18
+ GitHub Actions verification job.
22
19
 
23
- ```bash
24
- npm run check
25
- npm run check:release-version
26
- python3 agent-wallet/tests/smoke_npm_installer.py
27
- python3 agent-wallet/tests/smoke_install_agent_wallet.py
28
- npm --cache /tmp/npm-cache pack --dry-run
29
- ```
20
+ An npm publish happens only when you push a git tag that starts with `v`, for
21
+ example `v0.1.10`.
30
22
 
31
- The GitHub workflow `.github/workflows/npm-installer.yml` verifies the package
32
- on pull requests and publishes tagged releases to npm through npm Trusted
33
- Publishing. Configure the npm package's trusted publisher before publishing:
23
+ The same tag workflow also creates a GitHub Release on the repository's
24
+ Releases page after npm publish succeeds.
25
+
26
+ The tag version must match both source version files:
34
27
 
35
28
  ```text
36
- Provider: GitHub Actions
37
- Organization or user: lopushok9
38
- Repository: Agent-Layer
39
- Workflow filename: npm-installer.yml
29
+ package.json
30
+ agent-wallet/pyproject.toml
40
31
  ```
41
32
 
42
- The `repository.url` field in `package.json` must exactly match the GitHub
43
- repository URL, for example `https://github.com/lopushok9/Agent-Layer.git`.
44
- Do not use the `git+https://` npm shorthand for Trusted Publishing releases.
33
+ If those versions do not match the tag, the workflow fails before publishing.
45
34
 
46
- Do not use `NPM_TOKEN` for publishing unless Trusted Publishing is unavailable.
47
- Token-based publishes can fail with `EOTP` when package or account policy
48
- requires two-factor authentication.
35
+ ## Stable Release
49
36
 
50
- Publish stable releases from version tags. The tag must match both
51
- `package.json` and `agent-wallet/pyproject.toml`:
37
+ Use a stable release when users should get it from the default install command.
52
38
 
53
- ```bash
54
- git tag v0.1.6
55
- git push origin v0.1.6
56
- ```
39
+ Example: publish `0.1.10` as npm `latest`.
57
40
 
58
- The workflow runs:
41
+ 1. Update `package.json`:
59
42
 
60
- ```bash
61
- npm publish --access public --tag latest
43
+ ```json
44
+ "version": "0.1.10"
62
45
  ```
63
46
 
64
- For pre-release tags, use a semver prerelease version in both package files,
65
- then push the matching tag. The workflow publishes those with npm tag `beta`:
47
+ 2. Update `agent-wallet/pyproject.toml`:
66
48
 
67
- ```bash
68
- git tag v0.1.7-beta.1
69
- git push origin v0.1.7-beta.1
49
+ ```toml
50
+ version = "0.1.10"
70
51
  ```
71
52
 
72
- Runtime updates are versioned under:
53
+ 3. Run local checks:
73
54
 
74
- ```text
75
- ~/.openclaw/agent-wallet-runtime/releases/<version>
76
- ~/.openclaw/agent-wallet-runtime/current
55
+ ```bash
56
+ npm run check
57
+ GITHUB_REF_NAME=v0.1.10 npm run check:release-version
58
+ python3 agent-wallet/tests/smoke_npm_installer.py
59
+ python3 agent-wallet/tests/smoke_install_agent_wallet.py
60
+ npm --cache /tmp/npm-cache pack --dry-run
77
61
  ```
78
62
 
79
- The CLI switches `current` only after a successful install/update. `rollback`
80
- switches `current` back to the recorded previous runtime or to a specific
81
- installed version.
82
-
83
- This repository's `v0.1.0-beta.2` public release should be framed around six repo-owned deliverables:
63
+ 4. Commit the version change:
84
64
 
85
- 1. `mcp-server/` - the finance and crypto MCP server
86
- 2. `agent-wallet/` - the Python wallet backend
87
- 3. `.openclaw/extensions/agent-wallet/` - the repo-shipped OpenClaw extension bridge
88
- 4. `wdk-btc-wallet/` - the BTC-only wallet service built on Tether WDK
89
- 5. `provider-gateway/` - the shared non-custodial provider access layer
90
- 6. `docs/` - the Starlight-based documentation site
91
-
92
- ### Release title
93
-
94
- ```text
95
- AgentLayer Beta v0.1.0-beta.2
65
+ ```bash
66
+ git add package.json agent-wallet/pyproject.toml
67
+ git commit -m "Release npm installer 0.1.10"
96
68
  ```
97
69
 
98
- ### Release body
70
+ 5. Create and push the release tag:
99
71
 
100
- ```md
101
- This is the second public beta release of the OpenClaw finance stack.
72
+ ```bash
73
+ git tag -a v0.1.10 -m "v0.1.10"
74
+ git push origin main
75
+ git push origin v0.1.10
76
+ ```
102
77
 
103
- This release keeps the original beta foundation and adds three new repo-owned components:
78
+ 6. Check npm after GitHub Actions finishes:
104
79
 
105
- - `mcp-server/` - finance and crypto MCP server
106
- - `agent-wallet/` - Python wallet backend
107
- - `.openclaw/extensions/agent-wallet/` - OpenClaw extension bridge for the wallet backend
108
- - `wdk-btc-wallet/` - BTC-only wallet service for local Bitcoin operations
109
- - `provider-gateway/` - shared provider access for hosted Solana RPC defaults, Bags, and Jupiter Earn
110
- - `docs/` - documentation app for setup, architecture, and capability reference
80
+ ```bash
81
+ npm view @agentlayer.tech/wallet dist-tags
82
+ npm view @agentlayer.tech/wallet@latest version
83
+ ```
111
84
 
112
- ## Highlights
85
+ Expected result:
113
86
 
114
- - Expands the beta stack with a dedicated local BTC wallet service
115
- - Adds a non-custodial shared provider gateway for Solana RPC, Bags, and Jupiter Earn
116
- - Adds a separate documentation app for onboarding and reference material
117
- - Keeps the MCP server, wallet backend, and OpenClaw extension bridge as the core beta foundation
87
+ ```text
88
+ latest: 0.1.10
89
+ ```
118
90
 
119
- ## Included in this release
91
+ The GitHub Releases page should also contain a new release named `v0.1.10`.
120
92
 
121
- ### New in `v0.1.0-beta.2`
93
+ ## Beta Release
122
94
 
123
- #### `wdk-btc-wallet/`
95
+ Use a beta release when you want to test npm publishing without changing the
96
+ default user install command.
124
97
 
125
- - Separate BTC-only wallet service built on top of Tether WDK
126
- - Local encrypted wallet vault, localhost-only HTTP surface, and local bearer-token auth
127
- - Covers Bitcoin network selection, wallet lifecycle, balances, transfers, fees, and spendability
98
+ Example: publish `0.1.11-beta.1` as npm `beta`.
128
99
 
129
- #### `provider-gateway/`
100
+ 1. Set both version files to the beta version:
130
101
 
131
- - Shared non-custodial provider layer for onboarding-friendly defaults
132
- - Hosted Solana RPC gateway with method allowlist
133
- - Shared Bags launch and fees access plus shared Jupiter Earn relay
102
+ ```json
103
+ "version": "0.1.11-beta.1"
104
+ ```
134
105
 
135
- #### `docs/`
106
+ ```toml
107
+ version = "0.1.11-beta.1"
108
+ ```
136
109
 
137
- - Separate Starlight-based documentation app for AgentLayer
138
- - Covers getting started, infrastructure boundaries, wallet architecture, and capabilities
139
- - Gives the beta stack a repo-owned documentation surface for onboarding and review
110
+ 2. Run checks:
140
111
 
141
- ### Existing beta foundation
112
+ ```bash
113
+ npm run check
114
+ GITHUB_REF_NAME=v0.1.11-beta.1 npm run check:release-version
115
+ npm --cache /tmp/npm-cache pack --dry-run
116
+ ```
142
117
 
143
- #### `mcp-server/`
118
+ 3. Commit, tag, and push:
144
119
 
145
- - MCP server for crypto, DeFi, gas, on-chain, and agent identity workflows
146
- - Structured tools for market data, protocol analytics, and blockchain lookups
147
- - Self-hostable base for OpenClaw or other MCP-compatible clients
120
+ ```bash
121
+ git add package.json agent-wallet/pyproject.toml
122
+ git commit -m "Release npm installer 0.1.11-beta.1"
123
+ git tag -a v0.1.11-beta.1 -m "v0.1.11-beta.1"
124
+ git push origin main
125
+ git push origin v0.1.11-beta.1
126
+ ```
148
127
 
149
- #### `agent-wallet/`
128
+ 4. Test the beta package:
150
129
 
151
- - Local Solana wallet backend for OpenClaw-connected agents
152
- - Read, preview, prepare, and approval-gated execute flows
153
- - Local secret handling and explicit operator approval model for risky actions
130
+ ```bash
131
+ npx @agentlayer.tech/wallet@beta --version
132
+ npx @agentlayer.tech/wallet@beta doctor
133
+ ```
154
134
 
155
- #### `.openclaw/extensions/agent-wallet/`
135
+ The GitHub Releases page should contain a new prerelease named
136
+ `v0.1.11-beta.1`.
156
137
 
157
- - Thin TypeScript bridge from OpenClaw into the Python wallet backend
158
- - Repo-tracked plugin manifest and config schema
159
- - Keeps wallet policy and execution logic in Python while exposing a small operational tool surface to OpenClaw
138
+ ## What Ships
160
139
 
161
- ## Beta notes
140
+ The npm package is intentionally limited to the wallet installer runtime:
162
141
 
163
- - This is a beta release and should not be treated as production-ready custody infrastructure
164
- - Mainnet use should remain cautious, explicit, and operator-controlled
165
- - Early feedback on usability, safety, and integration gaps is expected and welcome
142
+ ```text
143
+ .openclaw/extensions/agent-wallet
144
+ agent-wallet
145
+ wdk-btc-wallet
146
+ wdk-evm-wallet
147
+ bin
148
+ scripts
149
+ setup.sh
150
+ install-from-github.sh
151
+ README.md
152
+ CHANGELOG.md
153
+ RELEASING.md
154
+ LICENSE
166
155
  ```
167
156
 
168
- ## Suggested release note structure
157
+ It must not ship unrelated repo projects or generated local state:
169
158
 
170
- ### Highlights
171
-
172
- - Expands the stack with `wdk-btc-wallet/`, `provider-gateway/`, and `docs/`
173
- - Keeps `mcp-server/`, `agent-wallet/`, and `.openclaw/extensions/agent-wallet/` as the base beta foundation
174
- - Beta release intended for testing, onboarding, and early adopters
175
-
176
- ### Included in this release
177
-
178
- #### `wdk-btc-wallet/`
159
+ ```text
160
+ landing
161
+ solana-8004
162
+ provider-gateway
163
+ mcp-server
164
+ agent-a2a-gateway
165
+ docs
166
+ node_modules
167
+ .venv
168
+ __pycache__
169
+ .pytest_cache
170
+ .DS_Store
171
+ wallet files
172
+ OpenClaw secrets
173
+ ```
179
174
 
180
- - Local BTC wallet service built on Tether WDK
181
- - Wallet lifecycle, balances, fee rates, spendability, and transfer support
182
- - Separate runtime from the existing Solana wallet backend
175
+ The package allowlist lives in `package.json` under `files`.
183
176
 
184
- #### `provider-gateway/`
177
+ ## Runtime Layout
185
178
 
186
- - Hosted Solana RPC defaults through a shared gateway
187
- - Bags launch and fees provider access
188
- - Jupiter Earn provider access
179
+ Installer releases are copied into the user's OpenClaw home:
189
180
 
190
- #### `docs/`
181
+ ```text
182
+ ~/.openclaw/agent-wallet-runtime/releases/<version>
183
+ ~/.openclaw/agent-wallet-runtime/current
184
+ ```
191
185
 
192
- - Separate documentation app for setup and architecture reference
193
- - Covers infrastructure and wallet capability docs
194
- - Repo-owned docs surface for the public beta
186
+ The CLI switches `current` only after a successful install or update.
195
187
 
196
- #### `mcp-server/`
188
+ Rollback switches `current` back to the previous runtime or to a specific
189
+ installed version:
197
190
 
198
- - MCP server for crypto, DeFi, and on-chain data workflows
199
- - Read-oriented market, protocol, gas, and identity tooling
200
- - Local/self-hostable deployment path
191
+ ```bash
192
+ npx @agentlayer.tech/wallet rollback
193
+ ```
201
194
 
202
- #### `agent-wallet/`
195
+ ## GitHub And npm Setup
203
196
 
204
- - Local Solana wallet backend for OpenClaw-connected agents
205
- - Read, preview, prepare, and approved execute flows
206
- - Encrypted local secret handling and explicit approval gating for risky actions
197
+ Publishing uses npm Trusted Publishing through GitHub Actions. The npm package
198
+ must have this trusted publisher configured:
207
199
 
208
- #### `.openclaw/extensions/agent-wallet/`
200
+ ```text
201
+ Provider: GitHub Actions
202
+ Organization or user: lopushok9
203
+ Repository: Agent-Layer
204
+ Workflow filename: npm-installer.yml
205
+ Environment name: empty
206
+ ```
209
207
 
210
- - Thin TypeScript bridge from OpenClaw into the Python wallet backend
211
- - Plugin manifest and config schema tracked in the repo
212
- - Repo-local extension package for OpenClaw integration
208
+ The `repository.url` field in `package.json` must exactly match the GitHub
209
+ repository URL:
213
210
 
214
- ### Beta notes
211
+ ```text
212
+ https://github.com/lopushok9/Agent-Layer.git
213
+ ```
215
214
 
216
- - This is a beta release and should not be presented as production-ready custody infrastructure
217
- - Mainnet usage should remain cautious and operator-controlled
215
+ Do not use `NPM_TOKEN` unless Trusted Publishing is unavailable. Token-based
216
+ publishes can fail with `EOTP` when npm requires two-factor authentication.
@@ -18,6 +18,7 @@ The package now includes a thin adapter for agent runtimes:
18
18
  - `agent_wallet.plugin_bundle.build_openclaw_plugin_bundle`
19
19
  - `agent_wallet.openclaw_runtime.onboard_openclaw_user_wallet`
20
20
  - `agent_wallet.openclaw_cli` for the official OpenClaw TypeScript plugin bridge
21
+ - `hermes/plugins/agent_wallet` as an optional Hermes Agent bridge to the same CLI
21
22
 
22
23
  It provides:
23
24
 
@@ -27,6 +28,23 @@ It provides:
27
28
  - OpenClaw-style plugin manifest and skill bundle
28
29
  - explicit network-aware results so the host and agent can see `devnet` vs `mainnet`
29
30
 
31
+ ## Hermes integration
32
+
33
+ The optional Hermes plugin is intentionally a bridge, not a port of the OpenClaw plugin. It registers:
34
+
35
+ - `agent_wallet_tools` - read-only discovery for the underlying Python adapter tool specs.
36
+ - `agent_wallet_invoke` - a dispatcher that calls `python -m agent_wallet.openclaw_cli invoke`.
37
+
38
+ Install it with:
39
+
40
+ ```bash
41
+ npx @agentlayer.tech/wallet hermes install --yes
42
+ ```
43
+
44
+ That command symlinks `hermes/plugins/agent_wallet` into `~/.hermes/plugins/agent_wallet`, enables the plugin with `hermes plugins enable agent-wallet`, and writes `AGENT_WALLET_PACKAGE_ROOT`, `AGENT_WALLET_PYTHON`, and `AGENT_WALLET_BOOT_KEY_FILE` into `~/.hermes/.env`. OpenClaw remains the canonical host integration and wallet safety policy remains in Python.
45
+
46
+ Hermes tool config must not contain wallet secrets. Use the existing sealed runtime path and host-issued approval tokens for execute flows. `AGENT_WALLET_BOOT_KEY_FILE` lets OpenClaw and Hermes reference one local boot-key file instead of duplicating the boot key across multiple env files.
47
+
30
48
  Current safe tools:
31
49
 
32
50
  - `get_wallet_capabilities`
@@ -13,6 +13,7 @@ class Settings(BaseSettings):
13
13
  agent_wallet_backend: str = "none"
14
14
  agent_wallet_sign_only: bool = False
15
15
  agent_wallet_boot_key: str = ""
16
+ agent_wallet_boot_key_file: str = ""
16
17
  agent_wallet_approval_ttl_seconds: int = 600
17
18
  agent_wallet_per_user_key_derivation: bool = True
18
19
  agent_wallet_encrypt_user_wallets: bool = True
@@ -297,7 +298,16 @@ def _env_bool(name: str, default: bool) -> bool:
297
298
 
298
299
  def resolve_boot_key() -> str:
299
300
  """Resolve the boot key used to unlock sealed secrets from disk."""
300
- return os.getenv("AGENT_WALLET_BOOT_KEY", settings.agent_wallet_boot_key).strip()
301
+ direct = os.getenv("AGENT_WALLET_BOOT_KEY", settings.agent_wallet_boot_key).strip()
302
+ if direct:
303
+ return direct
304
+ key_file = os.getenv("AGENT_WALLET_BOOT_KEY_FILE", settings.agent_wallet_boot_key_file).strip()
305
+ if not key_file:
306
+ return ""
307
+ try:
308
+ return Path(key_file).expanduser().read_text(encoding="utf-8").strip()
309
+ except OSError:
310
+ return ""
301
311
 
302
312
 
303
313
  def _reject_legacy_runtime_secret_env(var_name: str) -> None:
@@ -11,6 +11,14 @@ from agent_wallet.models import AgentToolResult, AgentToolSpec
11
11
  from agent_wallet.wallet_layer.base import AgentWalletBackend, WalletBackendError
12
12
 
13
13
 
14
+ def _canonical_json_text(payload: dict[str, Any]) -> str:
15
+ return json.dumps(payload, sort_keys=True, separators=(",", ":"))
16
+
17
+
18
+ def preview_payload_digest(preview: dict[str, Any]) -> str:
19
+ return hashlib.sha256(_canonical_json_text(preview).encode("utf-8")).hexdigest()
20
+
21
+
14
22
  WALLET_RUNTIME_INSTRUCTIONS = """
15
23
  Use wallet tools only when the user explicitly asks for wallet-related actions.
16
24
  Treat any signing request as sensitive.
@@ -4398,19 +4406,76 @@ class OpenClawWalletAdapter:
4398
4406
  ),
4399
4407
  )
4400
4408
 
4401
- execute_preview = await self.backend.preview_swap(
4402
- input_mint=input_mint.strip(),
4403
- output_mint=output_mint.strip(),
4404
- amount_ui=float(amount),
4405
- slippage_bps=slippage_bps,
4409
+ approval_payload = inspect_approval_token(
4410
+ approval_token,
4411
+ tool_name=tool_name,
4412
+ network=str(getattr(self.backend, "network", "unknown")),
4413
+ require_mainnet_confirmation=self._is_mainnet_for_backend(self.backend),
4406
4414
  )
4415
+ approval_summary = approval_payload.get("binding", {}).get("summary")
4416
+ if not isinstance(approval_summary, dict):
4417
+ raise WalletBackendError(
4418
+ "approval_token does not match the requested operation. Generate a new approval after previewing the exact action."
4419
+ )
4420
+ expected_summary = {
4421
+ "operation": "Swap",
4422
+ "network": str(getattr(self.backend, "network", "unknown")),
4423
+ "input_mint": input_mint.strip(),
4424
+ "output_mint": output_mint.strip(),
4425
+ "slippage_bps": slippage_bps,
4426
+ }
4427
+ for key, expected_value in expected_summary.items():
4428
+ if approval_summary.get(key) != expected_value:
4429
+ raise WalletBackendError(
4430
+ "approval_token does not match the requested operation. Generate a new approval after previewing the exact action."
4431
+ )
4432
+ try:
4433
+ approved_amount = float(approval_summary.get("input_amount_ui"))
4434
+ except (TypeError, ValueError):
4435
+ raise WalletBackendError(
4436
+ "approval_token does not match the requested operation. Generate a new approval after previewing the exact action."
4437
+ )
4438
+ if approved_amount != float(amount):
4439
+ raise WalletBackendError(
4440
+ "approval_token does not match the requested operation. Generate a new approval after previewing the exact action."
4441
+ )
4442
+
4443
+ approval_summary_copy = dict(approval_summary)
4444
+ approved_preview = args.get("_approved_preview")
4445
+ if isinstance(approval_summary_copy.get("_preview_digest"), str):
4446
+ if not isinstance(approved_preview, dict):
4447
+ raise WalletBackendError(
4448
+ "Approved swap preview payload is required for execute mode. Generate a new preview and approval before execute."
4449
+ )
4450
+ if preview_payload_digest(approved_preview) != approval_summary_copy["_preview_digest"]:
4451
+ raise WalletBackendError(
4452
+ "approved preview payload does not match the approval token. Generate a new preview and approval before execute."
4453
+ )
4454
+ preview_summary = self._build_confirmation_summary(
4455
+ action_label="Swap",
4456
+ payload=approved_preview,
4457
+ )
4458
+ summary_without_digest = {
4459
+ key: value
4460
+ for key, value in approval_summary_copy.items()
4461
+ if key != "_preview_digest"
4462
+ }
4463
+ if preview_summary != summary_without_digest:
4464
+ raise WalletBackendError(
4465
+ "approved preview payload does not match the approval token. Generate a new preview and approval before execute."
4466
+ )
4467
+ execute_preview = dict(approved_preview)
4468
+ else:
4469
+ execute_preview = await self.backend.preview_swap(
4470
+ input_mint=input_mint.strip(),
4471
+ output_mint=output_mint.strip(),
4472
+ amount_ui=float(amount),
4473
+ slippage_bps=slippage_bps,
4474
+ )
4407
4475
  self._require_execute_approval(
4408
4476
  approval_token=approval_token,
4409
4477
  tool_name=tool_name,
4410
- summary=self._build_confirmation_summary(
4411
- action_label="Swap",
4412
- payload=execute_preview,
4413
- ),
4478
+ summary=approval_summary_copy,
4414
4479
  action_label="Swap",
4415
4480
  )
4416
4481