@elizaos/plugin-wallet 2.0.0-beta.1
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/LICENSE +21 -0
- package/README.md +64 -0
- package/auto-enable.ts +76 -0
- package/dist/LpManagementService-BWrQ5-cO.mjs +353 -0
- package/dist/MockLpService-D_Apn4Fd.mjs +99 -0
- package/dist/aerodrome-CfnESC32.mjs +890 -0
- package/dist/chunk-hT5z_Zn9.mjs +35 -0
- package/dist/index.d.mts +34727 -0
- package/dist/index.mjs +21590 -0
- package/dist/lib/server-wallet-trade.d.mts +34 -0
- package/dist/lib/server-wallet-trade.mjs +306 -0
- package/dist/meteora-BPX39hZo.mjs +22640 -0
- package/dist/orca-Bybp1HXO.mjs +249 -0
- package/dist/pancakeswp-CkEXlXti.mjs +604 -0
- package/dist/plugin-ZO_MTyd0.mjs +529 -0
- package/dist/raydium-rfaM9yEf.mjs +539 -0
- package/dist/sdk/index.d.mts +32492 -0
- package/dist/sdk/index.mjs +6415 -0
- package/dist/types-D5252NZk.mjs +487 -0
- package/dist/uniswap-CReXgXVN.mjs +573 -0
- package/dist/wallet-action.d.mts +6 -0
- package/dist/wallet-action.mjs +820 -0
- package/package.json +152 -0
- package/src/actions/failure-codes.ts +79 -0
- package/src/actions/index.ts +1 -0
- package/src/analytics/birdeye/actions/wallet-search-address.ts +9 -0
- package/src/analytics/birdeye/birdeye-task.ts +175 -0
- package/src/analytics/birdeye/birdeye.ts +813 -0
- package/src/analytics/birdeye/constants.ts +74 -0
- package/src/analytics/birdeye/providers/agent-portfolio-provider.ts +18 -0
- package/src/analytics/birdeye/providers/market.ts +227 -0
- package/src/analytics/birdeye/providers/portfolio-factory.test.ts +138 -0
- package/src/analytics/birdeye/providers/portfolio-factory.ts +252 -0
- package/src/analytics/birdeye/providers/trending.ts +365 -0
- package/src/analytics/birdeye/providers/wallet.ts +14 -0
- package/src/analytics/birdeye/search-category.test.ts +207 -0
- package/src/analytics/birdeye/search-category.ts +506 -0
- package/src/analytics/birdeye/service.ts +992 -0
- package/src/analytics/birdeye/tasks/birdeye.ts +232 -0
- package/src/analytics/birdeye/types/api/common.ts +305 -0
- package/src/analytics/birdeye/types/api/defi.ts +220 -0
- package/src/analytics/birdeye/types/api/pair.ts +200 -0
- package/src/analytics/birdeye/types/api/search.ts +86 -0
- package/src/analytics/birdeye/types/api/token.ts +635 -0
- package/src/analytics/birdeye/types/api/trader.ts +76 -0
- package/src/analytics/birdeye/types/api/wallet.ts +181 -0
- package/src/analytics/birdeye/types/shared.ts +106 -0
- package/src/analytics/birdeye/utils.ts +700 -0
- package/src/analytics/dexscreener/errors.ts +28 -0
- package/src/analytics/dexscreener/index.ts +3 -0
- package/src/analytics/dexscreener/search-category.test.ts +49 -0
- package/src/analytics/dexscreener/search-category.ts +42 -0
- package/src/analytics/dexscreener/service.ts +595 -0
- package/src/analytics/dexscreener/types.ts +128 -0
- package/src/analytics/lpinfo/index.d.ts +7 -0
- package/src/analytics/lpinfo/index.ts +52 -0
- package/src/analytics/lpinfo/kamino/README.md +102 -0
- package/src/analytics/lpinfo/kamino/index.ts +24 -0
- package/src/analytics/lpinfo/kamino/providers/kaminoLiquidityProvider.ts +422 -0
- package/src/analytics/lpinfo/kamino/providers/kaminoPoolProvider.ts +365 -0
- package/src/analytics/lpinfo/kamino/providers/kaminoProvider.ts +496 -0
- package/src/analytics/lpinfo/kamino/services/kaminoLiquidityService.ts +1123 -0
- package/src/analytics/lpinfo/kamino/services/kaminoService.ts +758 -0
- package/src/analytics/lpinfo/steer/README.md +169 -0
- package/src/analytics/lpinfo/steer/index.ts +23 -0
- package/src/analytics/lpinfo/steer/providers/steerLiquidityProvider.ts +544 -0
- package/src/analytics/lpinfo/steer/services/steerLiquidityService.ts +1690 -0
- package/src/analytics/lpinfo/steer/steer-display-types.ts +99 -0
- package/src/analytics/news/index.ts +52 -0
- package/src/analytics/news/interfaces/types.ts +222 -0
- package/src/analytics/news/providers/defiNewsProvider.ts +734 -0
- package/src/analytics/news/services/newsDataService.ts +332 -0
- package/src/analytics/news/utils/formatters.ts +151 -0
- package/src/analytics/token-info/action.ts +240 -0
- package/src/analytics/token-info/index.ts +3 -0
- package/src/analytics/token-info/params.ts +215 -0
- package/src/analytics/token-info/providers.ts +681 -0
- package/src/analytics/token-info/service.ts +168 -0
- package/src/analytics/token-info/types.ts +74 -0
- package/src/audit/audit-log.ts +45 -0
- package/src/browser-shim/build-shim.ts +123 -0
- package/src/browser-shim/index.ts +5 -0
- package/src/browser-shim/shim.template.js +563 -0
- package/src/chains/evm/.github/workflows/npm-deploy.yml +112 -0
- package/src/chains/evm/LICENSE +21 -0
- package/src/chains/evm/README.md +106 -0
- package/src/chains/evm/actions/helpers.ts +147 -0
- package/src/chains/evm/actions/swap.ts +839 -0
- package/src/chains/evm/actions/transfer.ts +254 -0
- package/src/chains/evm/biome.json +61 -0
- package/src/chains/evm/bridge-router.ts +660 -0
- package/src/chains/evm/build.ts +89 -0
- package/src/chains/evm/chain-handler.ts +416 -0
- package/src/chains/evm/constants.ts +23 -0
- package/src/chains/evm/contracts/artifacts/OZGovernor.json +1707 -0
- package/src/chains/evm/contracts/artifacts/TimelockController.json +1007 -0
- package/src/chains/evm/contracts/artifacts/VoteToken.json +895 -0
- package/src/chains/evm/dex/aerodrome/index.ts +34 -0
- package/src/chains/evm/dex/aerodrome/services/AerodromeLpService.ts +558 -0
- package/src/chains/evm/dex/aerodrome/types.ts +318 -0
- package/src/chains/evm/dex/pancakeswp/index.ts +35 -0
- package/src/chains/evm/dex/pancakeswp/services/PancakeSwapV3LpService.ts +743 -0
- package/src/chains/evm/dex/pancakeswp/types.ts +65 -0
- package/src/chains/evm/dex/uniswap/index.ts +35 -0
- package/src/chains/evm/dex/uniswap/services/UniswapV3LpService.ts +759 -0
- package/src/chains/evm/dex/uniswap/types.ts +390 -0
- package/src/chains/evm/generated/specs/spec-helpers.ts +73 -0
- package/src/chains/evm/generated/specs/specs.ts +151 -0
- package/src/chains/evm/gov-router.ts +250 -0
- package/src/chains/evm/index.browser.ts +16 -0
- package/src/chains/evm/index.ts +31 -0
- package/src/chains/evm/prompts.ts +193 -0
- package/src/chains/evm/providers/get-balance.ts +123 -0
- package/src/chains/evm/providers/wallet.ts +715 -0
- package/src/chains/evm/routes/sign.ts +333 -0
- package/src/chains/evm/rpc-providers.ts +410 -0
- package/src/chains/evm/service.ts +140 -0
- package/src/chains/evm/templates/index.ts +10 -0
- package/src/chains/evm/types/index.ts +432 -0
- package/src/chains/evm/vitest.config.ts +18 -0
- package/src/chains/registry.ts +668 -0
- package/src/chains/solana/README.md +367 -0
- package/src/chains/wallet-action.ts +533 -0
- package/src/chains/wallet-router.test.ts +296 -0
- package/src/contracts.ts +65 -0
- package/src/core-augmentation.ts +10 -0
- package/src/index.ts +71 -0
- package/src/lib/server-wallet-trade.ts +192 -0
- package/src/lib/wallet-export-guard.ts +330 -0
- package/src/lp/actions/liquidity.ts +827 -0
- package/src/lp/e2e/real-token-tests.ts +428 -0
- package/src/lp/e2e/scenarios.ts +470 -0
- package/src/lp/e2e/test-utils.ts +145 -0
- package/src/lp/lp-manager-entry.ts +303 -0
- package/src/lp/services/ConcentratedLiquidityService.ts +120 -0
- package/src/lp/services/DexInteractionService.ts +226 -0
- package/src/lp/services/LpManagementService.test.ts +148 -0
- package/src/lp/services/LpManagementService.ts +632 -0
- package/src/lp/services/UserLpProfileService.ts +163 -0
- package/src/lp/services/VaultService.ts +153 -0
- package/src/lp/services/YieldOptimizationService.ts +344 -0
- package/src/lp/services/__tests__/MockLpService.ts +146 -0
- package/src/lp/tasks/LpAutoRebalanceTask.ts +117 -0
- package/src/lp/tasks/__tests__/LpAutoRebalanceTask.test.ts +370 -0
- package/src/lp/types.ts +582 -0
- package/src/lp/utils/solanaClient.ts +143 -0
- package/src/plugin.ts +125 -0
- package/src/policy/policy.ts +19 -0
- package/src/providers/canonical-provider.ts +27 -0
- package/src/providers/unified-wallet-provider.ts +79 -0
- package/src/register-routes.ts +11 -0
- package/src/routes/plugin.ts +47 -0
- package/src/routes/wallet-market-overview-route.ts +869 -0
- package/src/sdk/abi.ts +258 -0
- package/src/sdk/bridge/abis.ts +126 -0
- package/src/sdk/bridge/client.ts +518 -0
- package/src/sdk/bridge/index.ts +56 -0
- package/src/sdk/bridge/solana.ts +604 -0
- package/src/sdk/bridge/types.ts +202 -0
- package/src/sdk/convenience.ts +347 -0
- package/src/sdk/escrow/MutualStakeEscrow.ts +480 -0
- package/src/sdk/escrow/types.ts +64 -0
- package/src/sdk/escrow/verifiers.ts +73 -0
- package/src/sdk/identity/erc8004.ts +692 -0
- package/src/sdk/identity/reputation.ts +449 -0
- package/src/sdk/identity/uaid.ts +497 -0
- package/src/sdk/identity/validation.ts +372 -0
- package/src/sdk/index.ts +763 -0
- package/src/sdk/policy/SpendingPolicy.ts +260 -0
- package/src/sdk/policy/UptoBillingPolicy.ts +320 -0
- package/src/sdk/router/PaymentRouter.ts +215 -0
- package/src/sdk/router/index.ts +8 -0
- package/src/sdk/swap/SwapModule.ts +310 -0
- package/src/sdk/swap/abi.ts +117 -0
- package/src/sdk/swap/index.ts +34 -0
- package/src/sdk/swap/types.ts +135 -0
- package/src/sdk/tokens/decimals.ts +140 -0
- package/src/sdk/tokens/registry.ts +911 -0
- package/src/sdk/tokens/solana.ts +419 -0
- package/src/sdk/tokens/transfers.ts +327 -0
- package/src/sdk/types.ts +158 -0
- package/src/sdk/wallet-core.ts +115 -0
- package/src/sdk/x402/budget.ts +168 -0
- package/src/sdk/x402/chains/abstract/index.ts +280 -0
- package/src/sdk/x402/client.ts +320 -0
- package/src/sdk/x402/index.ts +46 -0
- package/src/sdk/x402/middleware.ts +92 -0
- package/src/sdk/x402/multi-asset.ts +144 -0
- package/src/sdk/x402/types.ts +156 -0
- package/src/services/wallet-backend-service.ts +328 -0
- package/src/types/wallet-router.ts +227 -0
- package/src/utils/intent-trajectory.ts +106 -0
- package/src/wallet/backend.ts +62 -0
- package/src/wallet/errors.ts +49 -0
- package/src/wallet/index.ts +27 -0
- package/src/wallet/local-eoa-backend.ts +201 -0
- package/src/wallet/pending.ts +60 -0
- package/src/wallet/select-backend.ts +47 -0
- package/src/wallet/steward-backend.ts +161 -0
- package/src/wallet-action.ts +1 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module x402/types
|
|
3
|
+
* x402 protocol type definitions and well-known asset constants.
|
|
4
|
+
*
|
|
5
|
+
* Implements the x402 HTTP payment protocol spec (coinbase/x402) for
|
|
6
|
+
* multi-chain USDC payments. Covers 10 mainnet chains: Base, Ethereum,
|
|
7
|
+
* Arbitrum, Polygon, Optimism, Avalanche, Unichain, Linea, Sonic, Worldchain.
|
|
8
|
+
*
|
|
9
|
+
* USDC addresses are sourced from Circle's official registry:
|
|
10
|
+
* https://developers.circle.com/stablecoins/usdc-contract-addresses
|
|
11
|
+
*/
|
|
12
|
+
// x402 protocol types — compatible with @x402/core spec
|
|
13
|
+
import type { Address, Hash } from "viem";
|
|
14
|
+
|
|
15
|
+
// ─── x402 Protocol Types (from coinbase/x402 spec) ───
|
|
16
|
+
|
|
17
|
+
/** Resource information included in x402 responses */
|
|
18
|
+
export interface X402ResourceInfo {
|
|
19
|
+
url: string;
|
|
20
|
+
description: string;
|
|
21
|
+
mimeType: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Payment requirements returned in 402 response PAYMENT-REQUIRED header */
|
|
25
|
+
export interface X402PaymentRequirements {
|
|
26
|
+
scheme: string; // e.g. "exact"
|
|
27
|
+
network: string; // e.g. "base:8453"
|
|
28
|
+
asset: string; // token contract address (e.g. USDC on Base)
|
|
29
|
+
amount: string; // amount in smallest unit (e.g. "1000000" = 1 USDC)
|
|
30
|
+
payTo: string; // recipient address
|
|
31
|
+
maxTimeoutSeconds: number;
|
|
32
|
+
extra: Record<string, unknown>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Full 402 response payload (base64-decoded from PAYMENT-REQUIRED header) */
|
|
36
|
+
export interface X402PaymentRequired {
|
|
37
|
+
x402Version: number;
|
|
38
|
+
error?: string;
|
|
39
|
+
resource: X402ResourceInfo;
|
|
40
|
+
accepts: X402PaymentRequirements[];
|
|
41
|
+
extensions?: Record<string, unknown>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Payment payload sent back with PAYMENT-SIGNATURE header */
|
|
45
|
+
export interface X402PaymentPayload {
|
|
46
|
+
x402Version: number;
|
|
47
|
+
resource: X402ResourceInfo;
|
|
48
|
+
accepted: X402PaymentRequirements;
|
|
49
|
+
payload: Record<string, unknown>; // scheme-specific (e.g. tx hash, signature)
|
|
50
|
+
extensions?: Record<string, unknown>;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Settlement response returned in PAYMENT-RESPONSE header */
|
|
54
|
+
export interface X402SettlementResponse {
|
|
55
|
+
success: boolean;
|
|
56
|
+
txHash?: string;
|
|
57
|
+
network?: string;
|
|
58
|
+
error?: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ─── AgentWallet x402 Client Types ───
|
|
62
|
+
|
|
63
|
+
/** Per-service spending cap configuration */
|
|
64
|
+
export interface X402ServiceBudget {
|
|
65
|
+
/** Domain or URL pattern (e.g. "api.example.com" or "*") */
|
|
66
|
+
service: string;
|
|
67
|
+
/** Max spend per single request in token base units */
|
|
68
|
+
maxPerRequest: bigint;
|
|
69
|
+
/** Max total spend per day in token base units */
|
|
70
|
+
dailyLimit: bigint;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Transaction log entry for x402 payments */
|
|
74
|
+
export interface X402TransactionLog {
|
|
75
|
+
timestamp: number;
|
|
76
|
+
service: string;
|
|
77
|
+
url: string;
|
|
78
|
+
amount: bigint;
|
|
79
|
+
token: Address;
|
|
80
|
+
recipient: Address;
|
|
81
|
+
txHash: Hash;
|
|
82
|
+
network: string;
|
|
83
|
+
scheme: string;
|
|
84
|
+
success: boolean;
|
|
85
|
+
error?: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Configuration for the x402 client */
|
|
89
|
+
export interface X402ClientConfig {
|
|
90
|
+
/** Service-level budget controls */
|
|
91
|
+
serviceBudgets?: X402ServiceBudget[];
|
|
92
|
+
/** Global daily spending limit (token base units, default: unlimited) */
|
|
93
|
+
globalDailyLimit?: bigint;
|
|
94
|
+
/** Global per-request max (token base units, default: unlimited) */
|
|
95
|
+
globalPerRequestMax?: bigint;
|
|
96
|
+
/** Supported networks (default: ["base:8453"]) */
|
|
97
|
+
supportedNetworks?: string[];
|
|
98
|
+
/** Supported assets by network (default: USDC on Base) */
|
|
99
|
+
supportedAssets?: Record<string, Address[]>;
|
|
100
|
+
/** Max retries after payment (default: 1) */
|
|
101
|
+
maxRetries?: number;
|
|
102
|
+
/** Custom facilitator URL (optional, for verify/settle) */
|
|
103
|
+
facilitatorUrl?: string;
|
|
104
|
+
/** Whether to auto-pay 402 responses (default: true) */
|
|
105
|
+
autoPay?: boolean;
|
|
106
|
+
/** Callback before payment — return false to reject */
|
|
107
|
+
onBeforePayment?: (
|
|
108
|
+
req: X402PaymentRequirements,
|
|
109
|
+
url: string,
|
|
110
|
+
) => Promise<boolean> | boolean;
|
|
111
|
+
/** Callback after payment */
|
|
112
|
+
onPaymentComplete?: (log: X402TransactionLog) => void;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ─── Well-known Assets ───
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* USDC contract addresses by network (chain-name:chainId format).
|
|
119
|
+
* Sources:
|
|
120
|
+
* - EVM chains: https://developers.circle.com/cctp/references/contract-addresses
|
|
121
|
+
* - Linea: https://linea.build/ecosystem/usdc
|
|
122
|
+
* - Unichain: https://docs.unichain.org/docs/technical-information/token-addresses
|
|
123
|
+
* - Sonic: https://docs.soniclabs.com/build/useful-addresses
|
|
124
|
+
* - Worldchain: https://docs.worldcoin.org/world-chain/addresses/usdc
|
|
125
|
+
*/
|
|
126
|
+
export const USDC_ADDRESSES: Record<string, Address> = {
|
|
127
|
+
// Testnets
|
|
128
|
+
"base-sepolia:84532": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
129
|
+
// Mainnets
|
|
130
|
+
"base:8453": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
131
|
+
"ethereum:1": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
132
|
+
"arbitrum:42161": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
|
|
133
|
+
"polygon:137": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
|
|
134
|
+
"bsc:56": "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",
|
|
135
|
+
"optimism:10": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
|
|
136
|
+
"avalanche:43114": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
|
|
137
|
+
"unichain:130": "0x078D782b760474a361dDA0AF3839290b0EF57AD6",
|
|
138
|
+
"linea:59144": "0x176211869cA2b568f2A7D4EE941E073a821EE1ff",
|
|
139
|
+
"sonic:146": "0x29219dd400f2Bf60E5a23d13Be72B486D4038894",
|
|
140
|
+
"worldchain:480": "0x79A02482A880bCE3B13e09Da970dC34db4CD24d1",
|
|
141
|
+
} as const;
|
|
142
|
+
|
|
143
|
+
/** Default supported networks (all mainnet chains) */
|
|
144
|
+
export const DEFAULT_SUPPORTED_NETWORKS = [
|
|
145
|
+
"base:8453",
|
|
146
|
+
"ethereum:1",
|
|
147
|
+
"arbitrum:42161",
|
|
148
|
+
"polygon:137",
|
|
149
|
+
"bsc:56",
|
|
150
|
+
"optimism:10",
|
|
151
|
+
"avalanche:43114",
|
|
152
|
+
"unichain:130",
|
|
153
|
+
"linea:59144",
|
|
154
|
+
"sonic:146",
|
|
155
|
+
"worldchain:480",
|
|
156
|
+
] as const;
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type IAgentRuntime,
|
|
3
|
+
type ITokenDataService,
|
|
4
|
+
type IWalletService,
|
|
5
|
+
Service,
|
|
6
|
+
ServiceType,
|
|
7
|
+
} from "@elizaos/core";
|
|
8
|
+
import { validateWalletBridgeParams } from "../chains/evm/bridge-router.js";
|
|
9
|
+
import { registerDefaultWalletChainHandlers } from "../chains/registry.js";
|
|
10
|
+
import type {
|
|
11
|
+
WalletChainHandler,
|
|
12
|
+
WalletChainHandlerMetadata,
|
|
13
|
+
WalletRouterContext,
|
|
14
|
+
WalletRouterFailure,
|
|
15
|
+
WalletRouterParams,
|
|
16
|
+
WalletRouterResult,
|
|
17
|
+
WalletRouterSubaction,
|
|
18
|
+
} from "../types/wallet-router.js";
|
|
19
|
+
import { normalizeWalletChainKey } from "../types/wallet-router.js";
|
|
20
|
+
import type { WalletBackend } from "../wallet/backend.js";
|
|
21
|
+
import { resolveWalletBackend } from "../wallet/select-backend.js";
|
|
22
|
+
import "../core-augmentation.js";
|
|
23
|
+
|
|
24
|
+
export const WALLET_BACKEND_SERVICE_TYPE = "wallet-backend" as const;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Runtime service exposing {@link WalletBackend}. Retrieve via
|
|
28
|
+
* `runtime.getService("wallet-backend")`.
|
|
29
|
+
*/
|
|
30
|
+
export class WalletBackendService extends Service {
|
|
31
|
+
static override serviceType = WALLET_BACKEND_SERVICE_TYPE;
|
|
32
|
+
|
|
33
|
+
override capabilityDescription =
|
|
34
|
+
"Unified wallet backend and chain router (EVM + Solana, local or Steward)";
|
|
35
|
+
|
|
36
|
+
private backend: WalletBackend | null = null;
|
|
37
|
+
private backendLoadError: unknown = null;
|
|
38
|
+
private readonly handlers = new Map<string, WalletChainHandler>();
|
|
39
|
+
private readonly aliases = new Map<string, string>();
|
|
40
|
+
|
|
41
|
+
static override async start(
|
|
42
|
+
runtime: IAgentRuntime,
|
|
43
|
+
): Promise<WalletBackendService> {
|
|
44
|
+
const svc = new WalletBackendService(runtime);
|
|
45
|
+
try {
|
|
46
|
+
svc.backend = await resolveWalletBackend(runtime);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
svc.backend = null;
|
|
49
|
+
svc.backendLoadError = error;
|
|
50
|
+
runtime.logger.warn(
|
|
51
|
+
{
|
|
52
|
+
error: error instanceof Error ? error.message : String(error),
|
|
53
|
+
},
|
|
54
|
+
"Wallet backend unavailable; wallet router will expose metadata and dry-run only until signing is configured",
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
registerDefaultWalletChainHandlers(svc, runtime);
|
|
58
|
+
return svc;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
getWalletBackend(): WalletBackend {
|
|
62
|
+
if (!this.backend) {
|
|
63
|
+
if (this.backendLoadError instanceof Error) {
|
|
64
|
+
throw this.backendLoadError;
|
|
65
|
+
}
|
|
66
|
+
throw new Error("Wallet backend is not configured");
|
|
67
|
+
}
|
|
68
|
+
return this.backend;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getWalletBackendOrNull(): WalletBackend | null {
|
|
72
|
+
return this.backend;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
registerChainHandler(handler: WalletChainHandler): void {
|
|
76
|
+
const key = normalizeWalletChainKey(handler.chain);
|
|
77
|
+
this.handlers.set(key, handler);
|
|
78
|
+
|
|
79
|
+
const aliases = new Set<string>([
|
|
80
|
+
handler.chain,
|
|
81
|
+
handler.chainId,
|
|
82
|
+
handler.name,
|
|
83
|
+
...handler.aliases,
|
|
84
|
+
]);
|
|
85
|
+
for (const alias of aliases) {
|
|
86
|
+
this.aliases.set(normalizeWalletChainKey(alias), key);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
listChainHandlers(): WalletChainHandlerMetadata[] {
|
|
91
|
+
return [...this.handlers.values()].map((handler) =>
|
|
92
|
+
this.toMetadata(handler),
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
listChainHandlersForSubaction(
|
|
97
|
+
subaction: WalletRouterSubaction,
|
|
98
|
+
): WalletChainHandlerMetadata[] {
|
|
99
|
+
return [...this.handlers.values()]
|
|
100
|
+
.filter((handler) => handler.supportedActions.includes(subaction))
|
|
101
|
+
.map((handler) => this.toMetadata(handler));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
getCapabilities(): {
|
|
105
|
+
readonly chains: readonly WalletChainHandlerMetadata[];
|
|
106
|
+
} {
|
|
107
|
+
return {
|
|
108
|
+
chains: this.listChainHandlers(),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async routeWalletAction(
|
|
113
|
+
params: WalletRouterParams,
|
|
114
|
+
): Promise<WalletRouterResult> {
|
|
115
|
+
const handlerResult = this.resolveHandler(params);
|
|
116
|
+
if (!handlerResult.ok) {
|
|
117
|
+
return handlerResult;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const { handler } = handlerResult;
|
|
121
|
+
const required = this.validateRequiredParams(params);
|
|
122
|
+
if (required) {
|
|
123
|
+
return required;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (params.dryRun || params.mode === "prepare") {
|
|
127
|
+
if (
|
|
128
|
+
params.dryRun &&
|
|
129
|
+
(!handler.dryRun.supported ||
|
|
130
|
+
!handler.dryRun.supportedActions.includes(params.subaction))
|
|
131
|
+
) {
|
|
132
|
+
return {
|
|
133
|
+
ok: false,
|
|
134
|
+
error: "DRY_RUN_UNSUPPORTED",
|
|
135
|
+
detail: `${handler.name} does not support dry-run for ${params.subaction}.`,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (params.subaction === "bridge") {
|
|
140
|
+
try {
|
|
141
|
+
const result = await handler.execute(params, this.createContext());
|
|
142
|
+
return {
|
|
143
|
+
ok: true,
|
|
144
|
+
handler: this.toMetadata(handler),
|
|
145
|
+
result,
|
|
146
|
+
};
|
|
147
|
+
} catch (error) {
|
|
148
|
+
return {
|
|
149
|
+
ok: false,
|
|
150
|
+
error: "EXECUTION_FAILED",
|
|
151
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
ok: true,
|
|
158
|
+
handler: this.toMetadata(handler),
|
|
159
|
+
result: {
|
|
160
|
+
status: "prepared",
|
|
161
|
+
chain: handler.chain,
|
|
162
|
+
chainId: handler.chainId,
|
|
163
|
+
subaction: params.subaction,
|
|
164
|
+
dryRun: params.dryRun,
|
|
165
|
+
mode: params.mode,
|
|
166
|
+
amount: params.amount,
|
|
167
|
+
fromToken: params.fromToken,
|
|
168
|
+
toToken: params.toToken,
|
|
169
|
+
to: params.recipient,
|
|
170
|
+
metadata: {
|
|
171
|
+
signer: handler.signer,
|
|
172
|
+
dryRun: handler.dryRun,
|
|
173
|
+
supportedActions: handler.supportedActions,
|
|
174
|
+
tokens: handler.tokens,
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
const result = await handler.execute(params, this.createContext());
|
|
182
|
+
return {
|
|
183
|
+
ok: true,
|
|
184
|
+
handler: this.toMetadata(handler),
|
|
185
|
+
result,
|
|
186
|
+
};
|
|
187
|
+
} catch (error) {
|
|
188
|
+
return {
|
|
189
|
+
ok: false,
|
|
190
|
+
error: "EXECUTION_FAILED",
|
|
191
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
override async stop(): Promise<void> {
|
|
197
|
+
// No persistent connections for local / Steward HTTP clients today.
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private resolveHandler(
|
|
201
|
+
params: WalletRouterParams,
|
|
202
|
+
):
|
|
203
|
+
| { readonly ok: true; readonly handler: WalletChainHandler }
|
|
204
|
+
| WalletRouterFailure {
|
|
205
|
+
if (params.chain) {
|
|
206
|
+
const alias = this.aliases.get(normalizeWalletChainKey(params.chain));
|
|
207
|
+
const handler = alias ? this.handlers.get(alias) : null;
|
|
208
|
+
if (!handler) {
|
|
209
|
+
return {
|
|
210
|
+
ok: false,
|
|
211
|
+
error: "UNSUPPORTED_CHAIN",
|
|
212
|
+
detail: `Unsupported wallet chain "${params.chain}".`,
|
|
213
|
+
candidates: this.listChainHandlers(),
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
if (!handler.supportedActions.includes(params.subaction)) {
|
|
217
|
+
return {
|
|
218
|
+
ok: false,
|
|
219
|
+
error: "UNSUPPORTED_SUBACTION",
|
|
220
|
+
detail: `${handler.name} does not support ${params.subaction}.`,
|
|
221
|
+
candidates: [this.toMetadata(handler)],
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
return { ok: true, handler };
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const candidates = [...this.handlers.values()].filter((handler) =>
|
|
228
|
+
handler.supportedActions.includes(params.subaction),
|
|
229
|
+
);
|
|
230
|
+
if (candidates.length === 0) {
|
|
231
|
+
return {
|
|
232
|
+
ok: false,
|
|
233
|
+
error: "UNSUPPORTED_SUBACTION",
|
|
234
|
+
detail: `No wallet chain supports ${params.subaction}.`,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
if (candidates.length > 1) {
|
|
238
|
+
return {
|
|
239
|
+
ok: false,
|
|
240
|
+
error: "AMBIGUOUS_CHAIN",
|
|
241
|
+
detail: `Choose a chain for wallet ${params.subaction}.`,
|
|
242
|
+
candidates: candidates.map((handler) => this.toMetadata(handler)),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const handler = candidates[0];
|
|
247
|
+
return { ok: true, handler };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
private validateRequiredParams(
|
|
251
|
+
params: WalletRouterParams,
|
|
252
|
+
): WalletRouterFailure | null {
|
|
253
|
+
if (params.subaction === "bridge") {
|
|
254
|
+
const detail = validateWalletBridgeParams(params);
|
|
255
|
+
return detail ? { ok: false, error: "INVALID_PARAMS", detail } : null;
|
|
256
|
+
}
|
|
257
|
+
if (!params.amount) {
|
|
258
|
+
return {
|
|
259
|
+
ok: false,
|
|
260
|
+
error: "INVALID_PARAMS",
|
|
261
|
+
detail: "amount is required.",
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
if (params.subaction === "transfer" && !params.recipient) {
|
|
265
|
+
return {
|
|
266
|
+
ok: false,
|
|
267
|
+
error: "INVALID_PARAMS",
|
|
268
|
+
detail: "recipient is required for transfer.",
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
if (params.subaction === "swap") {
|
|
272
|
+
if (!params.fromToken) {
|
|
273
|
+
return {
|
|
274
|
+
ok: false,
|
|
275
|
+
error: "INVALID_PARAMS",
|
|
276
|
+
detail: "fromToken is required for swap.",
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
if (!params.toToken) {
|
|
280
|
+
return {
|
|
281
|
+
ok: false,
|
|
282
|
+
error: "INVALID_PARAMS",
|
|
283
|
+
detail: "toToken is required for swap.",
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
private createContext(): WalletRouterContext {
|
|
291
|
+
return {
|
|
292
|
+
runtime: this.runtime,
|
|
293
|
+
walletBackend: this.backend,
|
|
294
|
+
walletServices: this.getWalletServices(),
|
|
295
|
+
tokenDataService: this.getTokenDataService(),
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
private getWalletServices(): IWalletService[] {
|
|
300
|
+
const runtime = this.runtime as IAgentRuntime & {
|
|
301
|
+
getServicesByType?: <T>(serviceName: string) => T[];
|
|
302
|
+
};
|
|
303
|
+
if (typeof runtime.getServicesByType !== "function") {
|
|
304
|
+
return [];
|
|
305
|
+
}
|
|
306
|
+
return runtime.getServicesByType<IWalletService>(ServiceType.WALLET);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
private getTokenDataService(): ITokenDataService | null {
|
|
310
|
+
return this.runtime.getService<ITokenDataService>(ServiceType.TOKEN_DATA);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
private toMetadata(handler: WalletChainHandler): WalletChainHandlerMetadata {
|
|
314
|
+
return {
|
|
315
|
+
chainId: handler.chainId,
|
|
316
|
+
chain: handler.chain,
|
|
317
|
+
name: handler.name,
|
|
318
|
+
aliases: [...handler.aliases],
|
|
319
|
+
supportedActions: [...handler.supportedActions],
|
|
320
|
+
tokens: handler.tokens.map((token) => ({ ...token })),
|
|
321
|
+
signer: { ...handler.signer },
|
|
322
|
+
dryRun: {
|
|
323
|
+
...handler.dryRun,
|
|
324
|
+
supportedActions: [...handler.dryRun.supportedActions],
|
|
325
|
+
},
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
IAgentRuntime,
|
|
3
|
+
ITokenDataService,
|
|
4
|
+
IWalletService,
|
|
5
|
+
} from "@elizaos/core";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import type { WalletBackend } from "../wallet/backend.js";
|
|
8
|
+
|
|
9
|
+
export const WALLET_ROUTER_SUBACTIONS = [
|
|
10
|
+
"transfer",
|
|
11
|
+
"swap",
|
|
12
|
+
"bridge",
|
|
13
|
+
"gov",
|
|
14
|
+
] as const;
|
|
15
|
+
|
|
16
|
+
export type WalletRouterSubaction = (typeof WALLET_ROUTER_SUBACTIONS)[number];
|
|
17
|
+
|
|
18
|
+
export const WALLET_ROUTER_MODES = ["prepare", "execute"] as const;
|
|
19
|
+
|
|
20
|
+
export type WalletRouterMode = (typeof WALLET_ROUTER_MODES)[number];
|
|
21
|
+
|
|
22
|
+
export const WALLET_GOV_OPS = ["propose", "vote", "queue", "execute"] as const;
|
|
23
|
+
|
|
24
|
+
export type WalletGovOp = (typeof WALLET_GOV_OPS)[number];
|
|
25
|
+
|
|
26
|
+
export interface WalletRouterParams {
|
|
27
|
+
readonly subaction: WalletRouterSubaction;
|
|
28
|
+
readonly chain?: string;
|
|
29
|
+
readonly toChain?: string;
|
|
30
|
+
readonly fromToken?: string;
|
|
31
|
+
readonly toToken?: string;
|
|
32
|
+
readonly amount?: string;
|
|
33
|
+
readonly recipient?: string;
|
|
34
|
+
readonly slippageBps?: number;
|
|
35
|
+
readonly mode: WalletRouterMode;
|
|
36
|
+
readonly dryRun: boolean;
|
|
37
|
+
readonly op?: WalletGovOp;
|
|
38
|
+
readonly governor?: string;
|
|
39
|
+
readonly proposalId?: string;
|
|
40
|
+
readonly support?: number;
|
|
41
|
+
readonly targets?: readonly string[];
|
|
42
|
+
readonly values?: readonly string[];
|
|
43
|
+
readonly calldatas?: readonly string[];
|
|
44
|
+
readonly description?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface WalletTokenMetadata {
|
|
48
|
+
readonly symbol: string;
|
|
49
|
+
readonly address: string;
|
|
50
|
+
readonly decimals?: number;
|
|
51
|
+
readonly native?: boolean;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface WalletSignerMetadata {
|
|
55
|
+
readonly required: boolean;
|
|
56
|
+
readonly kind: "evm" | "solana" | "off-chain";
|
|
57
|
+
readonly source?: string;
|
|
58
|
+
readonly description?: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface WalletDryRunMetadata {
|
|
62
|
+
readonly supported: boolean;
|
|
63
|
+
readonly supportedActions: readonly WalletRouterSubaction[];
|
|
64
|
+
readonly description?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface WalletChainHandlerMetadata {
|
|
68
|
+
readonly chainId: string;
|
|
69
|
+
readonly chain: string;
|
|
70
|
+
readonly name: string;
|
|
71
|
+
readonly aliases: readonly string[];
|
|
72
|
+
readonly supportedActions: readonly WalletRouterSubaction[];
|
|
73
|
+
readonly tokens: readonly WalletTokenMetadata[];
|
|
74
|
+
readonly signer: WalletSignerMetadata;
|
|
75
|
+
readonly dryRun: WalletDryRunMetadata;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface WalletRouterContext {
|
|
79
|
+
readonly runtime: IAgentRuntime;
|
|
80
|
+
readonly walletBackend: WalletBackend | null;
|
|
81
|
+
readonly walletServices: readonly IWalletService[];
|
|
82
|
+
readonly tokenDataService: ITokenDataService | null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface WalletRouterExecution {
|
|
86
|
+
readonly status: "prepared" | "submitted";
|
|
87
|
+
readonly chain: string;
|
|
88
|
+
readonly chainId: string;
|
|
89
|
+
readonly subaction: WalletRouterSubaction;
|
|
90
|
+
readonly dryRun: boolean;
|
|
91
|
+
readonly mode: WalletRouterMode;
|
|
92
|
+
readonly transactionHash?: string;
|
|
93
|
+
readonly signature?: string;
|
|
94
|
+
readonly from?: string;
|
|
95
|
+
readonly to?: string;
|
|
96
|
+
readonly amount?: string;
|
|
97
|
+
readonly fromToken?: string;
|
|
98
|
+
readonly toToken?: string;
|
|
99
|
+
readonly metadata?: Record<string, unknown>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface WalletChainHandler extends WalletChainHandlerMetadata {
|
|
103
|
+
execute(
|
|
104
|
+
params: WalletRouterParams,
|
|
105
|
+
context: WalletRouterContext,
|
|
106
|
+
): Promise<WalletRouterExecution>;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export type WalletRouterErrorCode =
|
|
110
|
+
| "INVALID_PARAMS"
|
|
111
|
+
| "UNSUPPORTED_CHAIN"
|
|
112
|
+
| "UNSUPPORTED_SUBACTION"
|
|
113
|
+
| "AMBIGUOUS_CHAIN"
|
|
114
|
+
| "DRY_RUN_UNSUPPORTED"
|
|
115
|
+
| "EXECUTION_FAILED";
|
|
116
|
+
|
|
117
|
+
export interface WalletRouterFailure {
|
|
118
|
+
readonly ok: false;
|
|
119
|
+
readonly error: WalletRouterErrorCode;
|
|
120
|
+
readonly detail: string;
|
|
121
|
+
readonly candidates?: readonly WalletChainHandlerMetadata[];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface WalletRouterSuccess {
|
|
125
|
+
readonly ok: true;
|
|
126
|
+
readonly result: WalletRouterExecution;
|
|
127
|
+
readonly handler: WalletChainHandlerMetadata;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export type WalletRouterResult = WalletRouterSuccess | WalletRouterFailure;
|
|
131
|
+
|
|
132
|
+
const optionalString = z
|
|
133
|
+
.union([z.string(), z.number()])
|
|
134
|
+
.optional()
|
|
135
|
+
.nullable()
|
|
136
|
+
.transform((value) => {
|
|
137
|
+
if (value === null || value === undefined) return undefined;
|
|
138
|
+
const out = String(value).trim();
|
|
139
|
+
return out.length > 0 ? out : undefined;
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const optionalPositiveAmount = optionalString.refine(
|
|
143
|
+
(value) => {
|
|
144
|
+
if (value === undefined) return true;
|
|
145
|
+
const parsed = Number(value);
|
|
146
|
+
return Number.isFinite(parsed) && parsed > 0;
|
|
147
|
+
},
|
|
148
|
+
{ message: "amount must be a positive number" },
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const optionalStringArray = z.preprocess((value) => {
|
|
152
|
+
if (value === null || value === undefined) return undefined;
|
|
153
|
+
if (Array.isArray(value)) {
|
|
154
|
+
return value
|
|
155
|
+
.map((item) => String(item).trim())
|
|
156
|
+
.filter((item) => item.length > 0);
|
|
157
|
+
}
|
|
158
|
+
if (typeof value === "string") {
|
|
159
|
+
return value
|
|
160
|
+
.split(",")
|
|
161
|
+
.map((item) => item.trim())
|
|
162
|
+
.filter((item) => item.length > 0);
|
|
163
|
+
}
|
|
164
|
+
return undefined;
|
|
165
|
+
}, z.array(z.string()).optional());
|
|
166
|
+
|
|
167
|
+
export const WalletRouterParamsSchema = z.object({
|
|
168
|
+
subaction: z.enum(WALLET_ROUTER_SUBACTIONS),
|
|
169
|
+
chain: optionalString,
|
|
170
|
+
toChain: optionalString,
|
|
171
|
+
fromToken: optionalString,
|
|
172
|
+
toToken: optionalString,
|
|
173
|
+
amount: optionalPositiveAmount,
|
|
174
|
+
recipient: optionalString,
|
|
175
|
+
slippageBps: z.coerce.number().int().min(0).max(10_000).optional(),
|
|
176
|
+
mode: z.enum(WALLET_ROUTER_MODES).default("prepare"),
|
|
177
|
+
dryRun: z
|
|
178
|
+
.preprocess((value) => {
|
|
179
|
+
if (typeof value === "string") {
|
|
180
|
+
const normalized = value.trim().toLowerCase();
|
|
181
|
+
if (
|
|
182
|
+
normalized === "true" ||
|
|
183
|
+
normalized === "1" ||
|
|
184
|
+
normalized === "yes"
|
|
185
|
+
) {
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
if (
|
|
189
|
+
normalized === "false" ||
|
|
190
|
+
normalized === "0" ||
|
|
191
|
+
normalized === "no"
|
|
192
|
+
) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return value;
|
|
197
|
+
}, z.boolean())
|
|
198
|
+
.default(false),
|
|
199
|
+
op: z.enum(WALLET_GOV_OPS).optional(),
|
|
200
|
+
governor: optionalString,
|
|
201
|
+
proposalId: optionalString,
|
|
202
|
+
support: z.coerce.number().int().min(0).max(2).optional(),
|
|
203
|
+
targets: optionalStringArray,
|
|
204
|
+
values: optionalStringArray,
|
|
205
|
+
calldatas: optionalStringArray,
|
|
206
|
+
description: optionalString,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
export function parseWalletRouterParams(input: unknown): WalletRouterParams {
|
|
210
|
+
return WalletRouterParamsSchema.parse(input) as WalletRouterParams;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export function isWalletRouterSubaction(
|
|
214
|
+
value: unknown,
|
|
215
|
+
): value is WalletRouterSubaction {
|
|
216
|
+
return (
|
|
217
|
+
typeof value === "string" &&
|
|
218
|
+
WALLET_ROUTER_SUBACTIONS.includes(value as WalletRouterSubaction)
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function normalizeWalletChainKey(value: string | number): string {
|
|
223
|
+
return String(value)
|
|
224
|
+
.trim()
|
|
225
|
+
.toLowerCase()
|
|
226
|
+
.replace(/[\s_-]+/g, "");
|
|
227
|
+
}
|