@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.
Files changed (200) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +64 -0
  3. package/auto-enable.ts +76 -0
  4. package/dist/LpManagementService-BWrQ5-cO.mjs +353 -0
  5. package/dist/MockLpService-D_Apn4Fd.mjs +99 -0
  6. package/dist/aerodrome-CfnESC32.mjs +890 -0
  7. package/dist/chunk-hT5z_Zn9.mjs +35 -0
  8. package/dist/index.d.mts +34727 -0
  9. package/dist/index.mjs +21590 -0
  10. package/dist/lib/server-wallet-trade.d.mts +34 -0
  11. package/dist/lib/server-wallet-trade.mjs +306 -0
  12. package/dist/meteora-BPX39hZo.mjs +22640 -0
  13. package/dist/orca-Bybp1HXO.mjs +249 -0
  14. package/dist/pancakeswp-CkEXlXti.mjs +604 -0
  15. package/dist/plugin-ZO_MTyd0.mjs +529 -0
  16. package/dist/raydium-rfaM9yEf.mjs +539 -0
  17. package/dist/sdk/index.d.mts +32492 -0
  18. package/dist/sdk/index.mjs +6415 -0
  19. package/dist/types-D5252NZk.mjs +487 -0
  20. package/dist/uniswap-CReXgXVN.mjs +573 -0
  21. package/dist/wallet-action.d.mts +6 -0
  22. package/dist/wallet-action.mjs +820 -0
  23. package/package.json +152 -0
  24. package/src/actions/failure-codes.ts +79 -0
  25. package/src/actions/index.ts +1 -0
  26. package/src/analytics/birdeye/actions/wallet-search-address.ts +9 -0
  27. package/src/analytics/birdeye/birdeye-task.ts +175 -0
  28. package/src/analytics/birdeye/birdeye.ts +813 -0
  29. package/src/analytics/birdeye/constants.ts +74 -0
  30. package/src/analytics/birdeye/providers/agent-portfolio-provider.ts +18 -0
  31. package/src/analytics/birdeye/providers/market.ts +227 -0
  32. package/src/analytics/birdeye/providers/portfolio-factory.test.ts +138 -0
  33. package/src/analytics/birdeye/providers/portfolio-factory.ts +252 -0
  34. package/src/analytics/birdeye/providers/trending.ts +365 -0
  35. package/src/analytics/birdeye/providers/wallet.ts +14 -0
  36. package/src/analytics/birdeye/search-category.test.ts +207 -0
  37. package/src/analytics/birdeye/search-category.ts +506 -0
  38. package/src/analytics/birdeye/service.ts +992 -0
  39. package/src/analytics/birdeye/tasks/birdeye.ts +232 -0
  40. package/src/analytics/birdeye/types/api/common.ts +305 -0
  41. package/src/analytics/birdeye/types/api/defi.ts +220 -0
  42. package/src/analytics/birdeye/types/api/pair.ts +200 -0
  43. package/src/analytics/birdeye/types/api/search.ts +86 -0
  44. package/src/analytics/birdeye/types/api/token.ts +635 -0
  45. package/src/analytics/birdeye/types/api/trader.ts +76 -0
  46. package/src/analytics/birdeye/types/api/wallet.ts +181 -0
  47. package/src/analytics/birdeye/types/shared.ts +106 -0
  48. package/src/analytics/birdeye/utils.ts +700 -0
  49. package/src/analytics/dexscreener/errors.ts +28 -0
  50. package/src/analytics/dexscreener/index.ts +3 -0
  51. package/src/analytics/dexscreener/search-category.test.ts +49 -0
  52. package/src/analytics/dexscreener/search-category.ts +42 -0
  53. package/src/analytics/dexscreener/service.ts +595 -0
  54. package/src/analytics/dexscreener/types.ts +128 -0
  55. package/src/analytics/lpinfo/index.d.ts +7 -0
  56. package/src/analytics/lpinfo/index.ts +52 -0
  57. package/src/analytics/lpinfo/kamino/README.md +102 -0
  58. package/src/analytics/lpinfo/kamino/index.ts +24 -0
  59. package/src/analytics/lpinfo/kamino/providers/kaminoLiquidityProvider.ts +422 -0
  60. package/src/analytics/lpinfo/kamino/providers/kaminoPoolProvider.ts +365 -0
  61. package/src/analytics/lpinfo/kamino/providers/kaminoProvider.ts +496 -0
  62. package/src/analytics/lpinfo/kamino/services/kaminoLiquidityService.ts +1123 -0
  63. package/src/analytics/lpinfo/kamino/services/kaminoService.ts +758 -0
  64. package/src/analytics/lpinfo/steer/README.md +169 -0
  65. package/src/analytics/lpinfo/steer/index.ts +23 -0
  66. package/src/analytics/lpinfo/steer/providers/steerLiquidityProvider.ts +544 -0
  67. package/src/analytics/lpinfo/steer/services/steerLiquidityService.ts +1690 -0
  68. package/src/analytics/lpinfo/steer/steer-display-types.ts +99 -0
  69. package/src/analytics/news/index.ts +52 -0
  70. package/src/analytics/news/interfaces/types.ts +222 -0
  71. package/src/analytics/news/providers/defiNewsProvider.ts +734 -0
  72. package/src/analytics/news/services/newsDataService.ts +332 -0
  73. package/src/analytics/news/utils/formatters.ts +151 -0
  74. package/src/analytics/token-info/action.ts +240 -0
  75. package/src/analytics/token-info/index.ts +3 -0
  76. package/src/analytics/token-info/params.ts +215 -0
  77. package/src/analytics/token-info/providers.ts +681 -0
  78. package/src/analytics/token-info/service.ts +168 -0
  79. package/src/analytics/token-info/types.ts +74 -0
  80. package/src/audit/audit-log.ts +45 -0
  81. package/src/browser-shim/build-shim.ts +123 -0
  82. package/src/browser-shim/index.ts +5 -0
  83. package/src/browser-shim/shim.template.js +563 -0
  84. package/src/chains/evm/.github/workflows/npm-deploy.yml +112 -0
  85. package/src/chains/evm/LICENSE +21 -0
  86. package/src/chains/evm/README.md +106 -0
  87. package/src/chains/evm/actions/helpers.ts +147 -0
  88. package/src/chains/evm/actions/swap.ts +839 -0
  89. package/src/chains/evm/actions/transfer.ts +254 -0
  90. package/src/chains/evm/biome.json +61 -0
  91. package/src/chains/evm/bridge-router.ts +660 -0
  92. package/src/chains/evm/build.ts +89 -0
  93. package/src/chains/evm/chain-handler.ts +416 -0
  94. package/src/chains/evm/constants.ts +23 -0
  95. package/src/chains/evm/contracts/artifacts/OZGovernor.json +1707 -0
  96. package/src/chains/evm/contracts/artifacts/TimelockController.json +1007 -0
  97. package/src/chains/evm/contracts/artifacts/VoteToken.json +895 -0
  98. package/src/chains/evm/dex/aerodrome/index.ts +34 -0
  99. package/src/chains/evm/dex/aerodrome/services/AerodromeLpService.ts +558 -0
  100. package/src/chains/evm/dex/aerodrome/types.ts +318 -0
  101. package/src/chains/evm/dex/pancakeswp/index.ts +35 -0
  102. package/src/chains/evm/dex/pancakeswp/services/PancakeSwapV3LpService.ts +743 -0
  103. package/src/chains/evm/dex/pancakeswp/types.ts +65 -0
  104. package/src/chains/evm/dex/uniswap/index.ts +35 -0
  105. package/src/chains/evm/dex/uniswap/services/UniswapV3LpService.ts +759 -0
  106. package/src/chains/evm/dex/uniswap/types.ts +390 -0
  107. package/src/chains/evm/generated/specs/spec-helpers.ts +73 -0
  108. package/src/chains/evm/generated/specs/specs.ts +151 -0
  109. package/src/chains/evm/gov-router.ts +250 -0
  110. package/src/chains/evm/index.browser.ts +16 -0
  111. package/src/chains/evm/index.ts +31 -0
  112. package/src/chains/evm/prompts.ts +193 -0
  113. package/src/chains/evm/providers/get-balance.ts +123 -0
  114. package/src/chains/evm/providers/wallet.ts +715 -0
  115. package/src/chains/evm/routes/sign.ts +333 -0
  116. package/src/chains/evm/rpc-providers.ts +410 -0
  117. package/src/chains/evm/service.ts +140 -0
  118. package/src/chains/evm/templates/index.ts +10 -0
  119. package/src/chains/evm/types/index.ts +432 -0
  120. package/src/chains/evm/vitest.config.ts +18 -0
  121. package/src/chains/registry.ts +668 -0
  122. package/src/chains/solana/README.md +367 -0
  123. package/src/chains/wallet-action.ts +533 -0
  124. package/src/chains/wallet-router.test.ts +296 -0
  125. package/src/contracts.ts +65 -0
  126. package/src/core-augmentation.ts +10 -0
  127. package/src/index.ts +71 -0
  128. package/src/lib/server-wallet-trade.ts +192 -0
  129. package/src/lib/wallet-export-guard.ts +330 -0
  130. package/src/lp/actions/liquidity.ts +827 -0
  131. package/src/lp/e2e/real-token-tests.ts +428 -0
  132. package/src/lp/e2e/scenarios.ts +470 -0
  133. package/src/lp/e2e/test-utils.ts +145 -0
  134. package/src/lp/lp-manager-entry.ts +303 -0
  135. package/src/lp/services/ConcentratedLiquidityService.ts +120 -0
  136. package/src/lp/services/DexInteractionService.ts +226 -0
  137. package/src/lp/services/LpManagementService.test.ts +148 -0
  138. package/src/lp/services/LpManagementService.ts +632 -0
  139. package/src/lp/services/UserLpProfileService.ts +163 -0
  140. package/src/lp/services/VaultService.ts +153 -0
  141. package/src/lp/services/YieldOptimizationService.ts +344 -0
  142. package/src/lp/services/__tests__/MockLpService.ts +146 -0
  143. package/src/lp/tasks/LpAutoRebalanceTask.ts +117 -0
  144. package/src/lp/tasks/__tests__/LpAutoRebalanceTask.test.ts +370 -0
  145. package/src/lp/types.ts +582 -0
  146. package/src/lp/utils/solanaClient.ts +143 -0
  147. package/src/plugin.ts +125 -0
  148. package/src/policy/policy.ts +19 -0
  149. package/src/providers/canonical-provider.ts +27 -0
  150. package/src/providers/unified-wallet-provider.ts +79 -0
  151. package/src/register-routes.ts +11 -0
  152. package/src/routes/plugin.ts +47 -0
  153. package/src/routes/wallet-market-overview-route.ts +869 -0
  154. package/src/sdk/abi.ts +258 -0
  155. package/src/sdk/bridge/abis.ts +126 -0
  156. package/src/sdk/bridge/client.ts +518 -0
  157. package/src/sdk/bridge/index.ts +56 -0
  158. package/src/sdk/bridge/solana.ts +604 -0
  159. package/src/sdk/bridge/types.ts +202 -0
  160. package/src/sdk/convenience.ts +347 -0
  161. package/src/sdk/escrow/MutualStakeEscrow.ts +480 -0
  162. package/src/sdk/escrow/types.ts +64 -0
  163. package/src/sdk/escrow/verifiers.ts +73 -0
  164. package/src/sdk/identity/erc8004.ts +692 -0
  165. package/src/sdk/identity/reputation.ts +449 -0
  166. package/src/sdk/identity/uaid.ts +497 -0
  167. package/src/sdk/identity/validation.ts +372 -0
  168. package/src/sdk/index.ts +763 -0
  169. package/src/sdk/policy/SpendingPolicy.ts +260 -0
  170. package/src/sdk/policy/UptoBillingPolicy.ts +320 -0
  171. package/src/sdk/router/PaymentRouter.ts +215 -0
  172. package/src/sdk/router/index.ts +8 -0
  173. package/src/sdk/swap/SwapModule.ts +310 -0
  174. package/src/sdk/swap/abi.ts +117 -0
  175. package/src/sdk/swap/index.ts +34 -0
  176. package/src/sdk/swap/types.ts +135 -0
  177. package/src/sdk/tokens/decimals.ts +140 -0
  178. package/src/sdk/tokens/registry.ts +911 -0
  179. package/src/sdk/tokens/solana.ts +419 -0
  180. package/src/sdk/tokens/transfers.ts +327 -0
  181. package/src/sdk/types.ts +158 -0
  182. package/src/sdk/wallet-core.ts +115 -0
  183. package/src/sdk/x402/budget.ts +168 -0
  184. package/src/sdk/x402/chains/abstract/index.ts +280 -0
  185. package/src/sdk/x402/client.ts +320 -0
  186. package/src/sdk/x402/index.ts +46 -0
  187. package/src/sdk/x402/middleware.ts +92 -0
  188. package/src/sdk/x402/multi-asset.ts +144 -0
  189. package/src/sdk/x402/types.ts +156 -0
  190. package/src/services/wallet-backend-service.ts +328 -0
  191. package/src/types/wallet-router.ts +227 -0
  192. package/src/utils/intent-trajectory.ts +106 -0
  193. package/src/wallet/backend.ts +62 -0
  194. package/src/wallet/errors.ts +49 -0
  195. package/src/wallet/index.ts +27 -0
  196. package/src/wallet/local-eoa-backend.ts +201 -0
  197. package/src/wallet/pending.ts +60 -0
  198. package/src/wallet/select-backend.ts +47 -0
  199. package/src/wallet/steward-backend.ts +161 -0
  200. package/src/wallet-action.ts +1 -0
