@agentlayer.tech/wallet 0.1.94 → 0.1.96
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 +2 -2
- package/.openclaw/extensions/agent-wallet/dist/index.js +70 -14
- package/.openclaw/extensions/agent-wallet/index.ts +70 -14
- package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +4 -2
- package/.openclaw/extensions/agent-wallet/package.json +1 -1
- package/VERSION +1 -1
- package/agent-wallet/README.md +3 -3
- package/agent-wallet/agent_wallet/__init__.py +1 -1
- package/agent-wallet/agent_wallet/autonomous_policy.py +2 -1
- package/agent-wallet/agent_wallet/config.py +7 -11
- package/agent-wallet/agent_wallet/networks.py +25 -0
- package/agent-wallet/agent_wallet/openclaw_adapter.py +171 -27
- package/agent-wallet/agent_wallet/providers/evm_portfolio.py +9 -2
- package/agent-wallet/agent_wallet/wallet_layer/base.py +19 -0
- package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +61 -1
- package/agent-wallet/openclaw.plugin.json +1 -1
- package/agent-wallet/pyproject.toml +1 -1
- package/agent-wallet/scripts/install_agent_wallet.py +29 -1
- package/claude-code/plugins/agent-wallet/.claude-plugin/plugin.json +1 -1
- package/claude-code/plugins/agent-wallet/AGENTLAYER_AGENT_GUIDE.md +282 -0
- package/claude-code/plugins/agent-wallet/README.md +2 -0
- package/claude-code/plugins/agent-wallet/commands/guide.md +40 -0
- package/codex/plugins/agent-wallet/.codex-plugin/plugin.json +1 -1
- package/codex/plugins/agent-wallet/server.py +15 -11
- package/codex/plugins/agent-wallet/skills/wallet-operator/SKILL.md +1 -1
- package/hermes/plugins/agent_wallet/plugin.yaml +1 -1
- package/package.json +1 -1
- package/wdk-btc-wallet/package.json +1 -1
- package/wdk-evm-wallet/.env.example +4 -1
- package/wdk-evm-wallet/README.md +18 -2
- package/wdk-evm-wallet/package.json +1 -1
- package/wdk-evm-wallet/src/config.js +34 -3
- package/wdk-evm-wallet/src/network_state.js +8 -2
- package/wdk-evm-wallet/src/server.js +12 -0
- package/wdk-evm-wallet/src/wdk_evm_wallet.js +132 -2
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
# AgentLayer Wallet — Agent Guide
|
|
2
|
+
|
|
3
|
+
> **Relationship to `skills/wallet-operator/SKILL.md`:** that file is the
|
|
4
|
+
> authoritative, terse routing skill actually loaded by hosts (provider map, param
|
|
5
|
+
> tables, approval-flow template) — keep changes to tool routing/params there, not
|
|
6
|
+
> here. This document is a narrative companion: written the way an agent (or a human
|
|
7
|
+
> reading over its shoulder) would want the product *explained*, not just routed —
|
|
8
|
+
> modeled on how the `catena` CLI ships a self-contained `catena guide` command
|
|
9
|
+
> alongside its terse `--help` output; the `/guide` command in this plugin serves
|
|
10
|
+
> that exact role. Tool names below are short; the full MCP name is
|
|
11
|
+
> `mcp__plugin_agent-wallet_agent-wallet__<name>`.
|
|
12
|
+
|
|
13
|
+
This server holds funds in the local AgentLayer wallet across Solana, EVM
|
|
14
|
+
(Ethereum, Base, Robinhood chain), and Bitcoin. It is not a generic
|
|
15
|
+
crypto-data tool — every write here moves real money unless stated as
|
|
16
|
+
mainnet-gated preview. Leverage markets (Flash Trade perps:
|
|
17
|
+
`flash_trade_open_position`, `flash_trade_close_position`,
|
|
18
|
+
`get_flash_trade_markets`, `get_flash_trade_positions`) are out of scope for
|
|
19
|
+
this guide — do not use them without separate instructions.
|
|
20
|
+
|
|
21
|
+
## What You Can Do
|
|
22
|
+
|
|
23
|
+
- **Solana**: transfers, swaps via Jupiter, native staking, Kamino (lending +
|
|
24
|
+
earn vaults + LP positions), token launches via Bags.
|
|
25
|
+
- **EVM** (Ethereum / Base / Robinhood): transfers, swaps (Velora or
|
|
26
|
+
Uniswap), and DeFi — Aave (lending), Lido (ETH staking), Morpho (markets +
|
|
27
|
+
vaults), and Uniswap concentrated liquidity positions (create / increase /
|
|
28
|
+
decrease / claim fees, V3 and V4 — existing V4 positions can't be
|
|
29
|
+
auto-discovered, only V3; for a V4 position the id has to come from the
|
|
30
|
+
user).
|
|
31
|
+
- **Cross-chain bridging** (LI.FI): Ethereum / Base / Solana to each other.
|
|
32
|
+
- **x402**: pay per-request HTTP 402 paywalls straight from the wallet —
|
|
33
|
+
preview the payment terms for free, then pay in one call.
|
|
34
|
+
|
|
35
|
+
See the sections below for exact tool names and parameters.
|
|
36
|
+
|
|
37
|
+
## Setup & Session State
|
|
38
|
+
|
|
39
|
+
1. `get_active_wallet_backend` — which backend (solana / evm / btc) is live
|
|
40
|
+
for this session, and whether it differs from the startup default.
|
|
41
|
+
2. `get_wallet_address` — the address for the active backend.
|
|
42
|
+
3. `get_wallet_capabilities` — chain, backend, and the safety limits in force.
|
|
43
|
+
4. `set_wallet_backend` (`backend`: solana / evm / ethereum / base /
|
|
44
|
+
robinhood / goat / btc / bitcoin, optional `network`) — switch backend for this
|
|
45
|
+
session without touching config files.
|
|
46
|
+
5. For EVM specifically: `get_evm_network` shows the effective network and
|
|
47
|
+
which networks support swaps; `set_evm_network` (ethereum / base /
|
|
48
|
+
robinhood / goat) changes it.
|
|
49
|
+
|
|
50
|
+
Balance reads (Solana): `get_wallet_balance` / `get_wallet_portfolio` are the
|
|
51
|
+
same enriched payload (native SOL + non-zero SPL accounts + USD pricing via
|
|
52
|
+
Jupiter) — `_portfolio` is just the more detailed name for the same call.
|
|
53
|
+
`get_wallet_overview` does the same lookup for an arbitrary backend/network/
|
|
54
|
+
address **without** switching the session's active wallet — use it to peek at
|
|
55
|
+
another chain or address in passing.
|
|
56
|
+
|
|
57
|
+
## Quick Commands (Claude Code slash commands)
|
|
58
|
+
|
|
59
|
+
The plugin also ships fixed-format slash commands for the most common
|
|
60
|
+
requests — faster and more predictable than a free-form tool call, but each
|
|
61
|
+
covers only its one exact use case:
|
|
62
|
+
|
|
63
|
+
| Command | What it does |
|
|
64
|
+
|---|---|
|
|
65
|
+
| `/wallet-setup` | Install or repair the local wallet backend runtime. |
|
|
66
|
+
| `/wallet-sol` | Print the Solana wallet portfolio. |
|
|
67
|
+
| `/wallet-evm` | Print the EVM wallet overview for the current/default network. |
|
|
68
|
+
| `/wallet-base` | Print the Base wallet overview, and switch the session's active backend to Base. |
|
|
69
|
+
| `/wallet-ethereum` | Print the Ethereum mainnet wallet overview. |
|
|
70
|
+
| `/cards` | Buy a Laso Finance prepaid card (US or international), paid via x402 from the connected wallet. |
|
|
71
|
+
| `/agentlayer-autonomous-approve` | Turn on the full autonomous permission group (see below), with an in-command confirmation step first. |
|
|
72
|
+
| `/agentlayer-autonomous-revoke` | Turn it back off. |
|
|
73
|
+
| `/guide` | Walk a new user through this document conversationally. |
|
|
74
|
+
|
|
75
|
+
Every command except `/wallet-setup` requires the user to type it themselves
|
|
76
|
+
— the agent cannot trigger them on its own.
|
|
77
|
+
|
|
78
|
+
## The preview → prepare → execute → approve Pattern
|
|
79
|
+
|
|
80
|
+
Nearly every write tool (transfers, swaps, staking, DeFi positions, BTC
|
|
81
|
+
sends, token launch) shares one lifecycle via a `mode` argument:
|
|
82
|
+
|
|
83
|
+
- `preview` — read-only summary of what the operation would do. No signing,
|
|
84
|
+
no broadcast. Always do this first.
|
|
85
|
+
- `prepare` — returns an execution plan (unsigned) for the same operation.
|
|
86
|
+
Requires `user_intent: true`. Used when the host needs to inspect the plan
|
|
87
|
+
before approving.
|
|
88
|
+
- `execute` — actually signs and broadcasts. Requires a host-issued approval
|
|
89
|
+
token bound to the exact previewed operation. In an interactive session the
|
|
90
|
+
host's own confirmation dialog supplies this. When it doesn't,
|
|
91
|
+
`issue_wallet_approval` is the explicit bridge step: call it with the
|
|
92
|
+
`tool_name` and the verbatim `confirmation_summary` from the prepare
|
|
93
|
+
response, plus `mainnet_confirmed: true` to acknowledge real funds are at
|
|
94
|
+
stake.
|
|
95
|
+
|
|
96
|
+
In Claude Code, don't call `issue_wallet_approval` or ask the user for a raw
|
|
97
|
+
`approval_token` yourself — the host's own confirmation dialog supplies it
|
|
98
|
+
once the user approves the call.
|
|
99
|
+
|
|
100
|
+
Never skip straight to `execute` on a mainnet operation the user has not
|
|
101
|
+
explicitly approved. Preview it, show the human what it does, then execute.
|
|
102
|
+
|
|
103
|
+
Always pass a short `purpose` string on write calls — it's the human-facing
|
|
104
|
+
audit label for what the transaction is for.
|
|
105
|
+
|
|
106
|
+
## Standing Authority: Autonomous Sessions
|
|
107
|
+
|
|
108
|
+
Two separate mechanisms remove the per-transaction approval step. Both grant
|
|
109
|
+
broad, real-money authority and must only be turned on when the user has
|
|
110
|
+
explicitly asked for it:
|
|
111
|
+
|
|
112
|
+
- **Scoped autonomous session** — `start_autonomous_session` (preview then
|
|
113
|
+
execute) opens a bounded session: `allowed_tools`, `allowed_networks`,
|
|
114
|
+
`allowed_recipients`, per-tx / hourly / daily spend caps, tx-rate cap,
|
|
115
|
+
operation count cap, and a session TTL. `allow_mainnet: true` is required to
|
|
116
|
+
let it touch real funds. `get_autonomous_session` reads current status
|
|
117
|
+
(active, limits, operations used, expiry); `stop_autonomous_session` always
|
|
118
|
+
works and hands control back to per-transaction approval.
|
|
119
|
+
- **Full high-trust permission group** — `agentlayer_autonomous_approve`
|
|
120
|
+
(scope `all`) is broader and unbounded by comparison: it covers *every*
|
|
121
|
+
wallet write tool (transfers, bridges, Solana swaps, staking, x402
|
|
122
|
+
payments, contract calls, EVM DeFi management) with no per-operation
|
|
123
|
+
allow-list. Requires `user_intent: true` and an explicit purpose.
|
|
124
|
+
`agentlayer_autonomous_status` reads it; `agentlayer_autonomous_revoke`
|
|
125
|
+
turns it off.
|
|
126
|
+
|
|
127
|
+
Prefer the scoped session over the full permission group whenever the task
|
|
128
|
+
has a defined boundary (a specific token, a specific recipient, a spend cap)
|
|
129
|
+
— it's the difference between "let the agent do this one job unattended" and
|
|
130
|
+
"let the agent spend freely until told to stop."
|
|
131
|
+
|
|
132
|
+
There is no narrower version of the full permission group — pass `scope:
|
|
133
|
+
"all"`; for a bounded grant, use the scoped session instead.
|
|
134
|
+
|
|
135
|
+
## Solana
|
|
136
|
+
|
|
137
|
+
- **Transfers**: `transfer_sol` (native), `transfer_spl_token` (by mint
|
|
138
|
+
address, optional `decimals` override).
|
|
139
|
+
- **Swaps**: `swap_solana_tokens` routes through Jupiter. Prefer
|
|
140
|
+
`mode: intent_preview` then `intent_execute` — it re-quotes fresh
|
|
141
|
+
immediately before sending and only executes within the previously
|
|
142
|
+
approved limits, which matters because Jupiter quotes expire fast. Legacy
|
|
143
|
+
`preview`/`prepare`/`execute` still works but is not preferred.
|
|
144
|
+
- **Prices**: `get_solana_token_prices` — Jupiter prices for a list of mints.
|
|
145
|
+
- **Housekeeping**: `close_empty_token_accounts` reclaims rent from
|
|
146
|
+
zero-balance SPL token accounts (preview lists them, execute closes up to
|
|
147
|
+
`limit`, default 8).
|
|
148
|
+
- **Native staking** (Solana Stake Program, not a DeFi protocol):
|
|
149
|
+
`stake_sol_native` (to a validator vote account), `get_solana_stake_account`
|
|
150
|
+
(activation status of one stake account), `get_solana_staking_validators`
|
|
151
|
+
(list validators by commission/activated stake), `deactivate_solana_stake`,
|
|
152
|
+
`withdraw_solana_stake`.
|
|
153
|
+
- **Kamino** (Solana's largest lend/earn/liquidity protocol):
|
|
154
|
+
- Discovery (read-only): `get_kamino_lend_markets` → main market first;
|
|
155
|
+
`get_kamino_lend_market_reserves` for per-token supply/borrow APY and
|
|
156
|
+
maxLtv; `get_kamino_vaults` for Earn-vault discovery
|
|
157
|
+
(`include_metrics: true` for APY/TVL, `token_mint` to filter).
|
|
158
|
+
- Lending writes: `kamino_lend_deposit`, `kamino_lend_borrow`,
|
|
159
|
+
`kamino_lend_repay`, `kamino_lend_withdraw` — all take `market`, `reserve`,
|
|
160
|
+
`amount_ui`; prefer `intent_preview` → `intent_execute` for the same
|
|
161
|
+
re-quote-before-send reason as swaps.
|
|
162
|
+
- Earn vault writes: `kamino_earn_deposit`, `kamino_earn_withdraw` (take
|
|
163
|
+
`kvault`, `amount_ui`).
|
|
164
|
+
- Position reads: `get_kamino_lend_user_obligations` (one market),
|
|
165
|
+
`get_kamino_open_positions` (all lending positions across markets),
|
|
166
|
+
`get_kamino_earn_positions`, `get_kamino_liquidity_positions`,
|
|
167
|
+
`get_kamino_lend_user_rewards`, and `get_kamino_portfolio` for the single
|
|
168
|
+
unified view across lending/earn/liquidity/staking.
|
|
169
|
+
- **Token launch**: `launch_bags_token` creates a token via Bags with a
|
|
170
|
+
fee-share config (`claimers` + `basis_points`, must sum to 10000) and an
|
|
171
|
+
optional `initial_buy_sol`. Same preview/prepare/execute lifecycle.
|
|
172
|
+
|
|
173
|
+
## EVM (Ethereum, Base, Robinhood chain)
|
|
174
|
+
|
|
175
|
+
- **Read utilities**: `get_evm_token_balance`, `get_evm_token_metadata`,
|
|
176
|
+
`get_evm_transaction_receipt` (by tx hash), `get_evm_fee_rates`.
|
|
177
|
+
- **Transfers**: `transfer_evm_native` (wei), `transfer_evm_token` (ERC-20,
|
|
178
|
+
raw base units + `token_address`).
|
|
179
|
+
- **Swaps — two independent routers, pick one**:
|
|
180
|
+
- Velora: `get_evm_swap_quote` (read-only) → `swap_evm_tokens`. Ethereum/
|
|
181
|
+
Base only.
|
|
182
|
+
- Uniswap: `get_uniswap_swap_quote` → `swap_evm_uniswap_tokens`. Covers
|
|
183
|
+
CLASSIC pools, UniswapX orders, and ETH↔WETH wrap/unwrap; supports
|
|
184
|
+
Ethereum, Base, and Robinhood chain; has a `slippage_bps` param (default
|
|
185
|
+
300 = 3%).
|
|
186
|
+
- `search_uniswap_pairs` finds a token's contract address by ticker/name
|
|
187
|
+
via DexScreener — **security note**: free-text ticker search can surface
|
|
188
|
+
impersonator tokens with fabricated liquidity/FDV, especially for tickers
|
|
189
|
+
claiming to represent a real-world stock/ETF. Verify the resolved
|
|
190
|
+
`token_address` independently (`get_evm_token_metadata`, or the chain's
|
|
191
|
+
official contract list) before quoting or swapping a real-world-asset
|
|
192
|
+
ticker — a successful quote does not itself prove legitimacy.
|
|
193
|
+
- **DeFi protocols** (read tools are free; every write follows preview →
|
|
194
|
+
execute):
|
|
195
|
+
- **Aave v3** (lending): `get_evm_aave_account` (health factor etc.),
|
|
196
|
+
`get_evm_aave_positions` (per-reserve supplied/borrowed),
|
|
197
|
+
`get_evm_aave_reserves` (market catalog) →
|
|
198
|
+
`manage_evm_aave_position` with `operation`: supply / withdraw / borrow /
|
|
199
|
+
repay.
|
|
200
|
+
- **Lido** (ETH liquid staking, Ethereum mainnet only):
|
|
201
|
+
`get_evm_lido_overview`, `get_evm_lido_positions` (stETH/wstETH),
|
|
202
|
+
`get_evm_lido_withdrawal_requests` →
|
|
203
|
+
`manage_evm_lido_position` (`stake_eth_for_wsteth` / `wrap_steth` /
|
|
204
|
+
`unwrap_wsteth`) and `manage_evm_lido_withdrawal`
|
|
205
|
+
(`request_withdrawal_steth` / `request_withdrawal_wsteth` /
|
|
206
|
+
`claim_withdrawal`, needs `request_id` to claim).
|
|
207
|
+
- **Morpho** (lending markets + curated vaults): `get_evm_morpho_markets` /
|
|
208
|
+
`get_evm_morpho_vaults` for discovery (filter by asset, sort by APY —
|
|
209
|
+
pair APY sorts with a `min_supply_usd`/`min_tvl_usd` floor to skip dust),
|
|
210
|
+
`get_evm_morpho_positions` for what the wallet currently holds →
|
|
211
|
+
`manage_evm_morpho_market_position` (supply_collateral / borrow / repay /
|
|
212
|
+
withdraw_collateral, isolated market by `market_id` or `market_preset`)
|
|
213
|
+
and `manage_evm_morpho_vault_position` (supply / withdraw, by
|
|
214
|
+
`vault_address` or `vault_preset`).
|
|
215
|
+
- **Uniswap Liquidity Provisioning** (concentrated LP positions, V3 and
|
|
216
|
+
V4): discovery first — `get_evm_uniswap_pools` finds an existing pool by
|
|
217
|
+
token pair and returns its `poolReferenceIdentifier`;
|
|
218
|
+
`get_evm_uniswap_positions` lists the wallet's V3 position NFTs (fee
|
|
219
|
+
tier, tick range, owed fees) — V4 position discovery isn't available
|
|
220
|
+
(V4's PositionManager isn't enumerable on-chain the way V3's is) →
|
|
221
|
+
`manage_evm_uniswap_liquidity` with `action`: create / increase /
|
|
222
|
+
decrease / claim_fees. `create` needs `existingPool.poolReference` (the
|
|
223
|
+
discovery tool's `poolReferenceIdentifier` value, under a different
|
|
224
|
+
field name); increase/decrease/claim_fees need the position's NFT token
|
|
225
|
+
id. Never guess either identifier — always discover it first, the tool
|
|
226
|
+
rejects the call outright if it's missing. This is a thin pass-through
|
|
227
|
+
to Uniswap's own official Liquidity API; deploying a brand-new pool is
|
|
228
|
+
out of scope.
|
|
229
|
+
|
|
230
|
+
## Cross-Chain Bridging (LI.FI)
|
|
231
|
+
|
|
232
|
+
- `get_lifi_supported_chains` — currently allowed chains for routing.
|
|
233
|
+
- `get_lifi_quote` — read-only quote between any two of Ethereum / Base /
|
|
234
|
+
Solana (bridge preferences via `allow_bridges` / `deny_bridges` /
|
|
235
|
+
`prefer_bridges`, slippage as a decimal fraction).
|
|
236
|
+
- `swap_evm_lifi_cross_chain_tokens` — execute EVM-origin (Ethereum/Base) →
|
|
237
|
+
Ethereum/Base/Solana.
|
|
238
|
+
- `swap_solana_lifi_cross_chain_tokens` — execute Solana-origin →
|
|
239
|
+
Ethereum/Base.
|
|
240
|
+
- `get_lifi_transfer_status` — poll a bridge transfer by source tx hash.
|
|
241
|
+
|
|
242
|
+
Same preview/prepare/execute + approval-token discipline as everything else.
|
|
243
|
+
Mayan routes are deliberately denied — see `skills/wallet-operator/SKILL.md`.
|
|
244
|
+
|
|
245
|
+
## Bitcoin
|
|
246
|
+
|
|
247
|
+
- `transfer_btc` — amount in `amount_sats`, optional `fee_rate` (sats/vB) or
|
|
248
|
+
`confirmation_target`.
|
|
249
|
+
- `get_btc_fee_rates`, `get_btc_max_spendable` (post-fee spendable estimate),
|
|
250
|
+
`get_btc_transfer_history` (filter by `direction`, paginate with
|
|
251
|
+
`limit`/`skip`).
|
|
252
|
+
|
|
253
|
+
## x402 — Paying HTTP 402 Endpoints
|
|
254
|
+
|
|
255
|
+
- `x402_search_services` — read-only discovery of paid services via CDP
|
|
256
|
+
Bazaar or Agentic Market (filter by `query`, `max_usd_price`, `network`).
|
|
257
|
+
- `x402_get_service_details` — resolve one service/resource URL into details.
|
|
258
|
+
- `x402_preview_request` — makes the *unpaid* request, reads the 402
|
|
259
|
+
challenge, and summarizes payment options. Does not pay.
|
|
260
|
+
- `x402_pay_request` — does the whole flow in one call: probes the endpoint,
|
|
261
|
+
validates it, signs the payment from the active wallet backend, and
|
|
262
|
+
returns the paid response. Requires `purpose`.
|
|
263
|
+
|
|
264
|
+
This is the same x402 v2 protocol the `catena` MCP/CLI speaks — a discrete
|
|
265
|
+
pay-per-request charge, not a subscription or usage meter — but here the
|
|
266
|
+
payer is this wallet directly rather than a governed bank rail, so there is
|
|
267
|
+
no separate approval-parking step: the preview → execute discipline above is
|
|
268
|
+
what stands between the agent and the payment.
|
|
269
|
+
|
|
270
|
+
## Explaining This to a Human
|
|
271
|
+
|
|
272
|
+
If asked to summarize this server in plain terms: it's a direct line to the
|
|
273
|
+
local AgentLayer wallet — Solana, an EVM chain (Ethereum/Base/Robinhood),
|
|
274
|
+
and Bitcoin — plus the major yield/lending/LP protocols on those chains
|
|
275
|
+
(Kamino, Aave, Lido, Morpho, Uniswap concentrated liquidity) and the ability
|
|
276
|
+
to pay per-request API/data paywalls (x402) straight from the wallet.
|
|
277
|
+
Everything that moves funds is gated by a preview step and an approval token
|
|
278
|
+
by default; "autonomous session" and "autonomous permission group" are the
|
|
279
|
+
two ways a human can explicitly grant the agent standing authority to skip
|
|
280
|
+
that per-transaction gate, bounded (the former) or broad (the latter) —
|
|
281
|
+
always confirm with the user before either one is enabled, and treat any
|
|
282
|
+
operation on mainnet as real, irreversible money movement.
|
|
@@ -66,6 +66,8 @@ no-op once the backend is healthy.
|
|
|
66
66
|
explicit in-command confirmation before enabling the standing permission.
|
|
67
67
|
- `/agentlayer-autonomous-revoke` — disable the combined autonomous permission
|
|
68
68
|
group for Base swaps and supported EVM DeFi tools.
|
|
69
|
+
- `/guide` — walk a new user through what this plugin can do, conversationally
|
|
70
|
+
(see `AGENTLAYER_AGENT_GUIDE.md` for the source material).
|
|
69
71
|
- `AGENT_WALLET_AUTO_BOOTSTRAP=0` — opt out of the auto-install: the
|
|
70
72
|
`SessionStart` hook then only reminds you to run `/wallet-setup` instead of
|
|
71
73
|
installing the backend itself.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Walk a new user through what the AgentLayer wallet plugin can do, conversationally.
|
|
3
|
+
allowed-tools: Bash(cat:*)
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Give the user a plain-language walkthrough of this wallet plugin, the way
|
|
8
|
+
you'd onboard someone who has never used it before.
|
|
9
|
+
|
|
10
|
+
1. Read the source material:
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
cat "${CLAUDE_PLUGIN_ROOT}/AGENTLAYER_AGENT_GUIDE.md"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
2. Do not paste or summarize the raw file section-by-section. Retell it as a
|
|
17
|
+
conversational walkthrough, addressed directly to the user ("you"), in
|
|
18
|
+
the language they've been using. Cover, roughly in this order:
|
|
19
|
+
|
|
20
|
+
- **What it is** — a direct line to their own local AgentLayer wallet
|
|
21
|
+
(Solana, an EVM chain, Bitcoin), not a generic crypto-data tool; every
|
|
22
|
+
write moves real money unless it's an explicit preview.
|
|
23
|
+
- **What they can do** — the "What You Can Do" list: Solana (transfers,
|
|
24
|
+
Jupiter swaps, staking, Kamino, Bags launches), EVM (transfers, swaps,
|
|
25
|
+
Aave/Lido/Morpho/Uniswap LP), cross-chain bridging, x402 payments.
|
|
26
|
+
- **How a session works** — the agent checks which backend/network is
|
|
27
|
+
active before doing anything, and can switch between them.
|
|
28
|
+
- **The quick commands** — list the slash commands from the "Quick
|
|
29
|
+
Commands" table by name and one-line purpose only; skip why each one
|
|
30
|
+
is or isn't model-invokable, that's implementation detail.
|
|
31
|
+
- **How money-moving operations work** — preview first, then execute
|
|
32
|
+
only after they confirm; keep this to the outcome (see it, approve it,
|
|
33
|
+
then it happens), not the internal approval-token mechanics.
|
|
34
|
+
- **Autonomous mode** — that it exists as an opt-in way to skip
|
|
35
|
+
per-operation confirmation, with a bounded (scoped) and an unbounded
|
|
36
|
+
(full) version, and that either requires them to explicitly ask for it.
|
|
37
|
+
|
|
38
|
+
3. Keep the whole thing skimmable — short paragraphs or a few bullets per
|
|
39
|
+
topic, no wall of text. Close by inviting them to ask about any specific
|
|
40
|
+
chain or protocol for the exact tool-level detail.
|
|
@@ -372,6 +372,7 @@ def _normalize_wallet_backend(value: Any) -> str:
|
|
|
372
372
|
"eth": "wdk_evm_local",
|
|
373
373
|
"base": "wdk_evm_local",
|
|
374
374
|
"robinhood": "wdk_evm_local",
|
|
375
|
+
"goat": "wdk_evm_local",
|
|
375
376
|
"wdk_evm_local": "wdk_evm_local",
|
|
376
377
|
"wdk-evm-local": "wdk_evm_local",
|
|
377
378
|
"evm_local": "wdk_evm_local",
|
|
@@ -385,7 +386,7 @@ def _normalize_wallet_backend(value: Any) -> str:
|
|
|
385
386
|
}
|
|
386
387
|
backend = aliases.get(normalized, normalized)
|
|
387
388
|
if backend not in BACKENDS:
|
|
388
|
-
raise RuntimeError("Wallet backend must be solana, evm, ethereum, base, robinhood, btc, or bitcoin.")
|
|
389
|
+
raise RuntimeError("Wallet backend must be solana, evm, ethereum, base, robinhood, goat, btc, or bitcoin.")
|
|
389
390
|
return backend
|
|
390
391
|
|
|
391
392
|
|
|
@@ -404,16 +405,17 @@ def _normalize_evm_network(value: Any) -> str:
|
|
|
404
405
|
"eth": "ethereum",
|
|
405
406
|
"eth-mainnet": "ethereum",
|
|
406
407
|
"base-mainnet": "base",
|
|
408
|
+
"goat-mainnet": "goat",
|
|
407
409
|
}
|
|
408
410
|
return aliases.get(normalized, normalized)
|
|
409
411
|
|
|
410
412
|
|
|
411
413
|
def _normalize_selectable_evm_network(value: Any) -> str:
|
|
412
414
|
network = _normalize_evm_network(value)
|
|
413
|
-
if network in {"sepolia", "base-sepolia", "base_sepolia"}:
|
|
414
|
-
raise RuntimeError("EVM testnets are no longer supported. Use ethereum, base, or
|
|
415
|
-
if network not in {"ethereum", "base", "robinhood"}:
|
|
416
|
-
raise RuntimeError("EVM network must be 'ethereum', 'base', or '
|
|
415
|
+
if network in {"sepolia", "base-sepolia", "base_sepolia", "goat-testnet", "goat-testnet3"}:
|
|
416
|
+
raise RuntimeError("EVM testnets are no longer supported. Use ethereum, base, robinhood, or goat.")
|
|
417
|
+
if network not in {"ethereum", "base", "robinhood", "goat"}:
|
|
418
|
+
raise RuntimeError("EVM network must be 'ethereum', 'base', 'robinhood', or 'goat'.")
|
|
417
419
|
return network
|
|
418
420
|
|
|
419
421
|
|
|
@@ -423,6 +425,8 @@ def _implied_evm_network_from_backend_alias(value: Any) -> str | None:
|
|
|
423
425
|
return "base"
|
|
424
426
|
if normalized == "robinhood":
|
|
425
427
|
return "robinhood"
|
|
428
|
+
if normalized in {"goat", "goat-mainnet"}:
|
|
429
|
+
return "goat"
|
|
426
430
|
if normalized in {"ethereum", "eth", "mainnet", "eth-mainnet"}:
|
|
427
431
|
return "ethereum"
|
|
428
432
|
return None
|
|
@@ -475,7 +479,7 @@ def _default_backend() -> str:
|
|
|
475
479
|
|
|
476
480
|
def _default_evm_network() -> str | None:
|
|
477
481
|
configured = _normalize_evm_network(os.getenv("WDK_EVM_NETWORK"))
|
|
478
|
-
if configured in {"ethereum", "base", "robinhood"}:
|
|
482
|
+
if configured in {"ethereum", "base", "robinhood", "goat"}:
|
|
479
483
|
return configured
|
|
480
484
|
return _configured_network_for_backend("wdk_evm_local")
|
|
481
485
|
|
|
@@ -1209,11 +1213,11 @@ def _manual_tool_definitions() -> list[dict[str, Any]]:
|
|
|
1209
1213
|
"properties": {
|
|
1210
1214
|
"backend": {
|
|
1211
1215
|
"type": "string",
|
|
1212
|
-
"description": "solana, evm, ethereum, base, robinhood, btc, or bitcoin.",
|
|
1216
|
+
"description": "solana, evm, ethereum, base, robinhood, goat, btc, or bitcoin.",
|
|
1213
1217
|
},
|
|
1214
1218
|
"network": {
|
|
1215
1219
|
"type": "string",
|
|
1216
|
-
"description": "Optional network override. Use ethereum, base, or
|
|
1220
|
+
"description": "Optional network override. Use ethereum, base, robinhood, or goat for EVM.",
|
|
1217
1221
|
},
|
|
1218
1222
|
"address": {
|
|
1219
1223
|
"type": "string",
|
|
@@ -1248,7 +1252,7 @@ def _manual_tool_definitions() -> list[dict[str, Any]]:
|
|
|
1248
1252
|
"properties": {
|
|
1249
1253
|
"backend": {
|
|
1250
1254
|
"type": "string",
|
|
1251
|
-
"description": "solana, evm, ethereum, base, robinhood, btc, or bitcoin.",
|
|
1255
|
+
"description": "solana, evm, ethereum, base, robinhood, goat, btc, or bitcoin.",
|
|
1252
1256
|
},
|
|
1253
1257
|
"wallet": {
|
|
1254
1258
|
"type": "string",
|
|
@@ -1266,14 +1270,14 @@ def _manual_tool_definitions() -> list[dict[str, Any]]:
|
|
|
1266
1270
|
{
|
|
1267
1271
|
"name": "set_evm_network",
|
|
1268
1272
|
"description": (
|
|
1269
|
-
"Set the active EVM network for this Codex MCP session to ethereum, base, or
|
|
1273
|
+
"Set the active EVM network for this Codex MCP session to ethereum, base, robinhood, or goat."
|
|
1270
1274
|
),
|
|
1271
1275
|
"input_schema": {
|
|
1272
1276
|
"type": "object",
|
|
1273
1277
|
"properties": {
|
|
1274
1278
|
"network": {
|
|
1275
1279
|
"type": "string",
|
|
1276
|
-
"description": "ethereum, base, or
|
|
1280
|
+
"description": "ethereum, base, robinhood, or goat.",
|
|
1277
1281
|
}
|
|
1278
1282
|
},
|
|
1279
1283
|
"required": ["network"],
|
|
@@ -16,4 +16,4 @@ Rules:
|
|
|
16
16
|
- On mainnet, restate the network, asset, amount, and destination before execute.
|
|
17
17
|
- Do not ask the user for `approval_token`. The bridge manages approval binding internally.
|
|
18
18
|
- If approval context is missing or stale, repeat preview instead of improvising.
|
|
19
|
-
- Use `set_wallet_backend` to switch between Solana, EVM, and Bitcoin wallets within a session, and `set_evm_network` to pick ethereum, base, or
|
|
19
|
+
- Use `set_wallet_backend` to switch between Solana, EVM, and Bitcoin wallets within a session, and `set_evm_network` to pick ethereum, base, robinhood, or goat.
|
package/package.json
CHANGED
|
@@ -11,7 +11,10 @@ WDK_EVM_RPC_GATEWAY_PROVIDER=alchemy
|
|
|
11
11
|
PROVIDER_GATEWAY_URL=https://agent-layer-production.up.railway.app
|
|
12
12
|
PROVIDER_GATEWAY_BEARER_TOKEN=
|
|
13
13
|
# Mainnet ethereum/base/robinhood are forced through provider-gateway -> Alchemy.
|
|
14
|
-
#
|
|
14
|
+
# GOAT mainnet is forced through provider-gateway -> shared GOAT RPC. The gateway
|
|
15
|
+
# is configured with SHARED_EVM_GOAT_RPC_URL=https://rpc.goat.network; it has no
|
|
16
|
+
# local URL override. Direct per-network URLs below are only relevant for the
|
|
17
|
+
# existing testnet-style paths.
|
|
15
18
|
WDK_EVM_ETHEREUM_RPC_URL=
|
|
16
19
|
WDK_EVM_SEPOLIA_RPC_URL=https://sepolia.drpc.org
|
|
17
20
|
WDK_EVM_BASE_RPC_URL=
|
package/wdk-evm-wallet/README.md
CHANGED
|
@@ -74,9 +74,22 @@ This service intentionally supports a narrow surface:
|
|
|
74
74
|
- `sepolia`
|
|
75
75
|
- `base`
|
|
76
76
|
- `base-sepolia`
|
|
77
|
+
- `robinhood`
|
|
78
|
+
- `goat` (GOAT Network mainnet, chain ID `2345`)
|
|
79
|
+
- `goat-testnet` (GOAT Testnet3, chain ID `48816`; local runtime testing only)
|
|
77
80
|
|
|
78
81
|
The active network is persistent and can be switched without changing code.
|
|
79
82
|
|
|
83
|
+
GOAT is an EVM-compatible network whose native transfer and gas asset is BTC
|
|
84
|
+
(18-decimal EVM base units), rather than ETH. Mainnet uses the allow-listed
|
|
85
|
+
provider-gateway `shared` route, whose only GOAT upstream is configured as
|
|
86
|
+
`SHARED_EVM_GOAT_RPC_URL` (normally `https://rpc.goat.network`). Testnet3 uses
|
|
87
|
+
the fixed official endpoint `https://rpc.testnet3.goat.network`. Higher-level
|
|
88
|
+
callers cannot supply a remote URL. Existing generic capabilities — native BTC
|
|
89
|
+
balance/transfer, ERC-20 reads/transfers, fee quotes, and receipts — are
|
|
90
|
+
available. GOAT bridge, DEX, and GOAT Flow/x402 operations remain deliberately
|
|
91
|
+
out of scope until they receive separate protocol-specific safety reviews.
|
|
92
|
+
|
|
80
93
|
## API
|
|
81
94
|
|
|
82
95
|
- `GET /health`
|
|
@@ -184,6 +197,7 @@ Environment variables:
|
|
|
184
197
|
- `WDK_EVM_SEPOLIA_RPC_URL`
|
|
185
198
|
- `WDK_EVM_BASE_RPC_URL`
|
|
186
199
|
- `WDK_EVM_BASE_SEPOLIA_RPC_URL`
|
|
200
|
+
- `WDK_EVM_ROBINHOOD_RPC_URL`
|
|
187
201
|
- `MORPHO_API_BASE_URL`
|
|
188
202
|
- `UNISWAP_API_KEY`
|
|
189
203
|
- `UNISWAP_TRADING_API_BASE_URL`
|
|
@@ -227,10 +241,12 @@ Gateway mode:
|
|
|
227
241
|
- `PROVIDER_GATEWAY_URL` defaults to `https://agent-layer-production.up.railway.app`
|
|
228
242
|
- set `PROVIDER_GATEWAY_URL=https://...` only when overriding the hosted default
|
|
229
243
|
- `PROVIDER_GATEWAY_BEARER_TOKEN` is optional and only needed when the gateway is protected
|
|
230
|
-
- `ethereum` and `
|
|
231
|
-
-
|
|
244
|
+
- `ethereum`, `base`, and `robinhood` mainnet are always routed through the provider gateway raw EVM RPC route pinned to `provider=alchemy`
|
|
245
|
+
- GOAT mainnet is always routed through the provider gateway raw EVM RPC route pinned to `provider=shared`; configure its only allowed upstream with `SHARED_EVM_GOAT_RPC_URL=https://rpc.goat.network`
|
|
232
246
|
- direct `WDK_EVM_ETHEREUM_RPC_URL` and `WDK_EVM_BASE_RPC_URL` values no longer override mainnet routing
|
|
233
247
|
- `WDK_EVM_SEPOLIA_RPC_URL` and `WDK_EVM_BASE_SEPOLIA_RPC_URL` remain direct per-network testnet overrides
|
|
248
|
+
- GOAT Testnet3 uses its fixed official public RPC endpoint. Mainnet requires a
|
|
249
|
+
gateway deployment that includes the GOAT shared-RPC allowlist.
|
|
234
250
|
|
|
235
251
|
Local security note:
|
|
236
252
|
|
|
@@ -27,7 +27,7 @@ function readPackageVersion() {
|
|
|
27
27
|
|
|
28
28
|
const PACKAGE_VERSION = readPackageVersion();
|
|
29
29
|
const DEFAULT_PROVIDER_GATEWAY_URL = "https://agent-layer-production.up.railway.app";
|
|
30
|
-
const ENFORCED_GATEWAY_MAINNETS = new Set(["ethereum", "base", "robinhood"]);
|
|
30
|
+
const ENFORCED_GATEWAY_MAINNETS = new Set(["ethereum", "base", "robinhood", "goat"]);
|
|
31
31
|
|
|
32
32
|
const DEFAULT_NETWORK_PROFILES = {
|
|
33
33
|
ethereum: {
|
|
@@ -55,6 +55,16 @@ const DEFAULT_NETWORK_PROFILES = {
|
|
|
55
55
|
providerUrl: "https://rpc.mainnet.chain.robinhood.com",
|
|
56
56
|
nativeSymbol: "ETH",
|
|
57
57
|
},
|
|
58
|
+
goat: {
|
|
59
|
+
chainId: 2345,
|
|
60
|
+
providerUrl: "https://rpc.goat.network",
|
|
61
|
+
nativeSymbol: "BTC",
|
|
62
|
+
},
|
|
63
|
+
"goat-testnet": {
|
|
64
|
+
chainId: 48816,
|
|
65
|
+
providerUrl: "https://rpc.testnet3.goat.network",
|
|
66
|
+
nativeSymbol: "BTC",
|
|
67
|
+
},
|
|
58
68
|
};
|
|
59
69
|
|
|
60
70
|
// Robinhood Chain uses the Universal Router 2.1.1 deployment. Keep this
|
|
@@ -191,6 +201,8 @@ function normalizeNetworkKey(value) {
|
|
|
191
201
|
"base-mainnet": "base",
|
|
192
202
|
base_sepolia: "base-sepolia",
|
|
193
203
|
"robinhood-mainnet": "robinhood",
|
|
204
|
+
"goat-mainnet": "goat",
|
|
205
|
+
"goat-testnet3": "goat-testnet",
|
|
194
206
|
};
|
|
195
207
|
return aliases[normalized] || normalized;
|
|
196
208
|
}
|
|
@@ -252,7 +264,7 @@ export function loadConfig(env = process.env) {
|
|
|
252
264
|
const network = normalizeNetworkKey(env.WDK_EVM_NETWORK ?? DEFAULTS.network) || DEFAULTS.network;
|
|
253
265
|
if (!Object.hasOwn(DEFAULT_NETWORK_PROFILES, network)) {
|
|
254
266
|
throw new Error(
|
|
255
|
-
"WDK_EVM_NETWORK must be one of: ethereum, sepolia, base, base-sepolia, robinhood."
|
|
267
|
+
"WDK_EVM_NETWORK must be one of: ethereum, sepolia, base, base-sepolia, robinhood, goat, goat-testnet."
|
|
256
268
|
);
|
|
257
269
|
}
|
|
258
270
|
|
|
@@ -274,10 +286,14 @@ export function loadConfig(env = process.env) {
|
|
|
274
286
|
function resolveProviderUrl(networkKey, envValue, fallbackUrl) {
|
|
275
287
|
const direct = String(envValue ?? "").trim();
|
|
276
288
|
if (ENFORCED_GATEWAY_MAINNETS.has(networkKey)) {
|
|
289
|
+
// GOAT's explicitly allow-listed gateway upstream is the official shared
|
|
290
|
+
// RPC. The other mainnets are pinned to Alchemy. Do not accept a caller-
|
|
291
|
+
// supplied upstream URL for any mainnet.
|
|
292
|
+
const enforcedProvider = networkKey === "goat" ? "shared" : "alchemy";
|
|
277
293
|
const enforcedGatewayUrl = buildGatewayEvmRpcUrl(
|
|
278
294
|
providerGatewayUrl,
|
|
279
295
|
networkKey,
|
|
280
|
-
|
|
296
|
+
enforcedProvider,
|
|
281
297
|
providerGatewayToken
|
|
282
298
|
);
|
|
283
299
|
if (!enforcedGatewayUrl) {
|
|
@@ -344,6 +360,21 @@ export function loadConfig(env = process.env) {
|
|
|
344
360
|
DEFAULT_NETWORK_PROFILES.robinhood.providerUrl
|
|
345
361
|
),
|
|
346
362
|
},
|
|
363
|
+
// GOAT is an EIP-1559 EVM network that uses BTC (18 decimals) as its
|
|
364
|
+
// native gas token. Keep the official RPC endpoint fixed in source: host
|
|
365
|
+
// integrations must never select an arbitrary remote RPC URL.
|
|
366
|
+
goat: {
|
|
367
|
+
...DEFAULT_NETWORK_PROFILES.goat,
|
|
368
|
+
providerUrl: resolveProviderUrl("goat", "", DEFAULT_NETWORK_PROFILES.goat.providerUrl),
|
|
369
|
+
},
|
|
370
|
+
"goat-testnet": {
|
|
371
|
+
...DEFAULT_NETWORK_PROFILES["goat-testnet"],
|
|
372
|
+
providerUrl: resolveProviderUrl(
|
|
373
|
+
"goat-testnet",
|
|
374
|
+
"",
|
|
375
|
+
DEFAULT_NETWORK_PROFILES["goat-testnet"].providerUrl
|
|
376
|
+
),
|
|
377
|
+
},
|
|
347
378
|
};
|
|
348
379
|
|
|
349
380
|
// Route Uniswap Trading API calls through the provider-gateway by default so the
|
|
@@ -12,11 +12,17 @@ function assertValidNetwork(network, fieldName = "network") {
|
|
|
12
12
|
"base-mainnet": "base",
|
|
13
13
|
base_sepolia: "base-sepolia",
|
|
14
14
|
"robinhood-mainnet": "robinhood",
|
|
15
|
+
"goat-mainnet": "goat",
|
|
16
|
+
"goat-testnet3": "goat-testnet",
|
|
15
17
|
};
|
|
16
18
|
const effective = aliases[normalized] || normalized;
|
|
17
|
-
if (
|
|
19
|
+
if (
|
|
20
|
+
!["ethereum", "sepolia", "base", "base-sepolia", "robinhood", "goat", "goat-testnet"].includes(
|
|
21
|
+
effective
|
|
22
|
+
)
|
|
23
|
+
) {
|
|
18
24
|
throw new Error(
|
|
19
|
-
`${fieldName} must be one of: ethereum, sepolia, base, base-sepolia, robinhood.`
|
|
25
|
+
`${fieldName} must be one of: ethereum, sepolia, base, base-sepolia, robinhood, goat, goat-testnet.`
|
|
20
26
|
);
|
|
21
27
|
}
|
|
22
28
|
return effective;
|