keyring-agent-core 0.1.0

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 (318) hide show
  1. package/README.md +169 -0
  2. package/dist/agent/AgentCore.d.ts +220 -0
  3. package/dist/agent/AgentCore.d.ts.map +1 -0
  4. package/dist/agent/AgentCore.js +950 -0
  5. package/dist/agent/AgentCore.js.map +1 -0
  6. package/dist/agent/QueryRewriter.d.ts +67 -0
  7. package/dist/agent/QueryRewriter.d.ts.map +1 -0
  8. package/dist/agent/QueryRewriter.js +262 -0
  9. package/dist/agent/QueryRewriter.js.map +1 -0
  10. package/dist/agent/Router.d.ts +33 -0
  11. package/dist/agent/Router.d.ts.map +1 -0
  12. package/dist/agent/Router.js +191 -0
  13. package/dist/agent/Router.js.map +1 -0
  14. package/dist/agent/Subagent.d.ts +63 -0
  15. package/dist/agent/Subagent.d.ts.map +1 -0
  16. package/dist/agent/Subagent.js +240 -0
  17. package/dist/agent/Subagent.js.map +1 -0
  18. package/dist/agent/Synthesizer.d.ts +11 -0
  19. package/dist/agent/Synthesizer.d.ts.map +1 -0
  20. package/dist/agent/Synthesizer.js +86 -0
  21. package/dist/agent/Synthesizer.js.map +1 -0
  22. package/dist/agent/index.d.ts +10 -0
  23. package/dist/agent/index.d.ts.map +1 -0
  24. package/dist/agent/index.js +24 -0
  25. package/dist/agent/index.js.map +1 -0
  26. package/dist/agent/subagents/AiAgent.d.ts +6 -0
  27. package/dist/agent/subagents/AiAgent.d.ts.map +1 -0
  28. package/dist/agent/subagents/AiAgent.js +48 -0
  29. package/dist/agent/subagents/AiAgent.js.map +1 -0
  30. package/dist/agent/subagents/NftAgent.d.ts +6 -0
  31. package/dist/agent/subagents/NftAgent.d.ts.map +1 -0
  32. package/dist/agent/subagents/NftAgent.js +69 -0
  33. package/dist/agent/subagents/NftAgent.js.map +1 -0
  34. package/dist/agent/subagents/PoolAgent.d.ts +6 -0
  35. package/dist/agent/subagents/PoolAgent.d.ts.map +1 -0
  36. package/dist/agent/subagents/PoolAgent.js +184 -0
  37. package/dist/agent/subagents/PoolAgent.js.map +1 -0
  38. package/dist/agent/subagents/TokenAgent.d.ts +6 -0
  39. package/dist/agent/subagents/TokenAgent.d.ts.map +1 -0
  40. package/dist/agent/subagents/TokenAgent.js +75 -0
  41. package/dist/agent/subagents/TokenAgent.js.map +1 -0
  42. package/dist/agent/subagents/WalletAgent.d.ts +6 -0
  43. package/dist/agent/subagents/WalletAgent.d.ts.map +1 -0
  44. package/dist/agent/subagents/WalletAgent.js +92 -0
  45. package/dist/agent/subagents/WalletAgent.js.map +1 -0
  46. package/dist/agent/subagents/index.d.ts +14 -0
  47. package/dist/agent/subagents/index.d.ts.map +1 -0
  48. package/dist/agent/subagents/index.js +38 -0
  49. package/dist/agent/subagents/index.js.map +1 -0
  50. package/dist/constants/abi.d.ts +520 -0
  51. package/dist/constants/abi.d.ts.map +1 -0
  52. package/dist/constants/abi.js +667 -0
  53. package/dist/constants/abi.js.map +1 -0
  54. package/dist/functions/pool.d.ts +25 -0
  55. package/dist/functions/pool.d.ts.map +1 -0
  56. package/dist/functions/pool.js +151 -0
  57. package/dist/functions/pool.js.map +1 -0
  58. package/dist/functions/web3.d.ts +32 -0
  59. package/dist/functions/web3.d.ts.map +1 -0
  60. package/dist/functions/web3.js +277 -0
  61. package/dist/functions/web3.js.map +1 -0
  62. package/dist/index.d.ts +24 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +65 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/llm/GeminiProvider.d.ts +16 -0
  67. package/dist/llm/GeminiProvider.d.ts.map +1 -0
  68. package/dist/llm/GeminiProvider.js +248 -0
  69. package/dist/llm/GeminiProvider.js.map +1 -0
  70. package/dist/llm/index.d.ts +2 -0
  71. package/dist/llm/index.d.ts.map +1 -0
  72. package/dist/llm/index.js +6 -0
  73. package/dist/llm/index.js.map +1 -0
  74. package/dist/memory/ChatHistory.d.ts +83 -0
  75. package/dist/memory/ChatHistory.d.ts.map +1 -0
  76. package/dist/memory/ChatHistory.js +143 -0
  77. package/dist/memory/ChatHistory.js.map +1 -0
  78. package/dist/memory/KnowledgeBase.d.ts +38 -0
  79. package/dist/memory/KnowledgeBase.d.ts.map +1 -0
  80. package/dist/memory/KnowledgeBase.js +139 -0
  81. package/dist/memory/KnowledgeBase.js.map +1 -0
  82. package/dist/memory/Summarizer.d.ts +12 -0
  83. package/dist/memory/Summarizer.d.ts.map +1 -0
  84. package/dist/memory/Summarizer.js +39 -0
  85. package/dist/memory/Summarizer.js.map +1 -0
  86. package/dist/memory/UpstashKnowledgeBase.d.ts +124 -0
  87. package/dist/memory/UpstashKnowledgeBase.d.ts.map +1 -0
  88. package/dist/memory/UpstashKnowledgeBase.js +152 -0
  89. package/dist/memory/UpstashKnowledgeBase.js.map +1 -0
  90. package/dist/memory/historyUtils.d.ts +58 -0
  91. package/dist/memory/historyUtils.d.ts.map +1 -0
  92. package/dist/memory/historyUtils.js +190 -0
  93. package/dist/memory/historyUtils.js.map +1 -0
  94. package/dist/memory/index.d.ts +7 -0
  95. package/dist/memory/index.d.ts.map +1 -0
  96. package/dist/memory/index.js +12 -0
  97. package/dist/memory/index.js.map +1 -0
  98. package/dist/memory/ingestKnowledgeBase.d.ts +17 -0
  99. package/dist/memory/ingestKnowledgeBase.d.ts.map +1 -0
  100. package/dist/memory/ingestKnowledgeBase.js +35 -0
  101. package/dist/memory/ingestKnowledgeBase.js.map +1 -0
  102. package/dist/services/MoralisService.d.ts +1350 -0
  103. package/dist/services/MoralisService.d.ts.map +1 -0
  104. package/dist/services/MoralisService.js +1364 -0
  105. package/dist/services/MoralisService.js.map +1 -0
  106. package/dist/services/PantographService.d.ts +38 -0
  107. package/dist/services/PantographService.d.ts.map +1 -0
  108. package/dist/services/PantographService.js +199 -0
  109. package/dist/services/PantographService.js.map +1 -0
  110. package/dist/services/PoolService.d.ts +241 -0
  111. package/dist/services/PoolService.d.ts.map +1 -0
  112. package/dist/services/PoolService.js +507 -0
  113. package/dist/services/PoolService.js.map +1 -0
  114. package/dist/services/UniswapService.d.ts +289 -0
  115. package/dist/services/UniswapService.d.ts.map +1 -0
  116. package/dist/services/UniswapService.js +585 -0
  117. package/dist/services/UniswapService.js.map +1 -0
  118. package/dist/services/swap/BaseSwapService.d.ts +17 -0
  119. package/dist/services/swap/BaseSwapService.d.ts.map +1 -0
  120. package/dist/services/swap/BaseSwapService.js +19 -0
  121. package/dist/services/swap/BaseSwapService.js.map +1 -0
  122. package/dist/services/swap/DebridgeAdapter.d.ts +20 -0
  123. package/dist/services/swap/DebridgeAdapter.d.ts.map +1 -0
  124. package/dist/services/swap/DebridgeAdapter.js +175 -0
  125. package/dist/services/swap/DebridgeAdapter.js.map +1 -0
  126. package/dist/services/swap/RelayAdapter.d.ts +19 -0
  127. package/dist/services/swap/RelayAdapter.d.ts.map +1 -0
  128. package/dist/services/swap/RelayAdapter.js +189 -0
  129. package/dist/services/swap/RelayAdapter.js.map +1 -0
  130. package/dist/services/swap/SwapServiceFactory.d.ts +24 -0
  131. package/dist/services/swap/SwapServiceFactory.d.ts.map +1 -0
  132. package/dist/services/swap/SwapServiceFactory.js +74 -0
  133. package/dist/services/swap/SwapServiceFactory.js.map +1 -0
  134. package/dist/services/swap/addresses.d.ts +3 -0
  135. package/dist/services/swap/addresses.d.ts.map +1 -0
  136. package/dist/services/swap/addresses.js +68 -0
  137. package/dist/services/swap/addresses.js.map +1 -0
  138. package/dist/services/swap/affiliate.d.ts +17 -0
  139. package/dist/services/swap/affiliate.d.ts.map +1 -0
  140. package/dist/services/swap/affiliate.js +126 -0
  141. package/dist/services/swap/affiliate.js.map +1 -0
  142. package/dist/services/swap/config.d.ts +9 -0
  143. package/dist/services/swap/config.d.ts.map +1 -0
  144. package/dist/services/swap/config.js +19 -0
  145. package/dist/services/swap/config.js.map +1 -0
  146. package/dist/services/swap/index.d.ts +10 -0
  147. package/dist/services/swap/index.d.ts.map +1 -0
  148. package/dist/services/swap/index.js +22 -0
  149. package/dist/services/swap/index.js.map +1 -0
  150. package/dist/services/swap/types.d.ts +89 -0
  151. package/dist/services/swap/types.d.ts.map +1 -0
  152. package/dist/services/swap/types.js +6 -0
  153. package/dist/services/swap/types.js.map +1 -0
  154. package/dist/tools/BaseTool.d.ts +15 -0
  155. package/dist/tools/BaseTool.d.ts.map +1 -0
  156. package/dist/tools/BaseTool.js +35 -0
  157. package/dist/tools/BaseTool.js.map +1 -0
  158. package/dist/tools/ToolRegistry.d.ts +27 -0
  159. package/dist/tools/ToolRegistry.d.ts.map +1 -0
  160. package/dist/tools/ToolRegistry.js +80 -0
  161. package/dist/tools/ToolRegistry.js.map +1 -0
  162. package/dist/tools/builtin/ai/MoralisCortexTool.d.ts +33 -0
  163. package/dist/tools/builtin/ai/MoralisCortexTool.d.ts.map +1 -0
  164. package/dist/tools/builtin/ai/MoralisCortexTool.js +76 -0
  165. package/dist/tools/builtin/ai/MoralisCortexTool.js.map +1 -0
  166. package/dist/tools/builtin/ai/SolanaCortexTool.d.ts +22 -0
  167. package/dist/tools/builtin/ai/SolanaCortexTool.d.ts.map +1 -0
  168. package/dist/tools/builtin/ai/SolanaCortexTool.js +80 -0
  169. package/dist/tools/builtin/ai/SolanaCortexTool.js.map +1 -0
  170. package/dist/tools/builtin/ai/index.d.ts +5 -0
  171. package/dist/tools/builtin/ai/index.d.ts.map +1 -0
  172. package/dist/tools/builtin/ai/index.js +8 -0
  173. package/dist/tools/builtin/ai/index.js.map +1 -0
  174. package/dist/tools/builtin/index.d.ts +6 -0
  175. package/dist/tools/builtin/index.d.ts.map +1 -0
  176. package/dist/tools/builtin/index.js +22 -0
  177. package/dist/tools/builtin/index.js.map +1 -0
  178. package/dist/tools/builtin/nft/NFTContractInfoTool.d.ts +21 -0
  179. package/dist/tools/builtin/nft/NFTContractInfoTool.d.ts.map +1 -0
  180. package/dist/tools/builtin/nft/NFTContractInfoTool.js +54 -0
  181. package/dist/tools/builtin/nft/NFTContractInfoTool.js.map +1 -0
  182. package/dist/tools/builtin/nft/NFTMetadataTool.d.ts +121 -0
  183. package/dist/tools/builtin/nft/NFTMetadataTool.d.ts.map +1 -0
  184. package/dist/tools/builtin/nft/NFTMetadataTool.js +159 -0
  185. package/dist/tools/builtin/nft/NFTMetadataTool.js.map +1 -0
  186. package/dist/tools/builtin/nft/WalletNFTsTool.d.ts +82 -0
  187. package/dist/tools/builtin/nft/WalletNFTsTool.d.ts.map +1 -0
  188. package/dist/tools/builtin/nft/WalletNFTsTool.js +172 -0
  189. package/dist/tools/builtin/nft/WalletNFTsTool.js.map +1 -0
  190. package/dist/tools/builtin/nft/index.d.ts +7 -0
  191. package/dist/tools/builtin/nft/index.d.ts.map +1 -0
  192. package/dist/tools/builtin/nft/index.js +10 -0
  193. package/dist/tools/builtin/nft/index.js.map +1 -0
  194. package/dist/tools/builtin/pool/EstimatePoolYieldTool.d.ts +124 -0
  195. package/dist/tools/builtin/pool/EstimatePoolYieldTool.d.ts.map +1 -0
  196. package/dist/tools/builtin/pool/EstimatePoolYieldTool.js +235 -0
  197. package/dist/tools/builtin/pool/EstimatePoolYieldTool.js.map +1 -0
  198. package/dist/tools/builtin/pool/OpenAddLiquidityFormTool.d.ts +127 -0
  199. package/dist/tools/builtin/pool/OpenAddLiquidityFormTool.d.ts.map +1 -0
  200. package/dist/tools/builtin/pool/OpenAddLiquidityFormTool.js +517 -0
  201. package/dist/tools/builtin/pool/OpenAddLiquidityFormTool.js.map +1 -0
  202. package/dist/tools/builtin/pool/PoolByAddressTool.d.ts +127 -0
  203. package/dist/tools/builtin/pool/PoolByAddressTool.d.ts.map +1 -0
  204. package/dist/tools/builtin/pool/PoolByAddressTool.js +237 -0
  205. package/dist/tools/builtin/pool/PoolByAddressTool.js.map +1 -0
  206. package/dist/tools/builtin/pool/PoolDetailTool.d.ts +127 -0
  207. package/dist/tools/builtin/pool/PoolDetailTool.d.ts.map +1 -0
  208. package/dist/tools/builtin/pool/PoolDetailTool.js +272 -0
  209. package/dist/tools/builtin/pool/PoolDetailTool.js.map +1 -0
  210. package/dist/tools/builtin/pool/PoolSearchTool.d.ts +50 -0
  211. package/dist/tools/builtin/pool/PoolSearchTool.d.ts.map +1 -0
  212. package/dist/tools/builtin/pool/PoolSearchTool.js +159 -0
  213. package/dist/tools/builtin/pool/PoolSearchTool.js.map +1 -0
  214. package/dist/tools/builtin/pool/PreviewAddLiquidityTool.d.ts +123 -0
  215. package/dist/tools/builtin/pool/PreviewAddLiquidityTool.d.ts.map +1 -0
  216. package/dist/tools/builtin/pool/PreviewAddLiquidityTool.js +380 -0
  217. package/dist/tools/builtin/pool/PreviewAddLiquidityTool.js.map +1 -0
  218. package/dist/tools/builtin/pool/TopPoolsTool.d.ts +68 -0
  219. package/dist/tools/builtin/pool/TopPoolsTool.d.ts.map +1 -0
  220. package/dist/tools/builtin/pool/TopPoolsTool.js +158 -0
  221. package/dist/tools/builtin/pool/TopPoolsTool.js.map +1 -0
  222. package/dist/tools/builtin/pool/index.d.ts +15 -0
  223. package/dist/tools/builtin/pool/index.d.ts.map +1 -0
  224. package/dist/tools/builtin/pool/index.js +18 -0
  225. package/dist/tools/builtin/pool/index.js.map +1 -0
  226. package/dist/tools/builtin/token/TokenAnalyticsTool.d.ts +71 -0
  227. package/dist/tools/builtin/token/TokenAnalyticsTool.d.ts.map +1 -0
  228. package/dist/tools/builtin/token/TokenAnalyticsTool.js +146 -0
  229. package/dist/tools/builtin/token/TokenAnalyticsTool.js.map +1 -0
  230. package/dist/tools/builtin/token/TokenHoldersTool.d.ts +81 -0
  231. package/dist/tools/builtin/token/TokenHoldersTool.d.ts.map +1 -0
  232. package/dist/tools/builtin/token/TokenHoldersTool.js +138 -0
  233. package/dist/tools/builtin/token/TokenHoldersTool.js.map +1 -0
  234. package/dist/tools/builtin/token/TokenInfoTool.d.ts +36 -0
  235. package/dist/tools/builtin/token/TokenInfoTool.d.ts.map +1 -0
  236. package/dist/tools/builtin/token/TokenInfoTool.js +163 -0
  237. package/dist/tools/builtin/token/TokenInfoTool.js.map +1 -0
  238. package/dist/tools/builtin/token/TokenScoreTool.d.ts +63 -0
  239. package/dist/tools/builtin/token/TokenScoreTool.d.ts.map +1 -0
  240. package/dist/tools/builtin/token/TokenScoreTool.js +147 -0
  241. package/dist/tools/builtin/token/TokenScoreTool.js.map +1 -0
  242. package/dist/tools/builtin/token/TopGainersTool.d.ts +46 -0
  243. package/dist/tools/builtin/token/TopGainersTool.d.ts.map +1 -0
  244. package/dist/tools/builtin/token/TopGainersTool.js +110 -0
  245. package/dist/tools/builtin/token/TopGainersTool.js.map +1 -0
  246. package/dist/tools/builtin/token/TopLosersTool.d.ts +66 -0
  247. package/dist/tools/builtin/token/TopLosersTool.d.ts.map +1 -0
  248. package/dist/tools/builtin/token/TopLosersTool.js +128 -0
  249. package/dist/tools/builtin/token/TopLosersTool.js.map +1 -0
  250. package/dist/tools/builtin/token/TrendingTokensTool.d.ts +39 -0
  251. package/dist/tools/builtin/token/TrendingTokensTool.d.ts.map +1 -0
  252. package/dist/tools/builtin/token/TrendingTokensTool.js +75 -0
  253. package/dist/tools/builtin/token/TrendingTokensTool.js.map +1 -0
  254. package/dist/tools/builtin/token/index.d.ts +15 -0
  255. package/dist/tools/builtin/token/index.d.ts.map +1 -0
  256. package/dist/tools/builtin/token/index.js +18 -0
  257. package/dist/tools/builtin/token/index.js.map +1 -0
  258. package/dist/tools/builtin/wallet/TransactionByHashTool.d.ts +70 -0
  259. package/dist/tools/builtin/wallet/TransactionByHashTool.d.ts.map +1 -0
  260. package/dist/tools/builtin/wallet/TransactionByHashTool.js +110 -0
  261. package/dist/tools/builtin/wallet/TransactionByHashTool.js.map +1 -0
  262. package/dist/tools/builtin/wallet/WalletApprovalsTool.d.ts +107 -0
  263. package/dist/tools/builtin/wallet/WalletApprovalsTool.d.ts.map +1 -0
  264. package/dist/tools/builtin/wallet/WalletApprovalsTool.js +163 -0
  265. package/dist/tools/builtin/wallet/WalletApprovalsTool.js.map +1 -0
  266. package/dist/tools/builtin/wallet/WalletDefiPositionsTool.d.ts +61 -0
  267. package/dist/tools/builtin/wallet/WalletDefiPositionsTool.d.ts.map +1 -0
  268. package/dist/tools/builtin/wallet/WalletDefiPositionsTool.js +99 -0
  269. package/dist/tools/builtin/wallet/WalletDefiPositionsTool.js.map +1 -0
  270. package/dist/tools/builtin/wallet/WalletDefiProtocolPositionsTool.d.ts +68 -0
  271. package/dist/tools/builtin/wallet/WalletDefiProtocolPositionsTool.d.ts.map +1 -0
  272. package/dist/tools/builtin/wallet/WalletDefiProtocolPositionsTool.js +114 -0
  273. package/dist/tools/builtin/wallet/WalletDefiProtocolPositionsTool.js.map +1 -0
  274. package/dist/tools/builtin/wallet/WalletDefiSummaryTool.d.ts +50 -0
  275. package/dist/tools/builtin/wallet/WalletDefiSummaryTool.d.ts.map +1 -0
  276. package/dist/tools/builtin/wallet/WalletDefiSummaryTool.js +79 -0
  277. package/dist/tools/builtin/wallet/WalletDefiSummaryTool.js.map +1 -0
  278. package/dist/tools/builtin/wallet/WalletHistoryTool.d.ts +31 -0
  279. package/dist/tools/builtin/wallet/WalletHistoryTool.d.ts.map +1 -0
  280. package/dist/tools/builtin/wallet/WalletHistoryTool.js +153 -0
  281. package/dist/tools/builtin/wallet/WalletHistoryTool.js.map +1 -0
  282. package/dist/tools/builtin/wallet/WalletNetWorthTool.d.ts +44 -0
  283. package/dist/tools/builtin/wallet/WalletNetWorthTool.d.ts.map +1 -0
  284. package/dist/tools/builtin/wallet/WalletNetWorthTool.js +122 -0
  285. package/dist/tools/builtin/wallet/WalletNetWorthTool.js.map +1 -0
  286. package/dist/tools/builtin/wallet/WalletNftTransfersTool.d.ts +86 -0
  287. package/dist/tools/builtin/wallet/WalletNftTransfersTool.d.ts.map +1 -0
  288. package/dist/tools/builtin/wallet/WalletNftTransfersTool.js +264 -0
  289. package/dist/tools/builtin/wallet/WalletNftTransfersTool.js.map +1 -0
  290. package/dist/tools/builtin/wallet/WalletPnlSummaryTool.d.ts +43 -0
  291. package/dist/tools/builtin/wallet/WalletPnlSummaryTool.d.ts.map +1 -0
  292. package/dist/tools/builtin/wallet/WalletPnlSummaryTool.js +88 -0
  293. package/dist/tools/builtin/wallet/WalletPnlSummaryTool.js.map +1 -0
  294. package/dist/tools/builtin/wallet/WalletPnlTool.d.ts +43 -0
  295. package/dist/tools/builtin/wallet/WalletPnlTool.d.ts.map +1 -0
  296. package/dist/tools/builtin/wallet/WalletPnlTool.js +174 -0
  297. package/dist/tools/builtin/wallet/WalletPnlTool.js.map +1 -0
  298. package/dist/tools/builtin/wallet/WalletTokenBalancesTool.d.ts +35 -0
  299. package/dist/tools/builtin/wallet/WalletTokenBalancesTool.d.ts.map +1 -0
  300. package/dist/tools/builtin/wallet/WalletTokenBalancesTool.js +67 -0
  301. package/dist/tools/builtin/wallet/WalletTokenBalancesTool.js.map +1 -0
  302. package/dist/tools/builtin/wallet/WalletTokenTransfersTool.d.ts +109 -0
  303. package/dist/tools/builtin/wallet/WalletTokenTransfersTool.d.ts.map +1 -0
  304. package/dist/tools/builtin/wallet/WalletTokenTransfersTool.js +353 -0
  305. package/dist/tools/builtin/wallet/WalletTokenTransfersTool.js.map +1 -0
  306. package/dist/tools/builtin/wallet/index.d.ts +25 -0
  307. package/dist/tools/builtin/wallet/index.d.ts.map +1 -0
  308. package/dist/tools/builtin/wallet/index.js +28 -0
  309. package/dist/tools/builtin/wallet/index.js.map +1 -0
  310. package/dist/tools/index.d.ts +4 -0
  311. package/dist/tools/index.d.ts.map +1 -0
  312. package/dist/tools/index.js +23 -0
  313. package/dist/tools/index.js.map +1 -0
  314. package/dist/types/index.d.ts +566 -0
  315. package/dist/types/index.d.ts.map +1 -0
  316. package/dist/types/index.js +6 -0
  317. package/dist/types/index.js.map +1 -0
  318. package/package.json +52 -0
