@oracle-agent/oracle 0.11.0 → 0.12.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 (308) hide show
  1. package/LICENSE +115 -201
  2. package/README.md +66 -84
  3. package/SECURITY.md +37 -12
  4. package/SETUP.md +207 -272
  5. package/dist/action-receipts.mjs +1 -0
  6. package/dist/action-semantics.mjs +1 -0
  7. package/dist/address-book.mjs +2 -0
  8. package/dist/bin/desk-server.mjs +14 -0
  9. package/dist/bin/oracle-data-mcp.mjs +8 -0
  10. package/dist/bin/oracle-init.mjs +24 -0
  11. package/dist/bin/oracle-public-server.mjs +5 -0
  12. package/dist/bin/oracle-route.mjs +22 -0
  13. package/dist/bin/oracle-scan.mjs +18 -0
  14. package/dist/bin/oracle-upgrade.mjs +21 -0
  15. package/dist/bin/oracle.mjs +68 -0
  16. package/dist/chains.mjs +1 -0
  17. package/dist/cli/commands/auth.mjs +16 -0
  18. package/dist/cli/commands/bootstrap.mjs +18 -0
  19. package/dist/cli/commands/chain.mjs +21 -0
  20. package/dist/cli/commands/chat.mjs +35 -0
  21. package/dist/cli/commands/credential.mjs +1 -0
  22. package/dist/cli/commands/data-mcp.mjs +2 -0
  23. package/dist/cli/commands/data.mjs +12 -0
  24. package/dist/cli/commands/doctor.mjs +5 -0
  25. package/dist/cli/commands/gate.mjs +13 -0
  26. package/dist/cli/commands/help.mjs +1 -0
  27. package/dist/cli/commands/init.mjs +3 -0
  28. package/dist/cli/commands/mcp.mjs +33 -0
  29. package/dist/cli/commands/model.mjs +44 -0
  30. package/dist/cli/commands/prepare.mjs +2 -0
  31. package/dist/cli/commands/public.mjs +3 -0
  32. package/dist/cli/commands/route.mjs +2 -0
  33. package/dist/cli/commands/runner.mjs +1 -0
  34. package/dist/cli/commands/scan.mjs +2 -0
  35. package/dist/cli/commands/setup.mjs +34 -0
  36. package/dist/cli/commands/sign.mjs +4 -0
  37. package/dist/cli/commands/signer.mjs +1 -0
  38. package/dist/cli/commands/upgrade.mjs +2 -0
  39. package/dist/cli/commands/vault.mjs +1 -0
  40. package/dist/cli/commands/version.mjs +2 -0
  41. package/dist/data/desk-data.mjs +12 -0
  42. package/dist/index.mjs +17 -0
  43. package/dist/nft-gas-war-guard.mjs +1 -0
  44. package/dist/onboarding/harness-configs.mjs +4 -0
  45. package/dist/portfolio-risk.mjs +1 -0
  46. package/dist/prepare-envelope.mjs +1 -0
  47. package/dist/public-control/policy-schema.mjs +1 -0
  48. package/dist/router/index.mjs +2 -0
  49. package/dist/scanner/index.mjs +4 -0
  50. package/dist/signals/index.mjs +1 -0
  51. package/dist/watch-preferences.mjs +1 -0
  52. package/package.json +27 -65
  53. package/public/oracle-splash/index.html +11 -1
  54. package/CONTRIBUTING.md +0 -98
  55. package/bin/desk-server.mjs +0 -440
  56. package/bin/oracle-data-mcp.mjs +0 -1019
  57. package/bin/oracle-init.mjs +0 -496
  58. package/bin/oracle-public-server.mjs +0 -36
  59. package/bin/oracle-route.mjs +0 -254
  60. package/bin/oracle-scan.mjs +0 -192
  61. package/bin/oracle-upgrade.mjs +0 -42
  62. package/bin/oracle.mjs +0 -33
  63. package/docs/adding-a-chain.md +0 -229
  64. package/docs/architecture.md +0 -138
  65. package/docs/cli.md +0 -47
  66. package/docs/connectors.md +0 -13
  67. package/docs/oracle-pack-standard.md +0 -29
  68. package/docs/profiles.md +0 -151
  69. package/docs/public-surface.md +0 -133
  70. package/examples/add-a-chain.mjs +0 -65
  71. package/examples/oracle-pack-template.mjs +0 -38
  72. package/examples/research-a-token.mjs +0 -70
  73. package/plugins/oracle-owner-gate/__init__.py +0 -227
  74. package/plugins/oracle-owner-gate/plugin.yaml +0 -9
  75. package/profiles/_template/SOUL.md +0 -54
  76. package/profiles/_template/profile.json +0 -22
  77. package/profiles/bitcoin-agent/SOUL.md +0 -31
  78. package/profiles/bitcoin-agent/profile.json +0 -32
  79. package/profiles/hyperliquid-agent/SOUL.md +0 -34
  80. package/profiles/hyperliquid-agent/profile.json +0 -37
  81. package/profiles/oracle/SOUL.md +0 -107
  82. package/profiles/oracle/profile.json +0 -39
  83. package/profiles/polymarket-agent/SOUL.md +0 -35
  84. package/profiles/polymarket-agent/profile.json +0 -34
  85. package/profiles/profile.schema.json +0 -90
  86. package/profiles/protocol-builder/SOUL.md +0 -57
  87. package/profiles/protocol-builder/profile.json +0 -39
  88. package/profiles/robinhood-agent/SOUL.md +0 -53
  89. package/profiles/robinhood-agent/profile.json +0 -40
  90. package/profiles/solana-agent/SOUL.md +0 -37
  91. package/profiles/solana-agent/profile.json +0 -37
  92. package/profiles/stable-agent/SOUL.md +0 -43
  93. package/profiles/stable-agent/profile.json +0 -37
  94. package/protocols/templates/safe-erc20/SECURITY.md +0 -16
  95. package/protocols/templates/safe-erc20/foundry.toml +0 -12
  96. package/protocols/templates/safe-erc20/remappings.txt +0 -2
  97. package/protocols/templates/safe-erc20/src/SafeERC20.sol +0 -53
  98. package/protocols/templates/safe-erc20/test/SafeERC20.t.sol +0 -72
  99. package/scripts/adversarial-bench.mjs +0 -114
  100. package/scripts/build-inscription.py +0 -230
  101. package/scripts/check-doc-drift.mjs +0 -123
  102. package/scripts/check-test-count.mjs +0 -105
  103. package/scripts/e2e-hl-markets.mjs +0 -21
  104. package/scripts/e2e-hl-perps.mjs +0 -48
  105. package/scripts/e2e-hypercore-staking.mjs +0 -128
  106. package/scripts/e2e-solana-bitcoin.mjs +0 -183
  107. package/scripts/protocol-template-gate.mjs +0 -15
  108. package/scripts/public-api-scan.mjs +0 -23
  109. package/scripts/secret-scan.mjs +0 -181
  110. package/scripts/verify-v3-venues.mjs +0 -192
  111. package/skills/balance/SKILL.md +0 -176
  112. package/skills/oracle-action-semantics/SKILL.md +0 -40
  113. package/skills/oracle-best-execution/SKILL.md +0 -127
  114. package/skills/oracle-bitcoin/SKILL.md +0 -53
  115. package/skills/oracle-chain-graphs-telegram-cards/SKILL.md +0 -59
  116. package/skills/oracle-chat/SKILL.md +0 -61
  117. package/skills/oracle-chat/chain.SKILL.md +0 -31
  118. package/skills/oracle-chat/setup.SKILL.md +0 -37
  119. package/skills/oracle-circuit-breaker/SKILL.md +0 -51
  120. package/skills/oracle-contract-research/SKILL.md +0 -55
  121. package/skills/oracle-desk/SKILL.md +0 -58
  122. package/skills/oracle-dex-launch/SKILL.md +0 -38
  123. package/skills/oracle-grants/SKILL.md +0 -69
  124. package/skills/oracle-hypercore-staking/SKILL.md +0 -57
  125. package/skills/oracle-hyperliquid/SKILL.md +0 -56
  126. package/skills/oracle-meme-token-sniper/SKILL.md +0 -73
  127. package/skills/oracle-multichain-nft-launch/SKILL.md +0 -338
  128. package/skills/oracle-multichain-token-launch/SKILL.md +0 -300
  129. package/skills/oracle-nft-gacha-launch/SKILL.md +0 -48
  130. package/skills/oracle-nft-mint-gas-war/SKILL.md +0 -63
  131. package/skills/oracle-polymarket/SKILL.md +0 -60
  132. package/skills/oracle-protocol-builder/SKILL.md +0 -59
  133. package/skills/oracle-protocol-security/SKILL.md +0 -60
  134. package/skills/oracle-public-product/SKILL.md +0 -44
  135. package/skills/oracle-receipts/SKILL.md +0 -52
  136. package/skills/oracle-rfq-tokenized-assets/SKILL.md +0 -69
  137. package/skills/oracle-smart-wallet-scanner/SKILL.md +0 -49
  138. package/skills/oracle-solana/SKILL.md +0 -65
  139. package/skills/oracle-solana-nft/SKILL.md +0 -54
  140. package/skills/oracle-token-research/SKILL.md +0 -67
  141. package/skins/oracle.yaml +0 -56
  142. package/src/action-receipts.mjs +0 -265
  143. package/src/action-semantics.mjs +0 -62
  144. package/src/address-book.mjs +0 -208
  145. package/src/agent-auth.mjs +0 -206
  146. package/src/approval-guard.mjs +0 -282
  147. package/src/attestation-secret.mjs +0 -88
  148. package/src/audit-log.mjs +0 -196
  149. package/src/auth/oauth.mjs +0 -672
  150. package/src/auto-slippage.mjs +0 -378
  151. package/src/capability-posture.mjs +0 -125
  152. package/src/chains.mjs +0 -62
  153. package/src/cli/chain-catalog.mjs +0 -215
  154. package/src/cli/chain-state.mjs +0 -74
  155. package/src/cli/commands/auth.mjs +0 -193
  156. package/src/cli/commands/bootstrap.mjs +0 -87
  157. package/src/cli/commands/chain.mjs +0 -143
  158. package/src/cli/commands/chat.mjs +0 -434
  159. package/src/cli/commands/credential.mjs +0 -9
  160. package/src/cli/commands/data-mcp.mjs +0 -18
  161. package/src/cli/commands/data.mjs +0 -75
  162. package/src/cli/commands/doctor.mjs +0 -136
  163. package/src/cli/commands/help.mjs +0 -7
  164. package/src/cli/commands/init.mjs +0 -27
  165. package/src/cli/commands/mcp.mjs +0 -142
  166. package/src/cli/commands/model.mjs +0 -99
  167. package/src/cli/commands/prepare.mjs +0 -12
  168. package/src/cli/commands/public.mjs +0 -20
  169. package/src/cli/commands/route.mjs +0 -12
  170. package/src/cli/commands/runner.mjs +0 -9
  171. package/src/cli/commands/scan.mjs +0 -12
  172. package/src/cli/commands/setup.mjs +0 -275
  173. package/src/cli/commands/sign.mjs +0 -21
  174. package/src/cli/commands/signer.mjs +0 -9
  175. package/src/cli/commands/upgrade.mjs +0 -12
  176. package/src/cli/commands/vault.mjs +0 -9
  177. package/src/cli/commands/version.mjs +0 -22
  178. package/src/cli/first-run.mjs +0 -23
  179. package/src/cli/kernel.mjs +0 -239
  180. package/src/cli/mcp-targets/chatgpt.mjs +0 -51
  181. package/src/cli/mcp-targets/claude-code.mjs +0 -39
  182. package/src/cli/mcp-targets/claude-desktop.mjs +0 -24
  183. package/src/cli/mcp-targets/codex.mjs +0 -41
  184. package/src/cli/mcp-targets/shared.mjs +0 -61
  185. package/src/cli/messaging-platforms.mjs +0 -209
  186. package/src/cli/model-config.mjs +0 -70
  187. package/src/cli/operator-dispatch.mjs +0 -258
  188. package/src/cli/oracle-harness.py +0 -415
  189. package/src/cli/paths.mjs +0 -83
  190. package/src/cli/runtime.mjs +0 -351
  191. package/src/cli/setup-state.mjs +0 -168
  192. package/src/cli/spawn-child.mjs +0 -43
  193. package/src/data/catalog.mjs +0 -585
  194. package/src/data/desk-data.mjs +0 -695
  195. package/src/data/http.mjs +0 -253
  196. package/src/data/provider-endpoint.mjs +0 -94
  197. package/src/data/providers/aerodrome.mjs +0 -245
  198. package/src/data/providers/balancer.mjs +0 -209
  199. package/src/data/providers/bitcoin-esplora.mjs +0 -216
  200. package/src/data/providers/bitcoin-meta.mjs +0 -378
  201. package/src/data/providers/blockscout.mjs +0 -14
  202. package/src/data/providers/bridges.mjs +0 -242
  203. package/src/data/providers/cowswap.mjs +0 -415
  204. package/src/data/providers/curve.mjs +0 -201
  205. package/src/data/providers/defillama.mjs +0 -88
  206. package/src/data/providers/dexscreener.mjs +0 -43
  207. package/src/data/providers/evm-rpc.mjs +0 -225
  208. package/src/data/providers/geckoterminal.mjs +0 -34
  209. package/src/data/providers/gmx.mjs +0 -496
  210. package/src/data/providers/hl-assets.mjs +0 -165
  211. package/src/data/providers/hl-info.mjs +0 -108
  212. package/src/data/providers/hl-markets.mjs +0 -210
  213. package/src/data/providers/hl-outcome.mjs +0 -61
  214. package/src/data/providers/hl-perps.mjs +0 -387
  215. package/src/data/providers/hl-staking.mjs +0 -353
  216. package/src/data/providers/hl-ws.mjs +0 -119
  217. package/src/data/providers/hyperevm-dex.mjs +0 -49
  218. package/src/data/providers/jupiter-venues.mjs +0 -119
  219. package/src/data/providers/jupiter.mjs +0 -315
  220. package/src/data/providers/lifi.mjs +0 -151
  221. package/src/data/providers/magiceden-sol.mjs +0 -406
  222. package/src/data/providers/morpho.mjs +0 -177
  223. package/src/data/providers/nft-gallery.mjs +0 -163
  224. package/src/data/providers/nft-portfolio.mjs +0 -494
  225. package/src/data/providers/odos.mjs +0 -156
  226. package/src/data/providers/oneinch.mjs +0 -174
  227. package/src/data/providers/opensea-multichain.mjs +0 -136
  228. package/src/data/providers/opensea-nft.mjs +0 -371
  229. package/src/data/providers/paraswap.mjs +0 -118
  230. package/src/data/providers/pendle.mjs +0 -188
  231. package/src/data/providers/poly-clob.mjs +0 -283
  232. package/src/data/providers/poly-public.mjs +0 -96
  233. package/src/data/providers/poly-ws.mjs +0 -103
  234. package/src/data/providers/portfolio-history.mjs +0 -394
  235. package/src/data/providers/portfolio.mjs +0 -594
  236. package/src/data/providers/rfq.mjs +0 -15
  237. package/src/data/providers/rh-agent.mjs +0 -59
  238. package/src/data/providers/satflow.mjs +0 -341
  239. package/src/data/providers/signed-material-guard.mjs +0 -108
  240. package/src/data/providers/solana-rpc.mjs +0 -197
  241. package/src/data/providers/uniswap-v3.mjs +0 -349
  242. package/src/data/providers/uniswap-v4.mjs +0 -414
  243. package/src/data/providers/zerox.mjs +0 -167
  244. package/src/data/public-api-scan.mjs +0 -61
  245. package/src/data/quote-placeholder.mjs +0 -31
  246. package/src/exact-integer.mjs +0 -72
  247. package/src/exec-policy.mjs +0 -455
  248. package/src/flags.mjs +0 -15
  249. package/src/fresh-window.mjs +0 -76
  250. package/src/gmx-attestation.mjs +0 -176
  251. package/src/index.mjs +0 -100
  252. package/src/nft-gas-war-guard.mjs +0 -139
  253. package/src/onboarding/agent-keys.mjs +0 -161
  254. package/src/onboarding/harness-configs.mjs +0 -102
  255. package/src/onboarding/index.mjs +0 -18
  256. package/src/onboarding/tiers.mjs +0 -139
  257. package/src/oracle-env.mjs +0 -47
  258. package/src/portfolio-risk.mjs +0 -170
  259. package/src/prepare-envelope.mjs +0 -204
  260. package/src/profile-upgrade.mjs +0 -277
  261. package/src/protocol-execution.mjs +0 -84
  262. package/src/protocol-templates/gate.mjs +0 -179
  263. package/src/protocol-templates/prepare-deploy.mjs +0 -81
  264. package/src/public-api/buzz-integration.mjs +0 -256
  265. package/src/public-api/connect-agent.mjs +0 -416
  266. package/src/public-api/grants.mjs +0 -142
  267. package/src/public-api/http.mjs +0 -389
  268. package/src/public-control/aa-adapter.mjs +0 -402
  269. package/src/public-control/build-registry.mjs +0 -227
  270. package/src/public-control/bundler-client.mjs +0 -357
  271. package/src/public-control/grant-indexer.mjs +0 -296
  272. package/src/public-control/policy-render.mjs +0 -69
  273. package/src/public-control/policy-schema.mjs +0 -318
  274. package/src/public-control/runtime-config.mjs +0 -275
  275. package/src/public-control/session-key-model.mjs +0 -374
  276. package/src/public-control/session-orchestrator.mjs +0 -412
  277. package/src/rfq/intent.mjs +0 -180
  278. package/src/rfq/sources.mjs +0 -181
  279. package/src/route-attestation.mjs +0 -132
  280. package/src/router/best-execution.mjs +0 -326
  281. package/src/router/index.mjs +0 -226
  282. package/src/router/prepare-bridge.mjs +0 -289
  283. package/src/router/prepare-route.mjs +0 -398
  284. package/src/router/proposal.mjs +0 -311
  285. package/src/router/risk-classifier.mjs +0 -119
  286. package/src/router/route-sources.mjs +0 -364
  287. package/src/scanner/chains.config.mjs +0 -430
  288. package/src/scanner/contract.mjs +0 -270
  289. package/src/scanner/evm-scanner.mjs +0 -394
  290. package/src/scanner/index.mjs +0 -9
  291. package/src/scanner/v2-venue.mjs +0 -335
  292. package/src/scanner/v3-venue.mjs +0 -290
  293. package/src/scopes.mjs +0 -44
  294. package/src/sell-simulation.mjs +0 -167
  295. package/src/signals/engine.mjs +0 -146
  296. package/src/signals/index.mjs +0 -1
  297. package/src/token-transfer-guard.mjs +0 -188
  298. package/src/tui/app.mjs +0 -438
  299. package/src/tui/backend.mjs +0 -145
  300. package/src/tui/format.mjs +0 -272
  301. package/src/tui/gateway-client.mjs +0 -177
  302. package/src/tui/input.mjs +0 -501
  303. package/src/tui/renderer.mjs +0 -443
  304. package/src/tui/standalone-client.mjs +0 -666
  305. package/src/tui/theme.mjs +0 -81
  306. package/src/vault-attestation.mjs +0 -146
  307. package/src/venues.mjs +0 -206
  308. package/src/watch-preferences.mjs +0 -85
