@elizaos/plugin-steward-app 2.0.3-beta.5 → 2.0.3-beta.7

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 (219) hide show
  1. package/dist/ApprovalQueue.d.ts +18 -0
  2. package/dist/ApprovalQueue.d.ts.map +1 -0
  3. package/dist/ApprovalQueue.js +420 -0
  4. package/dist/ApprovalQueue.js.map +1 -0
  5. package/dist/StewardLogo.d.ts +11 -0
  6. package/dist/StewardLogo.d.ts.map +1 -0
  7. package/dist/StewardLogo.js +36 -0
  8. package/dist/StewardLogo.js.map +1 -0
  9. package/dist/StewardView.d.ts +13 -0
  10. package/dist/StewardView.d.ts.map +1 -0
  11. package/dist/StewardView.helpers.d.ts +15 -0
  12. package/dist/StewardView.helpers.d.ts.map +1 -0
  13. package/dist/StewardView.helpers.js +45 -0
  14. package/dist/StewardView.helpers.js.map +1 -0
  15. package/dist/StewardView.interact.d.ts +2 -0
  16. package/dist/StewardView.interact.d.ts.map +1 -0
  17. package/dist/StewardView.interact.js +54 -0
  18. package/dist/StewardView.interact.js.map +1 -0
  19. package/dist/StewardView.js +249 -0
  20. package/dist/StewardView.js.map +1 -0
  21. package/dist/TransactionHistory.d.ts +22 -0
  22. package/dist/TransactionHistory.d.ts.map +1 -0
  23. package/dist/TransactionHistory.js +361 -0
  24. package/dist/TransactionHistory.js.map +1 -0
  25. package/dist/__fixtures__/steward-sdk-fixtures.d.ts +10 -0
  26. package/dist/__fixtures__/steward-sdk-fixtures.d.ts.map +1 -0
  27. package/dist/__fixtures__/steward-sdk-fixtures.js +60 -0
  28. package/dist/__fixtures__/steward-sdk-fixtures.js.map +1 -0
  29. package/dist/actions/wallet-action-shared.d.ts +15 -0
  30. package/dist/actions/wallet-action-shared.d.ts.map +1 -0
  31. package/dist/actions/wallet-action-shared.js +16 -0
  32. package/dist/actions/wallet-action-shared.js.map +1 -0
  33. package/dist/api/binance-skill-helpers.d.ts +21 -0
  34. package/dist/api/binance-skill-helpers.d.ts.map +1 -0
  35. package/dist/api/binance-skill-helpers.js +790 -0
  36. package/dist/api/binance-skill-helpers.js.map +1 -0
  37. package/dist/api/bsc-trade.d.ts +36 -0
  38. package/dist/api/bsc-trade.d.ts.map +1 -0
  39. package/dist/api/bsc-trade.js +796 -0
  40. package/dist/api/bsc-trade.js.map +1 -0
  41. package/dist/api/trade-safety.d.ts +35 -0
  42. package/dist/api/trade-safety.d.ts.map +1 -0
  43. package/dist/api/trade-safety.js +56 -0
  44. package/dist/api/trade-safety.js.map +1 -0
  45. package/dist/api/tx-service.d.ts +53 -0
  46. package/dist/api/tx-service.d.ts.map +1 -0
  47. package/dist/api/tx-service.js +206 -0
  48. package/dist/api/tx-service.js.map +1 -0
  49. package/dist/api/wallet-bsc-routes.d.ts +63 -0
  50. package/dist/api/wallet-bsc-routes.d.ts.map +1 -0
  51. package/dist/api/wallet-bsc-routes.js +337 -0
  52. package/dist/api/wallet-bsc-routes.js.map +1 -0
  53. package/dist/api/wallet-capability.d.ts +2 -0
  54. package/dist/api/wallet-capability.d.ts.map +1 -0
  55. package/dist/api/wallet-capability.js +15 -0
  56. package/dist/api/wallet-capability.js.map +1 -0
  57. package/dist/api/wallet-dex-prices.d.ts +43 -0
  58. package/dist/api/wallet-dex-prices.d.ts.map +1 -0
  59. package/dist/api/wallet-dex-prices.js +132 -0
  60. package/dist/api/wallet-dex-prices.js.map +1 -0
  61. package/dist/api/wallet-evm-balance.d.ts +72 -0
  62. package/dist/api/wallet-evm-balance.d.ts.map +1 -0
  63. package/dist/api/wallet-evm-balance.js +697 -0
  64. package/dist/api/wallet-evm-balance.js.map +1 -0
  65. package/dist/api/wallet-routes.d.ts +27 -0
  66. package/dist/api/wallet-routes.d.ts.map +1 -0
  67. package/dist/api/wallet-routes.js +556 -0
  68. package/dist/api/wallet-routes.js.map +1 -0
  69. package/dist/api/wallet-rpc.d.ts +73 -0
  70. package/dist/api/wallet-rpc.d.ts.map +1 -0
  71. package/dist/api/wallet-rpc.js +460 -0
  72. package/dist/api/wallet-rpc.js.map +1 -0
  73. package/dist/api/wallet-trade-routes.d.ts +104 -0
  74. package/dist/api/wallet-trade-routes.d.ts.map +1 -0
  75. package/dist/api/wallet-trade-routes.js +353 -0
  76. package/dist/api/wallet-trade-routes.js.map +1 -0
  77. package/dist/api/wallet-trading-profile.d.ts +31 -0
  78. package/dist/api/wallet-trading-profile.d.ts.map +1 -0
  79. package/dist/api/wallet-trading-profile.js +500 -0
  80. package/dist/api/wallet-trading-profile.js.map +1 -0
  81. package/dist/api/wallet.d.ts +60 -0
  82. package/dist/api/wallet.d.ts.map +1 -0
  83. package/dist/api/wallet.js +617 -0
  84. package/dist/api/wallet.js.map +1 -0
  85. package/dist/chain-utils.d.ts +10 -0
  86. package/dist/chain-utils.d.ts.map +1 -0
  87. package/dist/chain-utils.js +81 -0
  88. package/dist/chain-utils.js.map +1 -0
  89. package/dist/components/StewardSpatialView.d.ts +74 -0
  90. package/dist/components/StewardSpatialView.d.ts.map +1 -0
  91. package/dist/components/StewardSpatialView.js +309 -0
  92. package/dist/components/StewardSpatialView.js.map +1 -0
  93. package/dist/index.d.ts +20 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +77 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/plugin.d.ts +21 -0
  98. package/dist/plugin.d.ts.map +1 -0
  99. package/dist/plugin.js +319 -0
  100. package/dist/plugin.js.map +1 -0
  101. package/dist/providers/steward-balance.d.ts +12 -0
  102. package/dist/providers/steward-balance.d.ts.map +1 -0
  103. package/dist/providers/steward-balance.js +85 -0
  104. package/dist/providers/steward-balance.js.map +1 -0
  105. package/dist/providers/steward-receive-address.d.ts +12 -0
  106. package/dist/providers/steward-receive-address.d.ts.map +1 -0
  107. package/dist/providers/steward-receive-address.js +47 -0
  108. package/dist/providers/steward-receive-address.js.map +1 -0
  109. package/dist/register-routes.d.ts +2 -0
  110. package/dist/register-routes.d.ts.map +1 -0
  111. package/dist/register-routes.js +6 -0
  112. package/dist/register-routes.js.map +1 -0
  113. package/dist/register-terminal-view.d.ts +15 -0
  114. package/dist/register-terminal-view.d.ts.map +1 -0
  115. package/dist/register-terminal-view.js +34 -0
  116. package/dist/register-terminal-view.js.map +1 -0
  117. package/dist/routes/steward-bridge.d.ts +202 -0
  118. package/dist/routes/steward-bridge.d.ts.map +1 -0
  119. package/dist/routes/steward-bridge.js +776 -0
  120. package/dist/routes/steward-bridge.js.map +1 -0
  121. package/dist/routes/steward-compat-routes.d.ts +21 -0
  122. package/dist/routes/steward-compat-routes.d.ts.map +1 -0
  123. package/dist/routes/steward-compat-routes.js +350 -0
  124. package/dist/routes/steward-compat-routes.js.map +1 -0
  125. package/dist/routes/wallet-browser-compat-routes.d.ts +6 -0
  126. package/dist/routes/wallet-browser-compat-routes.d.ts.map +1 -0
  127. package/dist/routes/wallet-browser-compat-routes.js +402 -0
  128. package/dist/routes/wallet-browser-compat-routes.js.map +1 -0
  129. package/dist/routes/wallet-bsc-core-routes.d.ts +15 -0
  130. package/dist/routes/wallet-bsc-core-routes.d.ts.map +1 -0
  131. package/dist/routes/wallet-bsc-core-routes.js +59 -0
  132. package/dist/routes/wallet-bsc-core-routes.js.map +1 -0
  133. package/dist/routes/wallet-compat-routes.d.ts +13 -0
  134. package/dist/routes/wallet-compat-routes.d.ts.map +1 -0
  135. package/dist/routes/wallet-compat-routes.js +206 -0
  136. package/dist/routes/wallet-compat-routes.js.map +1 -0
  137. package/dist/routes/wallet-core-routes.d.ts +16 -0
  138. package/dist/routes/wallet-core-routes.d.ts.map +1 -0
  139. package/dist/routes/wallet-core-routes.js +48 -0
  140. package/dist/routes/wallet-core-routes.js.map +1 -0
  141. package/dist/routes/wallet-trade-compat-routes.d.ts +11 -0
  142. package/dist/routes/wallet-trade-compat-routes.d.ts.map +1 -0
  143. package/dist/routes/wallet-trade-compat-routes.js +570 -0
  144. package/dist/routes/wallet-trade-compat-routes.js.map +1 -0
  145. package/dist/security/hydrate-wallet-keys-from-platform-store.d.ts +7 -0
  146. package/dist/security/hydrate-wallet-keys-from-platform-store.d.ts.map +1 -0
  147. package/dist/security/hydrate-wallet-keys-from-platform-store.js +43 -0
  148. package/dist/security/hydrate-wallet-keys-from-platform-store.js.map +1 -0
  149. package/dist/security/wallet-os-store-actions.d.ts +14 -0
  150. package/dist/security/wallet-os-store-actions.d.ts.map +1 -0
  151. package/dist/security/wallet-os-store-actions.js +63 -0
  152. package/dist/security/wallet-os-store-actions.js.map +1 -0
  153. package/dist/services/steward-credentials.d.ts +2 -0
  154. package/dist/services/steward-credentials.d.ts.map +1 -0
  155. package/dist/services/steward-credentials.js +2 -0
  156. package/dist/services/steward-credentials.js.map +1 -0
  157. package/dist/services/steward-evm-account.d.ts +75 -0
  158. package/dist/services/steward-evm-account.d.ts.map +1 -0
  159. package/dist/services/steward-evm-account.js +279 -0
  160. package/dist/services/steward-evm-account.js.map +1 -0
  161. package/dist/services/steward-evm-bridge.d.ts +36 -0
  162. package/dist/services/steward-evm-bridge.d.ts.map +1 -0
  163. package/dist/services/steward-evm-bridge.js +78 -0
  164. package/dist/services/steward-evm-bridge.js.map +1 -0
  165. package/dist/services/steward-sidecar/health-check.d.ts +2 -0
  166. package/dist/services/steward-sidecar/health-check.d.ts.map +1 -0
  167. package/dist/services/steward-sidecar/health-check.js +2 -0
  168. package/dist/services/steward-sidecar/health-check.js.map +1 -0
  169. package/dist/services/steward-sidecar/helpers.d.ts +2 -0
  170. package/dist/services/steward-sidecar/helpers.d.ts.map +1 -0
  171. package/dist/services/steward-sidecar/helpers.js +2 -0
  172. package/dist/services/steward-sidecar/helpers.js.map +1 -0
  173. package/dist/services/steward-sidecar/process-management.d.ts +2 -0
  174. package/dist/services/steward-sidecar/process-management.d.ts.map +1 -0
  175. package/dist/services/steward-sidecar/process-management.js +2 -0
  176. package/dist/services/steward-sidecar/process-management.js.map +1 -0
  177. package/dist/services/steward-sidecar/types.d.ts +2 -0
  178. package/dist/services/steward-sidecar/types.d.ts.map +1 -0
  179. package/dist/services/steward-sidecar/types.js +2 -0
  180. package/dist/services/steward-sidecar/types.js.map +1 -0
  181. package/dist/services/steward-sidecar/wallet-setup.d.ts +2 -0
  182. package/dist/services/steward-sidecar/wallet-setup.d.ts.map +1 -0
  183. package/dist/services/steward-sidecar/wallet-setup.js +2 -0
  184. package/dist/services/steward-sidecar/wallet-setup.js.map +1 -0
  185. package/dist/services/steward-sidecar.d.ts +2 -0
  186. package/dist/services/steward-sidecar.d.ts.map +1 -0
  187. package/dist/services/steward-sidecar.js +2 -0
  188. package/dist/services/steward-sidecar.js.map +1 -0
  189. package/dist/services/steward-wallet.d.ts +25 -0
  190. package/dist/services/steward-wallet.d.ts.map +1 -0
  191. package/dist/services/steward-wallet.js +333 -0
  192. package/dist/services/steward-wallet.js.map +1 -0
  193. package/dist/steward-ui-state.d.ts +14 -0
  194. package/dist/steward-ui-state.d.ts.map +1 -0
  195. package/dist/steward-ui-state.js +46 -0
  196. package/dist/steward-ui-state.js.map +1 -0
  197. package/dist/steward-view-bundle.d.ts +3 -0
  198. package/dist/steward-view-bundle.d.ts.map +1 -0
  199. package/dist/steward-view-bundle.js +7 -0
  200. package/dist/steward-view-bundle.js.map +1 -0
  201. package/dist/types/bsc-trade.d.ts +180 -0
  202. package/dist/types/bsc-trade.d.ts.map +1 -0
  203. package/dist/types/bsc-trade.js +1 -0
  204. package/dist/types/bsc-trade.js.map +1 -0
  205. package/dist/types/index.d.ts +3 -0
  206. package/dist/types/index.d.ts.map +1 -0
  207. package/dist/types/index.js +3 -0
  208. package/dist/types/index.js.map +1 -0
  209. package/dist/types/steward.d.ts +83 -0
  210. package/dist/types/steward.d.ts.map +1 -0
  211. package/dist/types/steward.js +1 -0
  212. package/dist/types/steward.js.map +1 -0
  213. package/dist/ui.d.ts +7 -0
  214. package/dist/ui.d.ts.map +1 -0
  215. package/dist/ui.js +7 -0
  216. package/dist/ui.js.map +1 -0
  217. package/dist/views/bundle.js +601 -0
  218. package/dist/views/bundle.js.map +1 -0
  219. package/package.json +8 -8
