@agentlayer.tech/wallet 0.1.95 → 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.
Files changed (30) hide show
  1. package/.openclaw/extensions/agent-wallet/README.md +2 -2
  2. package/.openclaw/extensions/agent-wallet/dist/index.js +33 -15
  3. package/.openclaw/extensions/agent-wallet/index.ts +33 -15
  4. package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +2 -2
  5. package/.openclaw/extensions/agent-wallet/package.json +1 -1
  6. package/VERSION +1 -1
  7. package/agent-wallet/README.md +3 -3
  8. package/agent-wallet/agent_wallet/__init__.py +1 -1
  9. package/agent-wallet/agent_wallet/autonomous_policy.py +2 -1
  10. package/agent-wallet/agent_wallet/config.py +7 -11
  11. package/agent-wallet/agent_wallet/networks.py +25 -0
  12. package/agent-wallet/agent_wallet/openclaw_adapter.py +43 -25
  13. package/agent-wallet/agent_wallet/providers/evm_portfolio.py +9 -2
  14. package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +1 -1
  15. package/agent-wallet/openclaw.plugin.json +1 -1
  16. package/agent-wallet/pyproject.toml +1 -1
  17. package/claude-code/plugins/agent-wallet/.claude-plugin/plugin.json +1 -1
  18. package/claude-code/plugins/agent-wallet/AGENTLAYER_AGENT_GUIDE.md +2 -2
  19. package/codex/plugins/agent-wallet/.codex-plugin/plugin.json +1 -1
  20. package/codex/plugins/agent-wallet/server.py +15 -11
  21. package/codex/plugins/agent-wallet/skills/wallet-operator/SKILL.md +1 -1
  22. package/hermes/plugins/agent_wallet/plugin.yaml +1 -1
  23. package/package.json +1 -1
  24. package/wdk-btc-wallet/package.json +1 -1
  25. package/wdk-evm-wallet/.env.example +4 -1
  26. package/wdk-evm-wallet/README.md +18 -2
  27. package/wdk-evm-wallet/package.json +1 -1
  28. package/wdk-evm-wallet/src/config.js +34 -3
  29. package/wdk-evm-wallet/src/network_state.js +8 -2
  30. package/wdk-evm-wallet/src/wdk_evm_wallet.js +8 -2
@@ -97,8 +97,8 @@ Important:
97
97
  - The EVM tool surface is intentionally narrow: Velora and Uniswap swap quote/execute, Aave V3 account/reserve/position flows, native transfers, ERC-20 transfers, fee quotes, and receipt lookup only. No arbitrary calldata, standalone approvals, or generic contract execution are exposed to the agent.
98
98
  - Velora swap and Aave V3 support are currently limited to `ethereum` and `base`. Test carefully because the upstream WDK protocol packages are still beta.
99
99
  - Agents can call `set_wallet_backend` to switch the active wallet for the current OpenClaw plugin session between Solana, EVM, and Bitcoin. This does not edit `openclaw.json`; plugin config remains the startup default.
100
- - EVM core read and transfer tools accept an optional per-call `network` override for `ethereum`, `base`, or `robinhood`; Velora/Aave remain limited to Ethereum/Base, while Uniswap supports all three.
101
- - Agents can also call `set_evm_network` to select the active EVM network for the current OpenClaw plugin session. After that, EVM tools default to the selected network unless a specific call passes its own `network` value. Do not edit code, plugin config, or environment variables just to switch between Base, Ethereum, and Robinhood.
100
+ - EVM core read and transfer tools accept an optional per-call `network` override for `ethereum`, `base`, `robinhood`, or `goat`; Velora/Aave remain limited to Ethereum/Base, while Uniswap supports Ethereum/Base/Robinhood only. GOAT uses BTC as the native gas asset and exposes no bridge, DEX, or GOAT Flow/x402 operation through this core surface.
101
+ - Agents can also call `set_evm_network` to select the active EVM network for the current OpenClaw plugin session. After that, EVM tools default to the selected network unless a specific call passes its own `network` value. Do not edit code, plugin config, or environment variables just to switch between Base, Ethereum, Robinhood, and GOAT.
102
102
  - `get_wallet_balance` returns an enriched wallet overview for Solana and EVM: native balance, discovered token balances, per-asset USD values when pricing is available, and `total_value_usd`.
103
103
  - Solana wallet overview uses Solana RPC only for balance and token-account discovery. Token prices come from Jupiter, not RPC, and internal transfer/staking checks continue to use native-only balance reads.
104
104
  - If the user needs to recover the mnemonic later, host-side reveal stays outside the agent tool surface via `agent-wallet/scripts/manage_openclaw_btc_wallet.py reveal-seed`.
@@ -18,7 +18,8 @@ const PREVIEW_BOUND_SWAP_TOOLS = new Set([
18
18
  "flash_trade_open_position",
19
19
  "flash_trade_close_position",
20
20
  ]);
