@agentlayer.tech/wallet 0.1.28 → 0.1.30
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/extensions/agent-wallet/README.md +4 -5
- package/.openclaw/extensions/agent-wallet/dist/index.js +29 -20
- package/.openclaw/extensions/agent-wallet/index.ts +29 -20
- package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +2 -2
- package/.openclaw/extensions/agent-wallet/package.json +1 -1
- package/CHANGELOG.md +38 -0
- package/README.md +9 -0
- package/agent-wallet/README.md +18 -22
- package/agent-wallet/agent_wallet/bootstrap.py +28 -12
- package/agent-wallet/agent_wallet/btc_user_wallets.py +2 -7
- package/agent-wallet/agent_wallet/config.py +99 -22
- package/agent-wallet/agent_wallet/evm_user_wallets.py +2 -14
- package/agent-wallet/agent_wallet/openclaw_adapter.py +28 -32
- package/agent-wallet/agent_wallet/openclaw_runtime.py +3 -12
- package/agent-wallet/agent_wallet/providers/kamino.py +21 -4
- package/agent-wallet/agent_wallet/providers/solana_rpc.py +0 -23
- package/agent-wallet/agent_wallet/providers/x402.py +4 -9
- package/agent-wallet/agent_wallet/user_wallets.py +4 -3
- package/agent-wallet/agent_wallet/wallet_layer/base.py +3 -3
- package/agent-wallet/agent_wallet/wallet_layer/factory.py +8 -5
- package/agent-wallet/agent_wallet/wallet_layer/solana.py +437 -44
- package/agent-wallet/agent_wallet/wallet_layer/wdk_btc.py +2 -8
- package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +2 -12
- package/agent-wallet/examples/openclaw_runtime_onboarding.py +1 -1
- package/agent-wallet/examples/openclaw_user_wallet_example.py +1 -1
- package/agent-wallet/openclaw.plugin.json +1 -1
- package/agent-wallet/pyproject.toml +2 -1
- package/agent-wallet/scripts/bootstrap_openclaw_btc.py +3 -5
- package/agent-wallet/scripts/bootstrap_openclaw_evm.py +2 -12
- package/agent-wallet/scripts/build_release_bundle.py +1 -0
- package/agent-wallet/scripts/flash-sdk-bridge/bridge.mjs +1 -4
- package/agent-wallet/scripts/install_agent_wallet.py +1 -0
- package/agent-wallet/scripts/install_openclaw_local_config.py +4 -6
- package/agent-wallet/scripts/manage_openclaw_btc_wallet.py +2 -4
- package/agent-wallet/scripts/manage_openclaw_evm_wallet.py +2 -15
- package/agent-wallet/scripts/reveal_btc_seed.sh +7 -16
- package/agent-wallet/scripts/setup_btc_wallet.sh +7 -16
- package/agent-wallet/scripts/setup_evm_wallet.sh +1 -11
- package/agent-wallet/scripts/switch_openclaw_wallet_network.py +4 -1
- package/agent-wallet/skills/wallet-operator/SKILL.md +0 -1
- package/bin/openclaw-agent-wallet.mjs +289 -0
- package/claude-code/plugins/agent-wallet/.claude-plugin/plugin.json +20 -0
- package/claude-code/plugins/agent-wallet/.mcp.json +14 -0
- package/claude-code/plugins/agent-wallet/README.md +65 -0
- package/claude-code/plugins/agent-wallet/scripts/run_mcp.sh +34 -0
- package/claude-code/plugins/agent-wallet/skills/wallet-operator/SKILL.md +18 -0
- package/codex/plugins/agent-wallet/.codex-plugin/plugin.json +38 -0
- package/codex/plugins/agent-wallet/.mcp.json +15 -0
- package/codex/plugins/agent-wallet/README.md +39 -0
- package/codex/plugins/agent-wallet/scripts/run_mcp.sh +21 -0
- package/codex/plugins/agent-wallet/server.py +1077 -0
- package/codex/plugins/agent-wallet/skills/wallet-operator/SKILL.md +18 -0
- package/hermes/plugins/agent_wallet/schemas.py +2 -2
- package/hermes/plugins/agent_wallet/tools.py +17 -3
- package/package.json +6 -1
- package/setup.sh +2 -0
|
@@ -79,7 +79,7 @@ If that runtime is not present, set `plugins.entries.agent-wallet.config.package
|
|
|
79
79
|
|
|
80
80
|
That installs the Python backend, Node dependencies for the local BTC/EVM runtimes, patches the OpenClaw plugin config, and provisions the first encrypted per-user Solana mainnet wallet when no explicit signer is already configured. EVM readiness can still be auto-healed during normal wallet switching when the runtime has sealed local vault credentials.
|
|
81
81
|
|
|
82
|
-
For self-hosted installs, prefer `SOLANA_RPC_URL` / `SOLANA_RPC_URLS` in local env and treat the plugin `rpcUrl` / `rpcUrls` fields as fallback only. If the local runtime exposes `ALCHEMY_API_KEY` or `HELIUS_API_KEY`, the wallet can derive the Solana RPC URL automatically for `mainnet
|
|
82
|
+
For self-hosted installs, prefer `SOLANA_RPC_URL` / `SOLANA_RPC_URLS` in local env and treat the plugin `rpcUrl` / `rpcUrls` fields as fallback only. If the local runtime exposes `ALCHEMY_API_KEY` or `HELIUS_API_KEY`, the wallet can derive the Solana RPC URL automatically for `mainnet`. Local env always takes precedence over `openclaw.json`.
|
|
83
83
|
|
|
84
84
|
Provide only `AGENT_WALLET_BOOT_KEY` to the runtime. Provision `master_key`, `approval_secret`, and any signer `private_key` into `sealed_keys.json`, not `openclaw.json`.
|
|
85
85
|
|
|
@@ -134,14 +134,13 @@ For staking specifically, the normal agent flow should be:
|
|
|
134
134
|
|
|
135
135
|
The extension is already network-aware:
|
|
136
136
|
|
|
137
|
-
- `plugins.entries.agent-wallet.config.network` selects `mainnet
|
|
138
|
-
-
|
|
139
|
-
- switching
|
|
137
|
+
- `plugins.entries.agent-wallet.config.network` selects `mainnet` for Solana, `bitcoin` for BTC, or the supported EVM networks
|
|
138
|
+
- Solana mainnet wallets keep the same per-user file layout
|
|
139
|
+
- switching the configured backend network does not merge balances across chains
|
|
140
140
|
|
|
141
141
|
Recommended local switch helper:
|
|
142
142
|
|
|
143
143
|
```bash
|
|
144
|
-
python agent-wallet/scripts/switch_openclaw_wallet_network.py --network devnet
|
|
145
144
|
python agent-wallet/scripts/switch_openclaw_wallet_network.py --network mainnet
|
|
146
145
|
```
|
|
147
146
|
|
|
@@ -308,13 +308,15 @@ function normalizeEvmNetwork(value) {
|
|
|
308
308
|
eth: "ethereum",
|
|
309
309
|
"eth-mainnet": "ethereum",
|
|
310
310
|
"base-mainnet": "base",
|
|
311
|
-
base_sepolia: "base-sepolia",
|
|
312
311
|
};
|
|
313
312
|
return aliases[normalized] || normalized;
|
|
314
313
|
}
|
|
315
314
|
|
|
316
315
|
function normalizeSelectableEvmNetwork(value) {
|
|
317
316
|
const network = normalizeEvmNetwork(value);
|
|
317
|
+
if (["sepolia", "base-sepolia", "base_sepolia"].includes(network)) {
|
|
318
|
+
throw new Error("EVM testnets are no longer supported. Use ethereum or base.");
|
|
319
|
+
}
|
|
318
320
|
if (!["ethereum", "base"].includes(network)) {
|
|
319
321
|
throw new Error("EVM network must be 'ethereum' or 'base'.");
|
|
320
322
|
}
|
|
@@ -331,8 +333,11 @@ function normalizeSolanaNetwork(value) {
|
|
|
331
333
|
"mainnet-beta": "mainnet",
|
|
332
334
|
};
|
|
333
335
|
const normalized = aliases[network] || network;
|
|
334
|
-
if (
|
|
335
|
-
throw new Error("Solana
|
|
336
|
+
if (["devnet", "testnet"].includes(normalized)) {
|
|
337
|
+
throw new Error("Solana devnet/testnet are no longer supported. Use mainnet.");
|
|
338
|
+
}
|
|
339
|
+
if (normalized !== "mainnet") {
|
|
340
|
+
throw new Error("Solana network must be mainnet.");
|
|
336
341
|
}
|
|
337
342
|
return normalized;
|
|
338
343
|
}
|
|
@@ -347,8 +352,11 @@ function normalizeBtcNetwork(value) {
|
|
|
347
352
|
mainnet: "bitcoin",
|
|
348
353
|
};
|
|
349
354
|
const normalized = aliases[network] || network;
|
|
350
|
-
if (
|
|
351
|
-
throw new Error("Bitcoin
|
|
355
|
+
if (["testnet", "regtest"].includes(normalized)) {
|
|
356
|
+
throw new Error("Bitcoin testnet/regtest are no longer supported. Use bitcoin.");
|
|
357
|
+
}
|
|
358
|
+
if (normalized !== "bitcoin") {
|
|
359
|
+
throw new Error("Bitcoin network must be bitcoin.");
|
|
352
360
|
}
|
|
353
361
|
return normalized;
|
|
354
362
|
}
|
|
@@ -399,7 +407,6 @@ function inferBackendForTool(toolName) {
|
|
|
399
407
|
toolName === "transfer_spl_token" ||
|
|
400
408
|
toolName === "sign_wallet_message" ||
|
|
401
409
|
toolName === "close_empty_token_accounts" ||
|
|
402
|
-
toolName === "request_devnet_airdrop" ||
|
|
403
410
|
toolName === "get_wallet_portfolio" ||
|
|
404
411
|
toolName === "get_solana_token_prices"
|
|
405
412
|
) {
|
|
@@ -991,7 +998,7 @@ const walletSessionToolDefinitions = [
|
|
|
991
998
|
},
|
|
992
999
|
network: {
|
|
993
1000
|
type: "string",
|
|
994
|
-
description: "Optional network for the selected wallet. Examples: mainnet,
|
|
1001
|
+
description: "Optional network for the selected wallet. Examples: mainnet, ethereum, base, bitcoin.",
|
|
995
1002
|
},
|
|
996
1003
|
},
|
|
997
1004
|
required: ["backend"],
|
|
@@ -1269,6 +1276,21 @@ const solanaToolDefinitions = [
|
|
|
1269
1276
|
additionalProperties: false,
|
|
1270
1277
|
},
|
|
1271
1278
|
},
|
|
1279
|
+
{
|
|
1280
|
+
name: "get_kamino_open_positions",
|
|
1281
|
+
description:
|
|
1282
|
+
"Get all open Kamino lending positions for a Solana wallet on mainnet, aggregated across markets with loan details, reserve APYs, and rewards.",
|
|
1283
|
+
parameters: {
|
|
1284
|
+
type: "object",
|
|
1285
|
+
properties: {
|
|
1286
|
+
user: {
|
|
1287
|
+
type: "string",
|
|
1288
|
+
description: "Optional Solana wallet address override.",
|
|
1289
|
+
},
|
|
1290
|
+
},
|
|
1291
|
+
additionalProperties: false,
|
|
1292
|
+
},
|
|
1293
|
+
},
|
|
1272
1294
|
{
|
|
1273
1295
|
name: "sign_wallet_message",
|
|
1274
1296
|
description: "Sign an arbitrary message with the connected wallet after explicit user confirmation in chat.",
|
|
@@ -1683,19 +1705,6 @@ const solanaToolDefinitions = [
|
|
|
1683
1705
|
additionalProperties: false,
|
|
1684
1706
|
},
|
|
1685
1707
|
},
|
|
1686
|
-
{
|
|
1687
|
-
name: "request_devnet_airdrop",
|
|
1688
|
-
description: "Request devnet or testnet SOL from the faucet.",
|
|
1689
|
-
optional: true,
|
|
1690
|
-
parameters: {
|
|
1691
|
-
type: "object",
|
|
1692
|
-
properties: {
|
|
1693
|
-
amount: { type: "number" },
|
|
1694
|
-
},
|
|
1695
|
-
required: ["amount"],
|
|
1696
|
-
additionalProperties: false,
|
|
1697
|
-
},
|
|
1698
|
-
},
|
|
1699
1708
|
];
|
|
1700
1709
|
|
|
1701
1710
|
const btcToolDefinitions = [
|
|
@@ -308,13 +308,15 @@ function normalizeEvmNetwork(value) {
|
|
|
308
308
|
eth: "ethereum",
|
|
309
309
|
"eth-mainnet": "ethereum",
|
|
310
310
|
"base-mainnet": "base",
|
|
311
|
-
base_sepolia: "base-sepolia",
|
|
312
311
|
};
|
|
313
312
|
return aliases[normalized] || normalized;
|
|
314
313
|
}
|
|
315
314
|
|
|
316
315
|
function normalizeSelectableEvmNetwork(value) {
|
|
317
316
|
const network = normalizeEvmNetwork(value);
|
|
317
|
+
if (["sepolia", "base-sepolia", "base_sepolia"].includes(network)) {
|
|
318
|
+
throw new Error("EVM testnets are no longer supported. Use ethereum or base.");
|
|
319
|
+
}
|
|
318
320
|
if (!["ethereum", "base"].includes(network)) {
|
|
319
321
|
throw new Error("EVM network must be 'ethereum' or 'base'.");
|
|
320
322
|
}
|
|
@@ -331,8 +333,11 @@ function normalizeSolanaNetwork(value) {
|
|
|
331
333
|
"mainnet-beta": "mainnet",
|
|
332
334
|
};
|
|
333
335
|
const normalized = aliases[network] || network;
|
|
334
|
-
if (
|
|
335
|
-
throw new Error("Solana
|
|
336
|
+
if (["devnet", "testnet"].includes(normalized)) {
|
|
337
|
+
throw new Error("Solana devnet/testnet are no longer supported. Use mainnet.");
|
|
338
|
+
}
|
|
339
|
+
if (normalized !== "mainnet") {
|
|
340
|
+
throw new Error("Solana network must be mainnet.");
|
|
336
341
|
}
|
|
337
342
|
return normalized;
|
|
338
343
|
}
|
|
@@ -347,8 +352,11 @@ function normalizeBtcNetwork(value) {
|
|
|
347
352
|
mainnet: "bitcoin",
|
|
348
353
|
};
|
|
349
354
|
const normalized = aliases[network] || network;
|
|
350
|
-
if (
|
|
351
|
-
throw new Error("Bitcoin
|
|
355
|
+
if (["testnet", "regtest"].includes(normalized)) {
|
|
356
|
+
throw new Error("Bitcoin testnet/regtest are no longer supported. Use bitcoin.");
|
|
357
|
+
}
|
|
358
|
+
if (normalized !== "bitcoin") {
|
|
359
|
+
throw new Error("Bitcoin network must be bitcoin.");
|
|
352
360
|
}
|
|
353
361
|
return normalized;
|
|
354
362
|
}
|
|
@@ -399,7 +407,6 @@ function inferBackendForTool(toolName) {
|
|
|
399
407
|
toolName === "transfer_spl_token" ||
|
|
400
408
|
toolName === "sign_wallet_message" ||
|
|
401
409
|
toolName === "close_empty_token_accounts" ||
|
|
402
|
-
toolName === "request_devnet_airdrop" ||
|
|
403
410
|
toolName === "get_wallet_portfolio" ||
|
|
404
411
|
toolName === "get_solana_token_prices"
|
|
405
412
|
) {
|
|
@@ -991,7 +998,7 @@ const walletSessionToolDefinitions = [
|
|
|
991
998
|
},
|
|
992
999
|
network: {
|
|
993
1000
|
type: "string",
|
|
994
|
-
description: "Optional network for the selected wallet. Examples: mainnet,
|
|
1001
|
+
description: "Optional network for the selected wallet. Examples: mainnet, ethereum, base, bitcoin.",
|
|
995
1002
|
},
|
|
996
1003
|
},
|
|
997
1004
|
required: ["backend"],
|
|
@@ -1269,6 +1276,21 @@ const solanaToolDefinitions = [
|
|
|
1269
1276
|
additionalProperties: false,
|
|
1270
1277
|
},
|
|
1271
1278
|
},
|
|
1279
|
+
{
|
|
1280
|
+
name: "get_kamino_open_positions",
|
|
1281
|
+
description:
|
|
1282
|
+
"Get all open Kamino lending positions for a Solana wallet on mainnet, aggregated across markets with loan details, reserve APYs, and rewards.",
|
|
1283
|
+
parameters: {
|
|
1284
|
+
type: "object",
|
|
1285
|
+
properties: {
|
|
1286
|
+
user: {
|
|
1287
|
+
type: "string",
|
|
1288
|
+
description: "Optional Solana wallet address override.",
|
|
1289
|
+
},
|
|
1290
|
+
},
|
|
1291
|
+
additionalProperties: false,
|
|
1292
|
+
},
|
|
1293
|
+
},
|
|
1272
1294
|
{
|
|
1273
1295
|
name: "sign_wallet_message",
|
|
1274
1296
|
description: "Sign an arbitrary message with the connected wallet after explicit user confirmation in chat.",
|
|
@@ -1683,19 +1705,6 @@ const solanaToolDefinitions = [
|
|
|
1683
1705
|
additionalProperties: false,
|
|
1684
1706
|
},
|
|
1685
1707
|
},
|
|
1686
|
-
{
|
|
1687
|
-
name: "request_devnet_airdrop",
|
|
1688
|
-
description: "Request devnet or testnet SOL from the faucet.",
|
|
1689
|
-
optional: true,
|
|
1690
|
-
parameters: {
|
|
1691
|
-
type: "object",
|
|
1692
|
-
properties: {
|
|
1693
|
-
amount: { type: "number" },
|
|
1694
|
-
},
|
|
1695
|
-
required: ["amount"],
|
|
1696
|
-
additionalProperties: false,
|
|
1697
|
-
},
|
|
1698
|
-
},
|
|
1699
1708
|
];
|
|
1700
1709
|
|
|
1701
1710
|
const btcToolDefinitions = [
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"get_jupiter_earn_tokens",
|
|
36
36
|
"get_kamino_lend_market_reserves",
|
|
37
37
|
"get_kamino_lend_markets",
|
|
38
|
+
"get_kamino_open_positions",
|
|
38
39
|
"get_kamino_lend_user_obligations",
|
|
39
40
|
"get_kamino_lend_user_rewards",
|
|
40
41
|
"get_lifi_quote",
|
|
@@ -57,7 +58,6 @@
|
|
|
57
58
|
"manage_evm_aave_position",
|
|
58
59
|
"manage_evm_lido_position",
|
|
59
60
|
"manage_evm_lido_withdrawal",
|
|
60
|
-
"request_devnet_airdrop",
|
|
61
61
|
"set_evm_network",
|
|
62
62
|
"set_wallet_backend",
|
|
63
63
|
"sign_wallet_message",
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
},
|
|
93
93
|
"network": {
|
|
94
94
|
"type": "string",
|
|
95
|
-
"description": "Backend network selector. Solana uses mainnet
|
|
95
|
+
"description": "Backend network selector. Solana uses mainnet. BTC uses bitcoin. EVM uses ethereum/base."
|
|
96
96
|
},
|
|
97
97
|
"wdkBtcServiceUrl": {
|
|
98
98
|
"type": "string",
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## v0.1.30 - 2026-05-30
|
|
6
|
+
|
|
7
|
+
- Added a Claude Code plugin bridge under `claude-code/plugins/agent-wallet` so
|
|
8
|
+
the existing local wallet runtime can be used directly inside Claude Code
|
|
9
|
+
without creating a new wallet.
|
|
10
|
+
- The Claude Code bridge connects to the current `~/.openclaw` runtime and
|
|
11
|
+
reuses the same Solana, Bitcoin, and EVM wallet surface already used by
|
|
12
|
+
OpenClaw, Hermes, and Codex.
|
|
13
|
+
- Added `wallet claude-code install --yes`, which symlinks the bundled Claude
|
|
14
|
+
Code plugin into `~/.claude/plugins/agent-wallet` and attempts to register it
|
|
15
|
+
via the Claude Code CLI.
|
|
16
|
+
- Fixed the `smoke_install_from_github` test, which was failing because
|
|
17
|
+
`setup.sh` checks for the Codex plugin manifest but the test bundle never
|
|
18
|
+
created that path.
|
|
19
|
+
- Added the Claude Code plugin manifest check to `setup.sh` so bundle integrity
|
|
20
|
+
is validated for both the Codex and Claude Code plugin surfaces.
|
|
21
|
+
|
|
22
|
+
## v0.1.29 - 2026-05-29
|
|
23
|
+
|
|
24
|
+
- Added a new `Codex` plugin bridge under `codex/plugins/agent-wallet` so the
|
|
25
|
+
existing local wallet runtime can be used directly inside Codex without
|
|
26
|
+
creating a second wallet.
|
|
27
|
+
- Kept the Codex bridge non-custodial and additive: it reuses the current
|
|
28
|
+
`agent-wallet` runtime, existing wallets, and the current tool surface
|
|
29
|
+
instead of replacing OpenClaw or Hermes.
|
|
30
|
+
- Added `wallet codex install --yes`, which links the bundled Codex plugin into
|
|
31
|
+
the standard local plugin marketplace path and can ask Codex to install the
|
|
32
|
+
plugin from that local marketplace.
|
|
33
|
+
- Added `get_kamino_open_positions`, which aggregates the wallet's Kamino
|
|
34
|
+
positions across markets with loan details, reserve APYs, and rewards.
|
|
35
|
+
- Removed Solana devnet/testnet support from the wallet runtime, host bridges,
|
|
36
|
+
and local helper scripts so the supported Solana surface is now mainnet-only.
|
|
37
|
+
- Removed EVM testnet support from the wallet runtime and host bridges so the
|
|
38
|
+
supported EVM surface is now `ethereum` and `base` mainnet only.
|
|
39
|
+
- Removed Bitcoin `testnet` and `regtest` support from the wallet runtime,
|
|
40
|
+
host bridges, and local helper scripts so the supported BTC surface is now
|
|
41
|
+
`bitcoin` mainnet only.
|
|
42
|
+
|
|
5
43
|
## v0.1.28 - 2026-05-28
|
|
6
44
|
|
|
7
45
|
- Simplified `x402_pay_request` into a single-shot paid execution flow while
|
package/README.md
CHANGED
|
@@ -16,6 +16,12 @@ For Hermes:
|
|
|
16
16
|
npx @agentlayer.tech/wallet install --yes && npx @agentlayer.tech/wallet hermes install --yes
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
For Codex:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx @agentlayer.tech/wallet install --yes && npx @agentlayer.tech/wallet codex install --yes
|
|
23
|
+
```
|
|
24
|
+
|
|
19
25
|
AgentLayer is a beta local-first wallet and finance stack for agents.
|
|
20
26
|
|
|
21
27
|
The repository includes:
|
|
@@ -23,6 +29,7 @@ The repository includes:
|
|
|
23
29
|
- `agent-wallet/` - the main wallet backend for AgentLayer
|
|
24
30
|
- `.openclaw/` - the local AgentLayer bridge layer for the OpenClaw wallet integration
|
|
25
31
|
- `hermes/` - optional Hermes Agent plugin bridge for the same wallet backend
|
|
32
|
+
- `codex/` - optional Codex plugin bridge for the same wallet backend
|
|
26
33
|
- `wdk-btc-wallet/` - the local Bitcoin wallet service
|
|
27
34
|
- `wdk-evm-wallet/` - the local EVM wallet service
|
|
28
35
|
- `provider-gateway/` - shared provider access for Solana RPC, Bags, and related finance reads
|
|
@@ -84,6 +91,7 @@ Useful npm CLI commands:
|
|
|
84
91
|
wallet status
|
|
85
92
|
wallet doctor
|
|
86
93
|
wallet hermes install --yes
|
|
94
|
+
wallet codex install --yes
|
|
87
95
|
wallet update --yes
|
|
88
96
|
wallet update --yes --dry-run
|
|
89
97
|
wallet rollback
|
|
@@ -200,6 +208,7 @@ Kamino integration gives the wallet a structured Solana lending surface:
|
|
|
200
208
|
- `get_kamino_lend_market_reserves` - inspect reserve metrics for one Kamino market.
|
|
201
209
|
- `get_kamino_lend_user_obligations` - inspect the wallet's obligations inside a Kamino market.
|
|
202
210
|
- `get_kamino_lend_user_rewards` - fetch the wallet's Kamino rewards summary.
|
|
211
|
+
- `get_kamino_open_positions` - aggregate all open Kamino positions across markets with loan details, reserve APYs, and rewards.
|
|
203
212
|
- `kamino_lend_deposit` - preview, prepare, or execute a lending deposit.
|
|
204
213
|
- `kamino_lend_withdraw` - preview, prepare, or execute a lending withdrawal.
|
|
205
214
|
- `kamino_lend_borrow` - preview, prepare, or execute a borrow.
|
package/agent-wallet/README.md
CHANGED
|
@@ -26,7 +26,7 @@ It provides:
|
|
|
26
26
|
- runtime instructions for safe wallet usage
|
|
27
27
|
- a single `invoke()` method for safe dispatch
|
|
28
28
|
- OpenClaw-style plugin manifest and skill bundle
|
|
29
|
-
- explicit network-aware results so the host and agent can see
|
|
29
|
+
- explicit network-aware results so the host and agent can see the active chain network
|
|
30
30
|
|
|
31
31
|
## Hermes integration
|
|
32
32
|
|
|
@@ -98,6 +98,7 @@ Current safe tools:
|
|
|
98
98
|
- `get_kamino_lend_market_reserves`
|
|
99
99
|
- `get_kamino_lend_user_obligations`
|
|
100
100
|
- `get_kamino_lend_user_rewards`
|
|
101
|
+
- `get_kamino_open_positions`
|
|
101
102
|
- `jupiter_earn_deposit`
|
|
102
103
|
- `jupiter_earn_withdraw`
|
|
103
104
|
- `kamino_lend_deposit`
|
|
@@ -107,7 +108,6 @@ Current safe tools:
|
|
|
107
108
|
- `close_empty_token_accounts`
|
|
108
109
|
- `deactivate_solana_stake`
|
|
109
110
|
- `withdraw_solana_stake`
|
|
110
|
-
- `request_devnet_airdrop`
|
|
111
111
|
- `x402_search_services`
|
|
112
112
|
- `x402_get_service_details`
|
|
113
113
|
- `x402_preview_request`
|
|
@@ -190,7 +190,7 @@ For production `mainnet`, prefer a dedicated RPC instead of the public Solana en
|
|
|
190
190
|
|
|
191
191
|
- `SOLANA_RPC_URL` for one primary endpoint
|
|
192
192
|
- `SOLANA_RPC_URLS` as a comma-separated ordered failover list
|
|
193
|
-
- or just `ALCHEMY_API_KEY` / `HELIUS_API_KEY`, which auto-derive a primary Solana RPC for `mainnet`
|
|
193
|
+
- or just `ALCHEMY_API_KEY` / `HELIUS_API_KEY`, which auto-derive a primary Solana RPC for `mainnet`
|
|
194
194
|
|
|
195
195
|
Production recommendation: treat RPC as deployment-owned config, not wallet logic. Runtime env wins over `openclaw.json` plugin config, so keep `Alchemy/Helius/QuickNode` endpoints in deployment secrets or service env and use plugin `rpcUrl` / `rpcUrls` only as local fallback.
|
|
196
196
|
|
|
@@ -277,9 +277,7 @@ export AGENT_WALLET_BOOT_KEY='paste-generated-secret-here'
|
|
|
277
277
|
In that mode, `agent-wallet` will auto-resolve:
|
|
278
278
|
|
|
279
279
|
- `mainnet` -> `https://solana-mainnet.g.alchemy.com/v2/<ALCHEMY_API_KEY>`
|
|
280
|
-
- `devnet` -> `https://solana-devnet.g.alchemy.com/v2/<ALCHEMY_API_KEY>`
|
|
281
280
|
- `mainnet` -> `https://mainnet.helius-rpc.com/?api-key=<HELIUS_API_KEY>`
|
|
282
|
-
- `devnet` -> `https://devnet.helius-rpc.com/?api-key=<HELIUS_API_KEY>`
|
|
283
281
|
|
|
284
282
|
and still append the official Solana endpoint as fallback.
|
|
285
283
|
|
|
@@ -317,7 +315,7 @@ printf '%s\n' 'your-local-btc-password' | \
|
|
|
317
315
|
python -m agent_wallet.openclaw_cli btc-wallet-create \
|
|
318
316
|
--user-id alice@example.com \
|
|
319
317
|
--password-stdin \
|
|
320
|
-
--config-json '{"backend":"wdk_btc_local","network":"
|
|
318
|
+
--config-json '{"backend":"wdk_btc_local","network":"bitcoin","wdkBtcServiceUrl":"http://127.0.0.1:8080"}'
|
|
321
319
|
```
|
|
322
320
|
|
|
323
321
|
If you want a friendlier host-shell flow, use:
|
|
@@ -325,7 +323,7 @@ If you want a friendlier host-shell flow, use:
|
|
|
325
323
|
```bash
|
|
326
324
|
python scripts/manage_openclaw_btc_wallet.py setup \
|
|
327
325
|
--user-id alice@example.com \
|
|
328
|
-
--network
|
|
326
|
+
--network bitcoin \
|
|
329
327
|
--service-url http://127.0.0.1:8080
|
|
330
328
|
```
|
|
331
329
|
|
|
@@ -340,11 +338,11 @@ If you want a true one-command OpenClaw bootstrap, use:
|
|
|
340
338
|
```bash
|
|
341
339
|
python agent-wallet/scripts/bootstrap_openclaw_btc.py \
|
|
342
340
|
--user-id alice@example.com \
|
|
343
|
-
--network
|
|
341
|
+
--network bitcoin \
|
|
344
342
|
--service-url http://127.0.0.1:8080
|
|
345
343
|
```
|
|
346
344
|
|
|
347
|
-
|
|
345
|
+
You can also pass `--network mainnet`; the bootstrap normalizes that alias to `bitcoin`.
|
|
348
346
|
|
|
349
347
|
For the simplest host-side UX, use the shell wrapper instead:
|
|
350
348
|
|
|
@@ -356,7 +354,7 @@ That is the intended "agent/host installs, user only enters password" entrypoint
|
|
|
356
354
|
|
|
357
355
|
- the script wraps the full BTC bootstrap
|
|
358
356
|
- it auto-starts the local `wdk-btc-wallet` service for localhost URLs if needed
|
|
359
|
-
- it asks for `user-id` and
|
|
357
|
+
- it asks for `user-id` and defaults BTC network to `mainnet` if you did not pass it explicitly
|
|
360
358
|
- it prompts for the BTC wallet password interactively unless you explicitly pass `--password-stdin`
|
|
361
359
|
- it prefers `/tmp/agent-wallet-venv/bin/python`, then `agent-wallet/.venv/bin/python`, and only then falls back to system `python3`
|
|
362
360
|
- it creates or unlocks the BTC wallet binding and patches local OpenClaw config in one pass
|
|
@@ -407,7 +405,7 @@ For the local EVM backend (`backend=wdk_evm_local`), the lifecycle mirrors the B
|
|
|
407
405
|
- `agent-wallet` talks to it through a local bearer token loaded from `~/.openclaw/wdk-evm-wallet/local-auth-token`
|
|
408
406
|
- `agent-wallet` stores only a per-user EVM wallet binding under `~/.openclaw/users/<normalized-user-id>/wallets/evm-<network>-agent.json`
|
|
409
407
|
- the runtime can auto-create missing EVM bindings or auto-unlock the local vault during ordinary OpenClaw switching/tool calls when `sealed_keys.json` contains `wdk_evm_wallet_password`
|
|
410
|
-
- supported EVM networks are `ethereum
|
|
408
|
+
- supported EVM networks are `ethereum` and `base`
|
|
411
409
|
- OpenClaw-facing EVM tools accept an optional per-call `network` override for `ethereum` or `base`, so the agent can switch between the two mainnet EVM paths without editing host config
|
|
412
410
|
- EVM `get_wallet_balance` now returns an enriched portfolio-style payload with native balance, discovered ERC-20 balances, and USD values when token discovery and pricing are available
|
|
413
411
|
- if a requested EVM network binding is missing, `agent-wallet` auto-binds it from the same local wallet when there is exactly one reusable EVM wallet for that user or when `wdkEvmWalletId` is provided explicitly
|
|
@@ -430,7 +428,7 @@ That wrapper:
|
|
|
430
428
|
- defaults to `http://127.0.0.1:8081`
|
|
431
429
|
- can auto-start `wdk-evm-wallet/run-local.sh` if the local service is not already healthy
|
|
432
430
|
- creates or unlocks the local EVM wallet binding
|
|
433
|
-
- also binds the paired EVM network by default: `ethereum <-> base
|
|
431
|
+
- also binds the paired EVM network by default: `ethereum <-> base`
|
|
434
432
|
- stores the entered EVM vault password into `sealed_keys.json` when `AGENT_WALLET_BOOT_KEY` is available, so later OpenClaw wallet switching can auto-raise the EVM backend without another password prompt
|
|
435
433
|
- patches OpenClaw config to `backend=wdk_evm_local`
|
|
436
434
|
|
|
@@ -441,7 +439,7 @@ printf '%s\n' 'your-local-evm-password' | \
|
|
|
441
439
|
python -m agent_wallet.openclaw_cli evm-wallet-create \
|
|
442
440
|
--user-id alice@example.com \
|
|
443
441
|
--password-stdin \
|
|
444
|
-
--config-json '{"backend":"wdk_evm_local","network":"
|
|
442
|
+
--config-json '{"backend":"wdk_evm_local","network":"ethereum","wdkEvmServiceUrl":"http://127.0.0.1:8081"}'
|
|
445
443
|
```
|
|
446
444
|
|
|
447
445
|
After that, `onboard` and `invoke` can use the bound EVM wallet by `user_id` without manually passing `wdkEvmWalletId` every time.
|
|
@@ -500,14 +498,13 @@ This keeps wallet creation and custody in the host/runtime layer while the agent
|
|
|
500
498
|
|
|
501
499
|
The wallet backend is already network-scoped:
|
|
502
500
|
|
|
503
|
-
-
|
|
504
|
-
- per-user wallets
|
|
505
|
-
- switching networks does not mix balances
|
|
501
|
+
- Solana stays on `mainnet`
|
|
502
|
+
- per-user Solana wallets continue to use `solana-mainnet-agent.json`
|
|
503
|
+
- switching BTC or EVM networks does not mix balances across chains
|
|
506
504
|
|
|
507
505
|
For a local OpenClaw install, use:
|
|
508
506
|
|
|
509
507
|
```bash
|
|
510
|
-
python agent-wallet/scripts/switch_openclaw_wallet_network.py --network devnet
|
|
511
508
|
python agent-wallet/scripts/switch_openclaw_wallet_network.py --network mainnet
|
|
512
509
|
```
|
|
513
510
|
|
|
@@ -570,7 +567,7 @@ Operational notes:
|
|
|
570
567
|
|
|
571
568
|
- this path uses Solana RPC and the Stake Program directly, without third-party DeFi APIs
|
|
572
569
|
- stake creation allocates a new stake account controlled by the connected wallet as staker and withdrawer
|
|
573
|
-
- preview and prepare were live-checked
|
|
570
|
+
- preview and prepare were live-checked against a real wallet context
|
|
574
571
|
|
|
575
572
|
## Official OpenClaw plugin
|
|
576
573
|
|
|
@@ -612,13 +609,13 @@ Public-safe helper scripts are available in `agent-wallet/scripts/`:
|
|
|
612
609
|
Both scripts now use generic defaults instead of hardcoded local usernames or paths. Sensitive secrets must be supplied via protected environment variables, not config JSON or CLI arguments.
|
|
613
610
|
When `~/.openclaw/agent-wallet-runtime/current` exists, the config installer now prefers that trusted runtime path over a workspace checkout for the plugin manifest, package root, and Python bridge launcher.
|
|
614
611
|
|
|
615
|
-
Recommended
|
|
612
|
+
Recommended Solana mainnet setup:
|
|
616
613
|
|
|
617
614
|
```bash
|
|
618
615
|
AGENT_WALLET_BACKEND=solana_local
|
|
619
616
|
AGENT_WALLET_BOOT_KEY=change-this-in-production
|
|
620
|
-
SOLANA_NETWORK=
|
|
621
|
-
SOLANA_RPC_URLS=https://api.
|
|
617
|
+
SOLANA_NETWORK=mainnet
|
|
618
|
+
SOLANA_RPC_URLS=https://api.mainnet-beta.solana.com
|
|
622
619
|
SOLANA_AUTO_CREATE_WALLET=true
|
|
623
620
|
AGENT_WALLET_SIGN_ONLY=false
|
|
624
621
|
```
|
|
@@ -641,4 +638,3 @@ The package now supports:
|
|
|
641
638
|
- Jupiter-based swap preview and execution on mainnet
|
|
642
639
|
- compact swap `fee_summary` in preview/prepare/execute, including known network fees and route fee bps when Jupiter provides them
|
|
643
640
|
- zero-balance token account cleanup
|
|
644
|
-
- devnet/testnet faucet airdrop
|
|
@@ -5,7 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import json
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
-
from agent_wallet.config import refuse_mainnet_wallet_recreation
|
|
8
|
+
from agent_wallet.config import normalize_solana_network, refuse_mainnet_wallet_recreation
|
|
9
9
|
from agent_wallet.file_ops import atomic_write_text
|
|
10
10
|
from agent_wallet.wallet_layer.base import WalletBackendError
|
|
11
11
|
from agent_wallet.wallet_layer.base58 import b58encode
|
|
@@ -79,11 +79,12 @@ def load_wallet_pin(path: Path) -> dict[str, str] | None:
|
|
|
79
79
|
|
|
80
80
|
def write_wallet_pin(path: Path, *, address: str, network: str) -> dict[str, str]:
|
|
81
81
|
"""Persist the expected wallet address for later mismatch checks."""
|
|
82
|
+
normalized_network = normalize_solana_network(network)
|
|
82
83
|
payload = {
|
|
83
84
|
"kind": WALLET_ADDRESS_PIN_KIND,
|
|
84
85
|
"version": WALLET_ADDRESS_PIN_VERSION,
|
|
85
86
|
"address": address,
|
|
86
|
-
"network":
|
|
87
|
+
"network": normalized_network,
|
|
87
88
|
"wallet_file": path.name,
|
|
88
89
|
}
|
|
89
90
|
pin_path = resolve_wallet_pin_path(path)
|
|
@@ -97,7 +98,7 @@ def write_wallet_pin(path: Path, *, address: str, network: str) -> dict[str, str
|
|
|
97
98
|
|
|
98
99
|
def ensure_wallet_pin(path: Path, *, address: str, network: str) -> dict[str, str]:
|
|
99
100
|
"""Ensure the wallet pin exists and matches the expected address."""
|
|
100
|
-
expected_network = network
|
|
101
|
+
expected_network = normalize_solana_network(network)
|
|
101
102
|
existing = load_wallet_pin(path)
|
|
102
103
|
if existing is None:
|
|
103
104
|
return write_wallet_pin(path, address=address, network=expected_network)
|
|
@@ -114,7 +115,7 @@ def ensure_wallet_pin(path: Path, *, address: str, network: str) -> dict[str, st
|
|
|
114
115
|
|
|
115
116
|
def refuse_recreation_if_pinned(path: Path, *, network: str) -> None:
|
|
116
117
|
"""Refuse to recreate a wallet when a mainnet address is already pinned."""
|
|
117
|
-
expected_network = network
|
|
118
|
+
expected_network = normalize_solana_network(network)
|
|
118
119
|
if expected_network != "mainnet" or not refuse_mainnet_wallet_recreation():
|
|
119
120
|
return
|
|
120
121
|
existing = load_wallet_pin(path)
|
|
@@ -128,7 +129,11 @@ def refuse_recreation_if_pinned(path: Path, *, network: str) -> None:
|
|
|
128
129
|
|
|
129
130
|
def ensure_solana_wallet_ready() -> dict[str, str] | None:
|
|
130
131
|
"""Ensure that a Solana wallet exists when auto-create is enabled."""
|
|
131
|
-
from agent_wallet.config import
|
|
132
|
+
from agent_wallet.config import (
|
|
133
|
+
default_solana_wallet_path,
|
|
134
|
+
resolve_solana_private_key,
|
|
135
|
+
settings,
|
|
136
|
+
)
|
|
132
137
|
|
|
133
138
|
if settings.agent_wallet_backend.strip().lower() not in {"solana", "solana_local", "solana-local"}:
|
|
134
139
|
return None
|
|
@@ -136,8 +141,13 @@ def ensure_solana_wallet_ready() -> dict[str, str] | None:
|
|
|
136
141
|
if resolve_solana_private_key():
|
|
137
142
|
return {"address": "", "path": ""}
|
|
138
143
|
|
|
144
|
+
normalized_network = normalize_solana_network(settings.solana_network)
|
|
139
145
|
configured_path = settings.solana_agent_keypair_path.strip()
|
|
140
|
-
path =
|
|
146
|
+
path = (
|
|
147
|
+
Path(configured_path).expanduser()
|
|
148
|
+
if configured_path
|
|
149
|
+
else default_solana_wallet_path(normalized_network)
|
|
150
|
+
)
|
|
141
151
|
|
|
142
152
|
if path.exists():
|
|
143
153
|
return {"address": "", "path": str(path)}
|
|
@@ -145,9 +155,9 @@ def ensure_solana_wallet_ready() -> dict[str, str] | None:
|
|
|
145
155
|
if not settings.solana_auto_create_wallet:
|
|
146
156
|
return None
|
|
147
157
|
|
|
148
|
-
refuse_recreation_if_pinned(path, network=
|
|
158
|
+
refuse_recreation_if_pinned(path, network=normalized_network)
|
|
149
159
|
created = create_solana_wallet_file(path)
|
|
150
|
-
write_wallet_pin(path, address=created["address"], network=
|
|
160
|
+
write_wallet_pin(path, address=created["address"], network=normalized_network)
|
|
151
161
|
return created
|
|
152
162
|
|
|
153
163
|
|
|
@@ -155,22 +165,28 @@ def describe_bootstrap() -> dict[str, str | bool]:
|
|
|
155
165
|
"""Return the effective bootstrap configuration for installer/runtime usage."""
|
|
156
166
|
from agent_wallet.config import (
|
|
157
167
|
default_solana_wallet_path,
|
|
168
|
+
normalize_solana_network,
|
|
158
169
|
resolve_solana_rpc_url,
|
|
159
170
|
resolve_runtime_solana_rpc_urls,
|
|
160
171
|
settings,
|
|
161
172
|
)
|
|
162
173
|
|
|
174
|
+
normalized_network = normalize_solana_network(settings.solana_network)
|
|
163
175
|
configured_path = settings.solana_agent_keypair_path.strip()
|
|
164
|
-
path =
|
|
176
|
+
path = (
|
|
177
|
+
Path(configured_path).expanduser()
|
|
178
|
+
if configured_path
|
|
179
|
+
else default_solana_wallet_path(normalized_network)
|
|
180
|
+
)
|
|
165
181
|
rpc_urls = resolve_runtime_solana_rpc_urls(
|
|
166
|
-
|
|
182
|
+
normalized_network,
|
|
167
183
|
settings.solana_rpc_url,
|
|
168
184
|
settings.solana_rpc_urls,
|
|
169
185
|
)
|
|
170
186
|
return {
|
|
171
187
|
"backend": settings.agent_wallet_backend,
|
|
172
|
-
"network":
|
|
173
|
-
"rpc_url": rpc_urls[0] if rpc_urls else resolve_solana_rpc_url(
|
|
188
|
+
"network": normalized_network,
|
|
189
|
+
"rpc_url": rpc_urls[0] if rpc_urls else resolve_solana_rpc_url(normalized_network, ""),
|
|
174
190
|
"rpc_urls": rpc_urls,
|
|
175
191
|
"auto_create_wallet": settings.solana_auto_create_wallet,
|
|
176
192
|
"keypair_path": str(path),
|
|
@@ -6,19 +6,14 @@ import json
|
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
|
-
from agent_wallet.config import resolve_openclaw_home, settings
|
|
9
|
+
from agent_wallet.config import normalize_btc_network, resolve_openclaw_home, settings
|
|
10
10
|
from agent_wallet.providers.wdk_btc_local import WdkBtcLocalClient
|
|
11
11
|
from agent_wallet.user_wallets import normalize_user_id
|
|
12
12
|
from agent_wallet.wallet_layer.base import WalletBackendError
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def _normalize_btc_network(value: str | None) -> str:
|
|
16
|
-
|
|
17
|
-
aliases = {"mainnet": "bitcoin"}
|
|
18
|
-
network = aliases.get(network, network)
|
|
19
|
-
if network not in {"bitcoin", "testnet", "regtest"}:
|
|
20
|
-
return "bitcoin"
|
|
21
|
-
return network
|
|
16
|
+
return normalize_btc_network(value)
|
|
22
17
|
|
|
23
18
|
|
|
24
19
|
def _resolve_service_url(service_url: str | None = None) -> str:
|