@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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 up2itnow0822
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # @elizaos/plugin-wallet
2
+
3
+ Unified non-custodial wallet for elizaOS agents. Replaces the legacy fan-out across `plugin-evm`, `plugin-solana`, `plugin-raydium`, `plugin-orca`, `plugin-meteora`, `plugin-jupiter`, `plugin-lp-manager`, `plugin-clanker`, and the former `elizaos-plugin-agentwallet` stub with one canonical action+provider surface governed by [`docs/architecture/wallet-and-trading.md`](../../../docs/architecture/wallet-and-trading.md).
4
+
5
+ ## Surface
6
+
7
+ The plugin exposes **10 canonical planner-visible actions**:
8
+
9
+ | Action | Purpose |
10
+ |--------|---------|
11
+ | `TRADE` | Open positions, swap, bridge. Discriminated by `kind`: `perp` (Hyperliquid), `prediction` (Polymarket), `spot` / `swap` (Li.Fi on EVM, Jupiter on Solana), `bridge` (Li.Fi / CCTP). |
12
+ | `MANAGE_POSITION` | Close, modify, cancel orders. |
13
+ | `QUERY_MARKET` | Read-only price / depth / funding / chart / news / sentiment. No wallet required. |
14
+ | `QUERY_PORTFOLIO` | Balances, positions, P&L, history. |
15
+ | `LEND` | Supply / borrow / repay / withdraw on Aave or Morpho. |
16
+ | `MANAGE_LP` | Open / close / collect / rebalance LP positions. EVM (Uniswap V3, Aerodrome) + Solana (Raydium, Orca Whirlpools, Meteora DLMM) behind one surface. |
17
+ | `TRANSFER` | Move value to an arbitrary external address. EVM + Solana. Always policy-checked. |
18
+ | `SET_AUTOMATION` | DCA, threshold triggers, P&L exits. |
19
+ | `MANAGE_AUTOMATION` | List / pause / resume / delete automations. |
20
+ | `MINT` | Token launches via Clanker on Base. |
21
+
22
+ These dispatch into **typed providers** (one per venue / data source). Adding a new venue means adding a provider, **not** a new planner verb.
23
+
24
+ ## Wallet abstraction
25
+
26
+ Two backends behind `WalletBackend`:
27
+
28
+ - **`LocalEoaBackend`** — desktop default. EOA private keys hydrated from the OS keychain. Optional ERC-6551 token-bound account mode (via the bundled SDK at `./sdk`) for on-chain spend policy enforcement.
29
+ - **`StewardBackend`** — cloud + mobile default. Multi-tenant Steward service is the only custody primitive in cloud. No fallback to local.
30
+
31
+ See `src/wallet/` for interface and impls. `ELIZA_WALLET_BACKEND=local|steward|auto` selects at runtime.
32
+
33
+ ## Layout
34
+
35
+ ```
36
+ src/
37
+ index.ts # Plugin export
38
+ plugin.ts # Plugin object: actions + providers + services
39
+ sdk/ # Lifted from agent-wallet-sdk (ERC-6551, x402, CCTP, swap, escrow, identity, multi-token, payment router)
40
+ wallet/ # WalletBackend interface + LocalEoa + Steward
41
+ policy/ # PolicyModule (local + steward bridge)
42
+ providers/ # Canonical providers (one per venue / data source)
43
+ actions/ # Canonical actions (TRADE, MANAGE_POSITION, ...)
44
+ audit/ # Append-only hash-chained audit log
45
+ ```
46
+
47
+ The `sdk/` subtree carries forward primitives from [agent-wallet-sdk](https://github.com/up2itnow0822/agent-wallet-sdk) (MIT). See `SDK-LICENSE`. The wallet/policy/providers/actions/audit subtrees implement the canonical architecture in the spec.
48
+
49
+ ## Migration status
50
+
51
+ This plugin is being built incrementally. Tracked phases:
52
+
53
+ - **Phase 0** — interfaces (`WalletBackend`, `CanonicalProvider`, `CanonicalAction`, `PolicyModule`, audit log schema, failure-code unions).
54
+ - **Phase 1** — backend impls + `@elizaos/plugin-wallet` composes legacy `plugin-evm` + `plugin-solana`; migrate call sites to consume `WalletBackend` only.
55
+ - **Phase 2** — provider lifts (13+ providers).
56
+ - **Phase 3** — canonical action implementations.
57
+ - **Phase 4** — approval-queue surface (SSE + decision endpoint + tray + Capacitor bridge).
58
+ - **Phase 5** — EVM + Solana chain implementations live under `src/chains/`; migrate remaining callsites to `WalletBackend` only; expand test coverage.
59
+
60
+ See `docs/architecture/wallet-and-trading.md` §I for the dependency graph.
61
+
62
+ ## License
63
+
64
+ MIT. Source code under `src/sdk/` originates from [agent-wallet-sdk](https://github.com/up2itnow0822/agent-wallet-sdk) (MIT, attribution preserved in `SDK-LICENSE`).
package/auto-enable.ts ADDED
@@ -0,0 +1,76 @@
1
+ // Auto-enable check for @elizaos/plugin-wallet.
2
+ //
3
+ // Plugin manifest entry-point — referenced by package.json's
4
+ // `elizaos.plugin.autoEnableModule`. Keep this module light: env reads only,
5
+ // no service init, no transitive imports of the full plugin runtime. The
6
+ // auto-enable engine loads dozens of these per boot.
7
+ //
8
+ // EVM detection mirrors `evmAutoEnableReasonFromCapability` in
9
+ // packages/agent/src/services/evm-signing-capability.ts — kept inline so this
10
+ // module has no cross-package import that would pull in agent/runtime code.
11
+ import type { PluginAutoEnableContext } from "@elizaos/core";
12
+
13
+ const PLACEHOLDER_RE =
14
+ /^\[?\s*(REDACTED|PLACEHOLDER|T(?:O)D(?:O)|CHANGEME|EMPTY)\s*]?$/i;
15
+
16
+ function isConcreteValue(value: string | undefined): boolean {
17
+ const trimmed = value?.trim();
18
+ return Boolean(trimmed) && !PLACEHOLDER_RE.test(trimmed as string);
19
+ }
20
+
21
+ /** True when any EVM signing path is available (local key or Steward). */
22
+ function hasEvmSigningPath(env: NodeJS.ProcessEnv): boolean {
23
+ if (isConcreteValue(env.EVM_PRIVATE_KEY)) return true;
24
+ const stewardUrl = env.STEWARD_API_URL?.trim();
25
+ const stewardToken = env.STEWARD_AGENT_TOKEN?.trim();
26
+ return Boolean(stewardUrl && stewardToken);
27
+ }
28
+
29
+ /** True when a Solana private key is set. */
30
+ function hasSolanaSigningPath(env: NodeJS.ProcessEnv): boolean {
31
+ return (
32
+ typeof env.SOLANA_PRIVATE_KEY === "string" &&
33
+ env.SOLANA_PRIVATE_KEY.trim().length > 0
34
+ );
35
+ }
36
+
37
+ /** True when cloud-provisioned Steward credentials are present. */
38
+ function hasCloudStewardWallet(env: NodeJS.ProcessEnv): boolean {
39
+ return (
40
+ env.ELIZA_CLOUD_PROVISIONED === "1" &&
41
+ Boolean(env.STEWARD_API_URL?.trim()) &&
42
+ Boolean(env.STEWARD_AGENT_TOKEN?.trim())
43
+ );
44
+ }
45
+
46
+ /**
47
+ * Enable plugin-wallet when ANY signing path is available:
48
+ * - EVM (local key or self-hosted/cloud Steward)
49
+ * - Solana local key
50
+ * - cloud-provisioned Steward
51
+ *
52
+ * Honors `ELIZA_AGENT_WALLET_AUTO_ENABLE === "0"` opt-out, and respects an
53
+ * explicit `enabled: false` on any of plugin-wallet's legacy entry names
54
+ * (`wallet`, `agent-wallet`, `evm`, `solana`). The central engine only
55
+ * checks the canonical short id (`wallet`); the legacy aliases need to be
56
+ * honored here.
57
+ */
58
+ export function shouldEnable(ctx: PluginAutoEnableContext): boolean {
59
+ const { env, config } = ctx;
60
+
61
+ if (env.ELIZA_AGENT_WALLET_AUTO_ENABLE === "0") return false;
62
+
63
+ const entries = (config?.plugins as Record<string, unknown> | undefined)
64
+ ?.entries as Record<string, { enabled?: boolean } | undefined> | undefined;
65
+ if (entries) {
66
+ for (const id of ["wallet", "agent-wallet", "evm", "solana"] as const) {
67
+ if (entries[id]?.enabled === false) return false;
68
+ }
69
+ }
70
+
71
+ return (
72
+ hasEvmSigningPath(env) ||
73
+ hasSolanaSigningPath(env) ||
74
+ hasCloudStewardWallet(env)
75
+ );
76
+ }
@@ -0,0 +1,353 @@
1
+ import { ILpService, logger } from "@elizaos/core";
2
+ //#region src/lp/services/LpManagementService.ts
3
+ const LP_MANAGEMENT_SERVICE_TYPE = "lp-management";
4
+ var NoMatchingLpProtocolError = class extends Error {
5
+ code = "NO_MATCHING_LP_PROTOCOL";
6
+ constructor(request) {
7
+ const details = [
8
+ request.chain ? `chain=${request.chain}` : void 0,
9
+ request.dex ? `dex=${request.dex}` : void 0,
10
+ request.chainId ? `chainId=${request.chainId}` : void 0
11
+ ].filter(Boolean).join(", ");
12
+ super(`No registered LP protocol matches ${details || "the request"}`);
13
+ this.name = "NoMatchingLpProtocolError";
14
+ }
15
+ };
16
+ function normalizeDex(dex) {
17
+ return dex?.trim().toLowerCase();
18
+ }
19
+ function normalizeChain(chain) {
20
+ return chain?.trim().toLowerCase();
21
+ }
22
+ function protocolKey(chain, dex) {
23
+ return `${normalizeChain(chain)}:${normalizeDex(dex)}`;
24
+ }
25
+ function poolId(pool) {
26
+ if (!pool) return void 0;
27
+ if (typeof pool === "string") return pool;
28
+ return pool.poolAddress || pool.id || pool.address;
29
+ }
30
+ function amountValue(params, key, fallback = "0") {
31
+ const amount = params.amount;
32
+ if (key === "value" && [
33
+ "string",
34
+ "number",
35
+ "bigint"
36
+ ].includes(typeof amount)) return String(amount);
37
+ if (amount && typeof amount === "object" && key in amount) {
38
+ const value = amount[key];
39
+ if (value !== void 0 && value !== null) return String(value);
40
+ }
41
+ const nested = params.amounts?.[key];
42
+ if (nested !== void 0 && nested !== null) return String(nested);
43
+ return fallback;
44
+ }
45
+ function bigintAmount(value, fallback = 0n) {
46
+ if (typeof value === "bigint") return value;
47
+ if (typeof value === "number" && Number.isFinite(value)) return BigInt(Math.trunc(value));
48
+ if (typeof value === "string" && value.trim()) return BigInt(value.trim());
49
+ return fallback;
50
+ }
51
+ function unsupported(protocol, operation) {
52
+ return {
53
+ success: false,
54
+ error: `${operation} is not implemented for ${protocol.dex} on ${protocol.chain}`
55
+ };
56
+ }
57
+ var LpManagementService = class LpManagementService extends ILpService {
58
+ static serviceType = LP_MANAGEMENT_SERVICE_TYPE;
59
+ capabilityDescription = "Aggregates registered DEX liquidity pool protocol providers across chains.";
60
+ protocols = /* @__PURE__ */ new Map();
61
+ static async start(runtime) {
62
+ const service = new LpManagementService(runtime);
63
+ logger.info("[LpManagementService] started");
64
+ return service;
65
+ }
66
+ async stop() {
67
+ this.protocols.clear();
68
+ logger.info("[LpManagementService] stopped");
69
+ }
70
+ getDexName() {
71
+ return "lp-management";
72
+ }
73
+ registerProtocol(provider) {
74
+ const key = protocolKey(provider.chain, provider.dex);
75
+ const normalizedProvider = {
76
+ ...provider,
77
+ id: provider.id || key,
78
+ chain: normalizeChain(provider.chain),
79
+ dex: normalizeDex(provider.dex)
80
+ };
81
+ if (this.protocols.has(key)) logger.warn(`[LpManagementService] Replacing LP protocol provider ${key}`);
82
+ this.protocols.set(key, normalizedProvider);
83
+ }
84
+ unregisterProtocol(request) {
85
+ if (!request.chain || !request.dex) return false;
86
+ return this.protocols.delete(protocolKey(request.chain, request.dex));
87
+ }
88
+ listProtocols(request = {}) {
89
+ return this.matchingProtocols(request);
90
+ }
91
+ async listPools(params = {}) {
92
+ const requireMatch = Boolean(params.chain || params.dex || params.chainId);
93
+ const protocols = this.matchingProtocols(params);
94
+ if (protocols.length === 0) {
95
+ if (requireMatch) throw new NoMatchingLpProtocolError(params);
96
+ return [];
97
+ }
98
+ return (await Promise.all(protocols.map(async (protocol) => {
99
+ try {
100
+ return await protocol.listPools(params);
101
+ } catch (error) {
102
+ logger.warn(`[LpManagementService] Failed to list pools for ${protocol.chain}:${protocol.dex}`, error instanceof Error ? error.message : String(error));
103
+ return [];
104
+ }
105
+ }))).flat();
106
+ }
107
+ async openPosition(params) {
108
+ return this.resolveProtocol(params).openPosition(params);
109
+ }
110
+ async closePosition(params) {
111
+ return this.resolveProtocol(params).closePosition(params);
112
+ }
113
+ async repositionPosition(params) {
114
+ const protocol = this.resolveProtocol(params);
115
+ if (!protocol.repositionPosition) return unsupported(protocol, "reposition");
116
+ return protocol.repositionPosition(params);
117
+ }
118
+ async getPosition(params) {
119
+ return this.resolveProtocol(params).getPosition?.(params) ?? null;
120
+ }
121
+ async listPositions(params = {}) {
122
+ const protocols = this.matchingProtocols(params);
123
+ return (await Promise.all(protocols.map((protocol) => protocol.listPositions?.(params) ?? []))).flat();
124
+ }
125
+ async getPools(tokenAMint, tokenBMint) {
126
+ return this.listPools({
127
+ tokenA: tokenAMint,
128
+ tokenB: tokenBMint
129
+ });
130
+ }
131
+ async addLiquidity(params) {
132
+ return this.openPosition({
133
+ chain: params.chain || "solana",
134
+ dex: params.dexName,
135
+ userVault: params.userVault,
136
+ pool: params.poolId,
137
+ amount: {
138
+ tokenA: params.tokenAAmountLamports,
139
+ tokenB: params.tokenBAmountLamports
140
+ },
141
+ range: {
142
+ tickLowerIndex: params.tickLowerIndex,
143
+ tickUpperIndex: params.tickUpperIndex
144
+ },
145
+ slippageBps: params.slippageBps
146
+ });
147
+ }
148
+ async removeLiquidity(params) {
149
+ return this.closePosition({
150
+ chain: params.chain || "solana",
151
+ dex: params.dexName,
152
+ userVault: params.userVault,
153
+ pool: params.poolId,
154
+ amount: { lpToken: params.lpTokenAmountLamports },
155
+ slippageBps: params.slippageBps
156
+ });
157
+ }
158
+ async getLpPositionDetails(userAccountPublicKey, poolOrPositionIdentifier) {
159
+ for (const protocol of this.protocols.values()) {
160
+ if (!protocol.getPosition) continue;
161
+ const position = await protocol.getPosition({
162
+ owner: userAccountPublicKey,
163
+ pool: poolOrPositionIdentifier,
164
+ position: poolOrPositionIdentifier
165
+ });
166
+ if (position) return position;
167
+ }
168
+ return null;
169
+ }
170
+ async getMarketDataForPools(poolIds) {
171
+ const marketData = await Promise.all(Array.from(this.protocols.values()).map((protocol) => protocol.getMarketData?.(poolIds) ?? {}));
172
+ return Object.assign({}, ...marketData);
173
+ }
174
+ matchingProtocols(request) {
175
+ const requestedChain = normalizeChain(request.chain);
176
+ const requestedDex = normalizeDex(request.dex);
177
+ return Array.from(this.protocols.values()).filter((protocol) => {
178
+ if (requestedChain && protocol.chain !== requestedChain) return false;
179
+ if (requestedDex && protocol.dex !== requestedDex) return false;
180
+ if (request.chainId !== void 0 && protocol.supportedChainIds?.length && !protocol.supportedChainIds.includes(request.chainId)) return false;
181
+ return protocol.supportsRequest?.(request) ?? true;
182
+ });
183
+ }
184
+ resolveProtocol(request) {
185
+ const matches = this.matchingProtocols(request);
186
+ if (matches.length === 0) throw new NoMatchingLpProtocolError(request);
187
+ if (matches.length > 1) throw new Error(`Multiple LP protocols match this request (${matches.map((protocol) => `${protocol.chain}:${protocol.dex}`).join(", ")}). Specify chain and dex.`);
188
+ return matches[0];
189
+ }
190
+ };
191
+ async function getLpManagementService(runtime) {
192
+ const existing = runtime.getService(LP_MANAGEMENT_SERVICE_TYPE);
193
+ if (existing) return existing;
194
+ if (typeof runtime.getServiceLoadPromise === "function") return await runtime.getServiceLoadPromise("lp-management") ?? null;
195
+ return null;
196
+ }
197
+ async function registerLpProtocolProvider(runtime, provider) {
198
+ const registry = await getLpManagementService(runtime);
199
+ if (!registry) {
200
+ logger.warn(`[LpManagementService] Cannot register ${provider.chain}:${provider.dex}; registry service is unavailable`);
201
+ return;
202
+ }
203
+ registry.registerProtocol(provider);
204
+ }
205
+ function createSolanaLpProtocolProvider({ dex, label, service }) {
206
+ const provider = {
207
+ id: `solana:${normalizeDex(dex)}`,
208
+ chain: "solana",
209
+ dex: normalizeDex(dex),
210
+ label,
211
+ service,
212
+ supportsRequest: (request) => (!request.chain || normalizeChain(request.chain) === "solana") && (!request.dex || normalizeDex(request.dex) === normalizeDex(dex)),
213
+ listPools: async (params) => {
214
+ if (typeof service.getPools !== "function") return [];
215
+ return service.getPools(params.tokenA, params.tokenB);
216
+ },
217
+ openPosition: async (params) => {
218
+ if (typeof service.addLiquidity !== "function") return unsupported(provider, "open");
219
+ const id = poolId(params.pool);
220
+ if (!id) return {
221
+ success: false,
222
+ error: "Pool is required"
223
+ };
224
+ return service.addLiquidity({
225
+ userVault: params.userVault,
226
+ poolId: id,
227
+ tokenAAmountLamports: amountValue(params, "tokenA", amountValue(params, "value")),
228
+ tokenBAmountLamports: amountValue(params, "tokenB", void 0),
229
+ slippageBps: params.slippageBps ?? 50,
230
+ tickLowerIndex: params.range?.tickLowerIndex ?? params.range?.tickLower,
231
+ tickUpperIndex: params.range?.tickUpperIndex ?? params.range?.tickUpper
232
+ });
233
+ },
234
+ closePosition: async (params) => {
235
+ if (typeof service.removeLiquidity !== "function") return unsupported(provider, "close");
236
+ const id = poolId(params.pool) || params.position;
237
+ if (!id) return {
238
+ success: false,
239
+ error: "Pool or position is required"
240
+ };
241
+ return service.removeLiquidity({
242
+ userVault: params.userVault,
243
+ poolId: id,
244
+ lpTokenAmountLamports: amountValue(params, "lpToken", amountValue(params, "value")),
245
+ slippageBps: params.slippageBps ?? 50
246
+ });
247
+ },
248
+ getPosition: async (params) => {
249
+ if (typeof service.getLpPositionDetails !== "function") return null;
250
+ const identifier = params.position || poolId(params.pool);
251
+ if (!params.owner || !identifier) return null;
252
+ return service.getLpPositionDetails(params.owner, identifier);
253
+ },
254
+ getMarketData: async (poolIds) => {
255
+ if (typeof service.getMarketDataForPools !== "function") return {};
256
+ return service.getMarketDataForPools(poolIds);
257
+ }
258
+ };
259
+ if (typeof service.repositionPosition === "function") provider.repositionPosition = (params) => service.repositionPosition(params);
260
+ return provider;
261
+ }
262
+ function createEvmLpProtocolProvider({ dex, label, service }) {
263
+ const supportedChainIds = typeof service.getSupportedChainIds === "function" ? service.getSupportedChainIds() : [];
264
+ const provider = {
265
+ id: `evm:${normalizeDex(dex)}`,
266
+ chain: "evm",
267
+ dex: normalizeDex(dex),
268
+ label,
269
+ service,
270
+ supportedChainIds,
271
+ supportsRequest: (request) => {
272
+ if (request.chain && normalizeChain(request.chain) !== "evm") return false;
273
+ if (request.dex && normalizeDex(request.dex) !== normalizeDex(dex)) return false;
274
+ if (request.chainId !== void 0 && supportedChainIds.length > 0) return supportedChainIds.includes(request.chainId);
275
+ return true;
276
+ },
277
+ listPools: async (params) => {
278
+ const chainIds = params.chainId ? [params.chainId] : supportedChainIds;
279
+ return (await Promise.all(chainIds.map((chainId) => service.getPools(chainId, params.tokenA, params.tokenB, params.feeTier)))).flat();
280
+ },
281
+ openPosition: async (params) => {
282
+ if (!params.wallet) return {
283
+ success: false,
284
+ error: "EVM wallet is required"
285
+ };
286
+ if (!params.chainId) return {
287
+ success: false,
288
+ error: "EVM chainId is required"
289
+ };
290
+ const id = poolId(params.pool);
291
+ if (!id) return {
292
+ success: false,
293
+ error: "Pool address is required"
294
+ };
295
+ const evmParams = {
296
+ wallet: params.wallet,
297
+ chainId: params.chainId,
298
+ poolAddress: id,
299
+ tokenAAmount: bigintAmount(amountValue(params, "tokenA", amountValue(params, "value"))),
300
+ tokenBAmount: bigintAmount(amountValue(params, "tokenB", void 0), void 0),
301
+ slippageBps: params.slippageBps ?? 50,
302
+ tickLower: params.range?.tickLower ?? params.range?.tickLowerIndex,
303
+ tickUpper: params.range?.tickUpper ?? params.range?.tickUpperIndex,
304
+ deadline: params.deadline
305
+ };
306
+ return service.addLiquidity(evmParams);
307
+ },
308
+ closePosition: async (params) => {
309
+ if (!params.wallet) return {
310
+ success: false,
311
+ error: "EVM wallet is required"
312
+ };
313
+ if (!params.chainId) return {
314
+ success: false,
315
+ error: "EVM chainId is required"
316
+ };
317
+ const id = poolId(params.pool);
318
+ if (!id) return {
319
+ success: false,
320
+ error: "Pool address is required"
321
+ };
322
+ const evmParams = {
323
+ wallet: params.wallet,
324
+ chainId: params.chainId,
325
+ poolAddress: id,
326
+ tokenId: params.tokenId !== void 0 ? bigintAmount(params.tokenId) : params.position ? bigintAmount(params.position) : void 0,
327
+ lpTokenAmount: bigintAmount(amountValue(params, "lpToken", amountValue(params, "value")), void 0),
328
+ percentageToRemove: typeof params.amount === "object" ? params.amount?.percentage : void 0,
329
+ slippageBps: params.slippageBps ?? 50,
330
+ deadline: params.deadline
331
+ };
332
+ return service.removeLiquidity(evmParams);
333
+ },
334
+ getPosition: async (params) => {
335
+ if (!params.owner || !params.chainId) return null;
336
+ const id = poolId(params.pool);
337
+ if (!id) return null;
338
+ return service.getPositionDetails(params.chainId, params.owner, id, params.tokenId !== void 0 ? bigintAmount(params.tokenId) : params.position ? bigintAmount(params.position) : void 0);
339
+ },
340
+ listPositions: async (params) => {
341
+ if (!params.owner || !params.chainId) return [];
342
+ return service.getAllPositions(params.chainId, params.owner);
343
+ },
344
+ getMarketData: async (poolIds) => {
345
+ if (typeof service.getMarketData !== "function") return {};
346
+ return service.getMarketData(poolIds);
347
+ }
348
+ };
349
+ if (typeof service.repositionPosition === "function") provider.repositionPosition = (params) => service.repositionPosition(params);
350
+ return provider;
351
+ }
352
+ //#endregion
353
+ export { getLpManagementService as a, createSolanaLpProtocolProvider as i, NoMatchingLpProtocolError as n, registerLpProtocolProvider as o, createEvmLpProtocolProvider as r, LpManagementService as t };
@@ -0,0 +1,99 @@
1
+ import { a as getLpManagementService, i as createSolanaLpProtocolProvider } from "./LpManagementService-BWrQ5-cO.mjs";
2
+ import { Service } from "@elizaos/core";
3
+ //#region src/lp/services/__tests__/MockLpService.ts
4
+ var MockLpService = class extends Service {
5
+ capabilityDescription = "Test-only LP service for registry scenarios.";
6
+ positions = /* @__PURE__ */ new Map();
7
+ constructor(runtime, dexName = "mock-dex") {
8
+ super(runtime);
9
+ this.dexName = dexName;
10
+ }
11
+ getDexName() {
12
+ return this.dexName;
13
+ }
14
+ async getPools(tokenAMint, tokenBMint) {
15
+ const pools = [{
16
+ id: `${this.dexName}-sol-usdc`,
17
+ displayName: `${this.dexName} SOL/USDC`,
18
+ dex: this.dexName,
19
+ tokenA: {
20
+ mint: "So11111111111111111111111111111111111111112",
21
+ symbol: "SOL",
22
+ decimals: 9
23
+ },
24
+ tokenB: {
25
+ mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
26
+ symbol: "USDC",
27
+ decimals: 6
28
+ },
29
+ apr: 12,
30
+ tvl: 1e6
31
+ }];
32
+ if (!tokenAMint && !tokenBMint) return pools;
33
+ return pools.filter((pool) => {
34
+ const mints = [pool.tokenA?.mint, pool.tokenB?.mint];
35
+ return (!tokenAMint || mints.includes(tokenAMint)) && (!tokenBMint || mints.includes(tokenBMint));
36
+ });
37
+ }
38
+ async addLiquidity(config) {
39
+ const owner = config.userVault?.publicKey?.toBase58?.() || "test-owner";
40
+ const position = {
41
+ poolId: config.poolId,
42
+ dex: this.dexName,
43
+ lpTokenBalance: {
44
+ address: `lp-${config.poolId}`,
45
+ balance: "1000",
46
+ decimals: 6,
47
+ symbol: "LP"
48
+ },
49
+ underlyingTokens: [],
50
+ accruedFees: [],
51
+ rewards: [],
52
+ valueUsd: 100
53
+ };
54
+ this.positions.set(owner, [...this.positions.get(owner) || [], position]);
55
+ return {
56
+ success: true,
57
+ transactionId: `mock-open-${this.dexName}`,
58
+ data: { poolId: config.poolId }
59
+ };
60
+ }
61
+ async removeLiquidity(config) {
62
+ const owner = config.userVault?.publicKey?.toBase58?.() || "test-owner";
63
+ this.positions.set(owner, (this.positions.get(owner) || []).filter((position) => position.poolId !== config.poolId));
64
+ return {
65
+ success: true,
66
+ transactionId: `mock-close-${this.dexName}`,
67
+ data: { poolId: config.poolId }
68
+ };
69
+ }
70
+ async getLpPositionDetails(owner, poolOrPositionIdentifier) {
71
+ return (this.positions.get(owner) || []).find((position) => position.poolId === poolOrPositionIdentifier) || null;
72
+ }
73
+ async getMarketDataForPools(poolIds) {
74
+ return Object.fromEntries(poolIds.map((poolId) => [poolId, {
75
+ apr: 12,
76
+ tvl: 1e6
77
+ }]));
78
+ }
79
+ async start() {}
80
+ async stop() {}
81
+ };
82
+ async function registerMockDexServices(runtime) {
83
+ const registry = await getLpManagementService(runtime);
84
+ if (!registry) return;
85
+ for (const dex of [
86
+ "raydium",
87
+ "orca",
88
+ "meteora"
89
+ ]) {
90
+ const service = new MockLpService(runtime, dex);
91
+ registry.registerProtocol(createSolanaLpProtocolProvider({
92
+ dex,
93
+ label: dex,
94
+ service
95
+ }));
96
+ }
97
+ }
98
+ //#endregion
99
+ export { registerMockDexServices };