@@ -0,0 +1,337 @@
1
+ import { logger } from "@elizaos/core";
2
+ import * as ethers from "ethers";
3
+ async function handleWalletBscRoutes(ctx) {
4
+ const {
5
+ req,
6
+ res,
7
+ method,
8
+ pathname,
9
+ url,
10
+ state,
11
+ json,
12
+ error,
13
+ readJsonBody,
14
+ deps
15
+ } = ctx;
16
+ if (method === "POST" && pathname === "/api/wallet/trade/preflight") {
17
+ const body = await readJsonBody(req, res);
18
+ if (!body) return true;
19
+ const addrs = deps.getWalletAddresses();
20
+ const walletRpcReadiness = deps.resolveWalletRpcReadiness(state.config);
21
+ try {
22
+ const result = await deps.buildBscTradePreflight({
23
+ walletAddress: addrs.evmAddress ?? null,
24
+ tokenAddress: body.tokenAddress,
25
+ rpcUrls: walletRpcReadiness.bscRpcUrls,
26
+ cloudManagedAccess: walletRpcReadiness.cloudManagedAccess
27
+ });
28
+ json(res, result);
29
+ } catch (err) {
30
+ logger.error(
31
+ `[api] BSC trade preflight failed: ${err instanceof Error ? err.message : err}`
32
+ );
33
+ error(
34
+ res,
35
+ `Trade preflight failed: ${err instanceof Error ? err.message : "unknown error"}`,
36
+ 500
37
+ );
38
+ }
39
+ return true;
40
+ }
41
+ if (method === "POST" && pathname === "/api/wallet/trade/quote") {
42
+ const body = await readJsonBody(req, res);
43
+ if (!body) return true;
44
+ if (!body.side || !body.tokenAddress || !body.amount) {
45
+ error(res, "side, tokenAddress, and amount are required", 400);
46
+ return true;
47
+ }
48
+ const addrs = deps.getWalletAddresses();
49
+ const walletRpcReadiness = deps.resolveWalletRpcReadiness(state.config);
50
+ try {
51
+ const result = await deps.buildBscTradeQuote({
52
+ walletAddress: addrs.evmAddress ?? null,
53
+ rpcUrls: walletRpcReadiness.bscRpcUrls,
54
+ cloudManagedAccess: walletRpcReadiness.cloudManagedAccess,
55
+ request: {
56
+ side: body.side,
57
+ tokenAddress: body.tokenAddress,
58
+ amount: body.amount,
59
+ slippageBps: body.slippageBps,
60
+ routeProvider: body.routeProvider
61
+ }
62
+ });
63
+ json(res, result);
64
+ } catch (err) {
65
+ logger.error(
66
+ `[api] BSC trade quote failed: ${err instanceof Error ? err.message : err}`
67
+ );
68
+ error(
69
+ res,
70
+ `Trade quote failed: ${err instanceof Error ? err.message : "unknown error"}`,
71
+ 500
72
+ );
73
+ }
74
+ return true;
75
+ }
76
+ if (method === "GET" && pathname === "/api/wallet/trade/tx-status") {
77
+ const hash = url.searchParams.get("hash");
78
+ if (!hash?.trim()) {
79
+ error(res, "hash query parameter is required", 400);
80
+ return true;
81
+ }
82
+ const walletRpcReadiness = deps.resolveWalletRpcReadiness(state.config);
83
+ const rpcUrl = deps.resolvePrimaryBscRpcUrl({
84
+ rpcUrls: walletRpcReadiness.bscRpcUrls,
85
+ cloudManagedAccess: walletRpcReadiness.cloudManagedAccess
86
+ });
87
+ if (!rpcUrl) {
88
+ error(res, "BSC RPC not configured.", 503);
89
+ return true;
90
+ }
91
+ try {
92
+ const provider = new ethers.JsonRpcProvider(rpcUrl);
93
+ const receipt = await provider.getTransactionReceipt(hash);
94
+ let txStatus;
95
+ let blockNumber = null;
96
+ let gasUsed = null;
97
+ let effectiveGasPriceWei = null;
98
+ let confirmations = 0;
99
+ let nonce = null;
100
+ if (!receipt) {
101
+ const tx = await provider.getTransaction(hash);
102
+ txStatus = tx ? "pending" : "not_found";
103
+ if (tx) nonce = tx.nonce;
104
+ } else {
105
+ txStatus = receipt.status === 1 ? "success" : "reverted";
106
+ blockNumber = receipt.blockNumber ?? null;
107
+ gasUsed = receipt.gasUsed?.toString() ?? null;
108
+ effectiveGasPriceWei = receipt.gasPrice?.toString() ?? null;
109
+ const currentBlock = await provider.getBlockNumber();
110
+ confirmations = blockNumber !== null ? Math.max(0, currentBlock - blockNumber) : 0;
111
+ const tx = await provider.getTransaction(hash);
112
+ if (tx) nonce = tx.nonce;
113
+ }
114
+ if (txStatus === "success" || txStatus === "reverted") {
115
+ try {
116
+ deps.updateWalletTradeLedgerEntryStatus(hash, {
117
+ status: txStatus,
118
+ confirmations,
119
+ nonce,
120
+ blockNumber,
121
+ gasUsed,
122
+ effectiveGasPriceWei,
123
+ explorerUrl: `https://bscscan.com/tx/${hash}`
124
+ });
125
+ } catch (ledgerErr) {
126
+ logger.warn(
127
+ `[api] Failed to update trade ledger: ${ledgerErr instanceof Error ? ledgerErr.message : ledgerErr}`
128
+ );
129
+ }
130
+ }
131
+ provider.destroy();
132
+ json(res, {
133
+ ok: true,
134
+ hash,
135
+ status: txStatus,
136
+ explorerUrl: `https://bscscan.com/tx/${hash}`,
137
+ chainId: 56,
138
+ blockNumber,
139
+ confirmations,
140
+ nonce,
141
+ gasUsed,
142
+ effectiveGasPriceWei
143
+ });
144
+ } catch (err) {
145
+ logger.error(
146
+ `[api] BSC tx-status failed: ${err instanceof Error ? err.message : err}`
147
+ );
148
+ error(
149
+ res,
150
+ `TX status check failed: ${err instanceof Error ? err.message : "unknown error"}`,
151
+ 500
152
+ );
153
+ }
154
+ return true;
155
+ }
156
+ if (method === "GET" && pathname === "/api/wallet/trading/profile") {
157
+ const windowParam = url.searchParams.get("window");
158
+ const sourceParam = url.searchParams.get("source");
159
+ const window = windowParam === "7d" || windowParam === "30d" || windowParam === "all" ? windowParam : "30d";
160
+ const source = sourceParam === "agent" || sourceParam === "manual" || sourceParam === "all" ? sourceParam : "all";
161
+ try {
162
+ const profile = deps.loadWalletTradingProfile({ window, source });
163
+ json(res, profile);
164
+ } catch (err) {
165
+ logger.error(
166
+ `[api] Wallet trading profile failed: ${err instanceof Error ? err.message : err}`
167
+ );
168
+ error(
169
+ res,
170
+ `Trading profile fetch failed: ${err instanceof Error ? err.message : "unknown error"}`,
171
+ 500
172
+ );
173
+ }
174
+ return true;
175
+ }
176
+ if (method === "POST" && pathname === "/api/wallet/transfer/execute") {
177
+ const body = await readJsonBody(req, res);
178
+ if (!body) return true;
179
+ if (!body.toAddress?.trim() || !body.amount?.trim() || !body.assetSymbol?.trim()) {
180
+ error(res, "toAddress, amount, and assetSymbol are required", 400);
181
+ return true;
182
+ }
183
+ const tradePermissionMode = deps.resolveTradePermissionMode(state.config);
184
+ const isAgentRequest = deps.isAgentAutomationRequest(req);
185
+ const hasLocalKey = Boolean(process.env.EVM_PRIVATE_KEY?.trim());
186
+ const canExecuteLocally = deps.canUseLocalTradeExecution(
187
+ tradePermissionMode,
188
+ isAgentRequest
189
+ );
190
+ const addrs = deps.getWalletAddresses();
191
+ const walletRpcReadiness = deps.resolveWalletRpcReadiness(state.config);
192
+ let toAddress;
193
+ try {
194
+ toAddress = ethers.getAddress(body.toAddress.trim());
195
+ } catch {
196
+ error(res, "Invalid toAddress \u2014 must be a valid EVM address", 400);
197
+ return true;
198
+ }
199
+ const isBnb = body.assetSymbol.toUpperCase() === "BNB";
200
+ let decimals = 18;
201
+ if (body.tokenAddress) {
202
+ try {
203
+ const tokenContract = new ethers.Contract(
204
+ body.tokenAddress,
205
+ ["function decimals() view returns (uint8)"],
206
+ new ethers.JsonRpcProvider(
207
+ deps.resolvePrimaryBscRpcUrl({
208
+ rpcUrls: walletRpcReadiness.bscRpcUrls,
209
+ cloudManagedAccess: walletRpcReadiness.cloudManagedAccess
210
+ }) ?? "https://bsc-dataseed1.binance.org/"
211
+ )
212
+ );
213
+ decimals = Number(await tokenContract.decimals());
214
+ } catch {
215
+ }
216
+ }
217
+ const unsignedTx = {
218
+ chainId: 56,
219
+ from: addrs.evmAddress ?? null,
220
+ to: isBnb ? toAddress : body.tokenAddress ?? toAddress,
221
+ data: isBnb ? "0x" : (() => {
222
+ const iface = new ethers.Interface([
223
+ "function transfer(address to, uint256 amount) returns (bool)"
224
+ ]);
225
+ return iface.encodeFunctionData("transfer", [
226
+ toAddress,
227
+ ethers.parseUnits(body.amount?.trim(), decimals)
228
+ ]);
229
+ })(),
230
+ valueWei: isBnb ? ethers.parseEther(body.amount.trim()).toString() : "0",
231
+ explorerUrl: "https://bscscan.com",
232
+ assetSymbol: body.assetSymbol,
233
+ amount: body.amount.trim(),
234
+ tokenAddress: body.tokenAddress
235
+ };
236
+ if (!hasLocalKey || !canExecuteLocally || body.confirm !== true) {
237
+ json(res, {
238
+ ok: true,
239
+ mode: hasLocalKey && canExecuteLocally ? "local-key" : "user-sign",
240
+ executed: false,
241
+ requiresUserSignature: true,
242
+ toAddress,
243
+ amount: body.amount.trim(),
244
+ assetSymbol: body.assetSymbol,
245
+ tokenAddress: body.tokenAddress,
246
+ unsignedTx
247
+ });
248
+ return true;
249
+ }
250
+ const rpcUrl = deps.resolvePrimaryBscRpcUrl({
251
+ rpcUrls: walletRpcReadiness.bscRpcUrls,
252
+ cloudManagedAccess: walletRpcReadiness.cloudManagedAccess
253
+ });
254
+ if (!rpcUrl) {
255
+ error(res, "BSC RPC not configured for local execution.", 503);
256
+ return true;
257
+ }
258
+ try {
259
+ const evmKey = process.env.EVM_PRIVATE_KEY ?? "";
260
+ const provider = new ethers.JsonRpcProvider(rpcUrl);
261
+ const wallet = new ethers.Wallet(
262
+ evmKey.startsWith("0x") ? evmKey : `0x${evmKey}`,
263
+ provider
264
+ );
265
+ const txReq = {
266
+ to: unsignedTx.to,
267
+ data: unsignedTx.data,
268
+ value: BigInt(unsignedTx.valueWei),
269
+ chainId: unsignedTx.chainId
270
+ };
271
+ const txResponse = await wallet.sendTransaction(txReq);
272
+ const nonce = txResponse.nonce;
273
+ provider.destroy();
274
+ json(res, {
275
+ ok: true,
276
+ mode: "local-key",
277
+ executed: true,
278
+ requiresUserSignature: false,
279
+ toAddress,
280
+ amount: body.amount.trim(),
281
+ assetSymbol: body.assetSymbol,
282
+ tokenAddress: body.tokenAddress,
283
+ unsignedTx,
284
+ execution: {
285
+ hash: txResponse.hash,
286
+ nonce,
287
+ gasLimit: txResponse.gasLimit?.toString() ?? "0",
288
+ valueWei: unsignedTx.valueWei,
289
+ explorerUrl: `https://bscscan.com/tx/${txResponse.hash}`,
290
+ blockNumber: null,
291
+ status: "pending"
292
+ }
293
+ });
294
+ } catch (err) {
295
+ logger.error(
296
+ `[api] Transfer execute failed: ${err instanceof Error ? err.message : err}`
297
+ );
298
+ error(
299
+ res,
300
+ `Transfer failed: ${err instanceof Error ? err.message : "unknown error"}`,
301
+ 500
302
+ );
303
+ }
304
+ return true;
305
+ }
306
+ if (method === "POST" && pathname === "/api/wallet/production-defaults") {
307
+ const changed = [];
308
+ if (!state.config.features) {
309
+ state.config.features = {};
310
+ }
311
+ const features = state.config.features;
312
+ if (!features.tradePermissionMode) {
313
+ features.tradePermissionMode = "user-sign-only";
314
+ changed.push("tradePermissionMode=user-sign-only");
315
+ }
316
+ if (changed.length > 0) {
317
+ try {
318
+ deps.saveElizaConfig(state.config);
319
+ } catch (err) {
320
+ logger.warn(
321
+ `[api] production-defaults config save failed: ${err instanceof Error ? err.message : err}`
322
+ );
323
+ }
324
+ }
325
+ json(res, {
326
+ ok: true,
327
+ applied: changed,
328
+ tradePermissionMode: deps.resolveTradePermissionMode(state.config)
329
+ });
330
+ return true;
331
+ }
332
+ return false;
333
+ }
334
+ export {
335
+ handleWalletBscRoutes
336
+ };
337
+ //# sourceMappingURL=wallet-bsc-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/api/wallet-bsc-routes.ts"],"sourcesContent":["/**\n * BSC wallet trade routes: preflight, quote, tx-status, trading profile,\n * transfer/execute, and production-defaults.\n *\n * Extracted from server.ts to reduce file size.\n */\n\nimport type http from \"node:http\";\nimport type { ElizaConfig } from \"@elizaos/agent\";\nimport type { ReadJsonBodyOptions } from \"@elizaos/core\";\nimport { logger } from \"@elizaos/core\";\nimport * as ethers from \"ethers\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface WalletBscRouteDeps {\n getWalletAddresses: () => {\n evmAddress: string | null;\n solanaAddress: string | null;\n };\n resolveWalletRpcReadiness: (config: ElizaConfig) => {\n bscRpcUrls: string[];\n cloudManagedAccess: boolean;\n };\n resolvePrimaryBscRpcUrl: (args: {\n rpcUrls: string[];\n cloudManagedAccess: boolean;\n }) => string | null;\n buildBscTradePreflight: (args: {\n walletAddress: string | null;\n tokenAddress?: string;\n rpcUrls: string[];\n cloudManagedAccess: boolean;\n }) => Promise<unknown>;\n buildBscTradeQuote: (args: {\n walletAddress: string | null;\n rpcUrls: string[];\n cloudManagedAccess: boolean;\n request: {\n side: \"buy\" | \"sell\";\n tokenAddress: string;\n amount: string;\n slippageBps?: number;\n routeProvider?: \"auto\" | \"pancakeswap-v2\" | \"0x\";\n };\n }) => Promise<unknown>;\n updateWalletTradeLedgerEntryStatus: (\n hash: string,\n update: unknown,\n ) => unknown;\n loadWalletTradingProfile: (opts: unknown) => unknown;\n resolveTradePermissionMode: (config: ElizaConfig) => unknown;\n isAgentAutomationRequest: (req: http.IncomingMessage) => boolean;\n canUseLocalTradeExecution: (\n mode: unknown,\n isAgentRequest: boolean,\n ) => boolean;\n saveElizaConfig: (config: ElizaConfig) => void;\n}\n\nexport interface WalletBscRouteContext {\n req: http.IncomingMessage;\n res: http.ServerResponse;\n method: string;\n pathname: string;\n url: URL;\n state: { config: ElizaConfig };\n json: (res: http.ServerResponse, data: unknown, status?: number) => void;\n error: (res: http.ServerResponse, message: string, status?: number) => void;\n readJsonBody: <T extends object>(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n options?: ReadJsonBodyOptions,\n ) => Promise<T | null>;\n deps: WalletBscRouteDeps;\n}\n\n// ---------------------------------------------------------------------------\n// Route handler\n// ---------------------------------------------------------------------------\n\nexport async function handleWalletBscRoutes(\n ctx: WalletBscRouteContext,\n): Promise<boolean> {\n const {\n req,\n res,\n method,\n pathname,\n url,\n state,\n json,\n error,\n readJsonBody,\n deps,\n } = ctx;\n\n // ── POST /api/wallet/trade/preflight ───────────────────────────────────\n if (method === \"POST\" && pathname === \"/api/wallet/trade/preflight\") {\n const body = await readJsonBody<{ tokenAddress?: string }>(req, res);\n if (!body) return true;\n\n const addrs = deps.getWalletAddresses();\n const walletRpcReadiness = deps.resolveWalletRpcReadiness(state.config);\n try {\n const result = await deps.buildBscTradePreflight({\n walletAddress: addrs.evmAddress ?? null,\n tokenAddress: body.tokenAddress,\n rpcUrls: walletRpcReadiness.bscRpcUrls,\n cloudManagedAccess: walletRpcReadiness.cloudManagedAccess,\n });\n json(res, result);\n } catch (err) {\n logger.error(\n `[api] BSC trade preflight failed: ${err instanceof Error ? err.message : err}`,\n );\n error(\n res,\n `Trade preflight failed: ${err instanceof Error ? err.message : \"unknown error\"}`,\n 500,\n );\n }\n return true;\n }\n\n // ── POST /api/wallet/trade/quote ────────────────────────────────────────\n if (method === \"POST\" && pathname === \"/api/wallet/trade/quote\") {\n const body = await readJsonBody<{\n side?: string;\n tokenAddress?: string;\n amount?: string;\n slippageBps?: number;\n routeProvider?: \"auto\" | \"pancakeswap-v2\" | \"0x\";\n }>(req, res);\n if (!body) return true;\n\n if (!body.side || !body.tokenAddress || !body.amount) {\n error(res, \"side, tokenAddress, and amount are required\", 400);\n return true;\n }\n\n const addrs = deps.getWalletAddresses();\n const walletRpcReadiness = deps.resolveWalletRpcReadiness(state.config);\n try {\n const result = await deps.buildBscTradeQuote({\n walletAddress: addrs.evmAddress ?? null,\n rpcUrls: walletRpcReadiness.bscRpcUrls,\n cloudManagedAccess: walletRpcReadiness.cloudManagedAccess,\n request: {\n side: body.side as \"buy\" | \"sell\",\n tokenAddress: body.tokenAddress,\n amount: body.amount,\n slippageBps: body.slippageBps,\n routeProvider: body.routeProvider,\n },\n });\n json(res, result);\n } catch (err) {\n logger.error(\n `[api] BSC trade quote failed: ${err instanceof Error ? err.message : err}`,\n );\n error(\n res,\n `Trade quote failed: ${err instanceof Error ? err.message : \"unknown error\"}`,\n 500,\n );\n }\n return true;\n }\n\n // ── GET /api/wallet/trade/tx-status ────────────────────────────────────\n if (method === \"GET\" && pathname === \"/api/wallet/trade/tx-status\") {\n const hash = url.searchParams.get(\"hash\");\n if (!hash?.trim()) {\n error(res, \"hash query parameter is required\", 400);\n return true;\n }\n\n const walletRpcReadiness = deps.resolveWalletRpcReadiness(state.config);\n const rpcUrl = deps.resolvePrimaryBscRpcUrl({\n rpcUrls: walletRpcReadiness.bscRpcUrls,\n cloudManagedAccess: walletRpcReadiness.cloudManagedAccess,\n });\n\n if (!rpcUrl) {\n error(res, \"BSC RPC not configured.\", 503);\n return true;\n }\n\n try {\n const provider = new ethers.JsonRpcProvider(rpcUrl);\n const receipt = await provider.getTransactionReceipt(hash);\n\n let txStatus: \"pending\" | \"success\" | \"reverted\" | \"not_found\";\n let blockNumber: number | null = null;\n let gasUsed: string | null = null;\n let effectiveGasPriceWei: string | null = null;\n let confirmations = 0;\n let nonce: number | null = null;\n\n if (!receipt) {\n const tx = await provider.getTransaction(hash);\n txStatus = tx ? \"pending\" : \"not_found\";\n if (tx) nonce = tx.nonce;\n } else {\n txStatus = receipt.status === 1 ? \"success\" : \"reverted\";\n blockNumber = receipt.blockNumber ?? null;\n gasUsed = receipt.gasUsed?.toString() ?? null;\n effectiveGasPriceWei = receipt.gasPrice?.toString() ?? null;\n const currentBlock = await provider.getBlockNumber();\n confirmations =\n blockNumber !== null ? Math.max(0, currentBlock - blockNumber) : 0;\n const tx = await provider.getTransaction(hash);\n if (tx) nonce = tx.nonce;\n }\n\n if (txStatus === \"success\" || txStatus === \"reverted\") {\n try {\n deps.updateWalletTradeLedgerEntryStatus(hash, {\n status: txStatus,\n confirmations,\n nonce,\n blockNumber,\n gasUsed,\n effectiveGasPriceWei,\n explorerUrl: `https://bscscan.com/tx/${hash}`,\n });\n } catch (ledgerErr) {\n logger.warn(\n `[api] Failed to update trade ledger: ${ledgerErr instanceof Error ? ledgerErr.message : ledgerErr}`,\n );\n }\n }\n\n provider.destroy();\n\n json(res, {\n ok: true,\n hash,\n status: txStatus,\n explorerUrl: `https://bscscan.com/tx/${hash}`,\n chainId: 56,\n blockNumber,\n confirmations,\n nonce,\n gasUsed,\n effectiveGasPriceWei,\n });\n } catch (err) {\n logger.error(\n `[api] BSC tx-status failed: ${err instanceof Error ? err.message : err}`,\n );\n error(\n res,\n `TX status check failed: ${err instanceof Error ? err.message : \"unknown error\"}`,\n 500,\n );\n }\n return true;\n }\n\n // ── GET /api/wallet/trading/profile ────────────────────────────────────\n if (method === \"GET\" && pathname === \"/api/wallet/trading/profile\") {\n const windowParam = url.searchParams.get(\"window\");\n const sourceParam = url.searchParams.get(\"source\");\n\n const window =\n windowParam === \"7d\" || windowParam === \"30d\" || windowParam === \"all\"\n ? windowParam\n : \"30d\";\n const source =\n sourceParam === \"agent\" ||\n sourceParam === \"manual\" ||\n sourceParam === \"all\"\n ? sourceParam\n : \"all\";\n\n try {\n const profile = deps.loadWalletTradingProfile({ window, source });\n json(res, profile);\n } catch (err) {\n logger.error(\n `[api] Wallet trading profile failed: ${err instanceof Error ? err.message : err}`,\n );\n error(\n res,\n `Trading profile fetch failed: ${err instanceof Error ? err.message : \"unknown error\"}`,\n 500,\n );\n }\n return true;\n }\n\n // ── POST /api/wallet/transfer/execute ──────────────────────────────────\n if (method === \"POST\" && pathname === \"/api/wallet/transfer/execute\") {\n const body = await readJsonBody<{\n toAddress?: string;\n amount?: string;\n assetSymbol?: string;\n tokenAddress?: string;\n confirm?: boolean;\n }>(req, res);\n if (!body) return true;\n\n if (\n !body.toAddress?.trim() ||\n !body.amount?.trim() ||\n !body.assetSymbol?.trim()\n ) {\n error(res, \"toAddress, amount, and assetSymbol are required\", 400);\n return true;\n }\n\n const tradePermissionMode = deps.resolveTradePermissionMode(state.config);\n const isAgentRequest = deps.isAgentAutomationRequest(req);\n const hasLocalKey = Boolean(process.env.EVM_PRIVATE_KEY?.trim());\n const canExecuteLocally = deps.canUseLocalTradeExecution(\n tradePermissionMode,\n isAgentRequest,\n );\n const addrs = deps.getWalletAddresses();\n const walletRpcReadiness = deps.resolveWalletRpcReadiness(state.config);\n\n let toAddress: string;\n try {\n toAddress = ethers.getAddress(body.toAddress.trim());\n } catch {\n error(res, \"Invalid toAddress — must be a valid EVM address\", 400);\n return true;\n }\n\n const isBnb = body.assetSymbol.toUpperCase() === \"BNB\";\n\n let decimals = 18;\n if (body.tokenAddress) {\n try {\n const tokenContract = new ethers.Contract(\n body.tokenAddress,\n [\"function decimals() view returns (uint8)\"],\n new ethers.JsonRpcProvider(\n deps.resolvePrimaryBscRpcUrl({\n rpcUrls: walletRpcReadiness.bscRpcUrls,\n cloudManagedAccess: walletRpcReadiness.cloudManagedAccess,\n }) ?? \"https://bsc-dataseed1.binance.org/\",\n ),\n );\n decimals = Number(await tokenContract.decimals());\n } catch {\n // Fallback to 18 if decimals call fails\n }\n }\n\n const unsignedTx = {\n chainId: 56,\n from: addrs.evmAddress ?? null,\n to: isBnb ? toAddress : (body.tokenAddress ?? toAddress),\n data: isBnb\n ? \"0x\"\n : (() => {\n const iface = new ethers.Interface([\n \"function transfer(address to, uint256 amount) returns (bool)\",\n ]);\n return iface.encodeFunctionData(\"transfer\", [\n toAddress,\n ethers.parseUnits(body.amount?.trim(), decimals),\n ]);\n })(),\n valueWei: isBnb ? ethers.parseEther(body.amount.trim()).toString() : \"0\",\n explorerUrl: \"https://bscscan.com\",\n assetSymbol: body.assetSymbol,\n amount: body.amount.trim(),\n tokenAddress: body.tokenAddress,\n };\n\n if (!hasLocalKey || !canExecuteLocally || body.confirm !== true) {\n json(res, {\n ok: true,\n mode: hasLocalKey && canExecuteLocally ? \"local-key\" : \"user-sign\",\n executed: false,\n requiresUserSignature: true,\n toAddress,\n amount: body.amount.trim(),\n assetSymbol: body.assetSymbol,\n tokenAddress: body.tokenAddress,\n unsignedTx,\n });\n return true;\n }\n\n const rpcUrl = deps.resolvePrimaryBscRpcUrl({\n rpcUrls: walletRpcReadiness.bscRpcUrls,\n cloudManagedAccess: walletRpcReadiness.cloudManagedAccess,\n });\n\n if (!rpcUrl) {\n error(res, \"BSC RPC not configured for local execution.\", 503);\n return true;\n }\n\n try {\n const evmKey = process.env.EVM_PRIVATE_KEY ?? \"\";\n const provider = new ethers.JsonRpcProvider(rpcUrl);\n const wallet = new ethers.Wallet(\n evmKey.startsWith(\"0x\") ? evmKey : `0x${evmKey}`,\n provider,\n );\n\n const txReq: ethers.TransactionRequest = {\n to: unsignedTx.to,\n data: unsignedTx.data,\n value: BigInt(unsignedTx.valueWei),\n chainId: unsignedTx.chainId,\n };\n\n const txResponse = await wallet.sendTransaction(txReq);\n const nonce = txResponse.nonce;\n\n provider.destroy();\n\n json(res, {\n ok: true,\n mode: \"local-key\",\n executed: true,\n requiresUserSignature: false,\n toAddress,\n amount: body.amount.trim(),\n assetSymbol: body.assetSymbol,\n tokenAddress: body.tokenAddress,\n unsignedTx,\n execution: {\n hash: txResponse.hash,\n nonce,\n gasLimit: txResponse.gasLimit?.toString() ?? \"0\",\n valueWei: unsignedTx.valueWei,\n explorerUrl: `https://bscscan.com/tx/${txResponse.hash}`,\n blockNumber: null,\n status: \"pending\",\n },\n });\n } catch (err) {\n logger.error(\n `[api] Transfer execute failed: ${err instanceof Error ? err.message : err}`,\n );\n error(\n res,\n `Transfer failed: ${err instanceof Error ? err.message : \"unknown error\"}`,\n 500,\n );\n }\n return true;\n }\n\n // ── POST /api/wallet/production-defaults ───────────────────────────────\n if (method === \"POST\" && pathname === \"/api/wallet/production-defaults\") {\n const changed: string[] = [];\n\n if (!state.config.features) {\n state.config.features = {};\n }\n const features = state.config.features as Record<string, unknown>;\n\n if (!features.tradePermissionMode) {\n features.tradePermissionMode = \"user-sign-only\";\n changed.push(\"tradePermissionMode=user-sign-only\");\n }\n\n if (changed.length > 0) {\n try {\n deps.saveElizaConfig(state.config);\n } catch (err) {\n logger.warn(\n `[api] production-defaults config save failed: ${err instanceof Error ? err.message : err}`,\n );\n }\n }\n\n json(res, {\n ok: true,\n applied: changed,\n tradePermissionMode: deps.resolveTradePermissionMode(state.config),\n });\n return true;\n }\n\n return false;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,2 @@
1
+ export { EVM_PLUGIN_PACKAGE, isPluginLoadedByName, resolvePluginEvmLoaded, resolveWalletAutomationMode, resolveWalletCapabilityStatus, type WalletCapabilityStatus, } from "@elizaos/agent";
2
+ //# sourceMappingURL=wallet-capability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wallet-capability.d.ts","sourceRoot":"","sources":["../../src/api/wallet-capability.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,EACtB,2BAA2B,EAC3B,6BAA6B,EAC7B,KAAK,sBAAsB,GAC5B,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,15 @@
1
+ import {
2
+ EVM_PLUGIN_PACKAGE,
3
+ isPluginLoadedByName,
4
+ resolvePluginEvmLoaded,
5
+ resolveWalletAutomationMode,
6
+ resolveWalletCapabilityStatus
7
+ } from "@elizaos/agent";
8
+ export {
9
+ EVM_PLUGIN_PACKAGE,
10
+ isPluginLoadedByName,
11
+ resolvePluginEvmLoaded,
12
+ resolveWalletAutomationMode,
13
+ resolveWalletCapabilityStatus
14
+ };
15
+ //# sourceMappingURL=wallet-capability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/api/wallet-capability.ts"],"sourcesContent":["export {\n EVM_PLUGIN_PACKAGE,\n isPluginLoadedByName,\n resolvePluginEvmLoaded,\n resolveWalletAutomationMode,\n resolveWalletCapabilityStatus,\n type WalletCapabilityStatus,\n} from \"@elizaos/agent\";\n"],"mappings":"AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;","names":[]}
@@ -0,0 +1,43 @@
1
+ export declare const DEXSCREENER_CHAIN_MAP: Record<number, string>;
2
+ export declare const DEXPAPRIKA_CHAIN_MAP: Record<number, string>;
3
+ /** Wrapped native token addresses for pricing native balances via DEX APIs. */
4
+ export declare const WRAPPED_NATIVE: Record<number, string>;
5
+ export declare const DEX_PRICE_TIMEOUT_MS = 10000;
6
+ export interface DexScreenerPair {
7
+ baseToken?: {
8
+ address?: string;
9
+ };
10
+ priceUsd?: string | null;
11
+ liquidity?: {
12
+ usd?: number;
13
+ };
14
+ info?: {
15
+ imageUrl?: string;
16
+ };
17
+ }
18
+ /** Price + optional logo URL from DEX aggregators. */
19
+ export interface DexTokenMeta {
20
+ price: string;
21
+ logoUrl?: string;
22
+ }
23
+ /**
24
+ * Batch-fetch USD prices from DexScreener.
25
+ * Returns a map of lowercased contract address → price USD string.
26
+ */
27
+ export declare function fetchDexScreenerPrices(chainId: number, addresses: string[]): Promise<Map<string, DexTokenMeta>>;
28
+ /**
29
+ * Fetch individual token prices from DexPaprika as fallback.
30
+ * Only called for addresses that DexScreener couldn't price.
31
+ */
32
+ export declare function fetchDexPaprikaPrices(chainId: number, addresses: string[]): Promise<Map<string, DexTokenMeta>>;
33
+ /**
34
+ * Fetch USD prices for a list of token addresses using DexScreener (primary)
35
+ * with DexPaprika fallback. Returns a map of lowercased address → price string.
36
+ */
37
+ export declare function fetchDexPrices(chainId: number, addresses: string[]): Promise<Map<string, DexTokenMeta>>;
38
+ /**
39
+ * Compute USD value from a formatted balance string and a price string.
40
+ * Returns "0" if either value is invalid.
41
+ */
42
+ export declare function computeValueUsd(balance: string, priceUsd: string): string;
43
+ //# sourceMappingURL=wallet-dex-prices.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wallet-dex-prices.d.ts","sourceRoot":"","sources":["../../src/api/wallet-dex-prices.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAQxD,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAQvD,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAQjD,CAAC;AAEF,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAI3C,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7B,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9B;AAED,sDAAsD;AACtD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAsDpC;AAID;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CA2BpC;AAID;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAgBpC;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWzE"}
@@ -0,0 +1,132 @@
1
+ import { logger } from "@elizaos/core";
2
+ const DEXSCREENER_CHAIN_MAP = {
3
+ 1: "ethereum",
4
+ 56: "bsc",
5
+ 8453: "base",
6
+ 42161: "arbitrum",
7
+ 10: "optimism",
8
+ 137: "polygon",
9
+ 43114: "avalanche"
10
+ };
11
+ const DEXPAPRIKA_CHAIN_MAP = {
12
+ 1: "ethereum",
13
+ 56: "bsc",
14
+ 8453: "base",
15
+ 42161: "arbitrum_one",
16
+ 10: "optimism",
17
+ 137: "polygon_pos",
18
+ 43114: "avalanche"
19
+ };
20
+ const WRAPPED_NATIVE = {
21
+ 1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
22
+ 56: "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
23
+ 8453: "0x4200000000000000000000000000000000000006",
24
+ 42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
25
+ 10: "0x4200000000000000000000000000000000000006",
26
+ 137: "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270",
27
+ 43114: "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7"
28
+ };
29
+ const DEX_PRICE_TIMEOUT_MS = 1e4;
30
+ async function fetchDexScreenerPrices(chainId, addresses) {
31
+ const results = /* @__PURE__ */ new Map();
32
+ const chain = DEXSCREENER_CHAIN_MAP[chainId];
33
+ if (!chain || addresses.length === 0) return results;
34
+ const batches = [];
35
+ for (let i = 0; i < addresses.length; i += 30) {
36
+ batches.push(addresses.slice(i, i + 30));
37
+ }
38
+ await Promise.allSettled(
39
+ batches.map(async (batch) => {
40
+ try {
41
+ const joined = batch.join(",");
42
+ const res = await fetch(
43
+ `https://api.dexscreener.com/tokens/v1/${chain}/${joined}`,
44
+ { signal: AbortSignal.timeout(DEX_PRICE_TIMEOUT_MS) }
45
+ );
46
+ if (!res.ok) return;
47
+ const pairs = await res.json();
48
+ if (!Array.isArray(pairs)) return;
49
+ const best = /* @__PURE__ */ new Map();
50
+ for (const pair of pairs) {
51
+ const addr = pair.baseToken?.address?.toLowerCase();
52
+ if (!addr || !pair.priceUsd) continue;
53
+ const existing = best.get(addr);
54
+ if (!existing || (pair.liquidity?.usd ?? 0) > (existing.liquidity?.usd ?? 0)) {
55
+ best.set(addr, pair);
56
+ }
57
+ }
58
+ for (const [addr, pair] of best) {
59
+ if (pair.priceUsd) {
60
+ const logoUrl = pair.info?.imageUrl?.trim() || void 0;
61
+ results.set(addr, { price: String(pair.priceUsd), logoUrl });
62
+ }
63
+ }
64
+ logger.info(
65
+ `[wallet] DexScreener: ${best.size} prices for chain ${chain}`
66
+ );
67
+ } catch (err) {
68
+ logger.warn(
69
+ `[wallet] DexScreener fetch failed for chain ${chain}: ${String(err)}`
70
+ );
71
+ }
72
+ })
73
+ );
74
+ return results;
75
+ }
76
+ async function fetchDexPaprikaPrices(chainId, addresses) {
77
+ const results = /* @__PURE__ */ new Map();
78
+ const network = DEXPAPRIKA_CHAIN_MAP[chainId];
79
+ if (!network || addresses.length === 0) return results;
80
+ await Promise.allSettled(
81
+ addresses.slice(0, 20).map(async (addr) => {
82
+ try {
83
+ const res = await fetch(
84
+ `https://api.dexpaprika.com/networks/${network}/tokens/${addr}`,
85
+ { signal: AbortSignal.timeout(DEX_PRICE_TIMEOUT_MS) }
86
+ );
87
+ if (!res.ok) return;
88
+ const data = await res.json();
89
+ const price = Number(data.price_usd);
90
+ if (Number.isFinite(price) && price > 0) {
91
+ results.set(addr.toLowerCase(), { price: price.toString() });
92
+ }
93
+ } catch (err) {
94
+ logger.warn(
95
+ `[wallet] DexPaprika fetch failed for ${addr}: ${String(err)}`
96
+ );
97
+ }
98
+ })
99
+ );
100
+ return results;
101
+ }
102
+ async function fetchDexPrices(chainId, addresses) {
103
+ if (addresses.length === 0) return /* @__PURE__ */ new Map();
104
+ const lowerAddresses = addresses.map((a) => a.toLowerCase());
105
+ const results = await fetchDexScreenerPrices(chainId, lowerAddresses);
106
+ const missing = lowerAddresses.filter((a) => !results.has(a));
107
+ if (missing.length > 0) {
108
+ const fallback = await fetchDexPaprikaPrices(chainId, missing);
109
+ for (const [addr, meta] of fallback) {
110
+ results.set(addr, meta);
111
+ }
112
+ }
113
+ return results;
114
+ }
115
+ function computeValueUsd(balance, priceUsd) {
116
+ const bal = Number.parseFloat(balance);
117
+ const price = Number.parseFloat(priceUsd);
118
+ if (!Number.isFinite(bal) || !Number.isFinite(price) || bal <= 0 || price <= 0)
119
+ return "0";
120
+ return (bal * price).toFixed(2);
121
+ }
122
+ export {
123
+ DEXPAPRIKA_CHAIN_MAP,
124
+ DEXSCREENER_CHAIN_MAP,
125
+ DEX_PRICE_TIMEOUT_MS,
126
+ WRAPPED_NATIVE,
127
+ computeValueUsd,
128
+ fetchDexPaprikaPrices,
129
+ fetchDexPrices,
130
+ fetchDexScreenerPrices
131
+ };
132
+ //# sourceMappingURL=wallet-dex-prices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/api/wallet-dex-prices.ts"],"sourcesContent":["/**\n * DEX Price Oracle — DexScreener (primary) + DexPaprika (fallback).\n *\n * Fetches USD token prices from on-chain DEX aggregators.\n * Used by the wallet balance modules to annotate token rows with USD values.\n */\nimport { logger } from \"@elizaos/core\";\n\n// ── Chain ID → DEX API slug mappings ──────────────────────────────────\n\nexport const DEXSCREENER_CHAIN_MAP: Record<number, string> = {\n 1: \"ethereum\",\n 56: \"bsc\",\n 8453: \"base\",\n 42161: \"arbitrum\",\n 10: \"optimism\",\n 137: \"polygon\",\n 43114: \"avalanche\",\n};\n\nexport const DEXPAPRIKA_CHAIN_MAP: Record<number, string> = {\n 1: \"ethereum\",\n 56: \"bsc\",\n 8453: \"base\",\n 42161: \"arbitrum_one\",\n 10: \"optimism\",\n 137: \"polygon_pos\",\n 43114: \"avalanche\",\n};\n\n/** Wrapped native token addresses for pricing native balances via DEX APIs. */\nexport const WRAPPED_NATIVE: Record<number, string> = {\n 1: \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n 56: \"0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c\",\n 8453: \"0x4200000000000000000000000000000000000006\",\n 42161: \"0x82aF49447D8a07e3bd95BD0d56f35241523fBab1\",\n 10: \"0x4200000000000000000000000000000000000006\",\n 137: \"0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270\",\n 43114: \"0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7\",\n};\n\nexport const DEX_PRICE_TIMEOUT_MS = 10_000;\n\n// ── Types ─────────────────────────────────────────────────────────────\n\nexport interface DexScreenerPair {\n baseToken?: { address?: string };\n priceUsd?: string | null;\n liquidity?: { usd?: number };\n info?: { imageUrl?: string };\n}\n\n/** Price + optional logo URL from DEX aggregators. */\nexport interface DexTokenMeta {\n price: string;\n logoUrl?: string;\n}\n\n// ── DexScreener ───────────────────────────────────────────────────────\n\n/**\n * Batch-fetch USD prices from DexScreener.\n * Returns a map of lowercased contract address → price USD string.\n */\nexport async function fetchDexScreenerPrices(\n chainId: number,\n addresses: string[],\n): Promise<Map<string, DexTokenMeta>> {\n const results = new Map<string, DexTokenMeta>();\n const chain = DEXSCREENER_CHAIN_MAP[chainId];\n if (!chain || addresses.length === 0) return results;\n\n // DexScreener supports up to 30 addresses per request.\n const batches: string[][] = [];\n for (let i = 0; i < addresses.length; i += 30) {\n batches.push(addresses.slice(i, i + 30));\n }\n\n await Promise.allSettled(\n batches.map(async (batch) => {\n try {\n const joined = batch.join(\",\");\n const res = await fetch(\n `https://api.dexscreener.com/tokens/v1/${chain}/${joined}`,\n { signal: AbortSignal.timeout(DEX_PRICE_TIMEOUT_MS) },\n );\n if (!res.ok) return;\n const pairs: DexScreenerPair[] = await res.json();\n if (!Array.isArray(pairs)) return;\n\n // Group by base token address; pick the pair with highest liquidity.\n const best = new Map<string, DexScreenerPair>();\n for (const pair of pairs) {\n const addr = pair.baseToken?.address?.toLowerCase();\n if (!addr || !pair.priceUsd) continue;\n const existing = best.get(addr);\n if (\n !existing ||\n (pair.liquidity?.usd ?? 0) > (existing.liquidity?.usd ?? 0)\n ) {\n best.set(addr, pair);\n }\n }\n for (const [addr, pair] of best) {\n if (pair.priceUsd) {\n const logoUrl = pair.info?.imageUrl?.trim() || undefined;\n results.set(addr, { price: String(pair.priceUsd), logoUrl });\n }\n }\n logger.info(\n `[wallet] DexScreener: ${best.size} prices for chain ${chain}`,\n );\n } catch (err) {\n logger.warn(\n `[wallet] DexScreener fetch failed for chain ${chain}: ${String(err)}`,\n );\n }\n }),\n );\n\n return results;\n}\n\n// ── DexPaprika (fallback) ─────────────────────────────────────────────\n\n/**\n * Fetch individual token prices from DexPaprika as fallback.\n * Only called for addresses that DexScreener couldn't price.\n */\nexport async function fetchDexPaprikaPrices(\n chainId: number,\n addresses: string[],\n): Promise<Map<string, DexTokenMeta>> {\n const results = new Map<string, DexTokenMeta>();\n const network = DEXPAPRIKA_CHAIN_MAP[chainId];\n if (!network || addresses.length === 0) return results;\n\n await Promise.allSettled(\n addresses.slice(0, 20).map(async (addr) => {\n try {\n const res = await fetch(\n `https://api.dexpaprika.com/networks/${network}/tokens/${addr}`,\n { signal: AbortSignal.timeout(DEX_PRICE_TIMEOUT_MS) },\n );\n if (!res.ok) return;\n const data: { price_usd?: number | string } = await res.json();\n const price = Number(data.price_usd);\n if (Number.isFinite(price) && price > 0) {\n results.set(addr.toLowerCase(), { price: price.toString() });\n }\n } catch (err) {\n logger.warn(\n `[wallet] DexPaprika fetch failed for ${addr}: ${String(err)}`,\n );\n }\n }),\n );\n\n return results;\n}\n\n// ── Combined price fetcher ────────────────────────────────────────────\n\n/**\n * Fetch USD prices for a list of token addresses using DexScreener (primary)\n * with DexPaprika fallback. Returns a map of lowercased address → price string.\n */\nexport async function fetchDexPrices(\n chainId: number,\n addresses: string[],\n): Promise<Map<string, DexTokenMeta>> {\n if (addresses.length === 0) return new Map();\n\n const lowerAddresses = addresses.map((a) => a.toLowerCase());\n const results = await fetchDexScreenerPrices(chainId, lowerAddresses);\n\n // Fallback to DexPaprika for tokens DexScreener couldn't price.\n const missing = lowerAddresses.filter((a) => !results.has(a));\n if (missing.length > 0) {\n const fallback = await fetchDexPaprikaPrices(chainId, missing);\n for (const [addr, meta] of fallback) {\n results.set(addr, meta);\n }\n }\n\n return results;\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────\n\n/**\n * Compute USD value from a formatted balance string and a price string.\n * Returns \"0\" if either value is invalid.\n */\nexport function computeValueUsd(balance: string, priceUsd: string): string {\n const bal = Number.parseFloat(balance);\n const price = Number.parseFloat(priceUsd);\n if (\n !Number.isFinite(bal) ||\n !Number.isFinite(price) ||\n bal <= 0 ||\n price <= 0\n )\n return \"0\";\n return (bal * price).toFixed(2);\n}\n"],"mappings":"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","names":[]}