@oracle-agent/oracle 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 (169) hide show
  1. package/CONTRIBUTING.md +98 -0
  2. package/LICENSE +202 -0
  3. package/README.md +384 -0
  4. package/SECURITY.md +89 -0
  5. package/SETUP.md +235 -0
  6. package/artifacts/inscription/oracle-was-here-preview.png +0 -0
  7. package/artifacts/inscription/oracle-was-here.svg +1 -0
  8. package/artifacts/specialist-packs/oracle-full-crypto.json +273 -0
  9. package/bin/desk-server.mjs +438 -0
  10. package/bin/oracle-data-mcp.mjs +603 -0
  11. package/bin/oracle-init.mjs +423 -0
  12. package/bin/oracle-public-server.mjs +36 -0
  13. package/bin/oracle-route.mjs +254 -0
  14. package/bin/oracle-scan.mjs +192 -0
  15. package/docs/adding-a-chain.md +229 -0
  16. package/docs/architecture.md +135 -0
  17. package/docs/profiles.md +132 -0
  18. package/examples/add-a-chain.mjs +65 -0
  19. package/examples/research-a-token.mjs +70 -0
  20. package/package.json +90 -0
  21. package/profiles/_template/SOUL.md +47 -0
  22. package/profiles/_template/profile.json +22 -0
  23. package/profiles/bitcoin-agent/SOUL.md +31 -0
  24. package/profiles/bitcoin-agent/profile.json +32 -0
  25. package/profiles/hyperliquid-agent/SOUL.md +34 -0
  26. package/profiles/hyperliquid-agent/profile.json +37 -0
  27. package/profiles/oracle/SOUL.md +65 -0
  28. package/profiles/oracle/profile.json +35 -0
  29. package/profiles/polymarket-agent/SOUL.md +35 -0
  30. package/profiles/polymarket-agent/profile.json +34 -0
  31. package/profiles/profile.schema.json +90 -0
  32. package/profiles/protocol-builder/SOUL.md +50 -0
  33. package/profiles/protocol-builder/profile.json +37 -0
  34. package/profiles/robinhood-agent/SOUL.md +45 -0
  35. package/profiles/robinhood-agent/profile.json +39 -0
  36. package/profiles/solana-agent/SOUL.md +37 -0
  37. package/profiles/solana-agent/profile.json +37 -0
  38. package/profiles/stable-agent/SOUL.md +43 -0
  39. package/profiles/stable-agent/profile.json +37 -0
  40. package/public/oracle-console/app.js +272 -0
  41. package/public/oracle-console/bitcoin-wallets.js +206 -0
  42. package/public/oracle-console/index.html +91 -0
  43. package/public/oracle-console/styles.css +239 -0
  44. package/public/oracle-splash/index.html +931 -0
  45. package/scripts/build-inscription.py +230 -0
  46. package/scripts/check-test-count.mjs +105 -0
  47. package/scripts/e2e-hl-markets.mjs +21 -0
  48. package/scripts/e2e-hl-perps.mjs +48 -0
  49. package/scripts/e2e-hypercore-staking.mjs +128 -0
  50. package/scripts/e2e-solana-bitcoin.mjs +183 -0
  51. package/scripts/public-api-scan.mjs +23 -0
  52. package/scripts/secret-scan.mjs +181 -0
  53. package/scripts/verify-v3-venues.mjs +192 -0
  54. package/skills/oracle-best-execution/SKILL.md +127 -0
  55. package/skills/oracle-bitcoin/SKILL.md +53 -0
  56. package/skills/oracle-chain-graphs-telegram-cards/SKILL.md +59 -0
  57. package/skills/oracle-circuit-breaker/SKILL.md +51 -0
  58. package/skills/oracle-contract-research/SKILL.md +55 -0
  59. package/skills/oracle-desk/SKILL.md +58 -0
  60. package/skills/oracle-dex-launch/SKILL.md +38 -0
  61. package/skills/oracle-grants/SKILL.md +69 -0
  62. package/skills/oracle-hypercore-staking/SKILL.md +57 -0
  63. package/skills/oracle-hyperliquid/SKILL.md +56 -0
  64. package/skills/oracle-meme-token-sniper/SKILL.md +73 -0
  65. package/skills/oracle-nft-gacha-launch/SKILL.md +48 -0
  66. package/skills/oracle-nft-mint-gas-war/SKILL.md +63 -0
  67. package/skills/oracle-polymarket/SKILL.md +60 -0
  68. package/skills/oracle-protocol-builder/SKILL.md +38 -0
  69. package/skills/oracle-protocol-security/SKILL.md +60 -0
  70. package/skills/oracle-public-product/SKILL.md +44 -0
  71. package/skills/oracle-receipts/SKILL.md +52 -0
  72. package/skills/oracle-rfq-tokenized-assets/SKILL.md +69 -0
  73. package/skills/oracle-smart-wallet-scanner/SKILL.md +49 -0
  74. package/skills/oracle-solana/SKILL.md +65 -0
  75. package/skills/oracle-solana-nft/SKILL.md +54 -0
  76. package/skills/oracle-token-research/SKILL.md +67 -0
  77. package/src/agent-auth.mjs +191 -0
  78. package/src/approval-guard.mjs +282 -0
  79. package/src/attestation-secret.mjs +88 -0
  80. package/src/audit-log.mjs +196 -0
  81. package/src/auto-slippage.mjs +378 -0
  82. package/src/capability-posture.mjs +125 -0
  83. package/src/chains.mjs +62 -0
  84. package/src/data/catalog.mjs +495 -0
  85. package/src/data/desk-data.mjs +623 -0
  86. package/src/data/http.mjs +200 -0
  87. package/src/data/provider-endpoint.mjs +94 -0
  88. package/src/data/providers/aerodrome.mjs +244 -0
  89. package/src/data/providers/balancer.mjs +208 -0
  90. package/src/data/providers/bitcoin-esplora.mjs +230 -0
  91. package/src/data/providers/bitcoin-meta.mjs +378 -0
  92. package/src/data/providers/blockscout.mjs +14 -0
  93. package/src/data/providers/bridges.mjs +241 -0
  94. package/src/data/providers/cowswap.mjs +501 -0
  95. package/src/data/providers/curve.mjs +200 -0
  96. package/src/data/providers/defillama.mjs +88 -0
  97. package/src/data/providers/dexscreener.mjs +43 -0
  98. package/src/data/providers/evm-rpc.mjs +203 -0
  99. package/src/data/providers/geckoterminal.mjs +34 -0
  100. package/src/data/providers/gmx.mjs +495 -0
  101. package/src/data/providers/hl-info.mjs +102 -0
  102. package/src/data/providers/hl-markets.mjs +210 -0
  103. package/src/data/providers/hl-perps.mjs +382 -0
  104. package/src/data/providers/hl-staking.mjs +352 -0
  105. package/src/data/providers/hl-ws.mjs +119 -0
  106. package/src/data/providers/hyperevm-dex.mjs +49 -0
  107. package/src/data/providers/jupiter.mjs +182 -0
  108. package/src/data/providers/lifi.mjs +150 -0
  109. package/src/data/providers/magiceden-sol.mjs +355 -0
  110. package/src/data/providers/morpho.mjs +173 -0
  111. package/src/data/providers/odos.mjs +155 -0
  112. package/src/data/providers/oneinch.mjs +173 -0
  113. package/src/data/providers/opensea-multichain.mjs +136 -0
  114. package/src/data/providers/opensea-nft.mjs +99 -0
  115. package/src/data/providers/paraswap.mjs +117 -0
  116. package/src/data/providers/pendle.mjs +187 -0
  117. package/src/data/providers/poly-public.mjs +96 -0
  118. package/src/data/providers/poly-ws.mjs +103 -0
  119. package/src/data/providers/rh-agent.mjs +59 -0
  120. package/src/data/providers/satflow.mjs +336 -0
  121. package/src/data/providers/solana-rpc.mjs +186 -0
  122. package/src/data/providers/uniswap-v3.mjs +303 -0
  123. package/src/data/providers/zerox.mjs +166 -0
  124. package/src/data/public-api-scan.mjs +61 -0
  125. package/src/data/quote-placeholder.mjs +31 -0
  126. package/src/exact-integer.mjs +72 -0
  127. package/src/exec-policy.mjs +444 -0
  128. package/src/flags.mjs +15 -0
  129. package/src/fresh-window.mjs +76 -0
  130. package/src/gmx-attestation.mjs +175 -0
  131. package/src/index.mjs +50 -0
  132. package/src/nft-gas-war-guard.mjs +139 -0
  133. package/src/onboarding/agent-keys.mjs +157 -0
  134. package/src/onboarding/index.mjs +18 -0
  135. package/src/onboarding/tiers.mjs +139 -0
  136. package/src/oracle-env.mjs +38 -0
  137. package/src/protocol-execution.mjs +84 -0
  138. package/src/public-api/buzz-integration.mjs +256 -0
  139. package/src/public-api/connect-agent.mjs +397 -0
  140. package/src/public-api/grants.mjs +142 -0
  141. package/src/public-api/http.mjs +374 -0
  142. package/src/public-control/aa-adapter.mjs +402 -0
  143. package/src/public-control/build-registry.mjs +227 -0
  144. package/src/public-control/bundler-client.mjs +372 -0
  145. package/src/public-control/grant-indexer.mjs +296 -0
  146. package/src/public-control/policy-render.mjs +69 -0
  147. package/src/public-control/policy-schema.mjs +318 -0
  148. package/src/public-control/runtime-config.mjs +265 -0
  149. package/src/public-control/session-key-model.mjs +374 -0
  150. package/src/public-control/session-orchestrator.mjs +412 -0
  151. package/src/route-attestation.mjs +132 -0
  152. package/src/router/best-execution.mjs +221 -0
  153. package/src/router/index.mjs +185 -0
  154. package/src/router/prepare-bridge.mjs +288 -0
  155. package/src/router/prepare-route.mjs +341 -0
  156. package/src/router/proposal.mjs +311 -0
  157. package/src/router/risk-classifier.mjs +119 -0
  158. package/src/router/route-sources.mjs +292 -0
  159. package/src/scanner/chains.config.mjs +381 -0
  160. package/src/scanner/contract.mjs +270 -0
  161. package/src/scanner/evm-scanner.mjs +394 -0
  162. package/src/scanner/index.mjs +9 -0
  163. package/src/scanner/v2-venue.mjs +335 -0
  164. package/src/scanner/v3-venue.mjs +290 -0
  165. package/src/scopes.mjs +44 -0
  166. package/src/sell-simulation.mjs +167 -0
  167. package/src/token-transfer-guard.mjs +188 -0
  168. package/src/vault-attestation.mjs +145 -0
  169. package/src/venues.mjs +206 -0