@@ -0,0 +1,1364 @@
1
+ "use strict";
2
+ /**
3
+ * MoralisService — Moralis Web3 API + Cortex AI proxy.
4
+ *
5
+ * Adapted from keyring-chatbot-agent-sdk moralis service.
6
+ * Uses native fetch — no SDK dependencies.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.MoralisService = void 0;
10
+ const web3_1 = require("../functions/web3");
11
+ const PantographService_1 = require("./PantographService");
12
+ // ---------------------------------------------------------------------------
13
+ // Constants
14
+ // ---------------------------------------------------------------------------
15
+ const DEFAULT_BASE_URL = 'https://nft.keyring.app';
16
+ const DEFAULT_V1_BASE_URL = ' https://ed64-113-161-74-234.ngrok-free.app';
17
+ const DEFAULT_CORTEX_MODEL = 'gpt-4.1-mini';
18
+ const MINIMUM_TOKEN_BALANCE_PRICE_USD = 0.01;
19
+ const MAX_RETRIES = 5;
20
+ const RETRY_DELAY_MS = 1000;
21
+ /** Moralis uses 0xEeee…EE for native ETH; we normalise to 0x000…000 */
22
+ const ETH_SENTINEL = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
23
+ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
24
+ // ---------------------------------------------------------------------------
25
+ // Helpers
26
+ // ---------------------------------------------------------------------------
27
+ /** AI always provides hex chain IDs; default to Base (0x2105). */
28
+ function toMoralisChain(chain) {
29
+ return chain || '0x2105';
30
+ }
31
+ function buildQueryString(params) {
32
+ const parts = [];
33
+ for (const [key, value] of Object.entries(params)) {
34
+ if (value == null)
35
+ continue;
36
+ if (Array.isArray(value)) {
37
+ for (const v of value) {
38
+ parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(v))}`);
39
+ }
40
+ }
41
+ else {
42
+ parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
43
+ }
44
+ }
45
+ return parts.join('&');
46
+ }
47
+ function delay(ms) {
48
+ return new Promise((resolve) => setTimeout(resolve, ms));
49
+ }
50
+ /**
51
+ * Coerce the `/wallets/{address}/defi/positions` payload into an array.
52
+ *
53
+ * The proxy sometimes serialises the Moralis response as a plain object with
54
+ * stringified numeric keys (`{"0": {...}, "1": {...}}`) instead of a real
55
+ * JSON array. We accept both shapes and drop anything that doesn't look like
56
+ * a position row.
57
+ */
58
+ function normalizeDefiPositionsPayload(payload) {
59
+ if (Array.isArray(payload))
60
+ return payload;
61
+ if (payload && typeof payload === 'object') {
62
+ const obj = payload;
63
+ // v1 response shape: { meta, result: [...] }
64
+ if (Array.isArray(obj['result'])) {
65
+ return obj['result'].map((item) => ({
66
+ protocol_id: item.protocolId,
67
+ protocol_name: item.protocolName,
68
+ protocol_url: item.protocolUrl ?? '',
69
+ protocol_logo: item.protocolLogo ?? '',
70
+ position: {
71
+ label: item.position.label,
72
+ address: item.position.address,
73
+ balance_usd: item.position.balanceUsd ?? 0,
74
+ total_unclaimed_usd_value: item.position.unclaimedUsd ?? 0,
75
+ position_details: item.position.details,
76
+ tokens: item.position.tokens.map((t) => ({
77
+ token_type: t.tokenType,
78
+ address: t.address,
79
+ contract_address: t.address,
80
+ name: t.name ?? '',
81
+ symbol: t.symbol ?? '',
82
+ decimals: t.decimals ?? 18,
83
+ logo: t.logo,
84
+ balance: t.balance ?? '0',
85
+ balance_formatted: t.balanceFormatted ?? '0',
86
+ usd_price: t.usdPrice,
87
+ usd_value: t.usdValue,
88
+ })),
89
+ },
90
+ }));
91
+ }
92
+ // Proxy response shape: { "0": {...}, "1": {...} }
93
+ return Object.keys(obj)
94
+ .filter((k) => /^\d+$/.test(k))
95
+ .sort((a, b) => Number(a) - Number(b))
96
+ .map((k) => obj[k])
97
+ .filter((row) => !!row && typeof row === 'object');
98
+ }
99
+ return [];
100
+ }
101
+ /**
102
+ * Coerce a Moralis array response into a real array.
103
+ *
104
+ * Upstream returns a JSON array, but our proxy occasionally serialises it as
105
+ * `{ "0": {...}, "1": {...} }` (stringified numeric keys), or wraps it as
106
+ * `{ result: [...] }`. Accept all three shapes and drop anything that isn't a
107
+ * plain object row.
108
+ */
109
+ function normalizeArrayLikePayload(payload) {
110
+ if (Array.isArray(payload))
111
+ return payload;
112
+ if (payload && typeof payload === 'object') {
113
+ const obj = payload;
114
+ if (Array.isArray(obj.result))
115
+ return obj.result;
116
+ return Object.keys(obj)
117
+ .filter((k) => /^\d+$/.test(k))
118
+ .sort((a, b) => Number(a) - Number(b))
119
+ .map((k) => obj[k])
120
+ .filter((row) => !!row && typeof row === 'object');
121
+ }
122
+ return [];
123
+ }
124
+ // ---------------------------------------------------------------------------
125
+ // Service class
126
+ // ---------------------------------------------------------------------------
127
+ class MoralisService {
128
+ baseUrl;
129
+ v1BaseUrl;
130
+ cortexModel;
131
+ pantograph;
132
+ constructor(config) {
133
+ this.baseUrl = (config?.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, '');
134
+ this.v1BaseUrl = (config?.v1BaseUrl ?? DEFAULT_V1_BASE_URL).replace(/\/+$/, '');
135
+ this.cortexModel = config?.cortexModel ?? DEFAULT_CORTEX_MODEL;
136
+ this.pantograph = new PantographService_1.PantographService({ baseUrl: config?.pantographUrl });
137
+ }
138
+ // =========================================================================
139
+ // Token Balances
140
+ // =========================================================================
141
+ /**
142
+ * Get token balances for a wallet.
143
+ * Automatically enriches prices via Pantograph and filters dust.
144
+ */
145
+ async getWalletTokenBalances(params) {
146
+ const { address, chain, tokenAddresses, excludeSpam = false, excludeUnverifiedContracts = false } = params;
147
+ if (!address)
148
+ return { success: false, error: 'Address is required' };
149
+ if ((0, web3_1.isSolanaAddress)(address) && (chain?.toLowerCase() === 'solana' || chain === '0x736f6c')) {
150
+ return await this.getWalletTokenBalancesSolanaAddress({ address });
151
+ }
152
+ const moralisChain = toMoralisChain(chain);
153
+ let lastError = 'Unknown error';
154
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
155
+ try {
156
+ const query = {
157
+ chain: moralisChain,
158
+ exclude_spam: excludeSpam,
159
+ exclude_unverified_contracts: excludeUnverifiedContracts,
160
+ limit: 100,
161
+ };
162
+ if (tokenAddresses)
163
+ query.token_addresses = tokenAddresses;
164
+ const allResults = [];
165
+ let cursor = null;
166
+ do {
167
+ if (cursor)
168
+ query.cursor = cursor;
169
+ const qs = buildQueryString(query);
170
+ const url = `${this.baseUrl}/api/moralis/proxy/wallets/${encodeURIComponent(address)}/tokens?${qs}`;
171
+ const res = await fetch(url);
172
+ if (!res.ok)
173
+ throw new Error(`HTTP ${res.status}`);
174
+ const json = (await res.json());
175
+ const page = (json?.data ?? json);
176
+ if (page?.result?.length > 0)
177
+ allResults.push(...page.result);
178
+ cursor = page?.cursor ?? null;
179
+ } while (cursor);
180
+ const data = { result: allResults };
181
+ if (data?.result?.length > 0) {
182
+ // Filter by positive balance
183
+ data.result = data.result.filter((t) => parseFloat(t.balance || '0') > 0);
184
+ // Normalise ETH sentinel → zero address
185
+ data.result = data.result.map((t) => ({
186
+ ...t,
187
+ token_address: t.token_address.toLowerCase() === ETH_SENTINEL ? ZERO_ADDRESS : t.token_address,
188
+ }));
189
+ // Enrich prices from Pantograph
190
+ await this.enrichTokenPrices(data.result, moralisChain);
191
+ // Drop tokens whose value is known AND below minimum
192
+ data.result = data.result.filter((t) => t.usd_value == null || t.usd_value >= MINIMUM_TOKEN_BALANCE_PRICE_USD);
193
+ }
194
+ return { success: true, data };
195
+ }
196
+ catch (error) {
197
+ lastError = error instanceof Error ? error.message : 'Unknown error';
198
+ if (attempt < MAX_RETRIES)
199
+ await delay(RETRY_DELAY_MS);
200
+ }
201
+ }
202
+ return { success: false, error: lastError };
203
+ }
204
+ /**
205
+ * Get token balances for a Solana wallet address via Moralis Cortex AI.
206
+ * Since Moralis REST proxy does not natively support Solana token balances,
207
+ * we leverage Cortex AI to retrieve and structure the data.
208
+ */
209
+ async getWalletTokenBalancesSolanaAddress(params) {
210
+ const { address } = params;
211
+ if (!address)
212
+ return { success: false, error: 'Solana address is required' };
213
+ const prompt = [
214
+ `Retrieve all SPL token balances and the native SOL balance for the Solana wallet address: ${address}.`,
215
+ '',
216
+ 'Return the data as a valid JSON array (no markdown, no explanation, no commentary).',
217
+ 'Each element must be an object with exactly these fields:',
218
+ '- "token_address": string (the token mint address, or "So11111111111111111111111111111111111111112" for native SOL)',
219
+ '- "symbol": string (token ticker symbol)',
220
+ '- "name": string (full token name)',
221
+ '- "decimals": number',
222
+ '- "balance": string (raw balance as a string, without decimal formatting)',
223
+ '- "balance_formatted": string (human-readable balance with decimals applied)',
224
+ '- "usd_price": number or null (current USD price per token)',
225
+ '- "usd_value": number or null (total USD value = balance_formatted × usd_price)',
226
+ '- "possible_spam": boolean (true if the token is likely spam or a scam)',
227
+ '- "native_token": boolean (true only for native SOL)',
228
+ '- "logo": string or null (token logo URL if available)',
229
+ '',
230
+ 'Rules:',
231
+ '- Include ONLY tokens with a balance greater than 0.',
232
+ '- Always include native SOL if the wallet holds any.',
233
+ '- Sort by usd_value descending (highest value first), with null values at the end.',
234
+ '- Respond with ONLY the JSON array. No extra text.',
235
+ ].join('\n');
236
+ const cortexResult = await this.chatWithCortex({ prompt });
237
+ if (!cortexResult.success || !cortexResult.data?.text) {
238
+ return { success: false, error: cortexResult.error ?? 'Failed to get Solana token balances from Cortex AI' };
239
+ }
240
+ try {
241
+ // Extract JSON array from the response (strip potential markdown fences)
242
+ const raw = cortexResult.data.text
243
+ .replace(/```(?:json)?\s*/g, '')
244
+ .replace(/```/g, '')
245
+ .trim();
246
+ const parsed = JSON.parse(raw);
247
+ if (!Array.isArray(parsed)) {
248
+ return { success: false, error: 'Cortex AI returned non-array response' };
249
+ }
250
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
251
+ let result = parsed.map((t) => ({
252
+ token_address: t.token_address ?? '',
253
+ symbol: t.symbol ?? '',
254
+ name: t.name ?? '',
255
+ logo: t.logo ?? undefined,
256
+ thumbnail: t.logo ?? undefined,
257
+ decimals: t.decimals ?? 0,
258
+ balance: String(t.balance ?? '0'),
259
+ balance_formatted: String(t.balance_formatted ?? '0'),
260
+ possible_spam: t.possible_spam ?? false,
261
+ verified_contract: false,
262
+ native_token: t.native_token ?? false,
263
+ usd_price: t.usd_price ?? undefined,
264
+ usd_value: t.usd_value ?? undefined,
265
+ }));
266
+ // Enrich prices & logos from Pantograph (Solana chain)
267
+ await this.enrichTokenPrices(result, 'solana');
268
+ // Drop tokens whose value is known AND below minimum
269
+ result = result.filter((t) => t.usd_value == null || t.usd_value >= MINIMUM_TOKEN_BALANCE_PRICE_USD);
270
+ return { success: true, data: { result } };
271
+ }
272
+ catch {
273
+ return { success: false, error: 'Failed to parse Cortex AI response as token balances' };
274
+ }
275
+ }
276
+ // =========================================================================
277
+ // Token Metadata
278
+ // =========================================================================
279
+ /**
280
+ * Get metadata + price for a single token by contract address.
281
+ */
282
+ async getTokenMetadata(params) {
283
+ const { address, chain } = params;
284
+ if (!address)
285
+ return { success: false, error: 'Token address is required' };
286
+ const moralisChain = toMoralisChain(chain);
287
+ let lastError = 'Unknown error';
288
+ // Try Pantograph first (single source for metadata + price)
289
+ const pantographMeta = await this.pantograph.getTokenMetadata(address, moralisChain);
290
+ if (pantographMeta)
291
+ return { success: true, data: pantographMeta };
292
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
293
+ try {
294
+ // Fallback to Moralis proxy
295
+ const [metaRes, priceRes] = await Promise.allSettled([
296
+ fetch(`${this.baseUrl}/api/moralis/proxy/erc20/metadata?${buildQueryString({ chain: moralisChain, addresses: [address] })}`),
297
+ fetch(`${this.baseUrl}/api/moralis/proxy/erc20/${encodeURIComponent(address)}/price?${buildQueryString({ chain: moralisChain, include: 'percent_change' })}`),
298
+ ]);
299
+ let meta = null;
300
+ if (metaRes.status === 'fulfilled' && metaRes.value.ok) {
301
+ const metaJson = (await metaRes.value.json());
302
+ const metaList = Array.isArray(metaJson?.data) ? metaJson.data : Array.isArray(metaJson) ? metaJson : [];
303
+ meta = metaList[0];
304
+ }
305
+ if (!meta) {
306
+ lastError = 'Token metadata not found';
307
+ if (attempt < MAX_RETRIES)
308
+ await delay(RETRY_DELAY_MS);
309
+ continue;
310
+ }
311
+ let priceData = null;
312
+ if (priceRes.status === 'fulfilled' && priceRes.value.ok) {
313
+ const priceJson = (await priceRes.value.json());
314
+ priceData = priceJson?.data ?? priceJson;
315
+ }
316
+ return {
317
+ success: true,
318
+ data: {
319
+ ...meta,
320
+ ...(priceData?.usd_price ? { usd_price: priceData?.usd_price } : {}),
321
+ ...(priceData?.usd_price_change_percentage_24h
322
+ ? { usd_price_change_percentage_24h: priceData?.usd_price_change_percentage_24h }
323
+ : {}),
324
+ },
325
+ };
326
+ }
327
+ catch (error) {
328
+ lastError = error instanceof Error ? error.message : 'Unknown error';
329
+ if (attempt < MAX_RETRIES)
330
+ await delay(RETRY_DELAY_MS);
331
+ }
332
+ }
333
+ return { success: false, error: lastError };
334
+ }
335
+ // =========================================================================
336
+ // Wallet NFTs
337
+ // =========================================================================
338
+ /**
339
+ * Get NFTs owned by a wallet.
340
+ */
341
+ async getWalletNFTs(params) {
342
+ const { address, chain, limit = 10, excludeSpam = true, cursor, tokenAddresses, includePrices, format = 'decimal', } = params;
343
+ if (!address)
344
+ return { success: false, error: 'Address is required' };
345
+ const moralisChain = toMoralisChain(chain);
346
+ let lastError = 'Unknown error';
347
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
348
+ try {
349
+ const query = {
350
+ chain: moralisChain,
351
+ format,
352
+ limit,
353
+ exclude_spam: excludeSpam,
354
+ media_items: true,
355
+ normalizeMetadata: true,
356
+ };
357
+ if (cursor)
358
+ query.cursor = cursor;
359
+ if (includePrices)
360
+ query.include_prices = true;
361
+ if (tokenAddresses && tokenAddresses.length > 0) {
362
+ query['token_addresses'] = tokenAddresses;
363
+ }
364
+ const qs = buildQueryString(query);
365
+ const url = `${this.baseUrl}/api/moralis/proxy/${encodeURIComponent(address)}/nft?${qs}`;
366
+ const res = await fetch(url);
367
+ if (!res.ok)
368
+ throw new Error(`HTTP ${res.status}`);
369
+ const json = (await res.json());
370
+ const data = (json?.data ?? json);
371
+ return { success: true, data };
372
+ }
373
+ catch (error) {
374
+ lastError = error instanceof Error ? error.message : 'Unknown error';
375
+ if (attempt < MAX_RETRIES)
376
+ await delay(RETRY_DELAY_MS);
377
+ }
378
+ }
379
+ return { success: false, error: lastError };
380
+ }
381
+ // =========================================================================
382
+ // NFT Metadata (by contract + tokenId)
383
+ // =========================================================================
384
+ /**
385
+ * Get the full metadata for a single NFT identified by its contract address
386
+ * and token id via the Moralis `GET /nft/{address}/{token_id}` endpoint.
387
+ *
388
+ * Returns normalized metadata (name, description, image, attributes),
389
+ * media variants, floor-price, rarity, collection socials and sync
390
+ * timestamps. Only supported on EVM chains.
391
+ *
392
+ * Moralis docs: https://docs.moralis.com/data-api/evm/nft/metadata/nft-metadata
393
+ */
394
+ async getNftMetadata(params) {
395
+ const { address, tokenId, chain, format = 'decimal', normalizeMetadata = true, mediaItems = true, include, } = params;
396
+ if (!address)
397
+ return { success: false, error: 'NFT contract address is required' };
398
+ if (tokenId == null || tokenId === '')
399
+ return { success: false, error: 'Token ID is required' };
400
+ if (!(0, web3_1.isAddressEVM)(address)) {
401
+ return { success: false, error: 'NFT metadata lookup by token ID is only supported on EVM chains' };
402
+ }
403
+ const moralisChain = toMoralisChain(chain);
404
+ let lastError = 'Unknown error';
405
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
406
+ try {
407
+ const query = {
408
+ chain: moralisChain,
409
+ format,
410
+ normalizeMetadata,
411
+ media_items: mediaItems,
412
+ };
413
+ if (include)
414
+ query.include = include;
415
+ const qs = buildQueryString(query);
416
+ const url = `${this.baseUrl}/api/moralis/proxy/nft/${encodeURIComponent(address)}/${encodeURIComponent(tokenId)}?${qs}`;
417
+ const res = await fetch(url);
418
+ if (!res.ok)
419
+ throw new Error(`HTTP ${res.status}`);
420
+ const json = (await res.json());
421
+ const data = (json?.data ?? json);
422
+ return { success: true, data };
423
+ }
424
+ catch (error) {
425
+ lastError = error instanceof Error ? error.message : 'Unknown error';
426
+ if (attempt < MAX_RETRIES)
427
+ await delay(RETRY_DELAY_MS);
428
+ }
429
+ }
430
+ return { success: false, error: lastError };
431
+ }
432
+ // =========================================================================
433
+ // NFT Contract Metadata
434
+ // =========================================================================
435
+ /**
436
+ * Get metadata for an NFT contract (name, symbol, contract_type).
437
+ *
438
+ * For EVM addresses, queries the Moralis REST proxy directly.
439
+ * For non-EVM addresses (e.g. Solana), delegates to Cortex AI.
440
+ */
441
+ async getNftContractMetadata(params) {
442
+ const { address, chain } = params;
443
+ if (!address)
444
+ return { success: false, error: 'Contract address is required' };
445
+ const moralisChain = toMoralisChain(chain);
446
+ let lastError = 'Unknown error';
447
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
448
+ try {
449
+ const qs = buildQueryString({ chain: moralisChain });
450
+ const url = `${this.baseUrl}/api/moralis/proxy/nft/${encodeURIComponent(address)}/metadata?${qs}`;
451
+ const res = await fetch(url);
452
+ if (!res.ok)
453
+ throw new Error(`HTTP ${res.status}`);
454
+ const json = (await res.json());
455
+ const data = (json?.data ?? json);
456
+ return { success: true, data };
457
+ }
458
+ catch (error) {
459
+ lastError = error instanceof Error ? error.message : 'Unknown error';
460
+ if (attempt < MAX_RETRIES)
461
+ await delay(RETRY_DELAY_MS);
462
+ }
463
+ }
464
+ return { success: false, error: lastError };
465
+ }
466
+ // =========================================================================
467
+ // Wallet Transaction History (Moralis REST)
468
+ // =========================================================================
469
+ /**
470
+ * Get a wallet's decoded on-chain transaction history via the Moralis
471
+ * `GET /wallets/{address}/history` endpoint.
472
+ *
473
+ * Moralis returns each transaction already categorised (send, token swap,
474
+ * nft purchase, airdrop, mint, contract interaction, …) with a human-readable
475
+ * summary and decoded native / ERC-20 / NFT transfer arrays attached.
476
+ *
477
+ * Pagination is supported via `cursor`. Pass the cursor from a previous
478
+ * response back in to fetch the next page.
479
+ *
480
+ * Solana is not supported by this REST endpoint. Only EVM addresses are
481
+ * accepted.
482
+ */
483
+ async getWalletHistory(params) {
484
+ const { address, chain, limit = 25, fromDate, toDate, fromBlock, toBlock, cursor, order = 'DESC', includeInternalTransactions, nftMetadata, } = params;
485
+ if (!address)
486
+ return { success: false, error: 'Address is required' };
487
+ if (!(0, web3_1.isAddressEVM)(address)) {
488
+ return { success: false, error: 'Wallet history is only supported for EVM addresses' };
489
+ }
490
+ const moralisChain = toMoralisChain(chain);
491
+ const safeLimit = Math.max(1, Math.min(100, Math.floor(limit)));
492
+ let lastError = 'Unknown error';
493
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
494
+ try {
495
+ const query = {
496
+ chain: moralisChain,
497
+ limit: safeLimit,
498
+ order,
499
+ };
500
+ if (fromDate)
501
+ query.from_date = fromDate;
502
+ if (toDate)
503
+ query.to_date = toDate;
504
+ if (fromBlock != null)
505
+ query.from_block = fromBlock;
506
+ if (toBlock != null)
507
+ query.to_block = toBlock;
508
+ if (cursor)
509
+ query.cursor = cursor;
510
+ if (includeInternalTransactions != null) {
511
+ query.include_internal_transactions = includeInternalTransactions;
512
+ }
513
+ if (nftMetadata != null)
514
+ query.nft_metadata = nftMetadata;
515
+ const qs = buildQueryString(query);
516
+ const url = `${this.baseUrl}/api/moralis/proxy/wallets/${encodeURIComponent(address)}/history?${qs}`;
517
+ const res = await fetch(url);
518
+ if (!res.ok)
519
+ throw new Error(`HTTP ${res.status}`);
520
+ const json = (await res.json());
521
+ const payload = json?.data ?? json;
522
+ const data = payload;
523
+ return { success: true, data };
524
+ }
525
+ catch (error) {
526
+ lastError = error instanceof Error ? error.message : 'Unknown error';
527
+ if (attempt < MAX_RETRIES)
528
+ await delay(RETRY_DELAY_MS);
529
+ }
530
+ }
531
+ return { success: false, error: lastError };
532
+ }
533
+ // =========================================================================
534
+ // Wallet ERC-20 Transfers (GET /{address}/erc20/transfers)
535
+ // =========================================================================
536
+ /**
537
+ * Get every ERC-20 transfer involving a wallet, optionally filtered by one
538
+ * or more token contract addresses.
539
+ *
540
+ * Use this to answer questions like:
541
+ * - "When did I last send USDC and to whom?"
542
+ * - "Who have I sent token 0x… to?"
543
+ * - "Who sent me USDC?"
544
+ * - "Show all USDT transfers for my wallet"
545
+ */
546
+ async getWalletTokenTransfers(params) {
547
+ const { address, chain, contractAddresses, limit = 25, fromDate, toDate, fromBlock, toBlock, cursor, order = 'DESC', } = params;
548
+ if (!address)
549
+ return { success: false, error: 'Address is required' };
550
+ if (!(0, web3_1.isAddressEVM)(address)) {
551
+ return { success: false, error: 'ERC-20 transfers are only supported for EVM addresses' };
552
+ }
553
+ const moralisChain = toMoralisChain(chain);
554
+ const safeLimit = Math.max(1, Math.min(100, Math.floor(limit)));
555
+ let lastError = 'Unknown error';
556
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
557
+ try {
558
+ const query = {
559
+ chain: moralisChain,
560
+ limit: safeLimit,
561
+ order,
562
+ };
563
+ if (fromDate)
564
+ query.from_date = fromDate;
565
+ if (toDate)
566
+ query.to_date = toDate;
567
+ if (fromBlock != null)
568
+ query.from_block = fromBlock;
569
+ if (toBlock != null)
570
+ query.to_block = toBlock;
571
+ if (cursor)
572
+ query.cursor = cursor;
573
+ if (contractAddresses?.length)
574
+ query.contract_addresses = contractAddresses;
575
+ const qs = buildQueryString(query);
576
+ const url = `${this.baseUrl}/api/moralis/proxy/${encodeURIComponent(address)}/erc20/transfers?${qs}`;
577
+ const res = await fetch(url);
578
+ if (!res.ok)
579
+ throw new Error(`HTTP ${res.status}`);
580
+ const json = (await res.json());
581
+ const payload = json?.data ?? json;
582
+ const data = payload;
583
+ return { success: true, data };
584
+ }
585
+ catch (error) {
586
+ lastError = error instanceof Error ? error.message : 'Unknown error';
587
+ if (attempt < MAX_RETRIES)
588
+ await delay(RETRY_DELAY_MS);
589
+ }
590
+ }
591
+ return { success: false, error: lastError };
592
+ }
593
+ // =========================================================================
594
+ // Wallet NFT Transfers (GET /{address}/nft/transfers)
595
+ // =========================================================================
596
+ /**
597
+ * Get every NFT transfer involving a wallet, optionally filtered by one
598
+ * or more NFT contract addresses.
599
+ *
600
+ * Use this to answer questions like:
601
+ * - "Which NFTs did I sell?"
602
+ * - "Who did I send my NFTs to?"
603
+ * - "Who sent me NFTs from collection 0x…?"
604
+ * - "Show all NFT transfers with last sale price"
605
+ */
606
+ async getWalletNftTransfers(params) {
607
+ const { address, chain, contractAddresses, limit = 25, fromDate, toDate, fromBlock, toBlock, cursor, order = 'DESC', includePrices, format = 'decimal', } = params;
608
+ if (!address)
609
+ return { success: false, error: 'Address is required' };
610
+ if (!(0, web3_1.isAddressEVM)(address)) {
611
+ return { success: false, error: 'NFT transfers are only supported for EVM addresses' };
612
+ }
613
+ const moralisChain = toMoralisChain(chain);
614
+ const safeLimit = Math.max(1, Math.min(100, Math.floor(limit)));
615
+ let lastError = 'Unknown error';
616
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
617
+ try {
618
+ const query = {
619
+ chain: moralisChain,
620
+ limit: safeLimit,
621
+ order,
622
+ format,
623
+ };
624
+ if (fromDate)
625
+ query.from_date = fromDate;
626
+ if (toDate)
627
+ query.to_date = toDate;
628
+ if (fromBlock != null)
629
+ query.from_block = fromBlock;
630
+ if (toBlock != null)
631
+ query.to_block = toBlock;
632
+ if (cursor)
633
+ query.cursor = cursor;
634
+ if (contractAddresses?.length)
635
+ query.contract_addresses = contractAddresses;
636
+ if (includePrices != null)
637
+ query.include_prices = includePrices;
638
+ const qs = buildQueryString(query);
639
+ const url = `${this.baseUrl}/api/moralis/proxy/${encodeURIComponent(address)}/nft/transfers?${qs}`;
640
+ const res = await fetch(url);
641
+ if (!res.ok)
642
+ throw new Error(`HTTP ${res.status}`);
643
+ const json = (await res.json());
644
+ const payload = json?.data ?? json;
645
+ const data = payload;
646
+ return { success: true, data };
647
+ }
648
+ catch (error) {
649
+ lastError = error instanceof Error ? error.message : 'Unknown error';
650
+ if (attempt < MAX_RETRIES)
651
+ await delay(RETRY_DELAY_MS);
652
+ }
653
+ }
654
+ return { success: false, error: lastError };
655
+ }
656
+ // =========================================================================
657
+ // Token Holders (GET /erc20/{address}/holders)
658
+ // =========================================================================
659
+ /**
660
+ * Get the paginated list of holders for an ERC-20 token.
661
+ *
662
+ * URL: GET /api/moralis/proxy/erc20/{contractAddress}/holders
663
+ *
664
+ * Use to answer questions like:
665
+ * - "Who holds USDC?"
666
+ * - "Show top holders of 0x…"
667
+ * - "How many wallets hold this token?"
668
+ * - "What % does the biggest holder control?"
669
+ */
670
+ async getTokenHolders(params) {
671
+ const { address, chain } = params;
672
+ if (!address)
673
+ return { success: false, error: 'Contract address is required' };
674
+ if (!(0, web3_1.isAddressEVM)(address)) {
675
+ return { success: false, error: 'Token holders is only supported for EVM contract addresses' };
676
+ }
677
+ const moralisChain = toMoralisChain(chain);
678
+ let lastError = 'Unknown error';
679
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
680
+ try {
681
+ const qs = buildQueryString({ chain: moralisChain });
682
+ const url = `${this.baseUrl}/api/moralis/proxy/erc20/${encodeURIComponent(address)}/holders?${qs}`;
683
+ const res = await fetch(url);
684
+ if (!res.ok)
685
+ throw new Error(`HTTP ${res.status}`);
686
+ const json = (await res.json());
687
+ const payload = json?.data ?? json;
688
+ const data = payload;
689
+ return { success: true, data };
690
+ }
691
+ catch (error) {
692
+ lastError = error instanceof Error ? error.message : 'Unknown error';
693
+ if (attempt < MAX_RETRIES)
694
+ await delay(RETRY_DELAY_MS);
695
+ }
696
+ }
697
+ return { success: false, error: lastError };
698
+ }
699
+ // =========================================================================
700
+ // Wallet Net Worth
701
+ // =========================================================================
702
+ /**
703
+ * Get a wallet's total net worth in USD, broken down per chain.
704
+ *
705
+ * URL: GET /api/moralis/proxy/wallets/{address}/net-worth
706
+ *
707
+ * Use to answer questions like:
708
+ * - "What's my total wallet value?"
709
+ * - "How much is my portfolio worth on each chain?"
710
+ */
711
+ async getWalletNetWorth(params) {
712
+ const { address, chains, excludeSpam, excludeUnverifiedContracts, maxTokenInactivity, minPairSideLiquidityUsd } = params;
713
+ if (!address)
714
+ return { success: false, error: 'Address is required' };
715
+ if (!(0, web3_1.isAddressEVM)(address)) {
716
+ return { success: false, error: 'Wallet net worth is only supported for EVM addresses' };
717
+ }
718
+ let lastError = 'Unknown error';
719
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
720
+ try {
721
+ const query = {};
722
+ if (chains && chains.length > 0)
723
+ query.chains = chains.map((c) => toMoralisChain(c));
724
+ if (excludeSpam != null)
725
+ query.exclude_spam = excludeSpam;
726
+ if (excludeUnverifiedContracts != null)
727
+ query.exclude_unverified_contracts = excludeUnverifiedContracts;
728
+ if (maxTokenInactivity != null)
729
+ query.max_token_inactivity = maxTokenInactivity;
730
+ if (minPairSideLiquidityUsd != null)
731
+ query.min_pair_side_liquidity_usd = minPairSideLiquidityUsd;
732
+ const qs = buildQueryString(query);
733
+ const url = `${this.baseUrl}/api/moralis/proxy/wallets/${encodeURIComponent(address)}/net-worth${qs ? `?${qs}` : ''}`;
734
+ const res = await fetch(url);
735
+ if (!res.ok)
736
+ throw new Error(`HTTP ${res.status}`);
737
+ const json = (await res.json());
738
+ const payload = json?.data ?? json;
739
+ const data = payload;
740
+ return { success: true, data };
741
+ }
742
+ catch (error) {
743
+ lastError = error instanceof Error ? error.message : 'Unknown error';
744
+ if (attempt < MAX_RETRIES)
745
+ await delay(RETRY_DELAY_MS);
746
+ }
747
+ }
748
+ return { success: false, error: lastError };
749
+ }
750
+ // =========================================================================
751
+ // Wallet PnL (Profitability)
752
+ // =========================================================================
753
+ /**
754
+ * Get aggregate profit-and-loss summary for a wallet.
755
+ *
756
+ * URL: GET /api/moralis/proxy/wallets/{address}/profitability/summary
757
+ *
758
+ * Mainnet only. Moralis supports: Ethereum (0x1), Base (0x2105), Polygon (0x89).
759
+ */
760
+ async getWalletPnlSummary(params) {
761
+ const { address, chain, days } = params;
762
+ if (!address)
763
+ return { success: false, error: 'Address is required' };
764
+ if (!(0, web3_1.isAddressEVM)(address)) {
765
+ return { success: false, error: 'Wallet PnL summary is only supported for EVM addresses' };
766
+ }
767
+ const moralisChain = toMoralisChain(chain);
768
+ let lastError = 'Unknown error';
769
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
770
+ try {
771
+ const query = { chain: moralisChain };
772
+ if (days)
773
+ query.days = days;
774
+ const qs = buildQueryString(query);
775
+ const url = `${this.baseUrl}/api/moralis/proxy/wallets/${encodeURIComponent(address)}/profitability/summary?${qs}`;
776
+ const res = await fetch(url);
777
+ if (!res.ok)
778
+ throw new Error(`HTTP ${res.status}`);
779
+ const json = (await res.json());
780
+ const payload = json?.data ?? json;
781
+ const data = payload;
782
+ return { success: true, data };
783
+ }
784
+ catch (error) {
785
+ lastError = error instanceof Error ? error.message : 'Unknown error';
786
+ if (attempt < MAX_RETRIES)
787
+ await delay(RETRY_DELAY_MS);
788
+ }
789
+ }
790
+ return { success: false, error: lastError };
791
+ }
792
+ /**
793
+ * Get per-token profit-and-loss breakdown for a wallet.
794
+ *
795
+ * URL: GET /api/moralis/proxy/wallets/{address}/profitability
796
+ *
797
+ * Mainnet only. Moralis supports: Ethereum (0x1), Base (0x2105), Polygon (0x89).
798
+ * tokenAddresses supports up to 25 addresses.
799
+ */
800
+ async getWalletPnl(params) {
801
+ const { address, chain, days, tokenAddresses } = params;
802
+ if (!address)
803
+ return { success: false, error: 'Address is required' };
804
+ if (!(0, web3_1.isAddressEVM)(address)) {
805
+ return { success: false, error: 'Wallet PnL is only supported for EVM addresses' };
806
+ }
807
+ const moralisChain = toMoralisChain(chain);
808
+ let lastError = 'Unknown error';
809
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
810
+ try {
811
+ const query = { chain: moralisChain };
812
+ if (days)
813
+ query.days = days;
814
+ if (tokenAddresses && tokenAddresses.length > 0) {
815
+ query.token_addresses = tokenAddresses.slice(0, 25);
816
+ }
817
+ const qs = buildQueryString(query);
818
+ const url = `${this.baseUrl}/api/moralis/proxy/wallets/${encodeURIComponent(address)}/profitability?${qs}`;
819
+ const res = await fetch(url);
820
+ if (!res.ok)
821
+ throw new Error(`HTTP ${res.status}`);
822
+ const json = (await res.json());
823
+ const payload = json?.data ?? json;
824
+ const data = payload;
825
+ return { success: true, data };
826
+ }
827
+ catch (error) {
828
+ lastError = error instanceof Error ? error.message : 'Unknown error';
829
+ if (attempt < MAX_RETRIES)
830
+ await delay(RETRY_DELAY_MS);
831
+ }
832
+ }
833
+ return { success: false, error: lastError };
834
+ }
835
+ // =========================================================================
836
+ // Transaction by Hash (GET /transaction/{hash}?decode=true)
837
+ // =========================================================================
838
+ /**
839
+ * Get a decoded transaction by its hash.
840
+ *
841
+ * URL: GET /api/moralis/proxy/transaction/{transactionHash}?chain=…&decode=true
842
+ *
843
+ * Returns full transaction details including decoded function call and
844
+ * decoded event logs, along with address labels and entity names.
845
+ */
846
+ async getTransactionByHash(params) {
847
+ const { transactionHash, chain } = params;
848
+ if (!transactionHash)
849
+ return { success: false, error: 'Transaction hash is required' };
850
+ const moralisChain = toMoralisChain(chain);
851
+ let lastError = 'Unknown error';
852
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
853
+ try {
854
+ const qs = buildQueryString({ chain: moralisChain });
855
+ const url = `${this.baseUrl}/api/moralis/proxy/transaction/${encodeURIComponent(transactionHash)}/verbose?${qs}`;
856
+ const res = await fetch(url);
857
+ if (!res.ok)
858
+ throw new Error(`HTTP ${res.status}`);
859
+ const json = (await res.json());
860
+ const payload = json?.data ?? json;
861
+ const data = payload;
862
+ return { success: true, data };
863
+ }
864
+ catch (error) {
865
+ lastError = error instanceof Error ? error.message : 'Unknown error';
866
+ if (attempt < MAX_RETRIES)
867
+ await delay(RETRY_DELAY_MS);
868
+ }
869
+ }
870
+ return { success: false, error: lastError };
871
+ }
872
+ // =========================================================================
873
+ // Wallet Approvals — active ERC-20 token approvals
874
+ // =========================================================================
875
+ /**
876
+ * List every active ERC-20 token approval granted by a wallet, paginated.
877
+ *
878
+ * URL: GET /api/moralis/proxy/wallets/{address}/approvals?chain=…&limit=…&cursor=…
879
+ *
880
+ * Moralis docs: https://docs.moralis.com/data-api/evm/wallet/approvals
881
+ *
882
+ * Mainnet EVM only. Each row includes the approved token (with current
883
+ * balance, USD price, `usd_at_risk`) and the spender (address, label,
884
+ * entity).
885
+ */
886
+ async getWalletApprovals(params) {
887
+ const { address, chain, limit, cursor } = params;
888
+ if (!address)
889
+ return { success: false, error: 'Address is required' };
890
+ if (!(0, web3_1.isAddressEVM)(address)) {
891
+ return { success: false, error: 'Wallet approvals are only supported for EVM addresses' };
892
+ }
893
+ const moralisChain = toMoralisChain(chain);
894
+ let lastError = 'Unknown error';
895
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
896
+ try {
897
+ const query = { chain: moralisChain };
898
+ if (limit != null)
899
+ query.limit = limit;
900
+ if (cursor)
901
+ query.cursor = cursor;
902
+ const qs = buildQueryString(query);
903
+ const url = `${this.baseUrl}/api/moralis/proxy/wallets/${encodeURIComponent(address)}/approvals?${qs}`;
904
+ const res = await fetch(url);
905
+ if (!res.ok)
906
+ throw new Error(`HTTP ${res.status}`);
907
+ const json = (await res.json());
908
+ const payload = json?.data ?? json;
909
+ const data = payload;
910
+ return { success: true, data };
911
+ }
912
+ catch (error) {
913
+ lastError = error instanceof Error ? error.message : 'Unknown error';
914
+ if (attempt < MAX_RETRIES)
915
+ await delay(RETRY_DELAY_MS);
916
+ }
917
+ }
918
+ return { success: false, error: lastError };
919
+ }
920
+ // =========================================================================
921
+ // Wallet DeFi — Protocols summary & positions
922
+ // =========================================================================
923
+ /**
924
+ * Get a DeFi summary for a wallet: aggregate USD value, unclaimed rewards
925
+ * and a per-protocol breakdown of where the wallet has positions.
926
+ *
927
+ * URL: GET /api/moralis/proxy/wallets/{address}/defi/summary?chain=…
928
+ *
929
+ * Moralis docs: https://docs.moralis.com/data-api/evm/wallet/wallet-protocols
930
+ *
931
+ * Mainnet EVM only.
932
+ */
933
+ async getWalletDefiSummary(params) {
934
+ const { address, chain } = params;
935
+ if (!address)
936
+ return { success: false, error: 'Address is required' };
937
+ if (!(0, web3_1.isAddressEVM)(address)) {
938
+ return { success: false, error: 'Wallet DeFi summary is only supported for EVM addresses' };
939
+ }
940
+ const moralisChain = toMoralisChain(chain);
941
+ let lastError = 'Unknown error';
942
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
943
+ try {
944
+ const qs = buildQueryString({ chains: moralisChain });
945
+ const url = `${this.v1BaseUrl}/api/moralis-v1/proxy/wallets/${encodeURIComponent(address)}/defi/summary?${qs}`;
946
+ const res = await fetch(url);
947
+ if (!res.ok)
948
+ throw new Error(`HTTP ${res.status}`);
949
+ const json = (await res.json());
950
+ const payload = json?.data ?? json;
951
+ const data = payload;
952
+ return { success: true, data };
953
+ }
954
+ catch (error) {
955
+ lastError = error instanceof Error ? error.message : 'Unknown error';
956
+ if (attempt < MAX_RETRIES)
957
+ await delay(RETRY_DELAY_MS);
958
+ }
959
+ }
960
+ return { success: false, error: lastError };
961
+ }
962
+ /**
963
+ * Get every DeFi position a wallet holds across all supported protocols,
964
+ * each enriched with the owning protocol's identity.
965
+ *
966
+ * URL: GET /api/moralis/proxy/wallets/{address}/defi/positions?chain=…
967
+ *
968
+ * Moralis docs: https://docs.moralis.com/data-api/evm/wallet/wallet-positions
969
+ */
970
+ async getWalletDefiPositions(params) {
971
+ const { address, chain } = params;
972
+ if (!address)
973
+ return { success: false, error: 'Address is required' };
974
+ if (!(0, web3_1.isAddressEVM)(address)) {
975
+ return { success: false, error: 'Wallet DeFi positions are only supported for EVM addresses' };
976
+ }
977
+ const moralisChain = toMoralisChain(chain);
978
+ let lastError = 'Unknown error';
979
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
980
+ try {
981
+ const qs = buildQueryString({ chains: moralisChain });
982
+ const url = `${this.v1BaseUrl}/api/moralis-v1/proxy/wallets/${encodeURIComponent(address)}/defi/positions?${qs}`;
983
+ const res = await fetch(url);
984
+ if (!res.ok)
985
+ throw new Error(`HTTP ${res.status}`);
986
+ const json = (await res.json());
987
+ const payload = json?.data ?? json;
988
+ const data = normalizeDefiPositionsPayload(payload);
989
+ return { success: true, data };
990
+ }
991
+ catch (error) {
992
+ lastError = error instanceof Error ? error.message : 'Unknown error';
993
+ if (attempt < MAX_RETRIES)
994
+ await delay(RETRY_DELAY_MS);
995
+ }
996
+ }
997
+ return { success: false, error: lastError };
998
+ }
999
+ /**
1000
+ * Get detailed positions a wallet holds inside a specific protocol
1001
+ * (e.g. `uniswap-v3`, `aave-v3`, `lido`).
1002
+ *
1003
+ * URL: GET /api/moralis/proxy/wallets/{address}/defi/{protocol}/positions?chain=…
1004
+ *
1005
+ * Moralis docs: https://docs.moralis.com/data-api/evm/wallet/detailed-positions
1006
+ */
1007
+ async getWalletDefiProtocolPositions(params) {
1008
+ const { address, protocol, chain } = params;
1009
+ if (!address)
1010
+ return { success: false, error: 'Address is required' };
1011
+ if (!protocol)
1012
+ return { success: false, error: 'Protocol identifier is required' };
1013
+ if (!(0, web3_1.isAddressEVM)(address)) {
1014
+ return { success: false, error: 'Wallet DeFi protocol positions are only supported for EVM addresses' };
1015
+ }
1016
+ const moralisChain = toMoralisChain(chain);
1017
+ let lastError = 'Unknown error';
1018
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
1019
+ try {
1020
+ const qs = buildQueryString({ chains: moralisChain });
1021
+ const url = `${this.v1BaseUrl}/api/moralis-v1/proxy/wallets/${encodeURIComponent(address)}/defi/${encodeURIComponent(protocol)}/positions?${qs}`;
1022
+ const res = await fetch(url);
1023
+ if (!res.ok)
1024
+ throw new Error(`HTTP ${res.status}`);
1025
+ const json = (await res.json());
1026
+ const raw = json;
1027
+ const r = raw.result;
1028
+ const data = {
1029
+ protocol_id: r.protocolId,
1030
+ protocol_name: r.protocolName,
1031
+ protocol_url: r.protocolUrl ?? '',
1032
+ protocol_logo: r.protocolLogo ?? '',
1033
+ total_usd_value: r.totalUsd ?? 0,
1034
+ total_unclaimed_usd_value: r.totalUnclaimedUsd ?? null,
1035
+ positions: r.positions.map((p) => ({
1036
+ label: p.label,
1037
+ address: p.address,
1038
+ balance_usd: p.balanceUsd ?? 0,
1039
+ total_unclaimed_usd_value: p.unclaimedUsd ?? 0,
1040
+ position_details: p.details,
1041
+ tokens: p.tokens.map((t) => ({
1042
+ token_type: t.tokenType,
1043
+ address: t.address,
1044
+ contract_address: t.address,
1045
+ name: t.name ?? '',
1046
+ symbol: t.symbol ?? '',
1047
+ decimals: t.decimals ?? 18,
1048
+ logo: t.logo,
1049
+ balance: t.balance ?? '0',
1050
+ balance_formatted: t.balanceFormatted ?? '0',
1051
+ usd_price: t.usdPrice,
1052
+ usd_value: t.usdValue,
1053
+ })),
1054
+ })),
1055
+ };
1056
+ return { success: true, data };
1057
+ }
1058
+ catch (error) {
1059
+ lastError = error instanceof Error ? error.message : 'Unknown error';
1060
+ if (attempt < MAX_RETRIES)
1061
+ await delay(RETRY_DELAY_MS);
1062
+ }
1063
+ }
1064
+ return { success: false, error: lastError };
1065
+ }
1066
+ // =========================================================================
1067
+ // Cortex AI Chat
1068
+ // =========================================================================
1069
+ /**
1070
+ * Chat with Moralis Cortex AI for blockchain insights.
1071
+ */
1072
+ async chatWithCortex(params) {
1073
+ const { prompt, model, systemPrompt, maxRetries = 5 } = params;
1074
+ if (!prompt)
1075
+ return { success: false, error: 'Prompt is required' };
1076
+ const fullPrompt = systemPrompt ? `${systemPrompt}\n\n---\n\nCurrent User's question: ${prompt}` : prompt;
1077
+ let lastError = 'Unknown error';
1078
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
1079
+ try {
1080
+ const url = `${this.baseUrl}/api/moralis-cortex/proxy/chat`;
1081
+ const res = await fetch(url, {
1082
+ method: 'POST',
1083
+ headers: {
1084
+ 'Content-Type': 'application/json',
1085
+ Accept: 'application/json',
1086
+ },
1087
+ body: JSON.stringify({
1088
+ prompt: fullPrompt,
1089
+ model: model ?? this.cortexModel,
1090
+ stream: false,
1091
+ }),
1092
+ });
1093
+ if (!res.ok)
1094
+ throw new Error(`HTTP ${res.status}`);
1095
+ const json = (await res.json());
1096
+ const data = (json?.data ?? json);
1097
+ if (!data?.text?.trim()) {
1098
+ lastError = 'Empty response from Cortex AI';
1099
+ if (attempt < maxRetries)
1100
+ await delay(RETRY_DELAY_MS);
1101
+ continue;
1102
+ }
1103
+ return { success: true, data };
1104
+ }
1105
+ catch (error) {
1106
+ lastError = error instanceof Error ? error.message : 'Unknown error';
1107
+ if (attempt < maxRetries)
1108
+ await delay(RETRY_DELAY_MS);
1109
+ }
1110
+ }
1111
+ return { success: false, error: lastError };
1112
+ }
1113
+ // =========================================================================
1114
+ // Search Tokens by Key — delegates to PantographService
1115
+ // =========================================================================
1116
+ /** Search for tokens by symbol or name keyword on a specific chain. */
1117
+ async searchTokensByKey(params) {
1118
+ return this.pantograph.searchTokensByKey(params);
1119
+ }
1120
+ // =========================================================================
1121
+ // Token Analytics
1122
+ // =========================================================================
1123
+ /**
1124
+ * Detailed trading analytics for a single token: buy/sell volume, unique
1125
+ * buyers/sellers, transaction counts, unique wallets, price change,
1126
+ * current USD price, total liquidity and FDV — all broken down across
1127
+ * 5min / 1h / 6h / 24h windows.
1128
+ *
1129
+ * URL: GET /api/moralis/proxy/tokens/{tokenAddress}/analytics
1130
+ * Upstream: GET https://deep-index.moralis.io/api/v2.2/tokens/{tokenAddress}/analytics
1131
+ *
1132
+ * Use to answer questions like:
1133
+ * - "How is PEPE trading today?"
1134
+ * - "What's the 24h buy vs sell volume for USDC?"
1135
+ * - "How many unique wallets interacted with this token in the last hour?"
1136
+ * - "Is buying or selling pressure stronger for this token?"
1137
+ */
1138
+ async getTokenAnalytics(params) {
1139
+ const { address, chain } = params;
1140
+ if (!address)
1141
+ return { success: false, error: 'Token contract address is required' };
1142
+ if (!(0, web3_1.isAddressEVM)(address)) {
1143
+ return { success: false, error: 'Token analytics is only supported for EVM contract addresses' };
1144
+ }
1145
+ const moralisChain = toMoralisChain(chain);
1146
+ let lastError = 'Unknown error';
1147
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
1148
+ try {
1149
+ const qs = buildQueryString({ chain: moralisChain });
1150
+ const url = `${this.baseUrl}/api/moralis/proxy/tokens/${encodeURIComponent(address)}/analytics?${qs}`;
1151
+ const res = await fetch(url);
1152
+ if (!res.ok)
1153
+ throw new Error(`HTTP ${res.status}`);
1154
+ const json = (await res.json());
1155
+ const payload = json?.data ?? json;
1156
+ const data = payload;
1157
+ return { success: true, data };
1158
+ }
1159
+ catch (error) {
1160
+ lastError = error instanceof Error ? error.message : 'Unknown error';
1161
+ if (attempt < MAX_RETRIES)
1162
+ await delay(RETRY_DELAY_MS);
1163
+ }
1164
+ }
1165
+ return { success: false, error: lastError };
1166
+ }
1167
+ // =========================================================================
1168
+ // Token Score
1169
+ // =========================================================================
1170
+ /**
1171
+ * Composite 0–100 health/safety score for a single token, plus the
1172
+ * underlying metrics Moralis uses to compute it: current USD price, paired
1173
+ * liquidity, multi-timeframe volume and transaction counts (10m / 30m /
1174
+ * 1h / 4h / 12h / 1d / 7d / 30d), and supply concentration (total + % held
1175
+ * by the top 10 wallets).
1176
+ *
1177
+ * URL: GET /api/moralis/proxy/tokens/{tokenAddress}/score
1178
+ * Upstream: GET https://deep-index.moralis.io/api/v2.2/tokens/{tokenAddress}/score
1179
+ *
1180
+ * Use to answer questions like:
1181
+ * - "Is PEPE a safe token?" (→ score)
1182
+ * - "What's the health score of this token?"
1183
+ * - "How concentrated is X's supply among top holders?" (→ metrics.supply.top10Percent)
1184
+ * - "How much volume did this token do over the last 7 days?" (→ metrics.volumeUsd.7d)
1185
+ */
1186
+ async getTokenScore(params) {
1187
+ const { address, chain } = params;
1188
+ if (!address)
1189
+ return { success: false, error: 'Token contract address is required' };
1190
+ if (!(0, web3_1.isAddressEVM)(address)) {
1191
+ return { success: false, error: 'Token score is only supported for EVM contract addresses' };
1192
+ }
1193
+ const moralisChain = toMoralisChain(chain);
1194
+ let lastError = 'Unknown error';
1195
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
1196
+ try {
1197
+ const qs = buildQueryString({ chain: moralisChain });
1198
+ const url = `${this.baseUrl}/api/moralis/proxy/tokens/${encodeURIComponent(address)}/score?${qs}`;
1199
+ const res = await fetch(url);
1200
+ if (!res.ok)
1201
+ throw new Error(`HTTP ${res.status}`);
1202
+ const json = (await res.json());
1203
+ const payload = json?.data ?? json;
1204
+ const data = payload;
1205
+ return { success: true, data };
1206
+ }
1207
+ catch (error) {
1208
+ lastError = error instanceof Error ? error.message : 'Unknown error';
1209
+ if (attempt < MAX_RETRIES)
1210
+ await delay(RETRY_DELAY_MS);
1211
+ }
1212
+ }
1213
+ return { success: false, error: lastError };
1214
+ }
1215
+ // =========================================================================
1216
+ // Trending Tokens
1217
+ // =========================================================================
1218
+ /**
1219
+ * List tokens trending on-chain based on trading activity, volume, liquidity
1220
+ * and holder growth. Moralis returns cross-chain results by default; pass a
1221
+ * `chain` to scope to a single network.
1222
+ *
1223
+ * URL: GET /api/moralis/proxy/tokens/trending
1224
+ * Upstream: GET https://deep-index.moralis.io/api/v2.2/tokens/trending
1225
+ *
1226
+ * Use to answer questions like:
1227
+ * - "What tokens are trending right now?"
1228
+ * - "Show me the hottest tokens on Base"
1229
+ * - "Which tokens have the most trading activity today?"
1230
+ */
1231
+ async getTrendingTokens(params) {
1232
+ const chain = params?.chain;
1233
+ const limit = params?.limit;
1234
+ let lastError = 'Unknown error';
1235
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
1236
+ try {
1237
+ const query = {};
1238
+ if (chain)
1239
+ query.chain = toMoralisChain(chain);
1240
+ if (limit != null)
1241
+ query.limit = limit;
1242
+ const qs = buildQueryString(query);
1243
+ const url = `${this.baseUrl}/api/moralis/proxy/tokens/trending${qs ? `?${qs}` : ''}`;
1244
+ const res = await fetch(url);
1245
+ if (!res.ok)
1246
+ throw new Error(`HTTP ${res.status}`);
1247
+ const json = (await res.json());
1248
+ const payload = json?.data ?? json;
1249
+ const data = normalizeArrayLikePayload(payload);
1250
+ return { success: true, data };
1251
+ }
1252
+ catch (error) {
1253
+ lastError = error instanceof Error ? error.message : 'Unknown error';
1254
+ if (attempt < MAX_RETRIES)
1255
+ await delay(RETRY_DELAY_MS);
1256
+ }
1257
+ }
1258
+ return { success: false, error: lastError };
1259
+ }
1260
+ // =========================================================================
1261
+ // Top Gainers (Discovery)
1262
+ // =========================================================================
1263
+ /**
1264
+ * List tokens with the highest USD price increase over a given timeframe.
1265
+ * Supports optional filters for minimum market cap and security score.
1266
+ *
1267
+ * URL: GET /api/moralis/proxy/discovery/tokens/top-gainers
1268
+ * Upstream: GET https://deep-index.moralis.io/api/v2.2/discovery/tokens/top-gainers
1269
+ *
1270
+ * Use to answer questions like:
1271
+ * - "What are today's top gainers?"
1272
+ * - "Which tokens pumped the most this week on Arbitrum?"
1273
+ * - "Show me safe tokens (security score ≥ 80) that gained in the last hour"
1274
+ */
1275
+ async getTopGainers(params) {
1276
+ const { chain, timeFrame, minMarketCap, securityScore } = params ?? {};
1277
+ let lastError = 'Unknown error';
1278
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
1279
+ try {
1280
+ const query = {};
1281
+ if (chain)
1282
+ query.chain = toMoralisChain(chain);
1283
+ if (timeFrame)
1284
+ query.time_frame = timeFrame;
1285
+ if (minMarketCap != null)
1286
+ query.min_market_cap = minMarketCap;
1287
+ if (securityScore != null)
1288
+ query.security_score = securityScore;
1289
+ const qs = buildQueryString(query);
1290
+ const url = `${this.baseUrl}/api/moralis/proxy/discovery/tokens/top-gainers${qs ? `?${qs}` : ''}`;
1291
+ const res = await fetch(url);
1292
+ if (!res.ok)
1293
+ throw new Error(`HTTP ${res.status}`);
1294
+ const json = (await res.json());
1295
+ const payload = json?.data ?? json;
1296
+ const data = normalizeArrayLikePayload(payload);
1297
+ return { success: true, data };
1298
+ }
1299
+ catch (error) {
1300
+ lastError = error instanceof Error ? error.message : 'Unknown error';
1301
+ if (attempt < MAX_RETRIES)
1302
+ await delay(RETRY_DELAY_MS);
1303
+ }
1304
+ }
1305
+ return { success: false, error: lastError };
1306
+ }
1307
+ // =========================================================================
1308
+ // Top Losers (Discovery)
1309
+ // =========================================================================
1310
+ /**
1311
+ * List tokens with the largest USD price decrease over a given timeframe.
1312
+ * Same filter set as top-gainers (min market cap, security score) and
1313
+ * identical response shape — only the ranking direction differs.
1314
+ *
1315
+ * URL: GET /api/moralis/proxy/discovery/tokens/top-losers
1316
+ * Upstream: GET https://deep-index.moralis.io/api/v2.2/discovery/tokens/top-losers
1317
+ *
1318
+ * Use to answer questions like:
1319
+ * - "What are today's biggest losers?"
1320
+ * - "Which tokens dumped the most this week on BSC?"
1321
+ * - "Worst performers in the last 24h with market cap over $50M"
1322
+ */
1323
+ async getTopLosers(params) {
1324
+ const { chain, timeFrame, minMarketCap, securityScore } = params ?? {};
1325
+ let lastError = 'Unknown error';
1326
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
1327
+ try {
1328
+ const query = {};
1329
+ if (chain)
1330
+ query.chain = toMoralisChain(chain);
1331
+ if (timeFrame)
1332
+ query.time_frame = timeFrame;
1333
+ if (minMarketCap != null)
1334
+ query.min_market_cap = minMarketCap;
1335
+ if (securityScore != null)
1336
+ query.security_score = securityScore;
1337
+ const qs = buildQueryString(query);
1338
+ const url = `${this.baseUrl}/api/moralis/proxy/discovery/tokens/top-losers${qs ? `?${qs}` : ''}`;
1339
+ const res = await fetch(url);
1340
+ if (!res.ok)
1341
+ throw new Error(`HTTP ${res.status}`);
1342
+ const json = (await res.json());
1343
+ const payload = json?.data ?? json;
1344
+ const data = normalizeArrayLikePayload(payload);
1345
+ return { success: true, data };
1346
+ }
1347
+ catch (error) {
1348
+ lastError = error instanceof Error ? error.message : 'Unknown error';
1349
+ if (attempt < MAX_RETRIES)
1350
+ await delay(RETRY_DELAY_MS);
1351
+ }
1352
+ }
1353
+ return { success: false, error: lastError };
1354
+ }
1355
+ // =========================================================================
1356
+ // Private helpers
1357
+ // =========================================================================
1358
+ /** Enrich token balances with price/logo data. Delegates to PantographService. */
1359
+ async enrichTokenPrices(tokens, moralisChain) {
1360
+ return this.pantograph.enrichTokenPrices(tokens, moralisChain);
1361
+ }
1362
+ }
1363
+ exports.MoralisService = MoralisService;
1364
+ //# sourceMappingURL=MoralisService.js.map