@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,632 @@
1
+ // @ts-nocheck — legacy code from absorbed plugins (lp-manager, lpinfo, dexscreener, defi-news, birdeye); strict types pending cleanup
2
+ import {
3
+ type IAgentRuntime,
4
+ ILpService,
5
+ type LpPositionDetails,
6
+ logger,
7
+ type PoolInfo,
8
+ type TokenBalance,
9
+ type TransactionResult,
10
+ } from "@elizaos/core";
11
+ import type { Address } from "viem";
12
+ import type {
13
+ AddLiquidityConfig,
14
+ EvmAddLiquidityParams,
15
+ EvmPoolInfo,
16
+ EvmRemoveLiquidityParams,
17
+ EvmTransactionResult,
18
+ IEvmLpService,
19
+ RemoveLiquidityConfig,
20
+ } from "../types.ts";
21
+
22
+ export const LP_MANAGEMENT_SERVICE_TYPE = "lp-management";
23
+
24
+ export type LpProtocolChain = "solana" | "evm";
25
+
26
+ export interface LpProtocolRequest {
27
+ chain?: LpProtocolChain | string;
28
+ dex?: string;
29
+ chainId?: number;
30
+ }
31
+
32
+ export interface LpListPoolsParams extends LpProtocolRequest {
33
+ tokenA?: string;
34
+ tokenB?: string;
35
+ feeTier?: number;
36
+ }
37
+
38
+ export interface LpPositionOperationParams extends LpProtocolRequest {
39
+ userVault?: object;
40
+ wallet?: { address: Address; privateKey: `0x${string}` };
41
+ owner?: string;
42
+ pool?: string | PoolInfo | EvmPoolInfo;
43
+ position?: string;
44
+ tokenId?: string | bigint;
45
+ amount?:
46
+ | string
47
+ | number
48
+ | bigint
49
+ | {
50
+ value?: string | number | bigint;
51
+ tokenA?: string | number | bigint;
52
+ tokenB?: string | number | bigint;
53
+ lpToken?: string | number | bigint;
54
+ percentage?: number;
55
+ };
56
+ amounts?: {
57
+ tokenA?: string | number | bigint;
58
+ tokenB?: string | number | bigint;
59
+ lpToken?: string | number | bigint;
60
+ };
61
+ range?: {
62
+ tickLower?: number;
63
+ tickUpper?: number;
64
+ tickLowerIndex?: number;
65
+ tickUpperIndex?: number;
66
+ priceLower?: number;
67
+ priceUpper?: number;
68
+ };
69
+ slippageBps?: number;
70
+ deadline?: bigint;
71
+ }
72
+
73
+ export interface LpProtocolProvider {
74
+ id: string;
75
+ chain: LpProtocolChain;
76
+ dex: string;
77
+ label?: string;
78
+ service?: unknown;
79
+ supportedChainIds?: number[];
80
+ supportsRequest?: (request: LpProtocolRequest) => boolean;
81
+ listPools(params: LpListPoolsParams): Promise<PoolInfo[]>;
82
+ openPosition(params: LpPositionOperationParams): Promise<TransactionResult>;
83
+ closePosition(params: LpPositionOperationParams): Promise<TransactionResult>;
84
+ repositionPosition?(
85
+ params: LpPositionOperationParams,
86
+ ): Promise<TransactionResult>;
87
+ getPosition?(
88
+ params: LpPositionOperationParams,
89
+ ): Promise<LpPositionDetails | null>;
90
+ listPositions?(
91
+ params: LpPositionOperationParams,
92
+ ): Promise<LpPositionDetails[]>;
93
+ getMarketData?(poolIds: string[]): Promise<Record<string, Partial<PoolInfo>>>;
94
+ }
95
+
96
+ export class NoMatchingLpProtocolError extends Error {
97
+ public readonly code = "NO_MATCHING_LP_PROTOCOL";
98
+
99
+ constructor(request: LpProtocolRequest) {
100
+ const details = [
101
+ request.chain ? `chain=${request.chain}` : undefined,
102
+ request.dex ? `dex=${request.dex}` : undefined,
103
+ request.chainId ? `chainId=${request.chainId}` : undefined,
104
+ ]
105
+ .filter(Boolean)
106
+ .join(", ");
107
+ super(`No registered LP protocol matches ${details || "the request"}`);
108
+ this.name = "NoMatchingLpProtocolError";
109
+ }
110
+ }
111
+
112
+ function normalizeDex(dex?: string): string | undefined {
113
+ return dex?.trim().toLowerCase();
114
+ }
115
+
116
+ function normalizeChain(chain?: string): string | undefined {
117
+ return chain?.trim().toLowerCase();
118
+ }
119
+
120
+ function protocolKey(chain: string, dex: string): string {
121
+ return `${normalizeChain(chain)}:${normalizeDex(dex)}`;
122
+ }
123
+
124
+ function poolId(pool?: string | PoolInfo | EvmPoolInfo): string | undefined {
125
+ if (!pool) return undefined;
126
+ if (typeof pool === "string") return pool;
127
+ return (
128
+ (pool as EvmPoolInfo).poolAddress ||
129
+ (pool as PoolInfo).id ||
130
+ (pool as { address?: string }).address
131
+ );
132
+ }
133
+
134
+ function amountValue(
135
+ params: LpPositionOperationParams,
136
+ key: "tokenA" | "tokenB" | "lpToken" | "value",
137
+ fallback = "0",
138
+ ): string {
139
+ const amount = params.amount;
140
+ if (
141
+ key === "value" &&
142
+ ["string", "number", "bigint"].includes(typeof amount)
143
+ ) {
144
+ return String(amount);
145
+ }
146
+ if (amount && typeof amount === "object" && key in amount) {
147
+ const value = amount[key];
148
+ if (value !== undefined && value !== null) return String(value);
149
+ }
150
+ const nested = params.amounts?.[key as keyof typeof params.amounts];
151
+ if (nested !== undefined && nested !== null) return String(nested);
152
+ return fallback;
153
+ }
154
+
155
+ function bigintAmount(value: unknown, fallback = 0n): bigint {
156
+ if (typeof value === "bigint") return value;
157
+ if (typeof value === "number" && Number.isFinite(value)) {
158
+ return BigInt(Math.trunc(value));
159
+ }
160
+ if (typeof value === "string" && value.trim()) {
161
+ return BigInt(value.trim());
162
+ }
163
+ return fallback;
164
+ }
165
+
166
+ function unsupported(
167
+ protocol: LpProtocolProvider,
168
+ operation: string,
169
+ ): TransactionResult {
170
+ return {
171
+ success: false,
172
+ error: `${operation} is not implemented for ${protocol.dex} on ${protocol.chain}`,
173
+ };
174
+ }
175
+
176
+ export class LpManagementService extends ILpService {
177
+ public static override readonly serviceType = LP_MANAGEMENT_SERVICE_TYPE;
178
+ public readonly capabilityDescription =
179
+ "Aggregates registered DEX liquidity pool protocol providers across chains.";
180
+
181
+ private protocols = new Map<string, LpProtocolProvider>();
182
+
183
+ static async start(runtime: IAgentRuntime): Promise<LpManagementService> {
184
+ const service = new LpManagementService(runtime);
185
+ logger.info("[LpManagementService] started");
186
+ return service;
187
+ }
188
+
189
+ async stop(): Promise<void> {
190
+ this.protocols.clear();
191
+ logger.info("[LpManagementService] stopped");
192
+ }
193
+
194
+ getDexName(): string {
195
+ return "lp-management";
196
+ }
197
+
198
+ registerProtocol(provider: LpProtocolProvider): void {
199
+ const key = protocolKey(provider.chain, provider.dex);
200
+ const normalizedProvider = {
201
+ ...provider,
202
+ id: provider.id || key,
203
+ chain: normalizeChain(provider.chain) as LpProtocolChain,
204
+ dex: normalizeDex(provider.dex),
205
+ };
206
+ if (this.protocols.has(key)) {
207
+ logger.warn(
208
+ `[LpManagementService] Replacing LP protocol provider ${key}`,
209
+ );
210
+ }
211
+ this.protocols.set(key, normalizedProvider);
212
+ }
213
+
214
+ unregisterProtocol(request: LpProtocolRequest): boolean {
215
+ if (!request.chain || !request.dex) return false;
216
+ return this.protocols.delete(protocolKey(request.chain, request.dex));
217
+ }
218
+
219
+ listProtocols(request: LpProtocolRequest = {}): LpProtocolProvider[] {
220
+ return this.matchingProtocols(request);
221
+ }
222
+
223
+ async listPools(params: LpListPoolsParams = {}): Promise<PoolInfo[]> {
224
+ const requireMatch = Boolean(params.chain || params.dex || params.chainId);
225
+ const protocols = this.matchingProtocols(params);
226
+ if (protocols.length === 0) {
227
+ if (requireMatch) throw new NoMatchingLpProtocolError(params);
228
+ return [];
229
+ }
230
+
231
+ const poolLists = await Promise.all(
232
+ protocols.map(async (protocol) => {
233
+ try {
234
+ return await protocol.listPools(params);
235
+ } catch (error) {
236
+ logger.warn(
237
+ `[LpManagementService] Failed to list pools for ${protocol.chain}:${protocol.dex}`,
238
+ error instanceof Error ? error.message : String(error),
239
+ );
240
+ return [];
241
+ }
242
+ }),
243
+ );
244
+
245
+ return poolLists.flat();
246
+ }
247
+
248
+ async openPosition(
249
+ params: LpPositionOperationParams,
250
+ ): Promise<TransactionResult> {
251
+ const protocol = this.resolveProtocol(params);
252
+ return protocol.openPosition(params);
253
+ }
254
+
255
+ async closePosition(
256
+ params: LpPositionOperationParams,
257
+ ): Promise<TransactionResult> {
258
+ const protocol = this.resolveProtocol(params);
259
+ return protocol.closePosition(params);
260
+ }
261
+
262
+ async repositionPosition(
263
+ params: LpPositionOperationParams,
264
+ ): Promise<TransactionResult> {
265
+ const protocol = this.resolveProtocol(params);
266
+ if (!protocol.repositionPosition) {
267
+ return unsupported(protocol, "reposition");
268
+ }
269
+ return protocol.repositionPosition(params);
270
+ }
271
+
272
+ async getPosition(
273
+ params: LpPositionOperationParams,
274
+ ): Promise<LpPositionDetails | null> {
275
+ const protocol = this.resolveProtocol(params);
276
+ return protocol.getPosition?.(params) ?? null;
277
+ }
278
+
279
+ async listPositions(
280
+ params: LpPositionOperationParams = {},
281
+ ): Promise<LpPositionDetails[]> {
282
+ const protocols = this.matchingProtocols(params);
283
+ const positionLists = await Promise.all(
284
+ protocols.map((protocol) => protocol.listPositions?.(params) ?? []),
285
+ );
286
+ return positionLists.flat();
287
+ }
288
+
289
+ async getPools(
290
+ tokenAMint?: string,
291
+ tokenBMint?: string,
292
+ ): Promise<PoolInfo[]> {
293
+ return this.listPools({ tokenA: tokenAMint, tokenB: tokenBMint });
294
+ }
295
+
296
+ async addLiquidity(
297
+ params: AddLiquidityConfig & { chain?: string },
298
+ ): Promise<TransactionResult & { lpTokensReceived?: TokenBalance }> {
299
+ return this.openPosition({
300
+ chain: params.chain || "solana",
301
+ dex: params.dexName,
302
+ userVault: params.userVault,
303
+ pool: params.poolId,
304
+ amount: {
305
+ tokenA: params.tokenAAmountLamports,
306
+ tokenB: params.tokenBAmountLamports,
307
+ },
308
+ range: {
309
+ tickLowerIndex: params.tickLowerIndex,
310
+ tickUpperIndex: params.tickUpperIndex,
311
+ },
312
+ slippageBps: params.slippageBps,
313
+ });
314
+ }
315
+
316
+ async removeLiquidity(
317
+ params: RemoveLiquidityConfig & { chain?: string },
318
+ ): Promise<TransactionResult & { tokensReceived?: TokenBalance[] }> {
319
+ return this.closePosition({
320
+ chain: params.chain || "solana",
321
+ dex: params.dexName,
322
+ userVault: params.userVault,
323
+ pool: params.poolId,
324
+ amount: { lpToken: params.lpTokenAmountLamports },
325
+ slippageBps: params.slippageBps,
326
+ });
327
+ }
328
+
329
+ async getLpPositionDetails(
330
+ userAccountPublicKey: string,
331
+ poolOrPositionIdentifier: string,
332
+ ): Promise<LpPositionDetails | null> {
333
+ for (const protocol of this.protocols.values()) {
334
+ if (!protocol.getPosition) continue;
335
+ const position = await protocol.getPosition({
336
+ owner: userAccountPublicKey,
337
+ pool: poolOrPositionIdentifier,
338
+ position: poolOrPositionIdentifier,
339
+ });
340
+ if (position) return position;
341
+ }
342
+ return null;
343
+ }
344
+
345
+ async getMarketDataForPools(
346
+ poolIds: string[],
347
+ ): Promise<Record<string, Partial<PoolInfo>>> {
348
+ const marketData = await Promise.all(
349
+ Array.from(this.protocols.values()).map(
350
+ (protocol) => protocol.getMarketData?.(poolIds) ?? {},
351
+ ),
352
+ );
353
+ return Object.assign({}, ...marketData);
354
+ }
355
+
356
+ private matchingProtocols(request: LpProtocolRequest): LpProtocolProvider[] {
357
+ const requestedChain = normalizeChain(request.chain);
358
+ const requestedDex = normalizeDex(request.dex);
359
+ return Array.from(this.protocols.values()).filter((protocol) => {
360
+ if (requestedChain && protocol.chain !== requestedChain) return false;
361
+ if (requestedDex && protocol.dex !== requestedDex) return false;
362
+ if (
363
+ request.chainId !== undefined &&
364
+ protocol.supportedChainIds?.length &&
365
+ !protocol.supportedChainIds.includes(request.chainId)
366
+ ) {
367
+ return false;
368
+ }
369
+ return protocol.supportsRequest?.(request) ?? true;
370
+ });
371
+ }
372
+
373
+ private resolveProtocol(request: LpProtocolRequest): LpProtocolProvider {
374
+ const matches = this.matchingProtocols(request);
375
+ if (matches.length === 0) {
376
+ throw new NoMatchingLpProtocolError(request);
377
+ }
378
+ if (matches.length > 1) {
379
+ throw new Error(
380
+ `Multiple LP protocols match this request (${matches
381
+ .map((protocol) => `${protocol.chain}:${protocol.dex}`)
382
+ .join(", ")}). Specify chain and dex.`,
383
+ );
384
+ }
385
+ return matches[0];
386
+ }
387
+ }
388
+
389
+ export async function getLpManagementService(
390
+ runtime: IAgentRuntime,
391
+ ): Promise<LpManagementService | null> {
392
+ const existing = runtime.getService<LpManagementService>(
393
+ LP_MANAGEMENT_SERVICE_TYPE,
394
+ );
395
+ if (existing) return existing;
396
+
397
+ if (typeof runtime.getServiceLoadPromise === "function") {
398
+ const loaded = await runtime.getServiceLoadPromise(
399
+ LP_MANAGEMENT_SERVICE_TYPE,
400
+ );
401
+ return (loaded as LpManagementService) ?? null;
402
+ }
403
+
404
+ return null;
405
+ }
406
+
407
+ export async function registerLpProtocolProvider(
408
+ runtime: IAgentRuntime,
409
+ provider: LpProtocolProvider,
410
+ ): Promise<void> {
411
+ const registry = await getLpManagementService(runtime);
412
+ if (!registry) {
413
+ logger.warn(
414
+ `[LpManagementService] Cannot register ${provider.chain}:${provider.dex}; registry service is unavailable`,
415
+ );
416
+ return;
417
+ }
418
+ registry.registerProtocol(provider);
419
+ }
420
+
421
+ export function createSolanaLpProtocolProvider({
422
+ dex,
423
+ label,
424
+ service,
425
+ }: {
426
+ dex: string;
427
+ label?: string;
428
+ service: Partial<ILpService> & Record<string, unknown>;
429
+ }): LpProtocolProvider {
430
+ const provider: LpProtocolProvider = {
431
+ id: `solana:${normalizeDex(dex)}`,
432
+ chain: "solana",
433
+ dex: normalizeDex(dex),
434
+ label,
435
+ service,
436
+ supportsRequest: (request) =>
437
+ (!request.chain || normalizeChain(request.chain) === "solana") &&
438
+ (!request.dex || normalizeDex(request.dex) === normalizeDex(dex)),
439
+ listPools: async (params) => {
440
+ if (typeof service.getPools !== "function") return [];
441
+ return service.getPools(params.tokenA, params.tokenB);
442
+ },
443
+ openPosition: async (params) => {
444
+ if (typeof service.addLiquidity !== "function") {
445
+ return unsupported(provider, "open");
446
+ }
447
+ const id = poolId(params.pool);
448
+ if (!id) return { success: false, error: "Pool is required" };
449
+ return service.addLiquidity({
450
+ userVault: params.userVault,
451
+ poolId: id,
452
+ tokenAAmountLamports: amountValue(
453
+ params,
454
+ "tokenA",
455
+ amountValue(params, "value"),
456
+ ),
457
+ tokenBAmountLamports: amountValue(params, "tokenB", undefined),
458
+ slippageBps: params.slippageBps ?? 50,
459
+ tickLowerIndex: params.range?.tickLowerIndex ?? params.range?.tickLower,
460
+ tickUpperIndex: params.range?.tickUpperIndex ?? params.range?.tickUpper,
461
+ });
462
+ },
463
+ closePosition: async (params) => {
464
+ if (typeof service.removeLiquidity !== "function") {
465
+ return unsupported(provider, "close");
466
+ }
467
+ const id = poolId(params.pool) || params.position;
468
+ if (!id) return { success: false, error: "Pool or position is required" };
469
+ return service.removeLiquidity({
470
+ userVault: params.userVault,
471
+ poolId: id,
472
+ lpTokenAmountLamports: amountValue(
473
+ params,
474
+ "lpToken",
475
+ amountValue(params, "value"),
476
+ ),
477
+ slippageBps: params.slippageBps ?? 50,
478
+ });
479
+ },
480
+ getPosition: async (params) => {
481
+ if (typeof service.getLpPositionDetails !== "function") return null;
482
+ const identifier = params.position || poolId(params.pool);
483
+ if (!params.owner || !identifier) return null;
484
+ return service.getLpPositionDetails(params.owner, identifier);
485
+ },
486
+ getMarketData: async (poolIds) => {
487
+ if (typeof service.getMarketDataForPools !== "function") return {};
488
+ return service.getMarketDataForPools(poolIds);
489
+ },
490
+ };
491
+
492
+ if (typeof service.repositionPosition === "function") {
493
+ provider.repositionPosition = (params) =>
494
+ service.repositionPosition(params);
495
+ }
496
+
497
+ return provider;
498
+ }
499
+
500
+ export function createEvmLpProtocolProvider({
501
+ dex,
502
+ label,
503
+ service,
504
+ }: {
505
+ dex: string;
506
+ label?: string;
507
+ service: IEvmLpService;
508
+ }): LpProtocolProvider {
509
+ const supportedChainIds =
510
+ typeof service.getSupportedChainIds === "function"
511
+ ? service.getSupportedChainIds()
512
+ : [];
513
+ const provider: LpProtocolProvider = {
514
+ id: `evm:${normalizeDex(dex)}`,
515
+ chain: "evm",
516
+ dex: normalizeDex(dex),
517
+ label,
518
+ service,
519
+ supportedChainIds,
520
+ supportsRequest: (request) => {
521
+ if (request.chain && normalizeChain(request.chain) !== "evm") {
522
+ return false;
523
+ }
524
+ if (request.dex && normalizeDex(request.dex) !== normalizeDex(dex)) {
525
+ return false;
526
+ }
527
+ if (request.chainId !== undefined && supportedChainIds.length > 0) {
528
+ return supportedChainIds.includes(request.chainId);
529
+ }
530
+ return true;
531
+ },
532
+ listPools: async (params) => {
533
+ const chainIds = params.chainId ? [params.chainId] : supportedChainIds;
534
+ const pools = await Promise.all(
535
+ chainIds.map((chainId) =>
536
+ service.getPools(
537
+ chainId,
538
+ params.tokenA as Address | undefined,
539
+ params.tokenB as Address | undefined,
540
+ params.feeTier,
541
+ ),
542
+ ),
543
+ );
544
+ return pools.flat();
545
+ },
546
+ openPosition: async (params) => {
547
+ if (!params.wallet)
548
+ return { success: false, error: "EVM wallet is required" };
549
+ if (!params.chainId)
550
+ return { success: false, error: "EVM chainId is required" };
551
+ const id = poolId(params.pool);
552
+ if (!id) return { success: false, error: "Pool address is required" };
553
+ const evmParams: EvmAddLiquidityParams = {
554
+ wallet: params.wallet,
555
+ chainId: params.chainId,
556
+ poolAddress: id as Address,
557
+ tokenAAmount: bigintAmount(
558
+ amountValue(params, "tokenA", amountValue(params, "value")),
559
+ ),
560
+ tokenBAmount: bigintAmount(
561
+ amountValue(params, "tokenB", undefined),
562
+ undefined,
563
+ ),
564
+ slippageBps: params.slippageBps ?? 50,
565
+ tickLower: params.range?.tickLower ?? params.range?.tickLowerIndex,
566
+ tickUpper: params.range?.tickUpper ?? params.range?.tickUpperIndex,
567
+ deadline: params.deadline,
568
+ };
569
+ return service.addLiquidity(evmParams);
570
+ },
571
+ closePosition: async (params) => {
572
+ if (!params.wallet)
573
+ return { success: false, error: "EVM wallet is required" };
574
+ if (!params.chainId)
575
+ return { success: false, error: "EVM chainId is required" };
576
+ const id = poolId(params.pool);
577
+ if (!id) return { success: false, error: "Pool address is required" };
578
+ const evmParams: EvmRemoveLiquidityParams = {
579
+ wallet: params.wallet,
580
+ chainId: params.chainId,
581
+ poolAddress: id as Address,
582
+ tokenId:
583
+ params.tokenId !== undefined
584
+ ? bigintAmount(params.tokenId)
585
+ : params.position
586
+ ? bigintAmount(params.position)
587
+ : undefined,
588
+ lpTokenAmount: bigintAmount(
589
+ amountValue(params, "lpToken", amountValue(params, "value")),
590
+ undefined,
591
+ ),
592
+ percentageToRemove:
593
+ typeof params.amount === "object"
594
+ ? params.amount?.percentage
595
+ : undefined,
596
+ slippageBps: params.slippageBps ?? 50,
597
+ deadline: params.deadline,
598
+ };
599
+ return service.removeLiquidity(evmParams);
600
+ },
601
+ getPosition: async (params) => {
602
+ if (!params.owner || !params.chainId) return null;
603
+ const id = poolId(params.pool);
604
+ if (!id) return null;
605
+ return service.getPositionDetails(
606
+ params.chainId,
607
+ params.owner as Address,
608
+ id as Address,
609
+ params.tokenId !== undefined
610
+ ? bigintAmount(params.tokenId)
611
+ : params.position
612
+ ? bigintAmount(params.position)
613
+ : undefined,
614
+ );
615
+ },
616
+ listPositions: async (params) => {
617
+ if (!params.owner || !params.chainId) return [];
618
+ return service.getAllPositions(params.chainId, params.owner as Address);
619
+ },
620
+ getMarketData: async (poolIds) => {
621
+ if (typeof service.getMarketData !== "function") return {};
622
+ return service.getMarketData(poolIds as Address[]);
623
+ },
624
+ };
625
+
626
+ if (typeof service.repositionPosition === "function") {
627
+ provider.repositionPosition = (params) =>
628
+ service.repositionPosition(params) as Promise<EvmTransactionResult>;
629
+ }
630
+
631
+ return provider;
632
+ }