@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,163 @@
1
+ // @ts-nocheck — legacy code from absorbed plugins (lp-manager, lpinfo, dexscreener, defi-news, birdeye); strict types pending cleanup
2
+ import { type IAgentRuntime, Service } from "@elizaos/core";
3
+ import type {
4
+ IUserLpProfileService,
5
+ TrackedLpPosition,
6
+ TrackedLpPositionInput,
7
+ UserLpProfile,
8
+ } from "../types.ts";
9
+
10
+ export class UserLpProfileService
11
+ extends Service
12
+ implements IUserLpProfileService
13
+ {
14
+ public static readonly serviceType = "UserLpProfileService";
15
+ public readonly capabilityDescription =
16
+ "Manages user profiles and preferences for LP management.";
17
+ private profiles: Map<string, UserLpProfile> = new Map();
18
+
19
+ async start(_runtime?: IAgentRuntime): Promise<void> {
20
+ // No-op
21
+ }
22
+
23
+ async stop(_runtime?: IAgentRuntime): Promise<void> {
24
+ // No-op
25
+ }
26
+
27
+ // Static methods required by ElizaOS Service architecture
28
+ static async start(runtime: IAgentRuntime): Promise<UserLpProfileService> {
29
+ const service = new UserLpProfileService(runtime);
30
+ await service.start(runtime);
31
+ return service;
32
+ }
33
+
34
+ static async stop(_runtime: IAgentRuntime): Promise<void> {
35
+ // No cleanup needed for static stop
36
+ }
37
+
38
+ public async ensureProfile(
39
+ userId: string,
40
+ vaultPublicKey: string,
41
+ encryptedSecretKey: string,
42
+ initialConfig?: Partial<UserLpProfile["autoRebalanceConfig"]>,
43
+ ): Promise<UserLpProfile> {
44
+ const profile = await this.getProfile(userId);
45
+ if (profile) {
46
+ // Update existing profile if vault details or config have changed
47
+ const updates: Partial<UserLpProfile> = {};
48
+ if (profile.vaultPublicKey !== vaultPublicKey) {
49
+ updates.vaultPublicKey = vaultPublicKey;
50
+ }
51
+ if (profile.encryptedSecretKey !== encryptedSecretKey) {
52
+ updates.encryptedSecretKey = encryptedSecretKey;
53
+ }
54
+ if (initialConfig) {
55
+ updates.autoRebalanceConfig = {
56
+ ...profile.autoRebalanceConfig,
57
+ ...initialConfig,
58
+ };
59
+ }
60
+ if (Object.keys(updates).length > 0) {
61
+ return this.updateProfile(userId, updates);
62
+ }
63
+ return profile;
64
+ }
65
+
66
+ const newProfile: UserLpProfile = {
67
+ userId,
68
+ vaultPublicKey,
69
+ encryptedSecretKey,
70
+ autoRebalanceConfig: {
71
+ enabled: false,
72
+ minGainThresholdPercent: 1.0,
73
+ maxSlippageBps: 50,
74
+ cycleIntervalHours: 24,
75
+ ...initialConfig,
76
+ },
77
+ trackedPositions: [],
78
+ createdAt: new Date().toISOString(),
79
+ updatedAt: new Date().toISOString(),
80
+ version: 1,
81
+ };
82
+
83
+ this.profiles.set(userId, newProfile);
84
+ return newProfile;
85
+ }
86
+
87
+ public async getProfile(userId: string): Promise<UserLpProfile | null> {
88
+ return this.profiles.get(userId) || null;
89
+ }
90
+
91
+ public async updateProfile(
92
+ userId: string,
93
+ updates: Partial<Omit<UserLpProfile, "userId" | "createdAt" | "version">>,
94
+ ): Promise<UserLpProfile> {
95
+ const profile = await this.getProfile(userId);
96
+ if (!profile) {
97
+ throw new Error("User profile not found.");
98
+ }
99
+
100
+ // Handle autoRebalanceConfig merging
101
+ const finalUpdates = { ...updates };
102
+ if (updates.autoRebalanceConfig && profile.autoRebalanceConfig) {
103
+ finalUpdates.autoRebalanceConfig = {
104
+ ...profile.autoRebalanceConfig,
105
+ ...updates.autoRebalanceConfig,
106
+ };
107
+ }
108
+
109
+ const updatedProfile: UserLpProfile = {
110
+ ...profile,
111
+ ...finalUpdates,
112
+ updatedAt: new Date().toISOString(),
113
+ version: (profile.version || 1) + 1,
114
+ };
115
+
116
+ this.profiles.set(userId, updatedProfile);
117
+ return updatedProfile;
118
+ }
119
+
120
+ public async addTrackedPosition(
121
+ userId: string,
122
+ position: TrackedLpPositionInput,
123
+ ): Promise<UserLpProfile> {
124
+ const profile = await this.getProfile(userId);
125
+ if (!profile) {
126
+ throw new Error("User profile not found.");
127
+ }
128
+
129
+ const newPosition: TrackedLpPosition = {
130
+ ...position,
131
+ trackedAt: new Date().toISOString(),
132
+ };
133
+
134
+ const updatedPositions = [...(profile.trackedPositions || []), newPosition];
135
+ return this.updateProfile(userId, { trackedPositions: updatedPositions });
136
+ }
137
+
138
+ public async removeTrackedPosition(
139
+ userId: string,
140
+ positionIdentifier: string,
141
+ ): Promise<UserLpProfile> {
142
+ const profile = await this.getProfile(userId);
143
+ if (!profile) {
144
+ throw new Error("User profile not found.");
145
+ }
146
+ const updatedPositions = (profile.trackedPositions || []).filter(
147
+ (p) => p.positionIdentifier !== positionIdentifier,
148
+ );
149
+ return this.updateProfile(userId, { trackedPositions: updatedPositions });
150
+ }
151
+
152
+ public async getTrackedPositions(
153
+ userId: string,
154
+ ): Promise<TrackedLpPosition[]> {
155
+ const profile = await this.getProfile(userId);
156
+ return profile?.trackedPositions || [];
157
+ }
158
+
159
+ async getAllProfilesWithAutoRebalanceEnabled(): Promise<UserLpProfile[]> {
160
+ const allProfiles = Array.from(this.profiles.values());
161
+ return allProfiles.filter((p) => p.autoRebalanceConfig.enabled);
162
+ }
163
+ }
@@ -0,0 +1,153 @@
1
+ // @ts-nocheck — legacy code from absorbed plugins (lp-manager, lpinfo, dexscreener, defi-news, birdeye); strict types pending cleanup
2
+ import { type IAgentRuntime, Service } from "@elizaos/core";
3
+ import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
4
+ import {
5
+ type Connection,
6
+ Keypair,
7
+ LAMPORTS_PER_SOL,
8
+ PublicKey,
9
+ } from "@solana/web3.js";
10
+ import type { IVaultService, TokenBalance } from "../types.ts";
11
+ import { getConnection } from "../utils/solanaClient.ts";
12
+
13
+ export class VaultService extends Service implements IVaultService {
14
+ public static readonly serviceType = "VaultService";
15
+ public readonly capabilityDescription =
16
+ "Manages secure vaults for user cryptographic keys.";
17
+
18
+ private connection!: Connection;
19
+ // Simple in-memory cache for vault public keys - in production, use proper storage
20
+ private vaultCache: Map<string, string> = new Map();
21
+
22
+ static async start(runtime: IAgentRuntime): Promise<VaultService> {
23
+ const service = new VaultService();
24
+ await service.start(runtime);
25
+ return service;
26
+ }
27
+
28
+ static async stop(_runtime: IAgentRuntime): Promise<void> {
29
+ // No cleanup needed for static stop
30
+ }
31
+
32
+ async start(runtime: IAgentRuntime): Promise<void> {
33
+ // Initialize connection
34
+ this.connection = getConnection(runtime);
35
+ }
36
+
37
+ async stop(): Promise<void> {
38
+ // No-op
39
+ }
40
+
41
+ public async createVault(
42
+ userId: string,
43
+ ): Promise<{ publicKey: string; secretKeyEncrypted: string }> {
44
+ const keypair = Keypair.generate();
45
+ const publicKey = keypair.publicKey.toBase58();
46
+ const secretKeyEncrypted = Buffer.from(keypair.secretKey).toString("hex");
47
+
48
+ // Cache the public key
49
+ this.vaultCache.set(userId, publicKey);
50
+
51
+ return { publicKey, secretKeyEncrypted };
52
+ }
53
+
54
+ public async getVaultKeypair(
55
+ userId: string,
56
+ encryptedSecretKey: string,
57
+ ): Promise<Keypair> {
58
+ try {
59
+ const secretKey = Buffer.from(encryptedSecretKey, "hex");
60
+ if (secretKey.length !== 64) {
61
+ throw new Error("Invalid secret key length.");
62
+ }
63
+ return Keypair.fromSecretKey(new Uint8Array(secretKey));
64
+ } catch (error) {
65
+ console.error(
66
+ `Failed to create Keypair from secret for user ${userId}:`,
67
+ error,
68
+ );
69
+ throw new Error("Could not derive Keypair from the provided secret.");
70
+ }
71
+ }
72
+
73
+ public async getVaultPublicKey(userId: string): Promise<string | null> {
74
+ // Check cache first
75
+ const cached = this.vaultCache.get(userId);
76
+ if (cached) {
77
+ return cached;
78
+ }
79
+
80
+ // In a real implementation, this would fetch from persistent storage
81
+ // For now, return null if not in cache
82
+ return null;
83
+ }
84
+
85
+ public async getBalances(publicKey: string): Promise<TokenBalance[]> {
86
+ try {
87
+ const pubKey = new PublicKey(publicKey);
88
+ const balances: TokenBalance[] = [];
89
+
90
+ // Get SOL balance
91
+ const solBalance = await this.connection.getBalance(pubKey);
92
+ balances.push({
93
+ address: "SOL",
94
+ balance: solBalance.toString(),
95
+ decimals: 9,
96
+ uiAmount: solBalance / LAMPORTS_PER_SOL,
97
+ name: "Solana",
98
+ symbol: "SOL",
99
+ });
100
+
101
+ // Get SPL token accounts
102
+ const tokenAccounts = await this.connection.getParsedTokenAccountsByOwner(
103
+ pubKey,
104
+ {
105
+ programId: TOKEN_PROGRAM_ID,
106
+ },
107
+ );
108
+
109
+ for (const account of tokenAccounts.value) {
110
+ const parsedInfo = account.account.data.parsed.info;
111
+ const tokenBalance = parsedInfo.tokenAmount;
112
+
113
+ balances.push({
114
+ address: parsedInfo.mint,
115
+ balance: tokenBalance.amount,
116
+ decimals: tokenBalance.decimals,
117
+ uiAmount: tokenBalance.uiAmount,
118
+ // Note: symbol and name would need to be fetched from token metadata
119
+ // For now, we'll leave them undefined
120
+ });
121
+ }
122
+
123
+ return balances;
124
+ } catch (error) {
125
+ console.error("Error fetching balances:", error);
126
+ throw new Error(
127
+ `Failed to fetch balances for ${publicKey}: ${error instanceof Error ? error.message : "Unknown error"}`,
128
+ );
129
+ }
130
+ }
131
+
132
+ public async exportPrivateKey(
133
+ userId: string,
134
+ encryptedSecretKey: string,
135
+ confirmationToken: string,
136
+ ): Promise<string> {
137
+ // In a real implementation, you would verify the confirmationToken
138
+ // For now, we'll do a simple check
139
+ if (!confirmationToken || confirmationToken.length < 6) {
140
+ throw new Error("Invalid confirmation token");
141
+ }
142
+
143
+ try {
144
+ const keypair = await this.getVaultKeypair(userId, encryptedSecretKey);
145
+ // Return base58 encoded private key
146
+ const bs58 = await import("bs58");
147
+ return bs58.default.encode(keypair.secretKey);
148
+ } catch (error) {
149
+ console.error("Error exporting private key:", error);
150
+ throw new Error("Failed to export private key");
151
+ }
152
+ }
153
+ }
@@ -0,0 +1,344 @@
1
+ // @ts-nocheck — legacy code from absorbed plugins (lp-manager, lpinfo, dexscreener, defi-news, birdeye); strict types pending cleanup
2
+ import { type IAgentRuntime, Service } from "@elizaos/core";
3
+ import { LAMPORTS_PER_SOL } from "@solana/web3.js"; // For SOL price placeholder
4
+ import type {
5
+ IDexInteractionService,
6
+ IUserLpProfileService,
7
+ LpPositionDetails,
8
+ OptimizationOpportunity,
9
+ PoolInfo,
10
+ TokenBalance,
11
+ } from "../types.ts";
12
+ import type { DexInteractionService } from "./DexInteractionService.ts";
13
+ import type { UserLpProfileService } from "./UserLpProfileService.ts";
14
+
15
+ // Placeholder constants - should be configurable or dynamically fetched
16
+ const _AVG_SOL_TX_FEE_LAMPORTS = BigInt(5000); // Average fee for a simple Solana transaction
17
+ const AVG_SWAP_TX_FEE_LAMPORTS = BigInt(10000); // Potentially higher for swaps involving more accounts/CUs
18
+ const AVG_LP_ADD_REMOVE_TX_FEE_LAMPORTS = BigInt(15000); // LP operations can be more complex
19
+ const PLACEHOLDER_SOL_PRICE_USD = 150; // Placeholder for SOL price in USD
20
+ const _PLACEHOLDER_SWAP_FEE_BPS = 30; // Placeholder for swap fee in basis points (0.3%)
21
+
22
+ /**
23
+ * Interface for the YieldOptimizationService.
24
+ * This service is responsible for fetching data about available LP pools,
25
+ * finding better yield opportunities, and calculating the costs of rebalancing.
26
+ */
27
+ export interface IYieldOptimizationService extends Service {
28
+ /**
29
+ * Fetches comprehensive data for all relevant pools across all supported DEXs.
30
+ * This data is used as the basis for finding optimization opportunities.
31
+ * @returns A promise that resolves to an array of PoolInfo objects.
32
+ */
33
+ fetchAllPoolData(): Promise<PoolInfo[]>;
34
+
35
+ /**
36
+ * Analyzes current LP positions and idle assets to find better yield opportunities.
37
+ * @param userId - The user's ID
38
+ * @param currentPositions - An array of the user's current LpPositionDetails.
39
+ * @param idleAssets - An array of the user's idle TokenBalance that could be deployed.
40
+ * @returns A promise that resolves to an array of OptimizationOpportunity objects.
41
+ */
42
+ findBestYieldOpportunities(
43
+ userId: string,
44
+ currentPositions: LpPositionDetails[],
45
+ idleAssets: TokenBalance[],
46
+ ): Promise<OptimizationOpportunity[]>;
47
+
48
+ /**
49
+ * Calculates the estimated cost of moving liquidity from one position/pool to another.
50
+ * This includes transaction fees, swap fees (if tokens need to be swapped), and potential slippage.
51
+ * @param fromPosition - The user's current LpPositionDetails (if rebalancing an existing position).
52
+ * @param toPool - The target PoolInfo to move liquidity to.
53
+ * @param solPriceUsd - The current SOL price in USD
54
+ * @param amountToMoveLamports - Optional. The specific amount of LP value (in SOL or stablecoin equivalent) to move.
55
+ * @returns A promise that resolves to an object detailing the costs.
56
+ */
57
+ calculateRebalanceCost(
58
+ fromPosition: LpPositionDetails | null,
59
+ toPool: PoolInfo,
60
+ solPriceUsd: number,
61
+ amountToMoveLamports?: string,
62
+ underlyingTokensToMove?: TokenBalance[], // Specific tokens being moved, if known (e.g. after withdrawal)
63
+ ): Promise<{
64
+ costSolLamports: string;
65
+ costUsd?: number;
66
+ steps: string[];
67
+ error?: string;
68
+ }>;
69
+
70
+ findBestYield(
71
+ userId: string,
72
+ currentTokenA: string,
73
+ currentTokenB: string,
74
+ ): Promise<OptimizationOpportunity[]>;
75
+ }
76
+
77
+ export class YieldOptimizationService
78
+ extends Service
79
+ implements IYieldOptimizationService
80
+ {
81
+ public static readonly serviceType = "YieldOptimizationService";
82
+ public readonly capabilityDescription =
83
+ "Finds and evaluates yield optimization opportunities across DEXs.";
84
+
85
+ private dexInteractionService!: IDexInteractionService;
86
+ private userLpProfileService!: IUserLpProfileService;
87
+
88
+ // Static methods required by ElizaOS Service architecture
89
+ static async start(
90
+ runtime: IAgentRuntime,
91
+ ): Promise<YieldOptimizationService> {
92
+ const service = new YieldOptimizationService(runtime);
93
+ await service.start(runtime);
94
+ return service;
95
+ }
96
+
97
+ static async stop(_runtime: IAgentRuntime): Promise<void> {
98
+ // No cleanup needed for static stop
99
+ }
100
+
101
+ async start(runtime: IAgentRuntime): Promise<void> {
102
+ const dexInteractionService =
103
+ runtime.getService<DexInteractionService>("dex-interaction");
104
+ const userLpProfileService = runtime.getService<UserLpProfileService>(
105
+ "UserLpProfileService",
106
+ );
107
+ if (!dexInteractionService || !userLpProfileService) {
108
+ throw new Error(
109
+ "Required services for YieldOptimizationService not available.",
110
+ );
111
+ }
112
+ this.dexInteractionService = dexInteractionService;
113
+ this.userLpProfileService = userLpProfileService;
114
+ }
115
+
116
+ async stop(): Promise<void> {
117
+ // No-op
118
+ }
119
+
120
+ async fetchAllPoolData(): Promise<PoolInfo[]> {
121
+ const pools = await this.dexInteractionService.getPools();
122
+ return pools;
123
+ }
124
+
125
+ async calculateRebalanceCost(
126
+ fromPositionOrNull: LpPositionDetails | null,
127
+ targetPool: PoolInfo,
128
+ solPriceUsd: number,
129
+ _valueOfLpTokensToMoveLamports?: string,
130
+ underlyingTokensAvailable?: TokenBalance[],
131
+ ): Promise<{
132
+ costSolLamports: string;
133
+ costUsd?: number;
134
+ steps: string[];
135
+ error?: string;
136
+ }> {
137
+ const steps: string[] = [];
138
+ let totalEstimatedCostLamports = BigInt(0);
139
+
140
+ if (fromPositionOrNull) {
141
+ steps.push(
142
+ `1. Withdraw from ${fromPositionOrNull.dex} pool: ${fromPositionOrNull.poolId}`,
143
+ );
144
+ totalEstimatedCostLamports += AVG_LP_ADD_REMOVE_TX_FEE_LAMPORTS;
145
+ }
146
+
147
+ let needsSwap = false;
148
+ if (underlyingTokensAvailable && underlyingTokensAvailable.length === 2) {
149
+ const targetTokenA = targetPool.tokenA.mint;
150
+ const targetTokenB = targetPool.tokenB.mint;
151
+ const hasTokenA = underlyingTokensAvailable.find(
152
+ (t) => t.address === targetTokenA,
153
+ );
154
+ const hasTokenB = underlyingTokensAvailable.find(
155
+ (t) => t.address === targetTokenB,
156
+ );
157
+ if (!hasTokenA || !hasTokenB) {
158
+ needsSwap = true;
159
+ }
160
+ } else if (fromPositionOrNull) {
161
+ const sourceTokens = fromPositionOrNull.underlyingTokens
162
+ .map((t: TokenBalance) => t.address)
163
+ .sort();
164
+ const targetTokens = [
165
+ targetPool.tokenA.mint,
166
+ targetPool.tokenB.mint,
167
+ ].sort();
168
+ if (sourceTokens.join(",") !== targetTokens.join(",")) {
169
+ needsSwap = true;
170
+ }
171
+ } else {
172
+ needsSwap = true;
173
+ }
174
+
175
+ if (needsSwap) {
176
+ steps.push(
177
+ `2. (Potentially) Swap tokens to match ${targetPool.tokenA.symbol || "TokenA"}/${targetPool.tokenB.symbol || "TokenB"}`,
178
+ );
179
+ totalEstimatedCostLamports += AVG_SWAP_TX_FEE_LAMPORTS;
180
+ }
181
+
182
+ steps.push(`3. Deposit to ${targetPool.dex} pool: ${targetPool.id}`);
183
+ totalEstimatedCostLamports += AVG_LP_ADD_REMOVE_TX_FEE_LAMPORTS;
184
+
185
+ const costSolLamportsStr = totalEstimatedCostLamports.toString();
186
+ const costUsd =
187
+ (Number(totalEstimatedCostLamports) / Number(LAMPORTS_PER_SOL)) *
188
+ solPriceUsd;
189
+
190
+ return {
191
+ costSolLamports: costSolLamportsStr,
192
+ costUsd: parseFloat(costUsd.toFixed(2)),
193
+ steps,
194
+ };
195
+ }
196
+
197
+ async findBestYieldOpportunities(
198
+ userId: string,
199
+ currentPositions: LpPositionDetails[],
200
+ idleAssets: TokenBalance[],
201
+ ): Promise<OptimizationOpportunity[]> {
202
+ const userProfile = await this.userLpProfileService.getProfile(userId);
203
+ if (!userProfile) {
204
+ return [];
205
+ }
206
+ const allAvailablePools = await this.fetchAllPoolData();
207
+ const opportunities: OptimizationOpportunity[] = [];
208
+ const solPriceUsdForCosting = PLACEHOLDER_SOL_PRICE_USD;
209
+
210
+ for (const position of currentPositions) {
211
+ const { underlyingTokens } = position;
212
+ const currentYield =
213
+ (position.metadata?.apy as number) ||
214
+ (position.metadata?.apr as number) ||
215
+ 0;
216
+
217
+ for (const targetPool of allAvailablePools) {
218
+ if (
219
+ targetPool.id === position.poolId &&
220
+ targetPool.dex === position.dex
221
+ )
222
+ continue;
223
+
224
+ const sourceMints = underlyingTokens.map(
225
+ (t: TokenBalance) => t.address,
226
+ );
227
+ const targetMints = [targetPool.tokenA.mint, targetPool.tokenB.mint];
228
+ const canPotentiallyFormPair = sourceMints.some((sm: string) =>
229
+ targetMints.includes(sm),
230
+ );
231
+
232
+ if (canPotentiallyFormPair) {
233
+ const estimatedNewYield = targetPool.apy || targetPool.apr || 0;
234
+ if (estimatedNewYield > currentYield) {
235
+ const costDetails = await this.calculateRebalanceCost(
236
+ position,
237
+ targetPool,
238
+ solPriceUsdForCosting,
239
+ undefined,
240
+ underlyingTokens,
241
+ );
242
+ const positionValueUsd = position.valueUsd || 1;
243
+ const costInYieldTerms =
244
+ (costDetails.costUsd || 0) / positionValueUsd;
245
+
246
+ const netGainPercent =
247
+ (estimatedNewYield - currentYield - costInYieldTerms) * 100;
248
+
249
+ if (
250
+ netGainPercent >
251
+ userProfile.autoRebalanceConfig.minGainThresholdPercent
252
+ ) {
253
+ opportunities.push({
254
+ sourcePosition: position,
255
+ sourcePool: {
256
+ id: position.poolId,
257
+ dex: position.dex,
258
+ tokenA: {
259
+ mint: position.underlyingTokens[0].address,
260
+ symbol: position.underlyingTokens[0].symbol,
261
+ decimals: position.underlyingTokens[0].decimals,
262
+ },
263
+ tokenB: {
264
+ mint: position.underlyingTokens[1].address,
265
+ symbol: position.underlyingTokens[1].symbol,
266
+ decimals: position.underlyingTokens[1].decimals,
267
+ },
268
+ apr: currentYield,
269
+ },
270
+ targetPool,
271
+ estimatedNewYield: estimatedNewYield * 100,
272
+ currentYield: currentYield * 100,
273
+ estimatedCostToMoveLamports: costDetails.costSolLamports,
274
+ estimatedCostToMoveUsd: costDetails.costUsd,
275
+ netGainPercent: parseFloat(netGainPercent.toFixed(2)),
276
+ reason: `Potential ${netGainPercent.toFixed(2)}% net APY increase. Current: ${(currentYield * 100).toFixed(2)}%, New: ${(estimatedNewYield * 100).toFixed(2)}%`,
277
+ actions: costDetails.steps,
278
+ });
279
+ }
280
+ }
281
+ }
282
+ }
283
+ }
284
+
285
+ if (idleAssets.length > 0) {
286
+ for (const pool of allAvailablePools) {
287
+ if (
288
+ (pool.apr || 0) <=
289
+ userProfile.autoRebalanceConfig.minGainThresholdPercent / 100
290
+ )
291
+ continue;
292
+ const canFormFromIdle = idleAssets.some(
293
+ (asset) =>
294
+ asset.address === pool.tokenA.mint ||
295
+ asset.address === pool.tokenB.mint,
296
+ );
297
+ if (canFormFromIdle) {
298
+ const costDetails = await this.calculateRebalanceCost(
299
+ null,
300
+ pool,
301
+ solPriceUsdForCosting,
302
+ undefined,
303
+ idleAssets,
304
+ );
305
+ if (
306
+ (pool.apr || 0) * 100 >
307
+ userProfile.autoRebalanceConfig.minGainThresholdPercent
308
+ ) {
309
+ opportunities.push({
310
+ targetPool: pool,
311
+ estimatedNewYield: (pool.apr || 0) * 100,
312
+ currentYield: 0,
313
+ estimatedCostToMoveLamports: costDetails.costSolLamports,
314
+ estimatedCostToMoveUsd: costDetails.costUsd,
315
+ netGainPercent:
316
+ (pool.apr || 0) * 100 -
317
+ ((costDetails.costUsd || 0) / 1000) * 100,
318
+ reason: `Deploy idle assets to ${pool.displayName || pool.id} with APR of ${((pool.apr || 0) * 100).toFixed(2)}%`,
319
+ actions: costDetails.steps.filter(
320
+ (s) => !s.toLowerCase().includes("withdraw"),
321
+ ),
322
+ });
323
+ }
324
+ }
325
+ }
326
+ }
327
+
328
+ opportunities.sort(
329
+ (a, b) => (b.netGainPercent || 0) - (a.netGainPercent || 0),
330
+ );
331
+ return opportunities;
332
+ }
333
+
334
+ public async findBestYield(
335
+ userId: string,
336
+ currentTokenA: string,
337
+ currentTokenB: string,
338
+ ): Promise<OptimizationOpportunity[]> {
339
+ console.log(
340
+ `Finding best yield for user ${userId} with tokens ${currentTokenA} and ${currentTokenB}`,
341
+ );
342
+ return [];
343
+ }
344
+ }