@@ -1,414 +0,0 @@
1
- // Uniswap V4 Quoter — multi-chain prepare-only quotes via eth_call.
2
- //
3
- // Cross-chain by design. Addresses are the official Uniswap V4 deployments
4
- // (docs.uniswap.org/contracts/v4/deployments, scraped 2026-08-02) plus the
5
- // Robinhood Chain deployment that the RH SQUEEZE book already proved live.
6
- //
7
- // WHY THIS EXISTS: a V3 factory quote can return a real, on-chain, DEAD shell
8
- // while the live book sits on V4. Verified on Robinhood 2026-08-02 with SQUEEZE
9
- // (V3 ~$7, V4 ~$471k). The impact ceiling blocks garbage V3 fills; this module
10
- // is the source that can actually price the live book.
11
- //
12
- // Scope:
13
- // * quoteExactInputSingle against V4Quoter
14
- // * poolId derivation (keccak of PoolKey) for identity checks
15
- // * catalog/list exposure
16
- // * prepare exact-input single-hop Universal Router calldata when recipient
17
- // and slippage are explicit; the fresh successful quote supplies PoolKey
18
- //
19
- // Never signs. Never broadcasts.
20
-
21
- import { AbiCoder, Interface, getAddress, isAddress, keccak256 } from "ethers";
22
- import { rpcCall } from "./evm-rpc.mjs";
23
- import { attachAutoSlippage } from "../../auto-slippage.mjs";
24
- import { stampPrepared } from "../../prepare-envelope.mjs";
25
-
26
- const abi = AbiCoder.defaultAbiCoder();
27
- const ZERO = "0x0000000000000000000000000000000000000000";
28
-
29
- /**
30
- * Official Uniswap V4 deployments + RH.
31
- * Source: Uniswap docs V4 deployments page (2026-08-02) and RH squeeze-v4 worktree.
32
- * Only chains Oracle already routes are listed here.
33
- *
34
- * @type {Record<number, {
35
- * name: string,
36
- * poolManager: string,
37
- * quoter: string,
38
- * stateView?: string,
39
- * universalRouter?: string,
40
- * weth: string,
41
- * usdc: string,
42
- * }>}
43
- */
44
- export const UNI_V4_CHAINS = {
45
- 1: {
46
- name: "ethereum",
47
- poolManager: "0x000000000004444c5dc75cB358380D2e3dE08A90",
48
- quoter: "0x52f0e24d1c21c8a0cb1e5a5dd6198556bd9e1203",
49
- stateView: "0x7ffe42c4a5deea5b0fec41c94c136cf115597227",
50
- universalRouter: "0x66a9893cc07d91d95644aedd05d03f95e1dba8af",
51
- weth: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
52
- usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
53
- },
54
- 10: {
55
- name: "optimism",
56
- poolManager: "0x9a13f98cb987694c9f086b1f5eb990eea8264ec3",
57
- quoter: "0x1f3131a13296fb91c90870043742c3cdbff1a8d7",
58
- stateView: "0xc18a3169788f4f75a170290584eca6395c75ecdb",
59
- universalRouter: "0x851116d9223fabed8e56c0e6b8ad0c31d98b3507",
60
- weth: "0x4200000000000000000000000000000000000006",
61
- usdc: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
62
- },
63
- 56: {
64
- name: "bsc",
65
- poolManager: "0x28e2ea090877bf75740558f6bfb36a5ffee9e9df",
66
- quoter: "0x9f75dd27d6664c475b90e105573e550ff69437b0",
67
- stateView: "0xd13dd3d6e93f276fafc9db9e6bb47c1180aee0c4",
68
- universalRouter: "0x1906c1d672b88cd1b9ac7593301ca990f94eae07",
69
- weth: "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
70
- usdc: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",
71
- },
72
- 137: {
73
- name: "polygon",
74
- poolManager: "0x67366782805870060151383f4bbff9dab53e5cd6",
75
- quoter: "0xb3d5c3dfc3a7aebff71895a7191796bffc2c81b9",
76
- stateView: "0x5ea1bd7974c8a611cbab0bdcafcb1d9cc9b3ba5a",
77
- universalRouter: "0x1095692a6237d83c6a72f3f5efedb9a670c49223",
78
- weth: "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270",
79
- usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
80
- },
81
- 8453: {
82
- name: "base",
83
- poolManager: "0x498581fF718922c3f8e6A244956aF099B2652b2b",
84
- quoter: "0x0d5e0f971ed27fbff6c2837bf31316121532048d",
85
- stateView: "0xa3c0c9b65bad0b08107aa264b0f3db444b867a71",
86
- universalRouter: "0x6ff5693b99212da76ad316178a184ab56d299b43",
87
- weth: "0x4200000000000000000000000000000000000006",
88
- usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
89
- },
90
- 42161: {
91
- name: "arbitrum",
92
- poolManager: "0x360e68faccca8ca495c1b759fd9eee466db9fb32",
93
- quoter: "0x3972c00f7ed4885e145823eb7c655375d275a1c5",
94
- stateView: "0x76fd297e2d437cd7f76d50f01afe6160f86e9990",
95
- universalRouter: "0xa51afafe0263b40edaef0df8781ea9aa03e381a3",
96
- weth: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
97
- usdc: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
98
- },
99
- 43114: {
100
- name: "avalanche",
101
- poolManager: "0x06380c0e0912312b5150364b9dc4542ba0dbbc85",
102
- quoter: "0xbe40675bb704506a3c2ccfb762dcfd1e979845c2",
103
- stateView: "0xc3c9e198c735a4b97e3e683f391ccbdd60b69286",
104
- universalRouter: "0x94b75331ae8d42c1b61065089b7d48fe14aa73b7",
105
- weth: "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7",
106
- usdc: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
107
- },
108
- // Robinhood Chain — V4 is the live book for SQUEEZE and other Doppler launches.
109
- // PoolManager/Quoter/UniversalRouter proved via V4 Swap/Init log emitters +
110
- // squeeze-v4 worktree (2026-08-02). usdc slot is USDG, same as V3 adapter.
111
- 4663: {
112
- name: "robinhood",
113
- poolManager: "0x8366a39cc670b4001a1121b8f6a443a643e40951",
114
- quoter: "0x8dc178efb8111bb0973dd9d722ebeff267c98f94",
115
- stateView: "0xf3334192d15450cdd385c8b70e03f9a6bd9e673b",
116
- universalRouter: "0x8876789976dEcBfCbBbe364623C63652db8C0904",
117
- weth: "0x0bd7d308f8e1639fab988df18a8011f41eacad73",
118
- usdc: "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168",
119
- },
120
- };
121
-
122
- // Common V4 fee/tickSpacing pairs. Callers can override with explicit fee+tickSpacing.
123
- export const UNI_V4_FEE_TIERS = [
124
- { fee: 100, tickSpacing: 1 },
125
- { fee: 500, tickSpacing: 10 },
126
- { fee: 3000, tickSpacing: 60 },
127
- { fee: 10000, tickSpacing: 200 },
128
- // Doppler / RH launch pools often use a 2.5% fee with tickSpacing 8.
129
- { fee: 25000, tickSpacing: 8 },
130
- ];
131
-
132
- const QUOTER_IFACE = new Interface([
133
- "function quoteExactInputSingle(((address currency0,address currency1,uint24 fee,int24 tickSpacing,address hooks) poolKey,bool zeroForOne,uint128 exactAmount,bytes hookData) params) returns (uint256 amountOut, uint256 gasEstimate)",
134
- ]);
135
- const UNIVERSAL_ROUTER_IFACE = new Interface([
136
- "function execute(bytes commands,bytes[] inputs,uint256 deadline) payable",
137
- ]);
138
-
139
- // Universal Router command/action constants from Commands.sol and Actions.sol.
140
- const V4_SWAP = "0x10";
141
- const V4_ACTIONS = "0x060c0f"; // SWAP_EXACT_IN_SINGLE, SETTLE_ALL, TAKE_ALL
142
- const PERMIT2 = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
143
-
144
- const NATIVE = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
145
-
146
- function chainMeta(chainId) {
147
- const id = Number(chainId);
148
- const m = UNI_V4_CHAINS[id];
149
- if (!m) {
150
- throw new Error(
151
- `uniswap-v4: unsupported chainId ${chainId} (supported: ${Object.keys(UNI_V4_CHAINS).join(", ")})`,
152
- );
153
- }
154
- return { chainId: id, ...m };
155
- }
156
-
157
- function normalizeToken(addr, chainId) {
158
- const meta = UNI_V4_CHAINS[Number(chainId)];
159
- if (!addr || addr === NATIVE || addr === ZERO || /^eth$/i.test(String(addr))) {
160
- return getAddress(meta.weth);
161
- }
162
- const s = String(addr);
163
- if (/^weth$/i.test(s)) return getAddress(meta.weth);
164
- if (/^usdc$/i.test(s) || /^usdg$/i.test(s)) return getAddress(meta.usdc);
165
- if (!isAddress(s)) throw new Error(`invalid token address: ${addr}`);
166
- return getAddress(s);
167
- }
168
-
169
- /**
170
- * V4 poolId = keccak256(abi.encode(currency0, currency1, fee, tickSpacing, hooks))
171
- * currency0 must be the lower address. Hooks default to address(0).
172
- */
173
- export function computeV4PoolId({ currency0, currency1, fee, tickSpacing, hooks = ZERO }) {
174
- const a = getAddress(currency0);
175
- const b = getAddress(currency1);
176
- if (a.toLowerCase() === b.toLowerCase()) throw new Error("poolKey currencies must differ");
177
- const [c0, c1] = a.toLowerCase() < b.toLowerCase() ? [a, b] : [b, a];
178
- const h = hooks && isAddress(hooks) ? getAddress(hooks) : ZERO;
179
- return keccak256(abi.encode(
180
- ["address", "address", "uint24", "int24", "address"],
181
- [c0, c1, Number(fee), Number(tickSpacing), h],
182
- ));
183
- }
184
-
185
- function buildPoolKey({ tokenIn, tokenOut, fee, tickSpacing, hooks = ZERO }) {
186
- const a = getAddress(tokenIn);
187
- const b = getAddress(tokenOut);
188
- const [currency0, currency1] = a.toLowerCase() < b.toLowerCase() ? [a, b] : [b, a];
189
- const zeroForOne = a.toLowerCase() === currency0.toLowerCase();
190
- return {
191
- poolKey: {
192
- currency0,
193
- currency1,
194
- fee: Number(fee),
195
- tickSpacing: Number(tickSpacing),
196
- hooks: hooks && isAddress(hooks) ? getAddress(hooks) : ZERO,
197
- },
198
- zeroForOne,
199
- };
200
- }
201
-
202
- /**
203
- * Quote exact-input single hop via V4Quoter.
204
- *
205
- * @param {object} q
206
- * @param {number} q.chainId
207
- * @param {string} [q.tokenIn]
208
- * @param {string} [q.tokenOut]
209
- * @param {string|number|bigint} q.amountIn
210
- * @param {number} [q.fee]
211
- * @param {number} [q.tickSpacing]
212
- * @param {string} [q.hooks]
213
- * @param {Array<{fee:number,tickSpacing:number}>} [q.tryTiers]
214
- */
215
- export async function uniV4QuoteExactIn(q = {}, opts = {}) {
216
- const { chainId, quoter, poolManager, universalRouter } = chainMeta(q.chainId ?? 8453);
217
- const tokenIn = normalizeToken(q.tokenIn || "WETH", chainId);
218
- const tokenOut = normalizeToken(q.tokenOut || UNI_V4_CHAINS[chainId].usdc, chainId);
219
- const amountIn = BigInt(q.amountIn ?? 0);
220
- if (amountIn <= 0n) throw new Error("amountIn required (raw base units)");
221
- if (amountIn > 0xffffffffffffffffffffffffffffffffn) {
222
- throw new Error("amountIn exceeds uint128");
223
- }
224
-
225
- const tiers =
226
- q.fee != null && q.tickSpacing != null
227
- ? [{ fee: Number(q.fee), tickSpacing: Number(q.tickSpacing) }]
228
- : q.tryTiers === false
229
- ? [{ fee: 500, tickSpacing: 10 }]
230
- : [...UNI_V4_FEE_TIERS];
231
-
232
- const hooks = q.hooks || ZERO;
233
- const results = [];
234
- let best = null;
235
-
236
- for (const tier of tiers) {
237
- const { poolKey, zeroForOne } = buildPoolKey({
238
- tokenIn,
239
- tokenOut,
240
- fee: tier.fee,
241
- tickSpacing: tier.tickSpacing,
242
- hooks,
243
- });
244
- const data = QUOTER_IFACE.encodeFunctionData("quoteExactInputSingle", [
245
- {
246
- poolKey,
247
- zeroForOne,
248
- exactAmount: amountIn,
249
- hookData: "0x",
250
- },
251
- ]);
252
- try {
253
- const raw = await rpcCall(chainId, "eth_call", [{ to: quoter, data }, "latest"], opts);
254
- if (!raw || raw === "0x") {
255
- results.push({ ...tier, ok: false, error: "empty result" });
256
- continue;
257
- }
258
- const decoded = QUOTER_IFACE.decodeFunctionResult("quoteExactInputSingle", raw);
259
- const row = {
260
- fee: tier.fee,
261
- tickSpacing: tier.tickSpacing,
262
- ok: true,
263
- amountOut: decoded[0].toString(),
264
- gasEstimate: decoded[1].toString(),
265
- poolKey,
266
- zeroForOne,
267
- poolId: computeV4PoolId({ ...poolKey }),
268
- };
269
- results.push(row);
270
- if (!best || BigInt(row.amountOut) > BigInt(best.amountOut)) best = row;
271
- } catch (e) {
272
- results.push({ ...tier, ok: false, error: String(e.message || e).slice(0, 160) });
273
- }
274
- }
275
-
276
- if (!best) {
277
- const err = results.map((r) => `${r.fee}/${r.tickSpacing}:${r.error || "fail"}`).join("; ");
278
- throw new Error(`uniswap-v4 quote failed chain=${chainId}: ${err}`);
279
- }
280
-
281
- return attachAutoSlippage(
282
- {
283
- venue: "uniswap-v4",
284
- chainId,
285
- chain: UNI_V4_CHAINS[chainId].name,
286
- poolManager,
287
- quoter,
288
- universalRouter: universalRouter || null,
289
- tokenIn,
290
- tokenOut,
291
- amountIn: amountIn.toString(),
292
- fee: best.fee,
293
- tickSpacing: best.tickSpacing,
294
- hooks: best.poolKey.hooks,
295
- poolId: best.poolId,
296
- zeroForOne: best.zeroForOne,
297
- amountOut: best.amountOut,
298
- gasEstimate: best.gasEstimate,
299
- triedTiers: results,
300
- best: true,
301
- executionReady: false,
302
- // A successful quote discovered the complete PoolKey. Preparation is only
303
- // advertised when its remaining safety inputs were explicit.
304
- prepareReady:
305
- typeof q.recipient === "string" && isAddress(q.recipient) && q.slippageBps != null,
306
- },
307
- {
308
- chainId,
309
- venue: universalRouter || quoter,
310
- amountOut: best.amountOut,
311
- liquidityUsd: q.liquidityUsd,
312
- priceChange5m: q.priceChange5m,
313
- requestedCapBps: q.maxSlippageBps ?? q.slippageBps,
314
- },
315
- );
316
- }
317
-
318
- /**
319
- * Prepare (never sign or broadcast) a V4 exact-input, single-hop swap.
320
- * A fresh successful quote is the source of truth for the complete PoolKey.
321
- * ERC-20 input only: native wrapping/unwrapping is intentionally not inferred.
322
- */
323
- export async function uniV4PrepareExactIn(q = {}, opts = {}) {
324
- const chainId = Number(q.chainId ?? 8453);
325
- const meta = chainMeta(chainId);
326
- if (!q.recipient) throw new Error("uniswap-v4 prepare requires recipient");
327
- const recipient = getAddress(q.recipient);
328
- if (q.slippageBps == null) {
329
- throw new Error("uniswap-v4 prepare requires explicit slippageBps");
330
- }
331
- const slippageBps = Number(q.slippageBps);
332
- if (!Number.isInteger(slippageBps) || slippageBps < 0 || slippageBps >= 10_000) {
333
- throw new Error("slippageBps must be an integer from 0 through 9999");
334
- }
335
- const rawInput = String(q.tokenIn || "");
336
- if (!rawInput || rawInput === NATIVE || rawInput === ZERO || /^eth$/i.test(rawInput)) {
337
- throw new Error("uniswap-v4 prepare currently requires an ERC-20 tokenIn; native input is not inferred");
338
- }
339
-
340
- const quote = await uniV4QuoteExactIn(q, opts);
341
- if (!meta.universalRouter) throw new Error(`uniswap-v4: no Universal Router on chain ${chainId}`);
342
- const amountOutMinimum = (BigInt(quote.amountOut) * BigInt(10_000 - slippageBps)) / 10_000n;
343
- const poolKey = {
344
- currency0: quote.zeroForOne ? quote.tokenIn : quote.tokenOut,
345
- currency1: quote.zeroForOne ? quote.tokenOut : quote.tokenIn,
346
- fee: quote.fee,
347
- tickSpacing: quote.tickSpacing,
348
- hooks: quote.hooks,
349
- };
350
- const minHopPriceX36 = 0n;
351
- const swap = abi.encode(
352
- ["tuple(tuple(address currency0,address currency1,uint24 fee,int24 tickSpacing,address hooks) poolKey,bool zeroForOne,uint128 amountIn,uint128 amountOutMinimum,uint256 minHopPriceX36,bytes hookData)"],
353
- [[poolKey, quote.zeroForOne, BigInt(quote.amountIn), amountOutMinimum, minHopPriceX36, "0x"]],
354
- );
355
- const settle = abi.encode(["address", "uint256"], [quote.tokenIn, BigInt(quote.amountIn)]);
356
- const take = abi.encode(["address", "uint256"], [quote.tokenOut, amountOutMinimum]);
357
- const plan = abi.encode(["bytes", "bytes[]"], [V4_ACTIONS, [swap, settle, take]]);
358
- const deadlineWindow = Math.min(600, Math.max(30, Number(q.deadlineSeconds ?? 300)));
359
- const nowSeconds = Number(opts.nowSeconds ?? Math.floor(Date.now() / 1000));
360
- const deadline = nowSeconds + deadlineWindow;
361
- const data = UNIVERSAL_ROUTER_IFACE.encodeFunctionData("execute", [V4_SWAP, [plan], deadline]);
362
-
363
- return stampPrepared({
364
- provider: "uniswap-v4",
365
- prepareReady: true,
366
- calldataReady: true,
367
- executionReady: false,
368
- requiresUserSignature: true,
369
- signingReady: false,
370
- broadcastReady: false,
371
- chainId,
372
- deadline,
373
- quote: { ...quote, amountOutMinimum: amountOutMinimum.toString(), slippageBps },
374
- requiresApproval: {
375
- token: quote.tokenIn,
376
- spender: PERMIT2,
377
- amount: quote.amountIn,
378
- note: "Universal Router V4 settlement uses Permit2; Permit2 authorization for the Universal Router is also required",
379
- },
380
- transaction: {
381
- chainId,
382
- from: recipient,
383
- to: meta.universalRouter,
384
- data,
385
- value: "0",
386
- },
387
- }, { provider: "uniswap-v4", kind: "univ4-swap-tx" });
388
- }
389
-
390
- export async function uniV4Chains() {
391
- return Object.entries(UNI_V4_CHAINS).map(([id, m]) => ({
392
- chainId: Number(id),
393
- name: m.name,
394
- poolManager: m.poolManager,
395
- quoter: m.quoter,
396
- stateView: m.stateView || null,
397
- universalRouter: m.universalRouter || null,
398
- weth: m.weth,
399
- usdc: m.usdc,
400
- }));
401
- }
402
-
403
- export async function uniV4Health(opts = {}) {
404
- const meta = chainMeta(opts.chainId ?? 8453);
405
- const code = await rpcCall(meta.chainId, "eth_getCode", [meta.quoter, "latest"], opts);
406
- const ok = typeof code === "string" && code !== "0x" && code.length > 4;
407
- return {
408
- ok,
409
- chainId: meta.chainId,
410
- quoter: meta.quoter,
411
- poolManager: meta.poolManager,
412
- codeBytes: ok ? (code.length - 2) / 2 : 0,
413
- };
414
- }
@@ -1,167 +0,0 @@
1
- // 0x Swap API v2 — price/quote. Requires ZEROX_API_KEY (or 0X_API_KEY).
2
-
3
- import { httpJson } from "../http.mjs";
4
- import { attachAutoSlippage, bindAutoSlippageGuardToCall, resolveAutoSlippage } from "../../auto-slippage.mjs";
5
- import { resolveProviderEndpoint, credentialedHeaders } from "../provider-endpoint.mjs";
6
- import { stampPrepared } from "../../prepare-envelope.mjs";
7
-
8
- export const ZEROX_API = "https://api.0x.org";
9
-
10
- function endpoint(opts = {}) {
11
- return resolveProviderEndpoint({
12
- provider: "zerox",
13
- defaultUrl: ZEROX_API,
14
- hosts: ["api.0x.org"],
15
- url: opts.baseUrl || process.env.ZEROX_API_URL,
16
- });
17
- }
18
-
19
- function base(opts = {}) {
20
- return endpoint(opts).baseUrl;
21
- }
22
-
23
- function apiKey(opts = {}) {
24
- return (
25
- opts.apiKey ||
26
- process.env.ZEROX_API_KEY ||
27
- process.env.OX_API_KEY ||
28
- process.env["0X_API_KEY"] ||
29
- ""
30
- );
31
- }
32
-
33
- function headers(opts = {}) {
34
- return credentialedHeaders(
35
- { "0x-version": "v2", accept: "application/json" },
36
- { "0x-api-key": apiKey(opts) },
37
- endpoint(opts).trusted
38
- );
39
- }
40
-
41
- export async function zeroxHealth(opts = {}) {
42
- if (!apiKey(opts)) {
43
- return { ok: false, configured: false, error: "ZEROX_API_KEY not set" };
44
- }
45
- try {
46
- const q = await zeroxPrice(
47
- {
48
- chainId: 8453,
49
- sellToken: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
50
- buyToken: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
51
- sellAmount: "1000000000000000",
52
- },
53
- opts
54
- );
55
- return { ok: true, configured: true, buyAmount: q.buyAmount || q.grossBuyAmount };
56
- } catch (e) {
57
- return { ok: false, configured: true, error: String(e.message || e).slice(0, 160) };
58
- }
59
- }
60
-
61
- /** Indicative price (no firm quote). */
62
- export async function zeroxPrice(q = {}, opts = {}) {
63
- if (!apiKey(opts)) throw new Error("ZEROX_API_KEY required for 0x");
64
- const {
65
- chainId = 8453,
66
- sellToken,
67
- buyToken,
68
- sellAmount,
69
- taker,
70
- } = q;
71
- if (!sellToken || !buyToken || !sellAmount) {
72
- throw new Error("zeroxPrice requires sellToken, buyToken, sellAmount");
73
- }
74
- const params = new URLSearchParams({
75
- chainId: String(chainId),
76
- sellToken,
77
- buyToken,
78
- sellAmount: String(sellAmount),
79
- });
80
- if (taker) params.set("taker", taker);
81
- return httpJson(`${base(opts)}/swap/allowance-holder/price?${params}`, {
82
- headers: headers(opts),
83
- fetchImpl: opts.fetchImpl,
84
- timeoutMs: opts.timeoutMs ?? 15_000,
85
- });
86
- }
87
-
88
- /** Firm quote (may include transaction). */
89
- export async function zeroxQuote(q = {}, opts = {}) {
90
- if (!apiKey(opts)) throw new Error("ZEROX_API_KEY required for 0x");
91
- const {
92
- chainId = 8453,
93
- sellToken,
94
- buyToken,
95
- sellAmount,
96
- taker,
97
- } = q;
98
- if (!sellToken || !buyToken || !sellAmount) {
99
- throw new Error("zeroxQuote requires sellToken, buyToken, sellAmount");
100
- }
101
- const selected = resolveAutoSlippage({
102
- liquidityUsd: q.liquidityUsd,
103
- priceChange5m: q.priceChange5m,
104
- requestedCapBps: q.maxSlippageBps ?? q.slippageBps,
105
- });
106
- if (!selected.executable) {
107
- throw new Error(`0x: route requires ${selected.requiredBps} bps above cap ${selected.capBps}`);
108
- }
109
- const params = new URLSearchParams({
110
- chainId: String(chainId),
111
- sellToken,
112
- buyToken,
113
- sellAmount: String(sellAmount),
114
- slippageBps: String(selected.selectedBps),
115
- });
116
- if (taker) params.set("taker", taker);
117
- const result = await httpJson(`${base(opts)}/swap/allowance-holder/quote?${params}`, {
118
- headers: headers(opts),
119
- fetchImpl: opts.fetchImpl,
120
- timeoutMs: opts.timeoutMs ?? 15_000,
121
- });
122
- const amountOut = result?.buyAmount || result?.grossBuyAmount;
123
- if (!amountOut) return { ...result, autoSlippagePolicy: selected };
124
- return attachAutoSlippage(result, {
125
- chainId,
126
- venue: result?.transaction?.to || result?.to || "0x",
127
- amountOut,
128
- liquidityUsd: q.liquidityUsd,
129
- priceChange5m: q.priceChange5m,
130
- requestedCapBps: q.maxSlippageBps ?? q.slippageBps,
131
- });
132
- }
133
-
134
- export async function zeroxPrepare(q = {}, opts = {}) {
135
- if (!q.taker) throw new Error("0x: taker required for executable prepare");
136
- const quote = await zeroxQuote(q, opts);
137
- const tx = quote?.transaction;
138
- if (!tx?.to || !tx?.data) throw new Error("0x: firm quote returned no transaction");
139
- const chainId = Number(q.chainId ?? 8453);
140
- const spender = quote?.issues?.allowance?.spender || quote?.allowanceTarget;
141
- return stampPrepared({
142
- provider: "zerox",
143
- calldataReady: true,
144
- // NOT executable authority. The bytes are assembled but nothing is signed:
145
- // the user's wallet is still the only thing that can authorize this. The
146
- // previous `executionReady: true` read as "cleared to execute" and trained
147
- // agents to treat a quote as permission.
148
- requiresUserSignature: true,
149
- signingReady: false,
150
- broadcastReady: false,
151
- chainId,
152
- quote,
153
- autoSlippage: quote.autoSlippage,
154
- requiresApproval: quote?.issues?.allowance?.actual != null && BigInt(quote.issues.allowance.actual) < BigInt(q.sellAmount)
155
- ? { token: q.sellToken, spender, amount: String(q.sellAmount) }
156
- : null,
157
- transaction: {
158
- chainId,
159
- from: q.taker,
160
- to: tx.to,
161
- data: tx.data,
162
- value: tx.value ?? "0x0",
163
- ...(tx.gas != null ? { gasLimit: tx.gas } : {}),
164
- slippageGuard: bindAutoSlippageGuardToCall(quote.autoSlippage, { chainId, venue: tx.to, data: tx.data }),
165
- },
166
- }, { provider: "zerox", kind: "zerox-tx" });
167
- }
@@ -1,61 +0,0 @@
1
- import { dataCatalog, dataHealth } from "./desk-data.mjs";
2
-
3
- export const COVERED_CHAINS = Object.freeze({
4
- 1: "Ethereum",
5
- 10: "Optimism",
6
- 56: "BNB Chain",
7
- 137: "Polygon",
8
- 988: "Stable",
9
- 999: "HyperEVM",
10
- 2741: "Abstract",
11
- 4663: "Robinhood Chain",
12
- 8453: "Base",
13
- 42161: "Arbitrum",
14
- 43114: "Avalanche",
15
- });
16
-
17
- function providerStatus(record) {
18
- if (!record) return "not-probed";
19
- if (!record.ok) return "down";
20
- if (record.detail?.configured === false) return "key-missing";
21
- if (record.detail?.ok === false) return "degraded";
22
- return "healthy";
23
- }
24
-
25
- export function buildPublicApiCoverage(catalog, health) {
26
- const globals = catalog.filter((p) => !p.chainIds.length).map((p) => p.id);
27
- const providers = Object.fromEntries(catalog.map((p) => [p.id, {
28
- venue: p.venue,
29
- auth: p.auth,
30
- chainIds: p.chainIds,
31
- ops: p.ops,
32
- description: p.description,
33
- status: providerStatus(health?.providers?.[p.id]),
34
- probe: health?.providers?.[p.id] || null,
35
- }]));
36
- const chains = {};
37
- for (const [chainId, name] of Object.entries(COVERED_CHAINS)) {
38
- const id = Number(chainId);
39
- const explicit = catalog.filter((p) => p.chainIds.includes(id)).map((p) => p.id);
40
- chains[chainId] = {
41
- name,
42
- providers: [...new Set([...globals, ...explicit])],
43
- explicitProviders: explicit,
44
- failClosed: explicit.length === 0,
45
- };
46
- }
47
- return {
48
- generatedAt: health?.when || new Date().toISOString(),
49
- coveredChainCount: Object.keys(COVERED_CHAINS).length,
50
- providerCount: catalog.length,
51
- globals,
52
- chains,
53
- providers,
54
- };
55
- }
56
-
57
- export async function scanPublicApis({ providers, timeoutMs = 12_000 } = {}) {
58
- const catalog = dataCatalog();
59
- const health = await dataHealth({ providers, timeoutMs });
60
- return buildPublicApiCoverage(catalog, health);
61
- }
@@ -1,31 +0,0 @@
1
- // Placeholder addresses for quote-only provider calls.
2
- //
3
- // Several aggregator APIs (LI.FI, CoW, bridge quoters) require a `from`/`user`
4
- // address to price a route, even when nothing will be signed. Hardcoding a real
5
- // operator wallet as that default is a privacy and correctness bug: public users
6
- // would silently quote against someone else's account, and balance-aware routers
7
- // can return routes tailored to that stranger's holdings.
8
- //
9
- // So: callers SHOULD pass their own address. When they don't, we fall back to a
10
- // well-known burn/zero-ish placeholder that holds nothing and signs nothing.
11
- //
12
- // vitalik.eth is deliberately NOT used here either -- a placeholder must be
13
- // obviously inert, not a real person's account.
14
-
15
- /**
16
- * ERC-191 "dead" address. Universally recognizable as a placeholder, holds no
17
- * meaningful balance, and cannot sign. Safe default for price-only queries.
18
- */
19
- export const QUOTE_PLACEHOLDER_ADDRESS =
20
- "0x000000000000000000000000000000000000dEaD";
21
-
22
- /**
23
- * Resolve the address to use for a quote-only request.
24
- *
25
- * @param {string} [preferred] caller-supplied address (their own wallet)
26
- * @returns {string} the caller's address when usable, else the inert placeholder
27
- */
28
- export function quoteAddress(preferred) {
29
- const v = String(preferred || "").trim();
30
- return /^0x[0-9a-fA-F]{40}$/.test(v) ? v : QUOTE_PLACEHOLDER_ADDRESS;
31
- }