@@ -0,0 +1,623 @@
1
+ // desk.data — unified read-only facade. Never touches wallet keys.
2
+
3
+ import { listProviders, getProvider } from "./catalog.mjs";
4
+ import { timed, mapLimit } from "./http.mjs";
5
+ import * as hl from "./providers/hl-info.mjs";
6
+ import * as poly from "./providers/poly-public.mjs";
7
+ import * as rh from "./providers/rh-agent.mjs";
8
+ import * as rpc from "./providers/evm-rpc.mjs";
9
+ import * as solana from "./providers/solana-rpc.mjs";
10
+ import * as bitcoin from "./providers/bitcoin-esplora.mjs";
11
+ import * as bitcoinMeta from "./providers/bitcoin-meta.mjs";
12
+ import * as satflow from "./providers/satflow.mjs";
13
+ import * as jupiter from "./providers/jupiter.mjs";
14
+ import * as llama from "./providers/defillama.mjs";
15
+ import * as lifi from "./providers/lifi.mjs";
16
+ import * as dxs from "./providers/dexscreener.mjs";
17
+ import * as uni from "./providers/uniswap-v3.mjs";
18
+ import * as aerodrome from "./providers/aerodrome.mjs";
19
+ import * as zerox from "./providers/zerox.mjs";
20
+ import * as bridges from "./providers/bridges.mjs";
21
+ import * as cow from "./providers/cowswap.mjs";
22
+ import * as oneinch from "./providers/oneinch.mjs";
23
+ import * as hlws from "./providers/hl-ws.mjs";
24
+ import * as polyws from "./providers/poly-ws.mjs";
25
+ import * as osnft from "./providers/opensea-nft.mjs";
26
+ import * as hevm from "./providers/hyperevm-dex.mjs";
27
+ import * as mesol from "./providers/magiceden-sol.mjs";
28
+ import * as hlstake from "./providers/hl-staking.mjs";
29
+ import * as hlmarkets from "./providers/hl-markets.mjs";
30
+ import * as hlperps from "./providers/hl-perps.mjs";
31
+ import * as gecko from "./providers/geckoterminal.mjs";
32
+ import * as curve from "./providers/curve.mjs";
33
+ import * as gmx from "./providers/gmx.mjs";
34
+ import * as morpho from "./providers/morpho.mjs";
35
+ import * as balancer from "./providers/balancer.mjs";
36
+ import * as pendle from "./providers/pendle.mjs";
37
+ import * as odos from "./providers/odos.mjs";
38
+ import * as blockscout from "./providers/blockscout.mjs";
39
+ import * as paraswap from "./providers/paraswap.mjs";
40
+
41
+ const OPS = {
42
+ "hl-info": {
43
+ health: (o) => hl.hlHealth(o),
44
+ allMids: (o) => hl.hlAllMids(o),
45
+ l2Book: (o, a = {}) => hl.hlL2Book(a.coin, o),
46
+ outcomeMeta: (o) => hl.hlOutcomeMeta(o),
47
+ clearinghouse: (o, a = {}) => hl.hlClearinghouse(a.user, o),
48
+ userFills: (o, a = {}) => hl.hlUserFills(a.user, o),
49
+ meta: (o) => hl.hlMeta(o),
50
+ metaAndAssetCtxs: (o) => hl.hlMetaAndAssetCtxs(o),
51
+ candleSnapshot: (o, a = {}) => hl.hlCandleSnapshot(a, o),
52
+ openOrders: (o, a = {}) => hl.hlOpenOrders(a.user, o),
53
+ frontendOpenOrders: (o, a = {}) => hl.hlFrontendOpenOrders(a.user, o),
54
+ userState: (o, a = {}) => hl.hlUserState(a.user, o),
55
+ spotMeta: (o) => hl.hlSpotMeta(o),
56
+ },
57
+ "poly-public": {
58
+ health: (o) => poly.polyHealth(o),
59
+ time: (o) => poly.polyTime(o),
60
+ markets: (o, a = {}) => poly.polyMarkets(a, o),
61
+ book: (o, a = {}) => poly.polyBook(a.tokenId, o),
62
+ midpoint: (o, a = {}) => poly.polyMidpoint(a.tokenId, o),
63
+ spread: (o, a = {}) => poly.polySpread(a.tokenId, o),
64
+ price: (o, a = {}) => poly.polyPrice(a.tokenId, { side: a.side }, o),
65
+ events: (o, a = {}) => poly.polyEvents(a, o),
66
+ },
67
+ "rh-agent": {
68
+ health: (o) => rh.rhHealth(o),
69
+ policy: (o) => rh.rhPolicy(o),
70
+ chainConfig: (o) => rh.rhChainConfig(o),
71
+ chainGas: (o) => rh.rhChainGas(o),
72
+ swapsConfig: (o) => rh.rhSwapsConfig(o),
73
+ swapsPresets: (o) => rh.rhSwapsPresets(o),
74
+ tradingStatus: (o) => rh.rhTradingStatus(o),
75
+ nftDrops: (o) => rh.rhNftDrops(o),
76
+ feeEstimate: (o) => rh.rhFeeEstimate(o),
77
+ },
78
+ "evm-rpc": {
79
+ health: (o, a = {}) => rpc.rpcHealth(a.chainId ?? 1, o),
80
+ healthAll: (o, a = {}) => rpc.rpcHealthAll({ ...o, chainIds: a.chainIds }),
81
+ blockNumber: (o, a = {}) => rpc.rpcBlockNumber(a.chainId ?? 1, o),
82
+ chainId: (o, a = {}) => rpc.rpcChainId(a.chainId ?? 1, o),
83
+ getBalance: (o, a = {}) => rpc.rpcGetBalance(a.chainId ?? 1, a.address, o),
84
+ call: (o, a = {}) => rpc.rpcCall(a.chainId ?? 1, a.method, a.params || [], o),
85
+ erc20Allowance: (o, a = {}) => rpc.erc20Allowance(a, o),
86
+ erc20Balance: (o, a = {}) => rpc.erc20BalanceOf(a, o),
87
+ transactionReceipt: (o, a = {}) => rpc.transactionReceipt(a, o),
88
+ },
89
+ "solana-rpc": {
90
+ health: (o) => solana.solanaHealth(o),
91
+ latestBlockhash: (o, a = {}) => solana.solanaLatestBlockhash(a, o),
92
+ getBalance: (o, a = {}) => solana.solanaGetBalance(a, o),
93
+ tokenAccounts: (o, a = {}) => solana.solanaTokenAccounts(a, o),
94
+ simulate: (o, a = {}) => solana.solanaSimulateTransaction(a, o),
95
+ },
96
+ "bitcoin-esplora": {
97
+ health: (o) => bitcoin.btcHealth(o),
98
+ tipHeight: (o) => bitcoin.btcTipHeight(o),
99
+ fees: (o) => bitcoin.btcFees(o),
100
+ address: (o, a = {}) => bitcoin.btcAddressInfo(a, o),
101
+ utxos: (o, a = {}) => bitcoin.btcUtxos(a, o),
102
+ tx: (o, a = {}) => bitcoin.btcTx(a, o),
103
+ decode: (o, a = {}) => bitcoin.btcDecodeTxHex(a, o),
104
+ },
105
+ "bitcoin-meta": {
106
+ health: (o) => bitcoinMeta.btcMetaHealth(o),
107
+ runeBalances: (o, a = {}) => bitcoinMeta.btcRuneBalances(a, o),
108
+ inscriptions: (o, a = {}) => bitcoinMeta.btcInscriptions(a, o),
109
+ inscriptionInfo: (o, a = {}) => bitcoinMeta.btcInscriptionInfo(a, o),
110
+ inscriptionChildren: (o, a = {}) => bitcoinMeta.btcInscriptionChildren(a, o),
111
+ ordBlockInfo: (o, a = {}) => bitcoinMeta.btcOrdBlockInfo(a, o),
112
+ },
113
+ satflow: {
114
+ health: (o) => satflow.satflowHealth(o),
115
+ collectionFloors: (o, a = {}) => satflow.satflowCollectionFloors(a, o),
116
+ collectionStats: (o, a = {}) => satflow.satflowCollectionStats(a, o),
117
+ item: (o, a = {}) => satflow.satflowItem(a, o),
118
+ walletContents: (o, a = {}) => satflow.satflowWalletContents(a, o),
119
+ floorListings: (o, a = {}) => satflow.satflowFloorListings(a, o),
120
+ preparePurchase: (o, a = {}) => satflow.satflowPreparePurchase(a, o),
121
+ prepareList: (o, a = {}) => satflow.satflowPrepareList(a, o),
122
+ },
123
+ jupiter: {
124
+ health: (o) => jupiter.jupiterHealth(o),
125
+ quote: (o, a = {}) => jupiter.jupiterQuote(a, o),
126
+ prepare: (o, a = {}) => jupiter.jupiterPrepareSwap(a, o),
127
+ },
128
+ defillama: {
129
+ health: (o) => llama.llamaHealth(o),
130
+ prices: (o, a = {}) => llama.llamaPrices(a.coins || [], o),
131
+ pricesBySymbol: (o, a = {}) => llama.llamaPricesBySymbol(a.symbols, o),
132
+ protocols: (o) => llama.llamaProtocols(o),
133
+ yields: (o, a = {}) => llama.llamaYields(a, o),
134
+ stablecoins: (o, a = {}) => llama.llamaStablecoins(a, o),
135
+ dexVolumes: (o, a = {}) => llama.llamaDexVolumes(a, o),
136
+ },
137
+ lifi: {
138
+ health: (o) => lifi.lifiHealth(o),
139
+ quote: (o, a = {}) => lifi.lifiQuote(a, o),
140
+ prepare: (o, a = {}) => lifi.lifiPrepare(a, o),
141
+ chains: (o) => lifi.lifiChains(o),
142
+ },
143
+ dexscreener: {
144
+ health: (o) => dxs.dexscreenerHealth(o),
145
+ token: (o, a = {}) => dxs.dexscreenerToken(a.address || a.tokenAddress, o),
146
+ search: (o, a = {}) => dxs.dexscreenerSearch(a.q || a.query, o),
147
+ pair: (o, a = {}) => dxs.dexscreenerPair(a.chainId, a.pairAddress, o),
148
+ },
149
+ "uniswap-v3": {
150
+ health: (o, a = {}) => uni.uniV3Health({ ...o, chainId: a.chainId ?? 8453 }),
151
+ quote: (o, a = {}) => uni.uniV3QuoteExactIn(a, o),
152
+ prepare: (o, a = {}) => uni.uniV3PrepareExactIn(a, o),
153
+ quotePath: (o, a = {}) => uni.uniV3QuoteExactInPath(a, o),
154
+ ethUsdc: (o, a = {}) => uni.uniV3EthUsdc(a, o),
155
+ chains: () => uni.uniV3Chains(),
156
+ },
157
+ aerodrome: {
158
+ health: (o, a = {}) => aerodrome.aerodromeHealth({ ...o, chainId: a.chainId ?? 8453 }),
159
+ quote: (o, a = {}) => aerodrome.aerodromeQuoteExactIn(a, o),
160
+ prepare: (o, a = {}) => aerodrome.aerodromePrepareExactIn(a, o),
161
+ chains: () => aerodrome.aerodromeChains(),
162
+ },
163
+ zerox: {
164
+ health: (o) => zerox.zeroxHealth(o),
165
+ price: (o, a = {}) => zerox.zeroxPrice(a, o),
166
+ quote: (o, a = {}) => zerox.zeroxQuote(a, o),
167
+ prepare: (o, a = {}) => zerox.zeroxPrepare(a, o),
168
+ },
169
+ across: {
170
+ health: (o) => bridges.acrossHealth(o),
171
+ suggestedFees: (o, a = {}) => bridges.acrossSuggestedFees(a, o),
172
+ },
173
+ hop: {
174
+ health: (o) => bridges.hopHealth(o),
175
+ quote: (o, a = {}) => bridges.hopQuote(a, o),
176
+ },
177
+ relay: {
178
+ health: (o) => bridges.relayHealth(o),
179
+ quote: (o, a = {}) => bridges.relayQuote(a, o),
180
+ prepare: (o, a = {}) => bridges.relayPrepare(a, o),
181
+ },
182
+ cowswap: {
183
+ health: (o) => cow.cowHealth(o),
184
+ quote: (o, a = {}) => cow.cowQuote(a, o),
185
+ prepareOrder: (o, a = {}) => cow.cowPrepareOrder(a, o),
186
+ order: (o, a = {}) => cow.cowOrder(a, o),
187
+ status: (o, a = {}) => cow.cowOrderStatus(a, o),
188
+ chains: () => cow.cowChains(),
189
+ },
190
+ oneinch: {
191
+ health: (o) => oneinch.oneinchHealth(o),
192
+ quote: (o, a = {}) => oneinch.oneinchQuote(a, o),
193
+ prepare: (o, a = {}) => oneinch.oneinchPrepare(a, o),
194
+ approveSpender: (o, a = {}) => oneinch.oneinchApproveSpender(a, o),
195
+ },
196
+ "hl-ws": {
197
+ health: (o) => hlws.hlWsHealth(o),
198
+ allMids: (o) => hlws.hlWsAllMids(o),
199
+ l2Book: (o, a = {}) => hlws.hlWsL2Book(a.coin, o),
200
+ snapshot: (o, a = {}) => hlws.hlWsSnapshot(a.subscription || a, o),
201
+ },
202
+ "poly-ws": {
203
+ health: (o, a = {}) => polyws.polyWsHealth({ ...o, assetId: a.assetId }),
204
+ book: (o, a = {}) => polyws.polyWsBook(a.assetId || a.tokenId, o),
205
+ snapshot: (o, a = {}) =>
206
+ polyws.polyWsSnapshot(a.assetIds || a.assets_ids || [a.assetId], o),
207
+ },
208
+ "opensea-nft": {
209
+ health: (o) => osnft.openseaHealth(o),
210
+ collection: (o, a = {}) => osnft.openseaCollection(a.slug, o),
211
+ floor: (o, a = {}) => osnft.openseaFloor(a.slug, o),
212
+ },
213
+
214
+ "hl-perps": {
215
+ health: (o) => hlmarkets.hlMarketsHealth(o),
216
+ assetInfo: (o, a = {}) => hlperps.hlPerpAssetInfo(a, o),
217
+ prepareOrder: (o, a = {}) => hlperps.hlPreparePerpOrder(a, o),
218
+ prepareCancel: (o, a = {}) => hlperps.hlPrepareCancelOrder(a, o),
219
+ prepareLeverage: (o, a = {}) => hlperps.hlPrepareUpdateLeverage(a, o),
220
+ prepareIsolatedMargin: (o, a = {}) => hlperps.hlPrepareUpdateIsolatedMargin(a, o),
221
+ prepareBracket: (o, a = {}) => hlperps.hlPrepareBracketOrder(a, o),
222
+ },
223
+ "hl-markets": {
224
+ health: (o) => hlmarkets.hlMarketsHealth(o),
225
+ markets: (o, a = {}) => hlmarkets.hlMarketDatapoints(a, o),
226
+ leaderboards: (o, a = {}) => hlmarkets.hlLeaderboards(a, o),
227
+ coin: (o, a = {}) => hlmarkets.hlCoinDatapoints(a, o),
228
+ spot: (o, a = {}) => hlmarkets.hlSpotDatapoints(a, o),
229
+ },
230
+ "magiceden-sol": {
231
+ health: (o) => mesol.magicEdenSolHealth(o),
232
+ stats: (o, a = {}) => mesol.magicEdenSolStats(a, o),
233
+ listings: (o, a = {}) => mesol.magicEdenSolListings(a, o),
234
+ tokenListings: (o, a = {}) => mesol.magicEdenSolTokenListing(a, o),
235
+ prepareBuy: (o, a = {}) => mesol.magicEdenSolPrepareBuy(a, o),
236
+ prepareList: (o, a = {}) => mesol.magicEdenSolPrepareList(a, o),
237
+ prepareMint: (o, a = {}) => mesol.magicEdenSolPrepareMint(a, o),
238
+ },
239
+ "hl-staking": {
240
+ health: (o) => hlstake.hlStakingHealth(o),
241
+ validators: (o) => hlstake.hlValidatorSummaries(o),
242
+ delegatorSummary: (o, a = {}) => hlstake.hlDelegatorSummary(a, o),
243
+ delegations: (o, a = {}) => hlstake.hlDelegations(a, o),
244
+ rewards: (o, a = {}) => hlstake.hlDelegatorRewards(a, o),
245
+ history: (o, a = {}) => hlstake.hlDelegatorHistory(a, o),
246
+ preflight: (o, a = {}) => hlstake.hlStakingPreflight(a, o),
247
+ prepareStakeDeposit: (o, a = {}) => hlstake.hlPrepareStakeDeposit(a, o),
248
+ prepareStakeWithdraw: (o, a = {}) => hlstake.hlPrepareStakeWithdraw(a, o),
249
+ prepareDelegate: (o, a = {}) => hlstake.hlPrepareDelegate(a, o),
250
+ },
251
+ "hyperevm-dex": {
252
+ health: (o) => hevm.hyperevmHealth(o),
253
+ search: (o, a = {}) => hevm.hyperevmSearch(a.q || a.query || "HYPE", o),
254
+ token: (o, a = {}) => hevm.hyperevmToken(a.address || a.tokenAddress, o),
255
+ },
256
+ geckoterminal: {
257
+ health: (o) => gecko.geckoHealth(o),
258
+ networks: (o, a = {}) => gecko.geckoNetworks(a, o),
259
+ pool: (o, a = {}) => gecko.geckoPool(a, o),
260
+ token: (o, a = {}) => gecko.geckoToken(a, o),
261
+ ohlcv: (o, a = {}) => gecko.geckoPoolOhlcv(a, o),
262
+ },
263
+ curve: {
264
+ health: (o) => curve.curveHealth(o),
265
+ openapi: (o) => curve.curveOpenApi(o),
266
+ pools: (o, a = {}) => curve.curvePools(a, o),
267
+ quote: (o, a = {}) => curve.curveQuote(a, o),
268
+ prepare: (o, a = {}) => curve.curvePrepare(a, o),
269
+ },
270
+ gmx: {
271
+ health: (o) => gmx.gmxHealth(o),
272
+ tickers: (o, a = {}) => gmx.gmxTickers(a, o),
273
+ markets: (o, a = {}) => gmx.gmxMarkets(a, o),
274
+ marketsInfo: (o, a = {}) => gmx.gmxMarketsInfo(a, o),
275
+ tokens: (o, a = {}) => gmx.gmxTokens(a, o),
276
+ prepareOrder: (o, a = {}) => gmx.gmxPrepareOrder(a, o),
277
+ positions: (o, a = {}) => gmx.gmxPositions(a, o),
278
+ orderStatus: (o, a = {}) => gmx.gmxOrderStatus(a, o),
279
+ verifyOrder: (o, a = {}) => gmx.gmxVerifyOrderReceipt(a, o),
280
+ },
281
+ morpho: {
282
+ health: (o) => morpho.morphoHealth(o),
283
+ markets: (o, a = {}) => morpho.morphoMarkets(a, o),
284
+ vaults: (o, a = {}) => morpho.morphoVaults(a, o),
285
+ prepareVault: (o, a = {}) => morpho.morphoPrepareVault(a, o),
286
+ },
287
+ balancer: {
288
+ health: (o) => balancer.balancerHealth(o),
289
+ pools: (o, a = {}) => balancer.balancerPools(a, o),
290
+ quote: (o, a = {}) => balancer.balancerQuote(a, o),
291
+ prepare: (o, a = {}) => balancer.balancerPrepare(a, o),
292
+ },
293
+ pendle: {
294
+ health: (o) => pendle.pendleHealth(o),
295
+ markets: (o, a = {}) => pendle.pendleMarkets(a, o),
296
+ quote: (o, a = {}) => pendle.pendleQuote(a, o),
297
+ prepare: (o, a = {}) => pendle.pendlePrepare(a, o),
298
+ },
299
+ odos: {
300
+ health: (o) => odos.odosHealth(o),
301
+ chains: (o) => odos.odosChains(o),
302
+ quote: (o, a = {}) => odos.odosQuote(a, o),
303
+ prepare: (o, a = {}) => odos.odosPrepare(a, o),
304
+ },
305
+ blockscout: {
306
+ health: (o) => blockscout.blockscoutHealth(o),
307
+ stats: (o, a = {}) => blockscout.blockscoutStats(a, o),
308
+ address: (o, a = {}) => blockscout.blockscoutAddress(a, o),
309
+ token: (o, a = {}) => blockscout.blockscoutToken(a, o),
310
+ },
311
+ paraswap: {
312
+ health: (o) => paraswap.paraswapHealth(o),
313
+ tokens: (o, a = {}) => paraswap.paraswapTokens(a, o),
314
+ price: (o, a = {}) => paraswap.paraswapPrice(a, o),
315
+ quote: (o, a = {}) => paraswap.paraswapPrice(a, o),
316
+ prepare: (o, a = {}) => paraswap.paraswapPrepare(a, o),
317
+ },
318
+ };
319
+
320
+ /**
321
+ * Ops that create state at a third-party venue or produce a signable
322
+ * authorization. They are NOT reads, and naming them `prepare*` does not make
323
+ * them harmless — a prepared purchase intent is a real object at a real
324
+ * marketplace, and a prepared EIP-712 action is one signature from settlement.
325
+ */
326
+ const STATE_CREATING_OPS = new Set([
327
+ "prepareBracket",
328
+ "prepareIsolatedMargin",
329
+ "prepareLeverage",
330
+ "prepareCancel",
331
+ "prepareOrder",
332
+ "preparePurchase",
333
+ "prepareList",
334
+ "prepareSell",
335
+ "prepareBuy",
336
+ "prepareMint",
337
+ "prepare",
338
+ "prepareStakeDeposit",
339
+ "prepareStakeWithdraw",
340
+ "prepareDelegate",
341
+ "prepareSwap",
342
+ "prepareTransfer",
343
+ "createOrder",
344
+ "cancelOrder",
345
+ ]);
346
+
347
+ /**
348
+ * Is this op allowed on the read/prepare data plane?
349
+ *
350
+ * The previous implementation was a NAME regex, which is not a boundary: it
351
+ * blocked `sendFoo` but allowed `txBroadcast`, `doSend`, `rawSign`,
352
+ * `orderSubmit` and `forceExecute`, while blocking nothing that actually
353
+ * mattered because every money-moving op here is named `prepare*`. The real
354
+ * control is the catalog: a provider may only be asked for an op it declares.
355
+ */
356
+ /**
357
+ * Providers that SIGN and SUBMIT. These are not data-plane providers: the
358
+ * read-only server must refuse them at the provider level, because a name-based
359
+ * verb filter is not a boundary (`op:"trade"` matches no exec-sounding word).
360
+ */
361
+ export const EXECUTION_PROVIDERS = new Set(["hl-exec"]);
362
+
363
+ /** True when the provider signs/submits and must never be served read-only. */
364
+ export function isExecutionProvider(providerId) {
365
+ return EXECUTION_PROVIDERS.has(String(providerId || ""));
366
+ }
367
+
368
+ export function assertDataOpAllowed(providerId, op, args = {}) {
369
+ const name = String(op || "");
370
+ const key = `${providerId}.${name}`;
371
+
372
+ if (EXECUTION_PROVIDERS.has(providerId)) {
373
+ throw new Error(`data plane forbidden execution provider: ${providerId}`);
374
+ }
375
+
376
+ // 1. The op must be declared by the provider. This is the actual boundary —
377
+ // an undeclared op cannot be reached regardless of what it is called.
378
+ // Checked SECOND so that a write-shaped name gets the "forbidden" error
379
+ // rather than "not declared": callers (and tests) distinguish the two.
380
+ const declared = listProviders().find((p) => p.id === providerId);
381
+
382
+ // 2. Reject anything that reads as a settlement verb. Substring matching, so
383
+ // txBroadcast / doSend / orderSubmit / forceExecute cannot slip past word
384
+ // boundaries the way they did under the old anchored regex.
385
+ if (/sign|execute|broadcast|submit|send|write|place/i.test(name) && !STATE_CREATING_OPS.has(name)) {
386
+ throw new Error(`data plane forbidden op: ${key}`);
387
+ }
388
+
389
+ if (declared && Array.isArray(declared.ops) && declared.ops.length > 0) {
390
+ if (!declared.ops.includes(name)) {
391
+ throw new Error(`data plane: provider ${providerId} does not support op ${name}`);
392
+ }
393
+ }
394
+
395
+ // 3. State-creating prepares are permitted on the data plane (that is its
396
+ // job) but must be visible as such to callers auditing behaviour.
397
+ if (STATE_CREATING_OPS.has(name) && args && typeof args === "object") {
398
+ Object.defineProperty(args, "__oracleStateCreating", { value: true, enumerable: false, configurable: true });
399
+ }
400
+
401
+ if (providerId === "evm-rpc" && name === "call") {
402
+ const method = String(args?.method || "").trim();
403
+ const allowed = new Set([
404
+ "eth_call",
405
+ "eth_getBalance",
406
+ "eth_blockNumber",
407
+ "eth_chainId",
408
+ "eth_getCode",
409
+ "eth_getLogs",
410
+ "eth_getTransactionByHash",
411
+ "eth_getTransactionReceipt",
412
+ "eth_getBlockByNumber",
413
+ "eth_getBlockByHash",
414
+ "eth_feeHistory",
415
+ "eth_gasPrice",
416
+ "eth_maxPriorityFeePerGas",
417
+ "net_version",
418
+ "web3_clientVersion",
419
+ ]);
420
+ if (!allowed.has(method)) {
421
+ throw new Error(`data plane allows only read-only JSON-RPC methods through evm-rpc.call: ${method || "<missing>"}`);
422
+ }
423
+ }
424
+ }
425
+
426
+ export async function dataCall(providerId, op, args = {}, opts = {}) {
427
+ // dataCall is the READ plane, and it is what the package root exports. An
428
+ // execution provider reached through here signs with a real key and submits
429
+ // to a venue — with no grant check, no policy, no cap and no user-intent
430
+ // proof. Blocking it only in the HTTP server left every package consumer and
431
+ // agent wrapper calling root dataCall wide open.
432
+ //
433
+ if (isExecutionProvider(providerId)) {
434
+ throw new Error(
435
+ `${providerId} is an execution provider: it signs and submits with a real key. ` +
436
+ "dataCall() is the public read plane and will not route to it."
437
+ );
438
+ }
439
+ assertDataOpAllowed(providerId, op, args);
440
+ const meta = getProvider(providerId);
441
+ if (!meta) throw new Error(`Unknown data provider: ${providerId}`);
442
+ if (!meta.ops.includes(op)) {
443
+ throw new Error(`Provider ${providerId} does not support op '${op}' (has: ${meta.ops.join(", ")})`);
444
+ }
445
+ const table = OPS[providerId];
446
+ if (!table || typeof table[op] !== "function") {
447
+ throw new Error(`No client implementation for ${providerId}.${op}`);
448
+ }
449
+ return table[op](opts, args);
450
+ }
451
+
452
+ export async function dataHealth({ providers, fetchImpl, timeoutMs, includeRpc, includeWs, concurrency } = {}) {
453
+ let ids = providers || listProviders().map((p) => p.id);
454
+ // healthAll on evm-rpc is slow; default health uses ethereum only via "health"
455
+ if (!includeRpc && !providers) {
456
+ // keep evm-rpc but its health is chain 1 only — fine
457
+ }
458
+ // WS health opens sockets — opt-in unless explicit provider list
459
+ if (!includeWs && !providers) {
460
+ ids = ids.filter((id) => id !== "hl-ws" && id !== "poly-ws");
461
+ }
462
+ const opts = { fetchImpl, timeoutMs: timeoutMs ?? 8_000 };
463
+ const out = {};
464
+ // Bounded fan-out: an unbounded Promise.all across every provider trips public
465
+ // rate limits (and makes one slow venue look like a global outage).
466
+ await mapLimit(ids, concurrency ?? 8, async (id) => {
467
+ if (!getProvider(id)) {
468
+ out[id] = { ok: false, ms: 0, error: "unknown provider" };
469
+ return;
470
+ }
471
+ const args = id === "evm-rpc" ? { chainId: 1 } : {};
472
+ const result = await timed(() => dataCall(id, "health", args, opts));
473
+ out[id] = result.ok
474
+ ? { ok: true, ms: result.ms, detail: result.data }
475
+ : { ok: false, ms: result.ms, error: result.error };
476
+ });
477
+ return { when: new Date().toISOString(), plane: "data", exec: false, providers: out };
478
+ }
479
+
480
+ export function dataCatalog() {
481
+ return listProviders().map((p) => ({
482
+ id: p.id,
483
+ venue: p.venue,
484
+ chainIds: p.chainIds,
485
+ auth: p.auth,
486
+ ops: p.ops,
487
+ execution: p.execution || "read-only",
488
+ description: p.description,
489
+ }));
490
+ }
491
+
492
+ export const data = {
493
+ catalog: dataCatalog,
494
+ health: dataHealth,
495
+ call: dataCall,
496
+ hl: {
497
+ health: (o) => dataCall("hl-info", "health", {}, o),
498
+ allMids: (o) => dataCall("hl-info", "allMids", {}, o),
499
+ l2Book: (coin, o) => dataCall("hl-info", "l2Book", { coin }, o),
500
+ outcomeMeta: (o) => dataCall("hl-info", "outcomeMeta", {}, o),
501
+ clearinghouse: (user, o) => dataCall("hl-info", "clearinghouse", { user }, o),
502
+ userFills: (user, o) => dataCall("hl-info", "userFills", { user }, o),
503
+ meta: (o) => dataCall("hl-info", "meta", {}, o),
504
+ metaAndAssetCtxs: (o) => dataCall("hl-info", "metaAndAssetCtxs", {}, o),
505
+ candleSnapshot: (a, o) => dataCall("hl-info", "candleSnapshot", a || {}, o),
506
+ openOrders: (user, o) => dataCall("hl-info", "openOrders", { user }, o),
507
+ userState: (user, o) => dataCall("hl-info", "userState", { user }, o),
508
+ spotMeta: (o) => dataCall("hl-info", "spotMeta", {}, o),
509
+ staking: {
510
+ health: (o) => dataCall("hl-staking", "health", {}, o),
511
+ validators: (o) => dataCall("hl-staking", "validators", {}, o),
512
+ summary: (user, o) => dataCall("hl-staking", "delegatorSummary", { user }, o),
513
+ delegations: (user, o) => dataCall("hl-staking", "delegations", { user }, o),
514
+ rewards: (user, o) => dataCall("hl-staking", "rewards", { user }, o),
515
+ history: (user, o) => dataCall("hl-staking", "history", { user }, o),
516
+ preflight: (user, o) => dataCall("hl-staking", "preflight", { user }, o),
517
+ prepareStake: (a, o) => dataCall("hl-staking", "prepareStakeDeposit", a || {}, o),
518
+ prepareUnstake: (a, o) => dataCall("hl-staking", "prepareStakeWithdraw", a || {}, o),
519
+ prepareDelegate: (a, o) => dataCall("hl-staking", "prepareDelegate", a || {}, o),
520
+ },
521
+ },
522
+ poly: {
523
+ health: (o) => dataCall("poly-public", "health", {}, o),
524
+ time: (o) => dataCall("poly-public", "time", {}, o),
525
+ markets: (a, o) => dataCall("poly-public", "markets", a || {}, o),
526
+ book: (tokenId, o) => dataCall("poly-public", "book", { tokenId }, o),
527
+ midpoint: (tokenId, o) => dataCall("poly-public", "midpoint", { tokenId }, o),
528
+ spread: (tokenId, o) => dataCall("poly-public", "spread", { tokenId }, o),
529
+ price: (tokenId, side, o) => dataCall("poly-public", "price", { tokenId, side }, o),
530
+ events: (a, o) => dataCall("poly-public", "events", a || {}, o),
531
+ },
532
+ rh: {
533
+ health: (o) => dataCall("rh-agent", "health", {}, o),
534
+ policy: (o) => dataCall("rh-agent", "policy", {}, o),
535
+ chainConfig: (o) => dataCall("rh-agent", "chainConfig", {}, o),
536
+ chainGas: (o) => dataCall("rh-agent", "chainGas", {}, o),
537
+ swapsConfig: (o) => dataCall("rh-agent", "swapsConfig", {}, o),
538
+ tradingStatus: (o) => dataCall("rh-agent", "tradingStatus", {}, o),
539
+ nftDrops: (o) => dataCall("rh-agent", "nftDrops", {}, o),
540
+ },
541
+ rpc: {
542
+ health: (chainId, o) => dataCall("evm-rpc", "health", { chainId }, o),
543
+ healthAll: (a, o) => dataCall("evm-rpc", "healthAll", a || {}, o),
544
+ blockNumber: (chainId, o) => dataCall("evm-rpc", "blockNumber", { chainId }, o),
545
+ getBalance: (chainId, address, o) => dataCall("evm-rpc", "getBalance", { chainId, address }, o),
546
+ call: (chainId, method, params, o) =>
547
+ dataCall("evm-rpc", "call", { chainId, method, params }, o),
548
+ },
549
+ solana: {
550
+ health: (o) => dataCall("solana-rpc", "health", {}, o),
551
+ latestBlockhash: (a, o) => dataCall("solana-rpc", "latestBlockhash", a || {}, o),
552
+ balance: (address, o) => dataCall("solana-rpc", "getBalance", { address }, o),
553
+ tokenAccounts: (a, o) => dataCall("solana-rpc", "tokenAccounts", a || {}, o),
554
+ simulate: (a, o) => dataCall("solana-rpc", "simulate", a || {}, o),
555
+ jupiterQuote: (a, o) => dataCall("jupiter", "quote", a || {}, o),
556
+ jupiterPrepare: (a, o) => dataCall("jupiter", "prepare", a || {}, o),
557
+ nftStats: (a, o) => dataCall("magiceden-sol", "stats", a || {}, o),
558
+ nftListings: (a, o) => dataCall("magiceden-sol", "listings", a || {}, o),
559
+ nftTokenListings: (a, o) => dataCall("magiceden-sol", "tokenListings", a || {}, o),
560
+ nftPrepareBuy: (a, o) => dataCall("magiceden-sol", "prepareBuy", a || {}, o),
561
+ nftPrepareList: (a, o) => dataCall("magiceden-sol", "prepareList", a || {}, o),
562
+ nftPrepareMint: (a, o) => dataCall("magiceden-sol", "prepareMint", a || {}, o),
563
+ },
564
+ bitcoin: {
565
+ health: (o) => dataCall("bitcoin-esplora", "health", {}, o),
566
+ tipHeight: (o) => dataCall("bitcoin-esplora", "tipHeight", {}, o),
567
+ fees: (o) => dataCall("bitcoin-esplora", "fees", {}, o),
568
+ address: (address, o) => dataCall("bitcoin-esplora", "address", { address }, o),
569
+ utxos: (address, o) => dataCall("bitcoin-esplora", "utxos", { address }, o),
570
+ tx: (txid, o) => dataCall("bitcoin-esplora", "tx", { txid }, o),
571
+ decode: (a, o) => dataCall("bitcoin-esplora", "decode", a || {}, o),
572
+ metaHealth: (o) => dataCall("bitcoin-meta", "health", {}, o),
573
+ runeBalances: (address, o) => dataCall("bitcoin-meta", "runeBalances", { address }, o),
574
+ inscriptions: (address, o) => dataCall("bitcoin-meta", "inscriptions", { address }, o),
575
+ satflowHealth: (o) => dataCall("satflow", "health", {}, o),
576
+ satflowFloors: (a, o) => dataCall("satflow", "collectionFloors", a || {}, o),
577
+ satflowWallet: (address, o) => dataCall("satflow", "walletContents", { address }, o),
578
+ },
579
+ prices: {
580
+ health: (o) => dataCall("defillama", "health", {}, o),
581
+ current: (coins, o) => dataCall("defillama", "prices", { coins }, o),
582
+ bySymbol: (symbols, o) => dataCall("defillama", "pricesBySymbol", { symbols }, o),
583
+ protocols: (o) => dataCall("defillama", "protocols", {}, o),
584
+ },
585
+ lifi: {
586
+ health: (o) => dataCall("lifi", "health", {}, o),
587
+ quote: (a, o) => dataCall("lifi", "quote", a || {}, o),
588
+ chains: (o) => dataCall("lifi", "chains", {}, o),
589
+ },
590
+ dex: {
591
+ health: (o) => dataCall("dexscreener", "health", {}, o),
592
+ token: (address, o) => dataCall("dexscreener", "token", { address }, o),
593
+ search: (q, o) => dataCall("dexscreener", "search", { q }, o),
594
+ pair: (chainId, pairAddress, o) =>
595
+ dataCall("dexscreener", "pair", { chainId, pairAddress }, o),
596
+ },
597
+ uni: {
598
+ health: (a, o) => dataCall("uniswap-v3", "health", a || {}, o),
599
+ quote: (a, o) => dataCall("uniswap-v3", "quote", a || {}, o),
600
+ quotePath: (a, o) => dataCall("uniswap-v3", "quotePath", a || {}, o),
601
+ ethUsdc: (a, o) => dataCall("uniswap-v3", "ethUsdc", a || {}, o),
602
+ chains: (o) => dataCall("uniswap-v3", "chains", {}, o),
603
+ },
604
+ bridges: {
605
+ across: (a, o) => dataCall("across", "suggestedFees", a || {}, o),
606
+ hop: (a, o) => dataCall("hop", "quote", a || {}, o),
607
+ relay: (a, o) => dataCall("relay", "quote", a || {}, o),
608
+ },
609
+ cow: {
610
+ quote: (a, o) => dataCall("cowswap", "quote", a || {}, o),
611
+ },
612
+ nft: {
613
+ floor: (slug, o) => dataCall("opensea-nft", "floor", { slug }, o),
614
+ collection: (slug, o) => dataCall("opensea-nft", "collection", { slug }, o),
615
+ },
616
+ hlWs: {
617
+ allMids: (o) => dataCall("hl-ws", "allMids", {}, o),
618
+ l2Book: (coin, o) => dataCall("hl-ws", "l2Book", { coin }, o),
619
+ },
620
+ polyWs: {
621
+ book: (assetId, o) => dataCall("poly-ws", "book", { assetId }, o),
622
+ },
623
+ };