@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.
- package/.openclaw/extensions/agent-wallet/README.md +2 -2
- package/.openclaw/extensions/agent-wallet/dist/index.js +33 -15
- package/.openclaw/extensions/agent-wallet/index.ts +33 -15
- package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +2 -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 +43 -25
- package/agent-wallet/agent_wallet/providers/evm_portfolio.py +9 -2
- package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +1 -1
- package/agent-wallet/openclaw.plugin.json +1 -1
- package/agent-wallet/pyproject.toml +1 -1
- package/claude-code/plugins/agent-wallet/.claude-plugin/plugin.json +1 -1
- package/claude-code/plugins/agent-wallet/AGENTLAYER_AGENT_GUIDE.md +2 -2
- 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/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 `
|
|
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
|
|
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
|
|
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 '
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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 '
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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.
|
|
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",
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.96
|
package/agent-wallet/README.md
CHANGED
|
@@ -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 `
|
|
387
|
-
- OpenClaw-facing EVM tools accept an optional per-call `network` override for
|
|
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
|
|
|
@@ -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 =
|
|
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
|
-
|
|
116
|
-
|
|
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
|
|
122
|
+
"EVM testnets are no longer supported by agent-wallet. Use ethereum, base, robinhood, or goat."
|
|
127
123
|
)
|
|
128
|
-
if normalized not in
|
|
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
|
|
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
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
|
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=
|
|
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
|
|
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.
|
|
5
|
+
"version": "0.1.96",
|
|
6
6
|
"skills": ["skills/wallet-operator"],
|
|
7
7
|
"configSchema": {
|
|
8
8
|
"type": "object",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-wallet",
|
|
3
3
|
"displayName": "Agent Wallet",
|
|
4
|
-
"version": "0.1.
|
|
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
|
|
@@ -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;
|
|
@@ -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 (
|
|
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;
|