21
- const EVM_CORE_NETWORKS = ["ethereum", "base", "robinhood"];
21
+ const EVM_CORE_NETWORKS = ["ethereum", "base", "robinhood", "goat"];
22
+ const EVM_UNISWAP_NETWORKS = ["ethereum", "base", "robinhood"];
22
23
  const AUTONOMOUS_BASE_SWAP_TOOLS = new Set([
23
24
  "swap_evm_tokens",
24
25
  "swap_evm_uniswap_tokens",
@@ -205,6 +206,7 @@ function normalizeWalletBackend(value) {
205
206
  eth: "wdk_evm_local",
206
207
  base: "wdk_evm_local",
207
208
  robinhood: "wdk_evm_local",
209
+ goat: "wdk_evm_local",
208
210
  wdk_evm_local: "wdk_evm_local",
209
211
  "wdk-evm-local": "wdk_evm_local",
210
212
  evm_local: "wdk_evm_local",
@@ -218,7 +220,7 @@ function normalizeWalletBackend(value) {
218
220
  };
219
221
  const backend = aliases[normalized] || normalized;
220
222
  if (!["solana_local", "wdk_evm_local", "wdk_btc_local"].includes(backend)) {
221
- throw new Error("Wallet backend must be solana, evm, ethereum, base, robinhood, btc, or bitcoin.");
223
+ throw new Error("Wallet backend must be solana, evm, ethereum, base, robinhood, goat, btc, or bitcoin.");
222
224
  }
223
225
  return backend;
224
226
  }
@@ -236,17 +238,18 @@ function normalizeEvmNetwork(value) {
236
238
  eth: "ethereum",
237
239
  "eth-mainnet": "ethereum",
238
240
  "base-mainnet": "base",
241
+ "goat-mainnet": "goat",
239
242
  };
240
243
  return aliases[normalized] || normalized;
241
244
  }
242
245
 
243
246
  function normalizeSelectableEvmNetwork(value) {
244
247
  const network = normalizeEvmNetwork(value);
245
- if (["sepolia", "base-sepolia", "base_sepolia"].includes(network)) {
246
- throw new Error("EVM testnets are no longer supported. Use ethereum, base, or robinhood.");
248
+ if (["sepolia", "base-sepolia", "base_sepolia", "goat-testnet", "goat-testnet3"].includes(network)) {
249
+ throw new Error("EVM testnets are no longer supported. Use ethereum, base, robinhood, or goat.");
247
250
  }
248
251
  if (!EVM_CORE_NETWORKS.includes(network)) {
249
- throw new Error("EVM network must be 'ethereum', 'base', or 'robinhood'.");
252
+ throw new Error("EVM network must be 'ethereum', 'base', 'robinhood', or 'goat'.");
250
253
  }
251
254
  return network;
252
255
  }
@@ -370,6 +373,10 @@ function networkForBackend(api, backend) {
370
373
  }
371
374
  }
372
375
 
376
+ function isGoatEvmNetwork(network) {
377
+ return ["goat", "goat-mainnet", "eip155:2345"].includes(String(network || "").trim().toLowerCase());
378
+ }
379
+
373
380
  function effectiveConfigForBackend(api, backend) {
374
381
  const config = resolvePluginConfig(api);
375
382
  return {
@@ -591,6 +598,8 @@ function registerTool(api, definition) {
591
598
  const impliedNetwork =
592
599
  ["base", "base-mainnet"].includes(requestedWallet)
593
600
  ? "base"
601
+ : ["goat", "goat-mainnet"].includes(requestedWallet)
602
+ ? "goat"
594
603
  : ["ethereum", "eth", "mainnet", "eth-mainnet"].includes(requestedWallet)
595
604
  ? "ethereum"
596
605
  : null;
@@ -674,6 +683,15 @@ function registerTool(api, definition) {
674
683
  if (activeBackend === "wdk_evm_local" && effectiveParams.network !== undefined) {
675
684
  configOverride.network = normalizeSelectableEvmNetwork(effectiveParams.network);
676
685
  }
686
+ if (
687
+ definition.name === "x402_pay_request" &&
688
+ activeBackend === "wdk_evm_local" &&
689
+ isGoatEvmNetwork(configOverride.network)
690
+ ) {
691
+ throw new Error(
692
+ "GOAT x402 payments are not enabled in this wallet surface. Use the supported core GOAT wallet operations instead."
693
+ );
694
+ }
677
695
  await attachApprovalForExecute(api, configOverride, userId, definition.name, effectiveParams);
678
696
  const executeWalletTool = async () =>
679
697
  callWalletCli(api, "invoke", [
@@ -844,12 +862,12 @@ const walletSessionToolDefinitions = [
844
862
  properties: {
845
863
  backend: {
846
864
  type: "string",
847
- enum: ["solana", "sol", "evm", "ethereum", "base", "robinhood", "bitcoin", "btc"],
865
+ enum: ["solana", "sol", "evm", "ethereum", "base", "robinhood", "goat", "bitcoin", "btc"],
848
866
  description: "Wallet backend or common alias to make active.",
849
867
  },
850
868
  network: {
851
869
  type: "string",
852
- description: "Optional network for the selected wallet. Examples: mainnet, ethereum, base, robinhood, bitcoin.",
870
+ description: "Optional network for the selected wallet. Examples: mainnet, ethereum, base, robinhood, goat, bitcoin.",
853
871
  },
854
872
  },
855
873
  required: ["backend"],
@@ -1640,7 +1658,7 @@ const evmToolDefinitions = [
1640
1658
  {
1641
1659
  name: "set_evm_network",
1642
1660
  description:
1643
- "Select the active EVM network for subsequent wallet tool calls in this OpenClaw plugin session. Use this to switch between ethereum, base, and robinhood instead of editing code or plugin configuration.",
1661
+ "Select the active EVM network for subsequent wallet tool calls in this OpenClaw plugin session. Use this to switch between ethereum, base, robinhood, and goat instead of editing code or plugin configuration.",
1644
1662
  parameters: {
1645
1663
  type: "object",
1646
1664
  properties: {
@@ -1693,7 +1711,7 @@ const evmToolDefinitions = [
1693
1711
  },
1694
1712
  {
1695
1713
  name: "get_evm_transaction_receipt",
1696
- description: "Get the transaction receipt for a broadcast EVM transaction hash.",
1714
+ description: "Get the transaction receipt for a broadcast EVM transaction hash. On GOAT, a receipt confirms L2 inclusion; it does not by itself prove Bitcoin-backed finality.",
1697
1715
  parameters: {
1698
1716
  type: "object",
1699
1717
  properties: {
@@ -1972,7 +1990,7 @@ const evmToolDefinitions = [
1972
1990
  token_out: { type: "string" },
1973
1991
  amount_in_raw: { type: "string" },
1974
1992
  slippage_bps: { type: "integer" },
1975
- network: { type: "string", enum: EVM_CORE_NETWORKS },
1993
+ network: { type: "string", enum: EVM_UNISWAP_NETWORKS },
1976
1994
  },
1977
1995
  required: ["token_in", "token_out", "amount_in_raw"],
1978
1996
  additionalProperties: false,
@@ -1990,7 +2008,7 @@ const evmToolDefinitions = [
1990
2008
  dex_id: { type: "string" },
1991
2009
  all_chains: { type: "boolean" },
1992
2010
  limit: { type: "integer" },
1993
- network: { type: "string", enum: EVM_CORE_NETWORKS },
2011
+ network: { type: "string", enum: EVM_UNISWAP_NETWORKS },
1994
2012
  },
1995
2013
  additionalProperties: false,
1996
2014
  },
@@ -2014,7 +2032,7 @@ const evmToolDefinitions = [
2014
2032
  },
2015
2033
  page_size: { type: "integer", minimum: 1, maximum: 20 },
2016
2034
  current_page: { type: "integer", minimum: 1 },
2017
- network: { type: "string", enum: EVM_CORE_NETWORKS },
2035
+ network: { type: "string", enum: EVM_UNISWAP_NETWORKS },
2018
2036
  },
2019
2037
  required: ["protocol"],
2020
2038
  additionalProperties: false,
@@ -2028,7 +2046,7 @@ const evmToolDefinitions = [
2028
2046
  properties: {
2029
2047
  protocol: { type: "string", enum: ["V3"] },
2030
2048
  limit: { type: "integer", minimum: 1, maximum: 100 },
2031
- network: { type: "string", enum: EVM_CORE_NETWORKS },
2049
+ network: { type: "string", enum: EVM_UNISWAP_NETWORKS },
2032
2050
  },
2033
2051
  additionalProperties: false,
2034
2052
  },
@@ -2047,7 +2065,7 @@ const evmToolDefinitions = [
2047
2065
  mode: { type: "string", enum: ["preview", "prepare", "execute"] },
2048
2066
  purpose: { type: "string" },
2049
2067
  user_intent: { type: "boolean" },
2050
- network: { type: "string", enum: EVM_CORE_NETWORKS },
2068
+ network: { type: "string", enum: EVM_UNISWAP_NETWORKS },
2051
2069
  },
2052
2070
  required: ["token_in", "token_out", "amount_in_raw", "mode", "purpose"],
2053
2071
  additionalProperties: false,
@@ -2070,7 +2088,7 @@ const evmToolDefinitions = [
2070
2088
  mode: { type: "string", enum: ["preview", "prepare", "execute"] },
2071
2089
  purpose: { type: "string" },
2072
2090
  user_intent: { type: "boolean" },
2073
- network: { type: "string", enum: EVM_CORE_NETWORKS },
2091
+ network: { type: "string", enum: EVM_UNISWAP_NETWORKS },
2074
2092
  },
2075
2093
  required: ["action", "protocol", "request", "mode", "purpose"],
2076
2094
  additionalProperties: false,
@@ -18,7 +18,8 @@ const PREVIEW_BOUND_SWAP_TOOLS = new Set([
18
18
  "flash_trade_open_position",
19
19
  "flash_trade_close_position",
20
20
  ]);
21
- const EVM_CORE_NETWORKS = ["ethereum", "base", "robinhood"];
21
+ const EVM_CORE_NETWORKS = ["ethereum", "base", "robinhood", "goat"];
22
+ const EVM_UNISWAP_NETWORKS = ["ethereum", "base", "robinhood"];
22
23
  const AUTONOMOUS_BASE_SWAP_TOOLS = new Set([
23
24
  "swap_evm_tokens",
24
25
  "swap_evm_uniswap_tokens",
@@ -205,6 +206,7 @@ function normalizeWalletBackend(value) {
205
206
  eth: "wdk_evm_local",
206
207
  base: "wdk_evm_local",
207
208
  robinhood: "wdk_evm_local",
209
+ goat: "wdk_evm_local",
208
210
  wdk_evm_local: "wdk_evm_local",
209
211
  "wdk-evm-local": "wdk_evm_local",
210
212
  evm_local: "wdk_evm_local",
@@ -218,7 +220,7 @@ function normalizeWalletBackend(value) {
218
220
  };
219
221
  const backend = aliases[normalized] || normalized;
220
222
  if (!["solana_local", "wdk_evm_local", "wdk_btc_local"].includes(backend)) {
221
- throw new Error("Wallet backend must be solana, evm, ethereum, base, robinhood, btc, or bitcoin.");
223
+ throw new Error("Wallet backend must be solana, evm, ethereum, base, robinhood, goat, btc, or bitcoin.");
222
224
  }
223
225
  return backend;
224
226
  }
@@ -236,17 +238,18 @@ function normalizeEvmNetwork(value) {
236
238
  eth: "ethereum",
237
239
  "eth-mainnet": "ethereum",
238
240
  "base-mainnet": "base",
241
+ "goat-mainnet": "goat",
239
242
  };
240
243
  return aliases[normalized] || normalized;
241
244
  }
242
245
 
243
246
  function normalizeSelectableEvmNetwork(value) {
244
247
  const network = normalizeEvmNetwork(value);
245
- if (["sepolia", "base-sepolia", "base_sepolia"].includes(network)) {
246
- throw new Error("EVM testnets are no longer supported. Use ethereum, base, or robinhood.");
248
+ if (["sepolia", "base-sepolia", "base_sepolia", "goat-testnet", "goat-testnet3"].includes(network)) {
249
+ throw new Error("EVM testnets are no longer supported. Use ethereum, base, robinhood, or goat.");
247
250
  }
248
251
  if (!EVM_CORE_NETWORKS.includes(network)) {
249
- throw new Error("EVM network must be 'ethereum', 'base', or 'robinhood'.");
252
+ throw new Error("EVM network must be 'ethereum', 'base', 'robinhood', or 'goat'.");
250
253
  }
251
254
  return network;
252
255
  }
@@ -370,6 +373,10 @@ function networkForBackend(api, backend) {
370
373
  }
371
374
  }
372
375
 
376
+ function isGoatEvmNetwork(network) {
377
+ return ["goat", "goat-mainnet", "eip155:2345"].includes(String(network || "").trim().toLowerCase());
378
+ }
379
+
373
380
  function effectiveConfigForBackend(api, backend) {
374
381
  const config = resolvePluginConfig(api);
375
382
  return {
@@ -591,6 +598,8 @@ function registerTool(api, definition) {
591
598
  const impliedNetwork =
592
599
  ["base", "base-mainnet"].includes(requestedWallet)
593
600
  ? "base"
601
+ : ["goat", "goat-mainnet"].includes(requestedWallet)
602
+ ? "goat"
594
603
  : ["ethereum", "eth", "mainnet", "eth-mainnet"].includes(requestedWallet)
595
604
  ? "ethereum"
596
605
  : null;
@@ -674,6 +683,15 @@ function registerTool(api, definition) {
674
683
  if (activeBackend === "wdk_evm_local" && effectiveParams.network !== undefined) {
675
684
  configOverride.network = normalizeSelectableEvmNetwork(effectiveParams.network);
676
685
  }
686
+ if (
687
+ definition.name === "x402_pay_request" &&
688
+ activeBackend === "wdk_evm_local" &&
689
+ isGoatEvmNetwork(configOverride.network)
690
+ ) {
691
+ throw new Error(
692
+ "GOAT x402 payments are not enabled in this wallet surface. Use the supported core GOAT wallet operations instead."
693
+ );
694
+ }
677
695
  await attachApprovalForExecute(api, configOverride, userId, definition.name, effectiveParams);
678
696
  const executeWalletTool = async () =>
679
697
  callWalletCli(api, "invoke", [
@@ -844,12 +862,12 @@ const walletSessionToolDefinitions = [
844
862
  properties: {
845
863
  backend: {
846
864
  type: "string",
847
- enum: ["solana", "sol", "evm", "ethereum", "base", "robinhood", "bitcoin", "btc"],
865
+ enum: ["solana", "sol", "evm", "ethereum", "base", "robinhood", "goat", "bitcoin", "btc"],
848
866
  description: "Wallet backend or common alias to make active.",
849
867
  },
850
868
  network: {
851
869
  type: "string",
852
- description: "Optional network for the selected wallet. Examples: mainnet, ethereum, base, robinhood, bitcoin.",
870
+ description: "Optional network for the selected wallet. Examples: mainnet, ethereum, base, robinhood, goat, bitcoin.",
853
871
  },
854
872
  },
855
873
  required: ["backend"],
@@ -1640,7 +1658,7 @@ const evmToolDefinitions = [
1640
1658
  {
1641
1659
  name: "set_evm_network",
1642
1660
  description:
1643
- "Select the active EVM network for subsequent wallet tool calls in this OpenClaw plugin session. Use this to switch between ethereum, base, and robinhood instead of editing code or plugin configuration.",
1661
+ "Select the active EVM network for subsequent wallet tool calls in this OpenClaw plugin session. Use this to switch between ethereum, base, robinhood, and goat instead of editing code or plugin configuration.",
1644
1662
  parameters: {
1645
1663
  type: "object",
1646
1664
  properties: {
@@ -1693,7 +1711,7 @@ const evmToolDefinitions = [
1693
1711
  },
1694
1712
  {
1695
1713
  name: "get_evm_transaction_receipt",
1696
- description: "Get the transaction receipt for a broadcast EVM transaction hash.",
1714
+ description: "Get the transaction receipt for a broadcast EVM transaction hash. On GOAT, a receipt confirms L2 inclusion; it does not by itself prove Bitcoin-backed finality.",
1697
1715
  parameters: {
1698
1716
  type: "object",
1699
1717
  properties: {
@@ -1972,7 +1990,7 @@ const evmToolDefinitions = [
1972
1990
  token_out: { type: "string" },
1973
1991
  amount_in_raw: { type: "string" },
1974
1992
  slippage_bps: { type: "integer" },
1975
- network: { type: "string", enum: EVM_CORE_NETWORKS },
1993
+ network: { type: "string", enum: EVM_UNISWAP_NETWORKS },
1976
1994
  },
1977
1995
  required: ["token_in", "token_out", "amount_in_raw"],
1978
1996
  additionalProperties: false,
@@ -1990,7 +2008,7 @@ const evmToolDefinitions = [
1990
2008
  dex_id: { type: "string" },
1991
2009
  all_chains: { type: "boolean" },
1992
2010
  limit: { type: "integer" },
1993
- network: { type: "string", enum: EVM_CORE_NETWORKS },
2011
+ network: { type: "string", enum: EVM_UNISWAP_NETWORKS },
1994
2012
  },
1995
2013
  additionalProperties: false,
1996
2014
  },
@@ -2014,7 +2032,7 @@ const evmToolDefinitions = [
2014
2032
  },
2015
2033
  page_size: { type: "integer", minimum: 1, maximum: 20 },
2016
2034
  current_page: { type: "integer", minimum: 1 },
2017
- network: { type: "string", enum: EVM_CORE_NETWORKS },
2035
+ network: { type: "string", enum: EVM_UNISWAP_NETWORKS },
2018
2036
  },
2019
2037
  required: ["protocol"],
2020
2038
  additionalProperties: false,
@@ -2028,7 +2046,7 @@ const evmToolDefinitions = [
2028
2046
  properties: {
2029
2047
  protocol: { type: "string", enum: ["V3"] },
2030
2048
  limit: { type: "integer", minimum: 1, maximum: 100 },
2031
- network: { type: "string", enum: EVM_CORE_NETWORKS },
2049
+ network: { type: "string", enum: EVM_UNISWAP_NETWORKS },
2032
2050
  },
2033
2051
  additionalProperties: false,
2034
2052
  },
@@ -2047,7 +2065,7 @@ const evmToolDefinitions = [
2047
2065
  mode: { type: "string", enum: ["preview", "prepare", "execute"] },
2048
2066
  purpose: { type: "string" },
2049
2067
  user_intent: { type: "boolean" },
2050
- network: { type: "string", enum: EVM_CORE_NETWORKS },
2068
+ network: { type: "string", enum: EVM_UNISWAP_NETWORKS },
2051
2069
  },
2052
2070
  required: ["token_in", "token_out", "amount_in_raw", "mode", "purpose"],
2053
2071
  additionalProperties: false,
@@ -2070,7 +2088,7 @@ const evmToolDefinitions = [
2070
2088
  mode: { type: "string", enum: ["preview", "prepare", "execute"] },
2071
2089
  purpose: { type: "string" },
2072
2090
  user_intent: { type: "boolean" },
2073
- network: { type: "string", enum: EVM_CORE_NETWORKS },
2091
+ network: { type: "string", enum: EVM_UNISWAP_NETWORKS },
2074
2092
  },
2075
2093
  required: ["action", "protocol", "request", "mode", "purpose"],
2076
2094
  additionalProperties: false,
@@ -2,7 +2,7 @@
2
2
  "id": "agent-wallet",
3
3
  "name": "Agent Wallet",
4
4
  "description": "Official OpenClaw plugin bridge for the agent-wallet backends, including Solana, local BTC, and local EVM.",
5
- "version": "0.1.95",
5
+ "version": "0.1.96",
6
6
  "contracts": {
7
7
  "tools": [
8
8
  "agentlayer_autonomous_approve",
@@ -100,7 +100,7 @@
100
100
  },
101
101
  "network": {
102
102
  "type": "string",
103
- "description": "Backend network selector. Solana uses mainnet. BTC uses bitcoin. EVM uses ethereum/base."
103
+ "description": "Backend network selector. Solana uses mainnet. BTC uses bitcoin. EVM uses ethereum/base/robinhood/goat."
104
104
  },
105
105
  "wdkBtcServiceUrl": {
106
106
  "type": "string",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentlayertech/agent-wallet-plugin",
3
- "version": "0.1.95",
3
+ "version": "0.1.96",
4
4
  "description": "OpenClaw plugin bridge for the AgentLayer wallet runtime.",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN ../../../LICENSE",
package/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.95
1
+ 0.1.96
@@ -383,8 +383,8 @@ For the local EVM backend (`backend=wdk_evm_local`), the lifecycle mirrors the B
383
383
  - `agent-wallet` talks to it through a local bearer token loaded from `~/.openclaw/wdk-evm-wallet/local-auth-token`
384
384
  - `agent-wallet` stores only a per-user EVM wallet binding under `~/.openclaw/users/<normalized-user-id>/wallets/evm-<network>-agent.json`
385
385
  - 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`
386
- - supported EVM networks are `ethereum` and `base`
387
- - 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
386
+ - supported EVM networks are `ethereum`, `base`, `robinhood`, and `goat`
387
+ - OpenClaw-facing EVM core read and transfer tools accept an optional per-call `network` override for those mainnet networks, so the agent can switch without editing host config. GOAT uses BTC as its 18-decimal native gas asset; token discovery is intentionally native-only until a reviewed GOAT indexer is added, while explicit ERC-20 balance and metadata reads remain available.
388
388
  - 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
389
389
  - 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
390
390
  - you can manage that binding through `agent_wallet.openclaw_cli`:
@@ -406,7 +406,7 @@ That wrapper:
406
406
  - defaults to `http://127.0.0.1:8081`
407
407
  - can auto-start `wdk-evm-wallet/run-local.sh` if the local service is not already healthy
408
408
  - creates or unlocks the local EVM wallet binding
409
- - also binds the paired EVM network by default: `ethereum <-> base`
409
+ - also binds the paired EVM network by default: `ethereum <-> base` (GOAT remains an independent EVM network binding)
410
410
  - 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
411
411
  - patches OpenClaw config to `backend=wdk_evm_local`
412
412
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Keep in sync with package.json, pyproject.toml, and the npm installer version.
4
4
  # scripts/check_release_version.mjs enforces this on release.
5
- __version__ = "0.1.95"
5
+ __version__ = "0.1.96"
6
6
 
7
7
  __all__ = [
8
8
  "config",
@@ -37,6 +37,7 @@ from dataclasses import dataclass, field
37
37
  from typing import Callable
38
38
 
39
39
  from agent_wallet.approval import issue_approval_token
40
+ from agent_wallet.networks import AUTONOMOUS_MAINNET_NETWORKS
40
41
  from agent_wallet.spending_limits import SpendingConfig, SpendingLedger
41
42
  from agent_wallet.wallet_layer.base import WalletBackendError
42
43
 
@@ -46,7 +47,7 @@ AUTONOMOUS_ISSUER = "autonomous-policy"
46
47
 
47
48
  #: Networks treated as "real money" and therefore gated behind
48
49
  #: ``allow_mainnet`` regardless of the per-tool allow-list.
49
- MAINNET_NETWORKS = frozenset({"mainnet", "mainnet-beta", "ethereum", "base", "robinhood", "arbitrum", "optimism", "polygon"})
50
+ MAINNET_NETWORKS = AUTONOMOUS_MAINNET_NETWORKS
50
51
 
51
52
  TokenIssuer = Callable[..., str]
52
53
 
@@ -7,6 +7,8 @@ from typing import Iterator
7
7
 
8
8
  from pydantic_settings import BaseSettings
9
9
 
10
+ from agent_wallet.networks import EVM_CORE_MAINNETS, EVM_CORE_NETWORK_ALIASES, EVM_CORE_TESTNETS
11
+
10
12
  PACKAGE_ROOT = Path(__file__).resolve().parents[1]
11
13
  DEFAULT_PROVIDER_GATEWAY_URL = "https://agent-layer-production.up.railway.app"
12
14
 
@@ -112,24 +114,18 @@ def normalize_solana_network(network: str | None) -> str:
112
114
  def normalize_evm_network(network: str | None) -> str:
113
115
  """Canonicalize supported EVM network names and reject testnets."""
114
116
  normalized = str(network or "").strip().lower() or "ethereum"
115
- aliases = {
116
- "mainnet": "ethereum",
117
- "eth": "ethereum",
118
- "eth-mainnet": "ethereum",
119
- "base-mainnet": "base",
120
- }
121
- normalized = aliases.get(normalized, normalized)
122
- if normalized in {"sepolia", "base-sepolia", "base_sepolia"}:
117
+ normalized = EVM_CORE_NETWORK_ALIASES.get(normalized, normalized)
118
+ if normalized in EVM_CORE_TESTNETS:
123
119
  from agent_wallet.wallet_layer.base import WalletBackendError
124
120
 
125
121
  raise WalletBackendError(
126
- "EVM testnets are no longer supported by agent-wallet. Use ethereum, base, or robinhood."
122
+ "EVM testnets are no longer supported by agent-wallet. Use ethereum, base, robinhood, or goat."
127
123
  )
128
- if normalized not in {"ethereum", "base", "robinhood"}:
124
+ if normalized not in EVM_CORE_MAINNETS:
129
125
  from agent_wallet.wallet_layer.base import WalletBackendError
130
126
 
131
127
  raise WalletBackendError(
132
- f"Unsupported EVM network: {normalized}. Use ethereum, base, or robinhood."
128
+ f"Unsupported EVM network: {normalized}. Use ethereum, base, robinhood, or goat."
133
129
  )
134
130
  return normalized
135
131
 
@@ -0,0 +1,25 @@
1
+ """Canonical network identifiers used by agent-wallet policy gates.
2
+
3
+ The Python wallet backend owns approval and autonomous-execution policy. Keep
4
+ the selectable EVM network set and its mainnet identities here so additions
5
+ cannot silently reach one policy gate but miss another.
6
+ """
7
+
8
+ EVM_CORE_MAINNETS = frozenset({"ethereum", "base", "robinhood", "goat"})
9
+ EVM_CORE_NETWORK_ALIASES = {
10
+ "mainnet": "ethereum",
11
+ "eth": "ethereum",
12
+ "eth-mainnet": "ethereum",
13
+ "base-mainnet": "base",
14
+ "goat-mainnet": "goat",
15
+ }
16
+ EVM_CORE_TESTNETS = frozenset({"sepolia", "base-sepolia", "base_sepolia", "goat-testnet", "goat-testnet3"})
17
+ EVM_CORE_MAINNET_CAIP_IDS = frozenset({"eip155:1", "eip155:8453", "eip155:4663", "eip155:2345"})
18
+ GOAT_EVM_NETWORK_IDENTIFIERS = frozenset({"goat", "goat-mainnet", "eip155:2345"})
19
+
20
+ # The autonomous engine may also govern legacy supported operation classes
21
+ # outside the selectable EVM wallet surface. Keep that superset derived from
22
+ # the core EVM mainnet definition rather than re-listing its members.
23
+ AUTONOMOUS_MAINNET_NETWORKS = frozenset(
24
+ {"mainnet", "mainnet-beta", "arbitrum", "optimism", "polygon"} | EVM_CORE_MAINNETS
25
+ )
@@ -11,6 +11,13 @@ from agent_wallet.approval import inspect_approval_token, verify_approval_token
11
11
  from agent_wallet.autonomous_policy import OperationRequest
12
12
  from agent_wallet.exceptions import ProviderError
13
13
  from agent_wallet.models import AgentToolResult, AgentToolSpec
14
+ from agent_wallet.networks import (
15
+ EVM_CORE_MAINNET_CAIP_IDS,
16
+ EVM_CORE_MAINNETS,
17
+ EVM_CORE_NETWORK_ALIASES,
18
+ EVM_CORE_TESTNETS,
19
+ GOAT_EVM_NETWORK_IDENTIFIERS,
20
+ )
14
21
  from agent_wallet.providers import x402
15
22
  from agent_wallet.wallet_layer.base import AgentWalletBackend, WalletBackendError
16
23
 
@@ -74,7 +81,7 @@ class OpenClawWalletAdapter:
74
81
  if chain == "bitcoin":
75
82
  return normalized == "bitcoin"
76
83
  if chain == "evm":
77
- return normalized in {"ethereum", "base", "robinhood", "eip155:1", "eip155:8453", "eip155:4663"}
84
+ return normalized in EVM_CORE_MAINNETS | EVM_CORE_MAINNET_CAIP_IDS
78
85
  if chain == "solana":
79
86
  return normalized in {"mainnet", "solana:5eykt4usfv8p8njdtrepy1vzkqzkvdp"}
80
87
  return normalized == "mainnet"
@@ -85,6 +92,10 @@ class OpenClawWalletAdapter:
85
92
  def _is_mainnet_for_backend(self, backend: AgentWalletBackend) -> bool:
86
93
  return self._is_mainnet_network(getattr(backend, "network", ""))
87
94
 
95
+ @staticmethod
96
+ def _is_goat_evm_network(network: Any) -> bool:
97
+ return str(network or "").strip().lower() in GOAT_EVM_NETWORK_IDENTIFIERS
98
+
88
99
  def _supports_evm_velora(self) -> bool:
89
100
  return str(getattr(self.backend, "chain", "")).strip().lower() == "evm" and self._is_mainnet()
90
101
 
@@ -93,17 +104,13 @@ class OpenClawWalletAdapter:
93
104
 
94
105
  def _normalize_evm_tool_network(self, value: Any) -> str:
95
106
  network = str(value or "").strip().lower()
96
- aliases = {
97
- "mainnet": "ethereum",
98
- "eth": "ethereum",
99
- "eth-mainnet": "ethereum",
100
- "base-mainnet": "base",
101
- }
102
- network = aliases.get(network, network)
103
- if network in {"sepolia", "base-sepolia", "base_sepolia"}:
104
- raise WalletBackendError("EVM testnets are no longer supported. Use ethereum, base, or robinhood.")
105
- if network not in {"ethereum", "base", "robinhood"}:
106
- raise WalletBackendError("EVM network must be 'ethereum', 'base', or 'robinhood'.")
107
+ network = EVM_CORE_NETWORK_ALIASES.get(network, network)
108
+ if network in EVM_CORE_TESTNETS:
109
+ raise WalletBackendError(
110
+ "EVM testnets are no longer supported. Use ethereum, base, robinhood, or goat."
111
+ )
112
+ if network not in EVM_CORE_MAINNETS:
113
+ raise WalletBackendError("EVM network must be 'ethereum', 'base', 'robinhood', or 'goat'.")
107
114
  return network
108
115
 
109
116
  def _resolve_backend_for_args(self, args: dict[str, Any]) -> AgentWalletBackend:
@@ -1229,7 +1236,7 @@ class OpenClawWalletAdapter:
1229
1236
  "properties": {
1230
1237
  "network": {
1231
1238
  "type": "string",
1232
- "enum": ["ethereum", "base", "robinhood"],
1239
+ "enum": ["ethereum", "base", "robinhood", "goat"],
1233
1240
  "description": "Optional EVM network override for this request.",
1234
1241
  },
1235
1242
  },
@@ -1246,7 +1253,7 @@ class OpenClawWalletAdapter:
1246
1253
  "properties": {
1247
1254
  "network": {
1248
1255
  "type": "string",
1249
- "enum": ["ethereum", "base", "robinhood"],
1256
+ "enum": ["ethereum", "base", "robinhood", "goat"],
1250
1257
  "description": "Optional EVM network override for this request.",
1251
1258
  },
1252
1259
  },
@@ -1271,7 +1278,7 @@ class OpenClawWalletAdapter:
1271
1278
  },
1272
1279
  "network": {
1273
1280
  "type": "string",
1274
- "enum": ["ethereum", "base", "robinhood"],
1281
+ "enum": ["ethereum", "base", "robinhood", "goat"],
1275
1282
  "description": "Optional EVM network override for this request.",
1276
1283
  },
1277
1284
  },
@@ -1352,7 +1359,7 @@ class OpenClawWalletAdapter:
1352
1359
  "properties": {
1353
1360
  "network": {
1354
1361
  "type": "string",
1355
- "enum": ["ethereum", "base", "robinhood"],
1362
+ "enum": ["ethereum", "base", "robinhood", "goat"],
1356
1363
  "description": "Optional EVM network override for this request.",
1357
1364
  },
1358
1365
  },
@@ -1365,7 +1372,7 @@ class OpenClawWalletAdapter:
1365
1372
  name="set_evm_network",
1366
1373
  description=(
1367
1374
  "Select the active EVM network for subsequent wallet tool calls in this "
1368
- "runtime session. Use this to switch between ethereum, base, and robinhood instead "
1375
+ "runtime session. Use this to switch between ethereum, base, robinhood, and goat instead "
1369
1376
  "of editing code or plugin configuration."
1370
1377
  ),
1371
1378
  input_schema={
@@ -1373,7 +1380,7 @@ class OpenClawWalletAdapter:
1373
1380
  "properties": {
1374
1381
  "network": {
1375
1382
  "type": "string",
1376
- "enum": ["ethereum", "base", "robinhood"],
1383
+ "enum": ["ethereum", "base", "robinhood", "goat"],
1377
1384
  "description": "EVM network to make active for subsequent calls.",
1378
1385
  },
1379
1386
  },
@@ -1395,7 +1402,7 @@ class OpenClawWalletAdapter:
1395
1402
  },
1396
1403
  "network": {
1397
1404
  "type": "string",
1398
- "enum": ["ethereum", "base", "robinhood"],
1405
+ "enum": ["ethereum", "base", "robinhood", "goat"],
1399
1406
  "description": "Optional EVM network override for this request.",
1400
1407
  },
1401
1408
  },
@@ -1417,7 +1424,7 @@ class OpenClawWalletAdapter:
1417
1424
  },
1418
1425
  "network": {
1419
1426
  "type": "string",
1420
- "enum": ["ethereum", "base", "robinhood"],
1427
+ "enum": ["ethereum", "base", "robinhood", "goat"],
1421
1428
  "description": "Optional EVM network override for this request.",
1422
1429
  },
1423
1430
  },
@@ -1435,7 +1442,7 @@ class OpenClawWalletAdapter:
1435
1442
  "properties": {
1436
1443
  "network": {
1437
1444
  "type": "string",
1438
- "enum": ["ethereum", "base", "robinhood"],
1445
+ "enum": ["ethereum", "base", "robinhood", "goat"],
1439
1446
  "description": "Optional EVM network override for this request.",
1440
1447
  },
1441
1448
  },
@@ -1446,7 +1453,10 @@ class OpenClawWalletAdapter:
1446
1453
  ),
1447
1454
  AgentToolSpec(
1448
1455
  name="get_evm_transaction_receipt",
1449
- description="Get the transaction receipt for a broadcast EVM transaction hash.",
1456
+ description=(
1457
+ "Get the transaction receipt for a broadcast EVM transaction hash. On GOAT, a receipt "
1458
+ "confirms L2 inclusion; it does not by itself prove Bitcoin-backed finality."
1459
+ ),
1450
1460
  input_schema={
1451
1461
  "type": "object",
1452
1462
  "properties": {
@@ -1456,7 +1466,7 @@ class OpenClawWalletAdapter:
1456
1466
  },
1457
1467
  "network": {
1458
1468
  "type": "string",
1459
- "enum": ["ethereum", "base", "robinhood"],
1469
+ "enum": ["ethereum", "base", "robinhood", "goat"],
1460
1470
  "description": "Optional EVM network override for this request.",
1461
1471
  },
1462
1472
  },
@@ -1489,7 +1499,7 @@ class OpenClawWalletAdapter:
1489
1499
  "approval_token": {"type": "string"},
1490
1500
  "network": {
1491
1501
  "type": "string",
1492
- "enum": ["ethereum", "base", "robinhood"],
1502
+ "enum": ["ethereum", "base", "robinhood", "goat"],
1493
1503
  "description": "Optional EVM network override for this request.",
1494
1504
  },
1495
1505
  },
@@ -1524,7 +1534,7 @@ class OpenClawWalletAdapter:
1524
1534
  "approval_token": {"type": "string"},
1525
1535
  "network": {
1526
1536
  "type": "string",
1527
- "enum": ["ethereum", "base", "robinhood"],
1537
+ "enum": ["ethereum", "base", "robinhood", "goat"],
1528
1538
  "description": "Optional EVM network override for this request.",
1529
1539
  },
1530
1540
  },
@@ -4320,6 +4330,14 @@ class OpenClawWalletAdapter:
4320
4330
  return AgentToolResult(tool=tool_name, ok=True, data=data)
4321
4331
 
4322
4332
  if tool_name == "x402_pay_request":
4333
+ if (
4334
+ str(getattr(active_backend, "chain", "")).strip().lower() == "evm"
4335
+ and self._is_goat_evm_network(getattr(active_backend, "network", ""))
4336
+ ):
4337
+ raise WalletBackendError(
4338
+ "GOAT x402 payments are not enabled in this wallet surface. "
4339
+ "Use the supported core GOAT wallet operations instead."
4340
+ )
4323
4341
  url = args.get("url")
4324
4342
  method = args.get("method", "GET")
4325
4343
  headers = args.get("headers")
@@ -117,6 +117,7 @@ TOKEN_METADATA: dict[str, dict[str, dict[str, Any]]] = {
117
117
  }
118
118
 
119
119
  COINGECKO_IDS = {
120
+ "BTC": "bitcoin",
120
121
  "ETH": "ethereum",
121
122
  "WETH": "ethereum",
122
123
  "USDC": "usd-coin",
@@ -142,7 +143,7 @@ _PRICE_CACHE: dict[str, tuple[float, float]] = {}
142
143
 
143
144
  def _normalize_network(network: str) -> str:
144
145
  normalized = str(network or "").strip().lower()
145
- if normalized not in {"ethereum", "base", "robinhood"}:
146
+ if normalized not in {"ethereum", "base", "robinhood", "goat"}:
146
147
  raise ProviderError("evm-portfolio", f"Unsupported EVM portfolio network: {network}")
147
148
  return normalized
148
149
 
@@ -207,7 +208,7 @@ async def _gateway_rpc_call(network: str, method: str, params: list[Any]) -> dic
207
208
  if not gateway_url:
208
209
  raise ProviderError(
209
210
  "evm-portfolio",
210
- "Provider gateway URL is required for EVM portfolio lookup on ethereum/base/robinhood.",
211
+ "Provider gateway URL is required for EVM portfolio lookup on supported EVM networks.",
211
212
  )
212
213
  try:
213
214
  response = await client.post(
@@ -230,6 +231,12 @@ async def _gateway_rpc_call(network: str, method: str, params: list[Any]) -> dic
230
231
 
231
232
  async def fetch_token_balances(address: str, network: str) -> list[dict[str, Any]]:
232
233
  normalized_network = _normalize_network(network)
234
+ # GOAT uses the shared RPC gateway rather than Alchemy. Its upstream does
235
+ # not provide Alchemy's account-wide ERC-20 index, so return a truthful
236
+ # native-only portfolio. Explicit per-token balance and metadata tools keep
237
+ # working through ordinary EVM RPC calls.
238
+ if normalized_network == "goat":
239
+ return []
233
240
  cache_key = f"{normalized_network}:{address.lower()}"
234
241
  cached = _cache_get_token_balances(cache_key)
235
242
  if cached is not None:
@@ -668,7 +668,7 @@ class WdkEvmLocalWalletBackend(AgentWalletBackend):
668
668
  "configured_network": self.network,
669
669
  "service_active_network": str(data.get("activeNetwork") or "").strip() or None,
670
670
  "available_networks": sorted(str(key) for key in profiles.keys()),
671
- "agent_selectable_networks": ["ethereum", "base", "robinhood"],
671
+ "agent_selectable_networks": ["ethereum", "base", "robinhood", "goat"],
672
672
  "swap_supported_networks": ["ethereum", "base", "robinhood"],
673
673
  "network_profiles": {
674
674
  str(network): {
@@ -2,7 +2,7 @@
2
2
  "id": "agent-wallet",
3
3
  "name": "Agent Wallet",
4
4
  "description": "Plugin-friendly wallet backend for OpenClaw agents with safe wallet tools and runtime instructions across Solana, local BTC, and local EVM.",
5
- "version": "0.1.95",
5
+ "version": "0.1.96",
6
6
  "skills": ["skills/wallet-operator"],
7
7
  "configSchema": {
8
8
  "type": "object",
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "openclaw-agent-wallet"
7
- version = "0.1.95"
7
+ version = "0.1.96"
8
8
  description = "Plugin-friendly wallet backend for OpenClaw agents"
9
9
  requires-python = ">=3.10"
10
10
  dependencies = [
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agent-wallet",
3
3
  "displayName": "Agent Wallet",
4
- "version": "0.1.95",
4
+ "version": "0.1.96",
5
5
  "description": "Claude Code bridge for the existing AgentLayer wallet runtime. Connects to Solana, Bitcoin, and EVM wallets without creating a new one.",
6
6
  "author": {
7
7
  "name": "AgentLayer"
@@ -41,11 +41,11 @@ See the sections below for exact tool names and parameters.
41
41
  2. `get_wallet_address` — the address for the active backend.
42
42
  3. `get_wallet_capabilities` — chain, backend, and the safety limits in force.
43
43
  4. `set_wallet_backend` (`backend`: solana / evm / ethereum / base /
44
- robinhood / btc / bitcoin, optional `network`) — switch backend for this
44
+ robinhood / goat / btc / bitcoin, optional `network`) — switch backend for this
45
45
  session without touching config files.
46
46
  5. For EVM specifically: `get_evm_network` shows the effective network and
47
47
  which networks support swaps; `set_evm_network` (ethereum / base /
48
- robinhood) changes it.
48
+ robinhood / goat) changes it.
49
49
 
50
50
  Balance reads (Solana): `get_wallet_balance` / `get_wallet_portfolio` are the
51
51
  same enriched payload (native SOL + non-zero SPL accounts + USD pricing via
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-wallet",
3
- "version": "0.1.95",
3
+ "version": "0.1.96",
4
4
  "description": "Codex plugin bridge for the AgentLayer wallet runtime.",
5
5
  "author": {
6
6
  "name": "AgentLayer"
@@ -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 robinhood.")
415
- if network not in {"ethereum", "base", "robinhood"}:
416
- raise RuntimeError("EVM network must be 'ethereum', 'base', or 'robinhood'.")
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 robinhood for EVM.",
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 robinhood."
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 robinhood.",
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 robinhood.
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.
@@ -1,5 +1,5 @@
1
1
  name: agent-wallet
2
- version: 0.1.95
2
+ version: 0.1.96
3
3
  description: Thin Hermes Agent bridge to the existing AgentLayer/OpenClaw wallet backend
4
4
  provides_tools:
5
5
  - agent_wallet_tools
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentlayer.tech/wallet",
3
- "version": "0.1.95",
3
+ "version": "0.1.96",
4
4
  "description": "Universal AgentLayer wallet installer for OpenClaw, Codex, Claude Code, and Hermes.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wdk-btc-wallet",
3
- "version": "0.1.95",
3
+ "version": "0.1.96",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "Separate BTC-only wallet service built on Tether WDK.",
@@ -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
- # Direct per-network URLs below are only relevant for testnet-style paths.
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=
@@ -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 `base` mainnet are always routed through the provider gateway raw EVM RPC route
231
- - `ethereum` and `base` mainnet are pinned to the gateway `provider=alchemy` path
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
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wdk-evm-wallet",
3
- "version": "0.1.95",
3
+ "version": "0.1.96",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "Separate EVM wallet service built on Tether WDK.",
@@ -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
- "alchemy",
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 (!["ethereum", "sepolia", "base", "base-sepolia", "robinhood"].includes(effective)) {
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;
@@ -602,11 +602,17 @@ function assertValidNetwork(network, fieldName = "network") {
602
602
  "base-mainnet": "base",
603
603
  base_sepolia: "base-sepolia",
604
604
  "robinhood-mainnet": "robinhood",
605
+ "goat-mainnet": "goat",
606
+ "goat-testnet3": "goat-testnet",
605
607
  };
606
608
  const effective = aliases[normalized] || normalized;
607
- if (!["ethereum", "sepolia", "base", "base-sepolia", "robinhood"].includes(effective)) {
609
+ if (
610
+ !["ethereum", "sepolia", "base", "base-sepolia", "robinhood", "goat", "goat-testnet"].includes(
611
+ effective
612
+ )
613
+ ) {
608
614
  throw new Error(
609
- `${fieldName} must be one of: ethereum, sepolia, base, base-sepolia, robinhood.`
615
+ `${fieldName} must be one of: ethereum, sepolia, base, base-sepolia, robinhood, goat, goat-testnet.`
610
616
  );
611
617
  }
612
618
  return effective;