@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,410 @@
1
+ /** Multi-provider RPC: Alchemy, Infura, Ankr, Eliza Cloud with per-chain fallback. */
2
+
3
+ import type { IAgentRuntime } from "@elizaos/core";
4
+ import { logger } from "@elizaos/core";
5
+
6
+ function hasStringSetting(runtime: IAgentRuntime, key: string): boolean {
7
+ const value = runtime.getSetting(key);
8
+ return typeof value === "string" && value.trim().length > 0;
9
+ }
10
+
11
+ function getStringSetting(runtime: IAgentRuntime, key: string): string | undefined {
12
+ const value = runtime.getSetting(key);
13
+ const normalized = typeof value === "string" ? value.trim() : "";
14
+ return normalized.length > 0 ? normalized : undefined;
15
+ }
16
+
17
+ function getObjectProperty(source: unknown, key: string): unknown {
18
+ if (typeof source !== "object" || source === null) return undefined;
19
+ return Reflect.get(source, key);
20
+ }
21
+
22
+ function getObjectStringProperty(source: unknown, key: string): string | undefined {
23
+ const value = getObjectProperty(source, key);
24
+ const normalized = typeof value === "string" ? value.trim() : "";
25
+ return normalized.length > 0 ? normalized : undefined;
26
+ }
27
+
28
+ function getCharacterSecret(runtime: IAgentRuntime, key: string): string | undefined {
29
+ const character = runtime.character;
30
+ const settings = getObjectProperty(character, "settings");
31
+ return (
32
+ getObjectStringProperty(getObjectProperty(character, "secrets"), key) ??
33
+ getObjectStringProperty(getObjectProperty(settings, "secrets"), key)
34
+ );
35
+ }
36
+
37
+ function getCloudApiKey(runtime: IAgentRuntime): string | undefined {
38
+ return (
39
+ getStringSetting(runtime, "ELIZAOS_CLOUD_API_KEY") ??
40
+ getCharacterSecret(runtime, "ELIZAOS_CLOUD_API_KEY") ??
41
+ (process.env.ELIZAOS_CLOUD_API_KEY?.trim() || undefined)
42
+ );
43
+ }
44
+
45
+ function hasCloudRpcAccess(runtime: IAgentRuntime): boolean {
46
+ return Boolean(getCloudApiKey(runtime));
47
+ }
48
+
49
+ export type RPCProviderName = "alchemy" | "infura" | "ankr" | "elizacloud";
50
+
51
+ export interface RPCProviderConfig {
52
+ name: RPCProviderName;
53
+ apiKey: string;
54
+ supportedChains: ReadonlySet<string>;
55
+ buildUrl: (chainName: string, apiKey: string) => string | null;
56
+ }
57
+
58
+ // Alchemy: https://docs.alchemy.com/reference/supported-chains
59
+ const ALCHEMY_CHAIN_MAP: Readonly<Record<string, string>> = {
60
+ mainnet: "eth-mainnet",
61
+ sepolia: "eth-sepolia",
62
+ holesky: "eth-holesky",
63
+ polygon: "polygon-mainnet",
64
+ polygonMumbai: "polygon-mumbai",
65
+ polygonAmoy: "polygon-amoy",
66
+ arbitrum: "arb-mainnet",
67
+ arbitrumSepolia: "arb-sepolia",
68
+ optimism: "opt-mainnet",
69
+ optimismSepolia: "opt-sepolia",
70
+ base: "base-mainnet",
71
+ baseSepolia: "base-sepolia",
72
+ zksync: "zksync-mainnet",
73
+ zksyncSepolia: "zksync-sepolia",
74
+ linea: "linea-mainnet",
75
+ lineaSepolia: "linea-sepolia",
76
+ scroll: "scroll-mainnet",
77
+ scrollSepolia: "scroll-sepolia",
78
+ blast: "blast-mainnet",
79
+ blastSepolia: "blast-sepolia",
80
+ avalanche: "avax-mainnet",
81
+ avalancheFuji: "avax-fuji",
82
+ bsc: "bnb-mainnet",
83
+ bscTestnet: "bnb-testnet",
84
+ celo: "celo-mainnet",
85
+ celoAlfajores: "celo-alfajores",
86
+ gnosis: "gnosis-mainnet",
87
+ worldchain: "worldchain-mainnet",
88
+ shape: "shape-mainnet",
89
+ };
90
+
91
+ // Infura: https://docs.infura.io/api/networks
92
+ const INFURA_CHAIN_MAP: Readonly<Record<string, string>> = {
93
+ mainnet: "mainnet",
94
+ sepolia: "sepolia",
95
+ holesky: "holesky",
96
+ polygon: "polygon-mainnet",
97
+ polygonMumbai: "polygon-mumbai",
98
+ polygonAmoy: "polygon-amoy",
99
+ arbitrum: "arbitrum-mainnet",
100
+ arbitrumSepolia: "arbitrum-sepolia",
101
+ optimism: "optimism-mainnet",
102
+ optimismSepolia: "optimism-sepolia",
103
+ base: "base-mainnet",
104
+ baseSepolia: "base-sepolia",
105
+ linea: "linea-mainnet",
106
+ lineaSepolia: "linea-sepolia",
107
+ blast: "blast-mainnet",
108
+ avalanche: "avalanche-mainnet",
109
+ avalancheFuji: "avalanche-fuji",
110
+ bsc: "bsc-mainnet",
111
+ celo: "celo-mainnet",
112
+ celoAlfajores: "celo-alfajores",
113
+ scroll: "scroll-mainnet",
114
+ scrollSepolia: "scroll-sepolia",
115
+ mantle: "mantle-mainnet",
116
+ mantleSepolia: "mantle-sepolia",
117
+ zkSyncEra: "zksync-mainnet",
118
+ zkSyncSepolia: "zksync-sepolia",
119
+ gnosis: "gnosis-mainnet",
120
+ };
121
+
122
+ // Ankr: https://www.ankr.com/docs/rpc-service/chains/chains-list/
123
+ const ANKR_CHAIN_MAP: Readonly<Record<string, string>> = {
124
+ mainnet: "eth",
125
+ sepolia: "eth_sepolia",
126
+ holesky: "eth_holesky",
127
+ polygon: "polygon",
128
+ polygonMumbai: "polygon_mumbai",
129
+ polygonAmoy: "polygon_amoy",
130
+ arbitrum: "arbitrum",
131
+ arbitrumSepolia: "arbitrum_sepolia",
132
+ optimism: "optimism",
133
+ optimismSepolia: "optimism_sepolia",
134
+ base: "base",
135
+ baseSepolia: "base_sepolia",
136
+ avalanche: "avalanche",
137
+ avalancheFuji: "avalanche_fuji",
138
+ bsc: "bsc",
139
+ bscTestnet: "bsc_testnet_chapel",
140
+ gnosis: "gnosis",
141
+ fantom: "fantom",
142
+ celo: "celo",
143
+ linea: "linea",
144
+ scroll: "scroll",
145
+ blast: "blast",
146
+ zksync: "zksync_era",
147
+ mantle: "mantle",
148
+ mode: "mode",
149
+ };
150
+
151
+ // Eliza Cloud proxy — shared endpoint for all chains
152
+ const ELIZACLOUD_SUPPORTED_CHAINS = new Set([
153
+ "mainnet",
154
+ "sepolia",
155
+ "holesky",
156
+ "polygon",
157
+ "polygonMumbai",
158
+ "polygonAmoy",
159
+ "arbitrum",
160
+ "arbitrumSepolia",
161
+ "optimism",
162
+ "optimismSepolia",
163
+ "base",
164
+ "baseSepolia",
165
+ "avalanche",
166
+ "avalancheFuji",
167
+ "bsc",
168
+ "bscTestnet",
169
+ "gnosis",
170
+ "fantom",
171
+ "celo",
172
+ "celoAlfajores",
173
+ "linea",
174
+ "lineaSepolia",
175
+ "scroll",
176
+ "scrollSepolia",
177
+ "blast",
178
+ "blastSepolia",
179
+ "zksync",
180
+ "zksyncSepolia",
181
+ "mantle",
182
+ "mantleSepolia",
183
+ "mode",
184
+ ]);
185
+
186
+ function createAlchemyProvider(apiKey: string): RPCProviderConfig {
187
+ return {
188
+ name: "alchemy",
189
+ apiKey,
190
+ supportedChains: new Set(Object.keys(ALCHEMY_CHAIN_MAP)),
191
+ buildUrl(chainName: string, key: string): string | null {
192
+ const slug = ALCHEMY_CHAIN_MAP[chainName];
193
+ if (!slug) return null;
194
+ return `https://${slug}.g.alchemy.com/v2/${key}`;
195
+ },
196
+ };
197
+ }
198
+
199
+ function createInfuraProvider(apiKey: string): RPCProviderConfig {
200
+ return {
201
+ name: "infura",
202
+ apiKey,
203
+ supportedChains: new Set(Object.keys(INFURA_CHAIN_MAP)),
204
+ buildUrl(chainName: string, key: string): string | null {
205
+ const slug = INFURA_CHAIN_MAP[chainName];
206
+ if (!slug) return null;
207
+ return `https://${slug}.infura.io/v3/${key}`;
208
+ },
209
+ };
210
+ }
211
+
212
+ function createAnkrProvider(apiKey: string): RPCProviderConfig {
213
+ return {
214
+ name: "ankr",
215
+ apiKey,
216
+ supportedChains: new Set(Object.keys(ANKR_CHAIN_MAP)),
217
+ buildUrl(chainName: string, key: string): string | null {
218
+ const slug = ANKR_CHAIN_MAP[chainName];
219
+ if (!slug) return null;
220
+ return `https://rpc.ankr.com/${slug}/${key}`;
221
+ },
222
+ };
223
+ }
224
+
225
+ function createElizaCloudProvider(apiKey: string, baseUrl: string): RPCProviderConfig {
226
+ return {
227
+ name: "elizacloud",
228
+ apiKey,
229
+ supportedChains: ELIZACLOUD_SUPPORTED_CHAINS,
230
+ buildUrl(chainName: string, _key: string): string | null {
231
+ if (!ELIZACLOUD_SUPPORTED_CHAINS.has(chainName)) return null;
232
+ return `${baseUrl}/proxy/evm-rpc/${chainName}`;
233
+ },
234
+ };
235
+ }
236
+
237
+ export interface ResolvedRPCProvider {
238
+ providerName: RPCProviderName;
239
+ rpcUrl: string;
240
+ headers: Record<string, string>;
241
+ }
242
+
243
+ export interface RPCProviderManager {
244
+ resolveForChain(chainName: string): ResolvedRPCProvider | null;
245
+ getConfiguredProviders(): RPCProviderName[];
246
+ getCoveredChains(): string[];
247
+ isChainCovered(chainName: string): boolean;
248
+ }
249
+
250
+ export function initRPCProviderManager(runtime: IAgentRuntime): RPCProviderManager {
251
+ const preferredRaw = runtime.getSetting("EVM_RPC_PROVIDER");
252
+ const preferred =
253
+ typeof preferredRaw === "string" ? (preferredRaw.toLowerCase() as RPCProviderName) : null;
254
+
255
+ const providers: RPCProviderConfig[] = [];
256
+
257
+ const alchemyKey = getStringSetting(runtime, "ALCHEMY_API_KEY");
258
+ if (alchemyKey) providers.push(createAlchemyProvider(alchemyKey));
259
+
260
+ const infuraKey = getStringSetting(runtime, "INFURA_API_KEY");
261
+ if (infuraKey) providers.push(createInfuraProvider(infuraKey));
262
+
263
+ const ankrKey = getStringSetting(runtime, "ANKR_API_KEY");
264
+ if (ankrKey) providers.push(createAnkrProvider(ankrKey));
265
+
266
+ if (hasCloudRpcAccess(runtime)) {
267
+ const cloudKey = getCloudApiKey(runtime);
268
+ if (cloudKey) {
269
+ const cloudBase =
270
+ getStringSetting(runtime, "ELIZAOS_CLOUD_BASE_URL") ??
271
+ (process.env.ELIZAOS_CLOUD_BASE_URL?.trim() || undefined) ??
272
+ "https://www.elizacloud.ai/api/v1";
273
+ providers.push(createElizaCloudProvider(cloudKey, cloudBase));
274
+ }
275
+ }
276
+
277
+ if (preferred) {
278
+ providers.sort((a, b) => {
279
+ if (a.name === preferred && b.name !== preferred) return -1;
280
+ if (b.name === preferred && a.name !== preferred) return 1;
281
+ return b.supportedChains.size - a.supportedChains.size;
282
+ });
283
+ }
284
+
285
+ if (providers.length > 0) {
286
+ logger.info(
287
+ `[EVM-RPC] Configured providers: ${providers.map((p) => p.name).join(", ")}` +
288
+ (preferred ? ` (preferred: ${preferred})` : "")
289
+ );
290
+ } else {
291
+ logger.info(
292
+ "[EVM-RPC] No managed RPC providers configured. " +
293
+ "Using per-chain custom RPC URLs (ETHEREUM_PROVIDER_<CHAIN> / EVM_PROVIDER_<CHAIN>) or viem defaults."
294
+ );
295
+ }
296
+
297
+ return {
298
+ resolveForChain(chainName: string): ResolvedRPCProvider | null {
299
+ const customRpc =
300
+ getStringSetting(runtime, `ETHEREUM_PROVIDER_${chainName.toUpperCase()}`) ??
301
+ getStringSetting(runtime, `EVM_PROVIDER_${chainName.toUpperCase()}`);
302
+
303
+ if (customRpc) {
304
+ return {
305
+ providerName: "alchemy" as RPCProviderName,
306
+ rpcUrl: customRpc,
307
+ headers: {},
308
+ };
309
+ }
310
+
311
+ for (const provider of providers) {
312
+ if (!provider.supportedChains.has(chainName)) continue;
313
+ const url = provider.buildUrl(chainName, provider.apiKey);
314
+ if (!url) continue;
315
+
316
+ const headers: Record<string, string> = {};
317
+ if (provider.name === "elizacloud") {
318
+ headers.Authorization = `Bearer ${provider.apiKey}`;
319
+ }
320
+
321
+ return {
322
+ providerName: provider.name,
323
+ rpcUrl: url,
324
+ headers,
325
+ };
326
+ }
327
+
328
+ return null;
329
+ },
330
+
331
+ getConfiguredProviders(): RPCProviderName[] {
332
+ return providers.map((p) => p.name);
333
+ },
334
+
335
+ getCoveredChains(): string[] {
336
+ const chains = new Set<string>();
337
+ for (const provider of providers) {
338
+ for (const chain of provider.supportedChains) {
339
+ chains.add(chain);
340
+ }
341
+ }
342
+ return Array.from(chains);
343
+ },
344
+
345
+ isChainCovered(chainName: string): boolean {
346
+ const hasCustom =
347
+ hasStringSetting(runtime, `ETHEREUM_PROVIDER_${chainName.toUpperCase()}`) ||
348
+ hasStringSetting(runtime, `EVM_PROVIDER_${chainName.toUpperCase()}`);
349
+ return hasCustom || providers.some((p) => p.supportedChains.has(chainName));
350
+ },
351
+ };
352
+ }
353
+
354
+ export function validateRPCProviderConfig(runtime: IAgentRuntime): {
355
+ valid: boolean;
356
+ providers: RPCProviderName[];
357
+ warnings: string[];
358
+ } {
359
+ const warnings: string[] = [];
360
+ const configuredProviders: RPCProviderName[] = [];
361
+
362
+ if (hasStringSetting(runtime, "ALCHEMY_API_KEY")) configuredProviders.push("alchemy");
363
+ if (hasStringSetting(runtime, "INFURA_API_KEY")) configuredProviders.push("infura");
364
+ if (hasStringSetting(runtime, "ANKR_API_KEY")) configuredProviders.push("ankr");
365
+ if (hasCloudRpcAccess(runtime)) configuredProviders.push("elizacloud");
366
+
367
+ // Check for any per-chain custom RPC URLs
368
+ let hasCustomRpc = false;
369
+ const settings = runtime.character?.settings;
370
+ let chainsToCheck: string[] = ["mainnet", "base"];
371
+ if (
372
+ typeof settings === "object" &&
373
+ settings !== null &&
374
+ "chains" in settings &&
375
+ typeof settings.chains === "object" &&
376
+ settings.chains !== null &&
377
+ "evm" in settings.chains &&
378
+ Array.isArray(settings.chains.evm)
379
+ ) {
380
+ chainsToCheck = settings.chains.evm.filter(
381
+ (chain): chain is string => typeof chain === "string"
382
+ );
383
+ }
384
+
385
+ for (const chain of chainsToCheck) {
386
+ if (
387
+ hasStringSetting(runtime, `ETHEREUM_PROVIDER_${chain.toUpperCase()}`) ||
388
+ hasStringSetting(runtime, `EVM_PROVIDER_${chain.toUpperCase()}`)
389
+ ) {
390
+ hasCustomRpc = true;
391
+ break;
392
+ }
393
+ }
394
+
395
+ if (configuredProviders.length === 0 && !hasCustomRpc) {
396
+ warnings.push(
397
+ "No RPC provider configured. Set at least one of: " +
398
+ "ALCHEMY_API_KEY, INFURA_API_KEY, ANKR_API_KEY, " +
399
+ "ELIZAOS_CLOUD_API_KEY from an Eliza Cloud login, " +
400
+ "or per-chain ETHEREUM_PROVIDER_<CHAIN> / EVM_PROVIDER_<CHAIN> URLs. " +
401
+ "Falling back to public RPC endpoints (rate-limited, not recommended for production)."
402
+ );
403
+ }
404
+
405
+ return {
406
+ valid: configuredProviders.length > 0 || hasCustomRpc,
407
+ providers: configuredProviders,
408
+ warnings,
409
+ };
410
+ }
@@ -0,0 +1,140 @@
1
+ import { type IAgentRuntime, logger, Service } from "@elizaos/core";
2
+ import {
3
+ CACHE_REFRESH_INTERVAL_MS,
4
+ EVM_SERVICE_NAME,
5
+ EVM_WALLET_DATA_CACHE_KEY,
6
+ } from "./constants";
7
+ import { initWalletProvider, type WalletProvider } from "./providers/wallet";
8
+ import { EVMError, EVMErrorCode, type SupportedChain } from "./types";
9
+
10
+ export interface EVMWalletData {
11
+ readonly address: string;
12
+ readonly chains: ReadonlyArray<{
13
+ readonly chainName: string;
14
+ readonly name: string;
15
+ readonly balance: string;
16
+ readonly symbol: string;
17
+ readonly chainId: number;
18
+ }>;
19
+ readonly timestamp: number;
20
+ }
21
+
22
+ export class EVMService extends Service {
23
+ static override serviceType: string = EVM_SERVICE_NAME;
24
+ capabilityDescription = "EVM blockchain wallet access";
25
+
26
+ private walletProvider: WalletProvider | null = null;
27
+ private refreshInterval: ReturnType<typeof setInterval> | null = null;
28
+
29
+ static async start(runtime: IAgentRuntime): Promise<EVMService> {
30
+ logger.log("Initializing EVMService");
31
+
32
+ const evmService = new EVMService(runtime);
33
+ evmService.walletProvider = await initWalletProvider(runtime);
34
+ await evmService.refreshWalletData();
35
+
36
+ if (evmService.refreshInterval) {
37
+ clearInterval(evmService.refreshInterval);
38
+ }
39
+
40
+ evmService.refreshInterval = setInterval(
41
+ () => evmService.refreshWalletData(),
42
+ CACHE_REFRESH_INTERVAL_MS
43
+ );
44
+
45
+ logger.log("EVM service initialized");
46
+ return evmService;
47
+ }
48
+
49
+ static async stop(runtime: IAgentRuntime): Promise<void> {
50
+ const service = runtime.getService(EVM_SERVICE_NAME);
51
+ if (!service) {
52
+ logger.error("EVMService not found");
53
+ return;
54
+ }
55
+
56
+ const evmService = service as EVMService;
57
+ await evmService.stop();
58
+ }
59
+
60
+ async stop(): Promise<void> {
61
+ if (this.refreshInterval) {
62
+ clearInterval(this.refreshInterval);
63
+ this.refreshInterval = null;
64
+ }
65
+ logger.log("EVM service shutdown");
66
+ }
67
+
68
+ async refreshWalletData(): Promise<void> {
69
+ if (!this.walletProvider) {
70
+ this.walletProvider = await initWalletProvider(this.runtime);
71
+ }
72
+
73
+ const address = this.walletProvider.getAddress();
74
+ const balances = await this.walletProvider.getWalletBalances();
75
+
76
+ const chainDetails: Array<{
77
+ chainName: string;
78
+ name: string;
79
+ balance: string;
80
+ symbol: string;
81
+ chainId: number;
82
+ }> = [];
83
+
84
+ for (const [chainName, balance] of Object.entries(balances)) {
85
+ try {
86
+ const chain = this.walletProvider.getChainConfigs(chainName as SupportedChain);
87
+ chainDetails.push({
88
+ chainName,
89
+ balance,
90
+ symbol: chain.nativeCurrency.symbol,
91
+ chainId: chain.id,
92
+ name: chain.name,
93
+ });
94
+ } catch (error) {
95
+ logger.error(
96
+ `Error formatting chain ${chainName}:`,
97
+ error instanceof Error ? error.message : String(error)
98
+ );
99
+ }
100
+ }
101
+
102
+ const walletData: EVMWalletData = {
103
+ address,
104
+ chains: chainDetails,
105
+ timestamp: Date.now(),
106
+ };
107
+
108
+ await this.runtime.setCache(EVM_WALLET_DATA_CACHE_KEY, walletData);
109
+
110
+ logger.log(
111
+ "EVM wallet data refreshed for chains:",
112
+ chainDetails.map((c) => c.chainName).join(", ")
113
+ );
114
+ }
115
+
116
+ async getCachedData(): Promise<EVMWalletData | undefined> {
117
+ const cachedData = await this.runtime.getCache<EVMWalletData>(EVM_WALLET_DATA_CACHE_KEY);
118
+ const now = Date.now();
119
+
120
+ if (!cachedData || now - cachedData.timestamp > CACHE_REFRESH_INTERVAL_MS) {
121
+ logger.log("EVM wallet data is stale, refreshing...");
122
+ await this.refreshWalletData();
123
+ return await this.runtime.getCache<EVMWalletData>(EVM_WALLET_DATA_CACHE_KEY);
124
+ }
125
+
126
+ return cachedData;
127
+ }
128
+
129
+ async forceUpdate(): Promise<EVMWalletData | undefined> {
130
+ await this.refreshWalletData();
131
+ return this.getCachedData();
132
+ }
133
+
134
+ getWalletProvider(): WalletProvider {
135
+ if (!this.walletProvider) {
136
+ throw new EVMError(EVMErrorCode.WALLET_NOT_INITIALIZED, "Wallet provider not initialized");
137
+ }
138
+ return this.walletProvider;
139
+ }
140
+ }
@@ -0,0 +1,10 @@
1
+ export {
2
+ bridgeTemplate,
3
+ executeProposalTemplate,
4
+ proposeTemplate,
5
+ queueProposalTemplate,
6
+ swapTemplate,
7
+ tokenBalanceTemplate,
8
+ transferTemplate,
9
+ voteTemplate,
10
+ } from "../prompts";