@@ -0,0 +1,240 @@
1
+ import type {
2
+ Action,
3
+ ActionResult,
4
+ HandlerCallback,
5
+ HandlerOptions,
6
+ IAgentRuntime,
7
+ Memory,
8
+ State,
9
+ } from "@elizaos/core";
10
+ import { parseTokenInfoParams, selectedContextMatches } from "./params";
11
+ import { TOKEN_INFO_SERVICE_TYPE, type TokenInfoService } from "./service";
12
+ import { TOKEN_INFO_SUBACTIONS } from "./types";
13
+
14
+ const TOKEN_INFO_CONTEXTS = ["finance", "crypto", "wallet"] as const;
15
+ const TOKEN_INFO_KEYWORDS = [
16
+ "token",
17
+ "coin",
18
+ "crypto",
19
+ "dexscreener",
20
+ "birdeye",
21
+ "coingecko",
22
+ "price",
23
+ "pair",
24
+ "pairs",
25
+ "market cap",
26
+ "liquidity",
27
+ "trending",
28
+ "wallet",
29
+ "portfolio",
30
+ "boosted",
31
+ "profile",
32
+ ] as const;
33
+
34
+ function hasTokenInfoIntent(message: Memory, state?: State): boolean {
35
+ const text = [
36
+ typeof message.content?.text === "string" ? message.content.text : "",
37
+ typeof state?.values?.recentMessages === "string"
38
+ ? state.values.recentMessages
39
+ : "",
40
+ ]
41
+ .join("\n")
42
+ .toLowerCase();
43
+ return TOKEN_INFO_KEYWORDS.some((keyword) => text.includes(keyword));
44
+ }
45
+
46
+ function unavailable(
47
+ callback: HandlerCallback | undefined,
48
+ text: string,
49
+ data: Record<string, unknown>,
50
+ ): ActionResult {
51
+ const dataAsContent = data as Parameters<HandlerCallback>[0]["data"];
52
+ callback?.({ text, actions: ["TOKEN_INFO"], data: dataAsContent });
53
+ return {
54
+ success: false,
55
+ text,
56
+ error: String(data.error ?? "TOKEN_INFO_UNAVAILABLE"),
57
+ data: data as ActionResult["data"],
58
+ };
59
+ }
60
+
61
+ export const tokenInfoAction: Action = {
62
+ name: "TOKEN_INFO",
63
+ contexts: [...TOKEN_INFO_CONTEXTS],
64
+ contextGate: { anyOf: [...TOKEN_INFO_CONTEXTS] },
65
+ roleGate: { minRole: "USER" },
66
+ similes: [
67
+ "DEXSCREENER_SEARCH",
68
+ "DEXSCREENER_TOKEN_INFO",
69
+ "DEXSCREENER_TRENDING",
70
+ "DEXSCREENER_NEW_PAIRS",
71
+ "DEXSCREENER_CHAIN_PAIRS",
72
+ "DEXSCREENER_BOOSTED_TOKENS",
73
+ "DEXSCREENER_TOKEN_PROFILES",
74
+ "BIRDEYE_LOOKUP",
75
+ "BIRDEYE_TOKEN_SEARCH",
76
+ "TOKEN_SEARCH",
77
+ "TOKEN_LOOKUP",
78
+ "TOKEN_PRICE",
79
+ "COINGECKO",
80
+ ],
81
+ description:
82
+ "Fetch crypto token and market information from registered providers. target selects provider (dexscreener, birdeye, coingecko). subaction selects search, token, trending, new-pairs, chain-pairs, boosted, profiles, or wallet.",
83
+ descriptionCompressed:
84
+ "Crypto token info provider registry: target dexscreener|birdeye|coingecko; subaction search|token|trending|new-pairs|chain-pairs|boosted|profiles|wallet.",
85
+ parameters: [
86
+ {
87
+ name: "target",
88
+ description:
89
+ "Provider to use. Omit to use the default provider for the subaction.",
90
+ required: false,
91
+ schema: { type: "string", enum: ["dexscreener", "birdeye", "coingecko"] },
92
+ examples: ["dexscreener", "birdeye", "coingecko"],
93
+ },
94
+ {
95
+ name: "subaction",
96
+ description: "Token information operation.",
97
+ required: true,
98
+ schema: { type: "string", enum: [...TOKEN_INFO_SUBACTIONS] },
99
+ examples: ["search", "token", "trending", "wallet"],
100
+ },
101
+ {
102
+ name: "query",
103
+ description:
104
+ "Search query, coin id, token symbol, token address, or wallet address.",
105
+ required: false,
106
+ schema: { type: "string" },
107
+ },
108
+ {
109
+ name: "address",
110
+ description: "Token or wallet address.",
111
+ required: false,
112
+ schema: { type: "string" },
113
+ },
114
+ {
115
+ name: "tokenAddress",
116
+ description: "Token contract address.",
117
+ required: false,
118
+ schema: { type: "string" },
119
+ },
120
+ {
121
+ name: "chain",
122
+ description:
123
+ "Chain/network for provider operations that need one, such as chain-pairs or CoinGecko contract lookup.",
124
+ required: false,
125
+ schema: { type: "string" },
126
+ examples: ["ethereum", "solana", "base"],
127
+ },
128
+ {
129
+ name: "timeframe",
130
+ description: "Trending window when supported.",
131
+ required: false,
132
+ schema: { type: "string", enum: ["1h", "6h", "24h"], default: "24h" },
133
+ },
134
+ {
135
+ name: "limit",
136
+ description: "Maximum result count.",
137
+ required: false,
138
+ schema: { type: "number", minimum: 1, maximum: 100, default: 10 },
139
+ },
140
+ {
141
+ name: "sortBy",
142
+ description: "Pair ranking metric for chain-pairs.",
143
+ required: false,
144
+ schema: {
145
+ type: "string",
146
+ enum: ["volume", "liquidity", "priceChange", "txns"],
147
+ },
148
+ },
149
+ {
150
+ name: "top",
151
+ description: "For boosted tokens, return top boosted rather than latest.",
152
+ required: false,
153
+ schema: { type: "boolean", default: false },
154
+ },
155
+ {
156
+ name: "id",
157
+ description: "CoinGecko coin id.",
158
+ required: false,
159
+ schema: { type: "string" },
160
+ },
161
+ ],
162
+ validate: async (_runtime, message, state) =>
163
+ selectedContextMatches(state, TOKEN_INFO_CONTEXTS) ||
164
+ hasTokenInfoIntent(message, state),
165
+ handler: async (
166
+ runtime: IAgentRuntime,
167
+ message: Memory,
168
+ state?: State,
169
+ options?: HandlerOptions | Record<string, unknown>,
170
+ callback?: HandlerCallback,
171
+ ): Promise<ActionResult> => {
172
+ const service = runtime.getService(
173
+ TOKEN_INFO_SERVICE_TYPE,
174
+ ) as TokenInfoService | null;
175
+ if (!service || typeof service.route !== "function") {
176
+ return unavailable(callback, "Token info service is not available.", {
177
+ actionName: "TOKEN_INFO",
178
+ error: "SERVICE_UNAVAILABLE",
179
+ });
180
+ }
181
+
182
+ const params = parseTokenInfoParams(message, state, options);
183
+ const routed = await service.route({
184
+ runtime,
185
+ message,
186
+ state,
187
+ options,
188
+ params,
189
+ callback,
190
+ });
191
+
192
+ if (routed.ok) {
193
+ const result = routed.result;
194
+ return {
195
+ ...result,
196
+ data: {
197
+ ...(result.data ?? {}),
198
+ actionName: "TOKEN_INFO",
199
+ target: routed.provider.name,
200
+ supportedProviders: service.listProviders(),
201
+ },
202
+ };
203
+ }
204
+
205
+ return unavailable(callback, routed.detail, {
206
+ actionName: "TOKEN_INFO",
207
+ error: routed.error,
208
+ detail: routed.detail,
209
+ providers: routed.providers,
210
+ });
211
+ },
212
+ examples: [
213
+ [
214
+ {
215
+ name: "{{user1}}",
216
+ content: { text: "Search for PEPE on DexScreener" },
217
+ },
218
+ {
219
+ name: "{{agent}}",
220
+ content: {
221
+ text: "Searching DexScreener.",
222
+ action: "TOKEN_INFO",
223
+ },
224
+ },
225
+ ],
226
+ [
227
+ {
228
+ name: "{{user1}}",
229
+ content: { text: "Look up bitcoin on CoinGecko" },
230
+ },
231
+ {
232
+ name: "{{agent}}",
233
+ content: {
234
+ text: "Looking up Bitcoin on CoinGecko.",
235
+ action: "TOKEN_INFO",
236
+ },
237
+ },
238
+ ],
239
+ ],
240
+ };
@@ -0,0 +1,3 @@
1
+ export { tokenInfoAction } from "./action";
2
+ export { TOKEN_INFO_SERVICE_TYPE, TokenInfoService } from "./service";
3
+ export * from "./types";
@@ -0,0 +1,215 @@
1
+ import type { HandlerOptions, Memory, State } from "@elizaos/core";
2
+ import {
3
+ TOKEN_INFO_SUBACTIONS,
4
+ type TokenInfoParams,
5
+ type TokenInfoSubaction,
6
+ } from "./types";
7
+
8
+ const SUBACTION_ALIASES: Record<string, TokenInfoSubaction> = {
9
+ lookup: "token",
10
+ info: "token",
11
+ "token-info": "token",
12
+ token_info: "token",
13
+ pairs: "chain-pairs",
14
+ "new pairs": "new-pairs",
15
+ new_pairs: "new-pairs",
16
+ chain_pairs: "chain-pairs",
17
+ chainpairs: "chain-pairs",
18
+ boosted_tokens: "boosted",
19
+ boostedtokens: "boosted",
20
+ token_profiles: "profiles",
21
+ tokenprofiles: "profiles",
22
+ wallet_address: "wallet",
23
+ "wallet-address": "wallet",
24
+ portfolio: "wallet",
25
+ };
26
+
27
+ export function readParams(options?: unknown): Record<string, unknown> {
28
+ const direct =
29
+ options && typeof options === "object"
30
+ ? (options as Record<string, unknown>)
31
+ : {};
32
+ const parameters =
33
+ direct.parameters && typeof direct.parameters === "object"
34
+ ? (direct.parameters as Record<string, unknown>)
35
+ : {};
36
+ return { ...direct, ...parameters };
37
+ }
38
+
39
+ export function readStringParam(
40
+ options: unknown,
41
+ ...keys: string[]
42
+ ): string | undefined {
43
+ const params = readParams(options);
44
+ for (const key of keys) {
45
+ const value = params[key];
46
+ if (typeof value === "string" && value.trim().length > 0) {
47
+ return value.trim();
48
+ }
49
+ }
50
+ return undefined;
51
+ }
52
+
53
+ export function readNumberParam(
54
+ options: unknown,
55
+ key: string,
56
+ fallback?: number,
57
+ ): number | undefined {
58
+ const value = readParams(options)[key];
59
+ const parsed =
60
+ typeof value === "number"
61
+ ? value
62
+ : typeof value === "string" && value.trim().length > 0
63
+ ? Number(value)
64
+ : Number.NaN;
65
+ return Number.isFinite(parsed) ? parsed : fallback;
66
+ }
67
+
68
+ export function readBooleanParam(
69
+ options: unknown,
70
+ key: string,
71
+ ): boolean | undefined {
72
+ const value = readParams(options)[key];
73
+ if (typeof value === "boolean") return value;
74
+ if (typeof value === "string") {
75
+ const normalized = value.trim().toLowerCase();
76
+ if (["true", "1", "yes"].includes(normalized)) return true;
77
+ if (["false", "0", "no"].includes(normalized)) return false;
78
+ }
79
+ return undefined;
80
+ }
81
+
82
+ export function normalizeTokenInfoSubaction(
83
+ value: unknown,
84
+ ): TokenInfoSubaction | undefined {
85
+ if (typeof value !== "string") return undefined;
86
+ const normalized = value
87
+ .trim()
88
+ .toLowerCase()
89
+ .replace(/[\s_]+/g, "-");
90
+ if ((TOKEN_INFO_SUBACTIONS as readonly string[]).includes(normalized)) {
91
+ return normalized as TokenInfoSubaction;
92
+ }
93
+ return (
94
+ SUBACTION_ALIASES[normalized] ?? SUBACTION_ALIASES[value.toLowerCase()]
95
+ );
96
+ }
97
+
98
+ export function inferTokenInfoSubaction(
99
+ message: Memory,
100
+ state?: State,
101
+ ): TokenInfoSubaction {
102
+ const text = [
103
+ typeof message.content?.text === "string" ? message.content.text : "",
104
+ typeof state?.values?.recentMessages === "string"
105
+ ? state.values.recentMessages
106
+ : "",
107
+ ]
108
+ .join("\n")
109
+ .toLowerCase();
110
+
111
+ if (/\b(wallet|portfolio|holdings)\b/.test(text)) return "wallet";
112
+ if (/\b(boosted|promoted|sponsored)\b/.test(text)) return "boosted";
113
+ if (/\b(profile|profiles)\b/.test(text)) return "profiles";
114
+ if (
115
+ /\b(new|latest|fresh)\b/.test(text) &&
116
+ /\b(pair|pairs|tokens?)\b/.test(text)
117
+ ) {
118
+ return "new-pairs";
119
+ }
120
+ if (
121
+ /\b(pair|pairs)\b/.test(text) &&
122
+ /\b(chain|ethereum|solana|base|bsc|polygon|arbitrum|optimism|avalanche)\b/.test(
123
+ text,
124
+ )
125
+ ) {
126
+ return "chain-pairs";
127
+ }
128
+ if (/\b(trending|hot|popular|gainers)\b/.test(text)) return "trending";
129
+ if (/\b(search|find|look for)\b/.test(text)) return "search";
130
+ return "token";
131
+ }
132
+
133
+ export function parseTokenInfoParams(
134
+ message: Memory,
135
+ state?: State,
136
+ options?: HandlerOptions | Record<string, unknown>,
137
+ ): TokenInfoParams {
138
+ const raw = readParams(options);
139
+ const content =
140
+ typeof message.content?.text === "string" ? message.content.text : "";
141
+ const subaction =
142
+ normalizeTokenInfoSubaction(
143
+ raw.subaction ?? raw.action ?? raw.operation ?? raw.kind,
144
+ ) ?? inferTokenInfoSubaction(message, state);
145
+ const target = readStringParam(raw, "target", "provider", "source");
146
+ const query =
147
+ readStringParam(raw, "query", "token", "symbol") ??
148
+ (subaction === "search" ? content : undefined);
149
+ const address = readStringParam(raw, "address", "tokenAddress", "wallet");
150
+ const timeframeRaw = readStringParam(raw, "timeframe");
151
+ const timeframe =
152
+ timeframeRaw === "1h" || timeframeRaw === "6h" || timeframeRaw === "24h"
153
+ ? timeframeRaw
154
+ : undefined;
155
+ const sortByRaw = readStringParam(raw, "sortBy", "sort");
156
+ const sortBy =
157
+ sortByRaw === "volume" ||
158
+ sortByRaw === "liquidity" ||
159
+ sortByRaw === "priceChange" ||
160
+ sortByRaw === "txns"
161
+ ? sortByRaw
162
+ : undefined;
163
+ const kindRaw = readStringParam(raw, "kind", "mode");
164
+ const kind =
165
+ kindRaw === "wallet-address" ||
166
+ kindRaw === "token-address" ||
167
+ kindRaw === "token-symbol"
168
+ ? kindRaw
169
+ : undefined;
170
+
171
+ return {
172
+ target,
173
+ subaction,
174
+ query,
175
+ address,
176
+ tokenAddress: readStringParam(raw, "tokenAddress") ?? address,
177
+ chain: readStringParam(raw, "chain", "network"),
178
+ timeframe,
179
+ limit: readNumberParam(raw, "limit"),
180
+ offset: readNumberParam(raw, "offset"),
181
+ sortBy,
182
+ top: readBooleanParam(raw, "top"),
183
+ kind,
184
+ id: readStringParam(raw, "id", "coinId"),
185
+ };
186
+ }
187
+
188
+ export function selectedContextMatches(
189
+ state: State | undefined,
190
+ contexts: readonly string[],
191
+ ): boolean {
192
+ const selected = new Set<string>();
193
+ const collect = (value: unknown) => {
194
+ if (!Array.isArray(value)) return;
195
+ for (const item of value) {
196
+ if (typeof item === "string") selected.add(item);
197
+ }
198
+ };
199
+ collect(
200
+ (state?.values as Record<string, unknown> | undefined)?.selectedContexts,
201
+ );
202
+ collect(
203
+ (state?.data as Record<string, unknown> | undefined)?.selectedContexts,
204
+ );
205
+ const contextObject = (state?.data as Record<string, unknown> | undefined)
206
+ ?.contextObject as
207
+ | {
208
+ trajectoryPrefix?: { selectedContexts?: unknown };
209
+ metadata?: { selectedContexts?: unknown };
210
+ }
211
+ | undefined;
212
+ collect(contextObject?.trajectoryPrefix?.selectedContexts);
213
+ collect(contextObject?.metadata?.selectedContexts);
214
+ return contexts.some((context) => selected.has(context));
215
+ }