@oracle-agent/oracle 0.13.0 → 0.14.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 (629) hide show
  1. package/CONTRIBUTING.md +99 -0
  2. package/README.md +531 -13
  3. package/SECURITY.md +112 -0
  4. package/SETUP.md +317 -0
  5. package/artifacts/inscription/oracle-was-here-preview.png +0 -0
  6. package/artifacts/inscription/oracle-was-here.svg +1 -0
  7. package/artifacts/specialist-packs/oracle-full-crypto.json +298 -0
  8. package/bin/desk-server.mjs +473 -0
  9. package/bin/oracle-data-mcp.mjs +1252 -0
  10. package/bin/oracle-equities.mjs +168 -0
  11. package/bin/oracle-init.mjs +525 -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/bin/oracle-upgrade.mjs +42 -0
  16. package/bin/oracle.mjs +28 -19
  17. package/docs/adding-a-chain.md +229 -0
  18. package/docs/architecture.md +139 -0
  19. package/docs/buzz-integration.md +115 -0
  20. package/docs/cli.md +143 -0
  21. package/docs/connectors.md +13 -0
  22. package/docs/hyperliquid-builder-code.md +50 -0
  23. package/docs/locals-only-fee-waiver.md +34 -0
  24. package/docs/oracle-pack-standard.md +29 -0
  25. package/docs/profiles.md +151 -0
  26. package/docs/public-surface.md +206 -0
  27. package/examples/add-a-chain.mjs +65 -0
  28. package/examples/oracle-pack-template.mjs +38 -0
  29. package/examples/research-a-token.mjs +70 -0
  30. package/package.json +110 -14
  31. package/plugins/oracle-owner-gate/__init__.py +288 -0
  32. package/plugins/oracle-owner-gate/plugin.yaml +9 -0
  33. package/profiles/_template/SOUL.md +54 -0
  34. package/profiles/_template/profile.json +22 -0
  35. package/profiles/bitcoin-agent/SOUL.md +31 -0
  36. package/profiles/bitcoin-agent/profile.json +32 -0
  37. package/profiles/hyperliquid-agent/SOUL.md +34 -0
  38. package/profiles/hyperliquid-agent/profile.json +38 -0
  39. package/profiles/oracle/SOUL.md +120 -0
  40. package/profiles/oracle/profile.json +40 -0
  41. package/profiles/polymarket-agent/SOUL.md +35 -0
  42. package/profiles/polymarket-agent/profile.json +34 -0
  43. package/profiles/profile.schema.json +90 -0
  44. package/profiles/protocol-builder/SOUL.md +57 -0
  45. package/profiles/protocol-builder/profile.json +39 -0
  46. package/profiles/robinhood-agent/SOUL.md +53 -0
  47. package/profiles/robinhood-agent/profile.json +41 -0
  48. package/profiles/solana-agent/SOUL.md +37 -0
  49. package/profiles/solana-agent/profile.json +38 -0
  50. package/profiles/stable-agent/SOUL.md +43 -0
  51. package/profiles/stable-agent/profile.json +38 -0
  52. package/protocols/templates/safe-erc20/SECURITY.md +16 -0
  53. package/protocols/templates/safe-erc20/foundry.toml +12 -0
  54. package/protocols/templates/safe-erc20/remappings.txt +2 -0
  55. package/protocols/templates/safe-erc20/src/SafeERC20.sol +53 -0
  56. package/protocols/templates/safe-erc20/test/SafeERC20.t.sol +72 -0
  57. package/public/agent-connect/app.js +84 -0
  58. package/public/agent-connect/index.html +83 -0
  59. package/public/agent-connect/styles.css +70 -0
  60. package/public/index.html +12 -0
  61. package/public/oracle-console/app.js +272 -0
  62. package/public/oracle-console/bitcoin-wallets.js +206 -0
  63. package/public/oracle-console/index.html +91 -0
  64. package/public/oracle-console/styles.css +239 -0
  65. package/public/oracle-splash/_variants/ice.html +2073 -0
  66. package/public/oracle-splash/_variants/ivory.html +2075 -0
  67. package/public/oracle-splash/assets/agents/claude.png +0 -0
  68. package/public/oracle-splash/assets/agents/codex.png +0 -0
  69. package/public/oracle-splash/assets/cli-chain-hyperliquid.jpg +0 -0
  70. package/public/oracle-splash/assets/desktop-app.jpg +0 -0
  71. package/public/oracle-splash/assets/hero/cli-session-poster.jpg +0 -0
  72. package/public/oracle-splash/assets/hero/cli-session.mp4 +0 -0
  73. package/public/oracle-splash/assets/hero/cli-session.webm +0 -0
  74. package/public/oracle-splash/assets/hero/orb-poster.jpg +0 -0
  75. package/public/oracle-splash/assets/hero/orb.avif +0 -0
  76. package/public/oracle-splash/assets/hero/orb.webm +0 -0
  77. package/public/oracle-splash/assets/hero/risk-session-poster.jpg +0 -0
  78. package/public/oracle-splash/assets/hero/risk-session.mp4 +0 -0
  79. package/public/oracle-splash/assets/hero/risk-session.webm +0 -0
  80. package/public/oracle-splash/assets/hero/route-session-poster.jpg +0 -0
  81. package/public/oracle-splash/assets/hero/route-session.mp4 +0 -0
  82. package/public/oracle-splash/assets/hero/route-session.webm +0 -0
  83. package/public/oracle-splash/assets/llms/claude.svg +1 -0
  84. package/public/oracle-splash/assets/llms/codex-icon.svg +1 -0
  85. package/public/oracle-splash/assets/llms/codex.svg +1 -0
  86. package/public/oracle-splash/assets/llms/cursor-icon.svg +12 -0
  87. package/public/oracle-splash/assets/llms/cursor.svg +17 -0
  88. package/public/oracle-splash/assets/llms/deepseek.svg +1 -0
  89. package/public/oracle-splash/assets/llms/gemini-icon.svg +1 -0
  90. package/public/oracle-splash/assets/llms/gemini.svg +1 -0
  91. package/public/oracle-splash/assets/llms/grok.svg +8 -0
  92. package/public/oracle-splash/assets/llms/hermes.png +0 -0
  93. package/public/oracle-splash/assets/llms/kimi-icon.svg +1 -0
  94. package/public/oracle-splash/assets/llms/kimi.svg +1 -0
  95. package/public/oracle-splash/assets/llms/manus.svg +18 -0
  96. package/public/oracle-splash/assets/llms/openclaw.svg +22 -0
  97. package/public/oracle-splash/assets/llms/perplexity.svg +1 -0
  98. package/public/oracle-splash/assets/llms/qwen.svg +1 -0
  99. package/public/oracle-splash/assets/llms/windsurf.svg +1 -0
  100. package/public/oracle-splash/assets/protocols/abcdex.png +0 -0
  101. package/public/oracle-splash/assets/protocols/across.png +0 -0
  102. package/public/oracle-splash/assets/protocols/aerodrome.png +0 -0
  103. package/public/oracle-splash/assets/protocols/balancer.png +0 -0
  104. package/public/oracle-splash/assets/protocols/cowswap.png +0 -0
  105. package/public/oracle-splash/assets/protocols/curve.png +0 -0
  106. package/public/oracle-splash/assets/protocols/dreamcash.png +0 -0
  107. package/public/oracle-splash/assets/protocols/felix.png +0 -0
  108. package/public/oracle-splash/assets/protocols/gmx.png +0 -0
  109. package/public/oracle-splash/assets/protocols/hyena.png +0 -0
  110. package/public/oracle-splash/assets/protocols/hyperbeat.png +0 -0
  111. package/public/oracle-splash/assets/protocols/hyperliquid.png +0 -0
  112. package/public/oracle-splash/assets/protocols/hyperswap.png +0 -0
  113. package/public/oracle-splash/assets/protocols/jupiter.png +0 -0
  114. package/public/oracle-splash/assets/protocols/kinetiq.png +0 -0
  115. package/public/oracle-splash/assets/protocols/lfj.png +0 -0
  116. package/public/oracle-splash/assets/protocols/lifi.png +0 -0
  117. package/public/oracle-splash/assets/protocols/magic-eden.png +0 -0
  118. package/public/oracle-splash/assets/protocols/morpho.png +0 -0
  119. package/public/oracle-splash/assets/protocols/odos.png +0 -0
  120. package/public/oracle-splash/assets/protocols/oneinch.png +0 -0
  121. package/public/oracle-splash/assets/protocols/opensea.png +0 -0
  122. package/public/oracle-splash/assets/protocols/pancakeswap.png +0 -0
  123. package/public/oracle-splash/assets/protocols/paragon.png +0 -0
  124. package/public/oracle-splash/assets/protocols/paraswap.png +0 -0
  125. package/public/oracle-splash/assets/protocols/pendle.png +0 -0
  126. package/public/oracle-splash/assets/protocols/polymarket.png +0 -0
  127. package/public/oracle-splash/assets/protocols/quickswap.png +0 -0
  128. package/public/oracle-splash/assets/protocols/relay.png +0 -0
  129. package/public/oracle-splash/assets/protocols/stargate.png +0 -0
  130. package/public/oracle-splash/assets/protocols/tradexyz.png +0 -0
  131. package/public/oracle-splash/assets/protocols/uniswap.png +0 -0
  132. package/public/oracle-splash/assets/protocols/velodrome.png +0 -0
  133. package/public/oracle-splash/assets/protocols/ventuals.png +0 -0
  134. package/public/oracle-splash/assets/wordmarks/across-icon.webp +0 -0
  135. package/public/oracle-splash/assets/wordmarks/across.svg +4 -0
  136. package/public/oracle-splash/assets/wordmarks/aerodrome.svg +23 -0
  137. package/public/oracle-splash/assets/wordmarks/balancer.svg +3 -0
  138. package/public/oracle-splash/assets/wordmarks/cowswap.svg +1 -0
  139. package/public/oracle-splash/assets/wordmarks/curve.png +0 -0
  140. package/public/oracle-splash/assets/wordmarks/gmx.svg +13 -0
  141. package/public/oracle-splash/assets/wordmarks/hop-icon.webp +0 -0
  142. package/public/oracle-splash/assets/wordmarks/hyena.svg +7 -0
  143. package/public/oracle-splash/assets/wordmarks/hyperliquid.svg +21 -0
  144. package/public/oracle-splash/assets/wordmarks/hyperswap.svg +13 -0
  145. package/public/oracle-splash/assets/wordmarks/jupiter.svg +35 -0
  146. package/public/oracle-splash/assets/wordmarks/kinetiq.svg +1 -0
  147. package/public/oracle-splash/assets/wordmarks/lfj.webp +0 -0
  148. package/public/oracle-splash/assets/wordmarks/lifi.png +0 -0
  149. package/public/oracle-splash/assets/wordmarks/magic-eden.svg +1 -0
  150. package/public/oracle-splash/assets/wordmarks/markets.svg +1 -0
  151. package/public/oracle-splash/assets/wordmarks/morpho.svg +1 -0
  152. package/public/oracle-splash/assets/wordmarks/odos.svg +3 -0
  153. package/public/oracle-splash/assets/wordmarks/oneinch-icon.webp +0 -0
  154. package/public/oracle-splash/assets/wordmarks/oneinch.svg +6 -0
  155. package/public/oracle-splash/assets/wordmarks/opensea-icon.svg +17 -0
  156. package/public/oracle-splash/assets/wordmarks/opensea.svg +1 -0
  157. package/public/oracle-splash/assets/wordmarks/outcome.svg +16 -0
  158. package/public/oracle-splash/assets/wordmarks/pancakeswap.svg +18 -0
  159. package/public/oracle-splash/assets/wordmarks/paragon.svg +9 -0
  160. package/public/oracle-splash/assets/wordmarks/paraswap.svg +16 -0
  161. package/public/oracle-splash/assets/wordmarks/pendle.png +0 -0
  162. package/public/oracle-splash/assets/wordmarks/polymarket.png +0 -0
  163. package/public/oracle-splash/assets/wordmarks/quickswap.png +0 -0
  164. package/public/oracle-splash/assets/wordmarks/relay.svg +8 -0
  165. package/public/oracle-splash/assets/wordmarks/satflow-icon.png +0 -0
  166. package/public/oracle-splash/assets/wordmarks/stargate-icon.webp +0 -0
  167. package/public/oracle-splash/assets/wordmarks/stargate.svg +15 -0
  168. package/public/oracle-splash/assets/wordmarks/uniswap.svg +18 -0
  169. package/public/oracle-splash/assets/wordmarks/velodrome.svg +84 -0
  170. package/public/oracle-splash/assets/wordmarks/xyz.svg +12 -0
  171. package/public/oracle-splash/assets/wordmarks/zerox-icon.webp +0 -0
  172. package/public/oracle-splash/brand/aave.webp +0 -0
  173. package/public/oracle-splash/brand/aavev2.webp +0 -0
  174. package/public/oracle-splash/brand/aborean.webp +0 -0
  175. package/public/oracle-splash/brand/across.webp +0 -0
  176. package/public/oracle-splash/brand/aerodrome.webp +0 -0
  177. package/public/oracle-splash/brand/afi.webp +0 -0
  178. package/public/oracle-splash/brand/arcus.webp +0 -0
  179. package/public/oracle-splash/brand/aster.webp +0 -0
  180. package/public/oracle-splash/brand/avant.webp +0 -0
  181. package/public/oracle-splash/brand/balancer.webp +0 -0
  182. package/public/oracle-splash/brand/beefy.webp +0 -0
  183. package/public/oracle-splash/brand/benqi.webp +0 -0
  184. package/public/oracle-splash/brand/bestinslot.ico +0 -0
  185. package/public/oracle-splash/brand/bitfi.webp +0 -0
  186. package/public/oracle-splash/brand/bonkswap.webp +0 -0
  187. package/public/oracle-splash/brand/bouncebit.webp +0 -0
  188. package/public/oracle-splash/brand/camelot.webp +0 -0
  189. package/public/oracle-splash/brand/compound.webp +0 -0
  190. package/public/oracle-splash/brand/concrete.webp +0 -0
  191. package/public/oracle-splash/brand/cow.webp +0 -0
  192. package/public/oracle-splash/brand/curve.webp +0 -0
  193. package/public/oracle-splash/brand/derive.webp +0 -0
  194. package/public/oracle-splash/brand/dolomite.webp +0 -0
  195. package/public/oracle-splash/brand/eigenlayer.webp +0 -0
  196. package/public/oracle-splash/brand/ekubo.webp +0 -0
  197. package/public/oracle-splash/brand/ethena.webp +0 -0
  198. package/public/oracle-splash/brand/etherfi.webp +0 -0
  199. package/public/oracle-splash/brand/etherfiborrow.webp +0 -0
  200. package/public/oracle-splash/brand/felix.webp +0 -0
  201. package/public/oracle-splash/brand/fluid.webp +0 -0
  202. package/public/oracle-splash/brand/fluxbeam.webp +0 -0
  203. package/public/oracle-splash/brand/folks.webp +0 -0
  204. package/public/oracle-splash/brand/fortyacres.webp +0 -0
  205. package/public/oracle-splash/brand/gainsnetwork.webp +0 -0
  206. package/public/oracle-splash/brand/gassss.webp +0 -0
  207. package/public/oracle-splash/brand/gmx.webp +0 -0
  208. package/public/oracle-splash/brand/harmonix.webp +0 -0
  209. package/public/oracle-splash/brand/hlorderbook.webp +0 -0
  210. package/public/oracle-splash/brand/hlp.webp +0 -0
  211. package/public/oracle-splash/brand/hop.webp +0 -0
  212. package/public/oracle-splash/brand/hyperbeat.webp +0 -0
  213. package/public/oracle-splash/brand/hyperlend.webp +0 -0
  214. package/public/oracle-splash/brand/hyperliquid.webp +0 -0
  215. package/public/oracle-splash/brand/hyperliquidhpl.webp +0 -0
  216. package/public/oracle-splash/brand/hyperliquidspot.webp +0 -0
  217. package/public/oracle-splash/brand/hyperswap.webp +0 -0
  218. package/public/oracle-splash/brand/hypha.webp +0 -0
  219. package/public/oracle-splash/brand/joedex.webp +0 -0
  220. package/public/oracle-splash/brand/jupiter.webp +0 -0
  221. package/public/oracle-splash/brand/kelp.webp +0 -0
  222. package/public/oracle-splash/brand/kinetiq.webp +0 -0
  223. package/public/oracle-splash/brand/kmhype.webp +0 -0
  224. package/public/oracle-splash/brand/kona.webp +0 -0
  225. package/public/oracle-splash/brand/konalend.webp +0 -0
  226. package/public/oracle-splash/brand/lfj.webp +0 -0
  227. package/public/oracle-splash/brand/lido.webp +0 -0
  228. package/public/oracle-splash/brand/lifi.webp +0 -0
  229. package/public/oracle-splash/brand/lighter.webp +0 -0
  230. package/public/oracle-splash/brand/lista.webp +0 -0
  231. package/public/oracle-splash/brand/loopedhype.webp +0 -0
  232. package/public/oracle-splash/brand/lorenzo.webp +0 -0
  233. package/public/oracle-splash/brand/magic-eden.webp +0 -0
  234. package/public/oracle-splash/brand/magiceden.webp +0 -0
  235. package/public/oracle-splash/brand/mempool.png +0 -0
  236. package/public/oracle-splash/brand/meteora.webp +0 -0
  237. package/public/oracle-splash/brand/morpho.webp +0 -0
  238. package/public/oracle-splash/brand/myriad.webp +0 -0
  239. package/public/oracle-splash/brand/noxa.webp +0 -0
  240. package/public/oracle-splash/brand/odos.webp +0 -0
  241. package/public/oracle-splash/brand/oneinch.webp +0 -0
  242. package/public/oracle-splash/brand/openbook.webp +0 -0
  243. package/public/oracle-splash/brand/opensea.webp +0 -0
  244. package/public/oracle-splash/brand/orca.webp +0 -0
  245. package/public/oracle-splash/brand/ordinals.png +0 -0
  246. package/public/oracle-splash/brand/ostium.webp +0 -0
  247. package/public/oracle-splash/brand/pancakeswap.webp +0 -0
  248. package/public/oracle-splash/brand/pendle.webp +0 -0
  249. package/public/oracle-splash/brand/perena.webp +0 -0
  250. package/public/oracle-splash/brand/pharaoh.webp +0 -0
  251. package/public/oracle-splash/brand/phoenix.webp +0 -0
  252. package/public/oracle-splash/brand/polymarket.webp +0 -0
  253. package/public/oracle-splash/brand/polynomial.webp +0 -0
  254. package/public/oracle-splash/brand/projectx.webp +0 -0
  255. package/public/oracle-splash/brand/pumpfun.webp +0 -0
  256. package/public/oracle-splash/brand/quickswap.webp +0 -0
  257. package/public/oracle-splash/brand/rain.webp +0 -0
  258. package/public/oracle-splash/brand/raydium.webp +0 -0
  259. package/public/oracle-splash/brand/relay.webp +0 -0
  260. package/public/oracle-splash/brand/rocketpool.webp +0 -0
  261. package/public/oracle-splash/brand/saber.webp +0 -0
  262. package/public/oracle-splash/brand/sakuraswap.webp +0 -0
  263. package/public/oracle-splash/brand/sanctum.webp +0 -0
  264. package/public/oracle-splash/brand/satflow.png +0 -0
  265. package/public/oracle-splash/brand/sierra.webp +0 -0
  266. package/public/oracle-splash/brand/sky.webp +0 -0
  267. package/public/oracle-splash/brand/solv.webp +0 -0
  268. package/public/oracle-splash/brand/spark.webp +0 -0
  269. package/public/oracle-splash/brand/sparksavings.webp +0 -0
  270. package/public/oracle-splash/brand/sphere.webp +0 -0
  271. package/public/oracle-splash/brand/ssv.webp +0 -0
  272. package/public/oracle-splash/brand/stabble.webp +0 -0
  273. package/public/oracle-splash/brand/stableswap.webp +0 -0
  274. package/public/oracle-splash/brand/stakewise.webp +0 -0
  275. package/public/oracle-splash/brand/stargate.webp +0 -0
  276. package/public/oracle-splash/brand/sthype.webp +0 -0
  277. package/public/oracle-splash/brand/sushiswap.webp +0 -0
  278. package/public/oracle-splash/brand/unisat.png +0 -0
  279. package/public/oracle-splash/brand/uniswap.webp +0 -0
  280. package/public/oracle-splash/brand/uniswapv2.webp +0 -0
  281. package/public/oracle-splash/brand/uniswapv4.webp +0 -0
  282. package/public/oracle-splash/brand/unit.webp +0 -0
  283. package/public/oracle-splash/brand/velodrome.webp +0 -0
  284. package/public/oracle-splash/brand/velora.webp +0 -0
  285. package/public/oracle-splash/brand/venus.webp +0 -0
  286. package/public/oracle-splash/brand/wbeth.webp +0 -0
  287. package/public/oracle-splash/brand/xsy.webp +0 -0
  288. package/public/oracle-splash/brand/yieldyak.webp +0 -0
  289. package/public/oracle-splash/brand/zerobase.webp +0 -0
  290. package/public/oracle-splash/brand/zerox.webp +0 -0
  291. package/public/oracle-splash/downloads/index.html +52 -0
  292. package/public/oracle-splash/favicon.ico +0 -0
  293. package/public/oracle-splash/favicon.svg +6 -0
  294. package/public/oracle-splash/index.html +2537 -0
  295. package/public/oracle-splash/mesh-graph.png +0 -0
  296. package/public/oracle-splash/mesh-graph.svg +216 -0
  297. package/scripts/adversarial-bench.mjs +114 -0
  298. package/scripts/build-dist.mjs +119 -0
  299. package/scripts/build-inscription.py +230 -0
  300. package/scripts/check-doc-drift.mjs +123 -0
  301. package/scripts/check-test-count.mjs +105 -0
  302. package/scripts/e2e-hl-markets.mjs +21 -0
  303. package/scripts/e2e-hl-perps.mjs +48 -0
  304. package/scripts/e2e-hypercore-staking.mjs +128 -0
  305. package/scripts/e2e-solana-bitcoin.mjs +183 -0
  306. package/scripts/guard-publish.mjs +22 -0
  307. package/scripts/protocol-template-gate.mjs +15 -0
  308. package/scripts/public-api-scan.mjs +23 -0
  309. package/scripts/publish-dist.mjs +67 -0
  310. package/scripts/record-hero-cli.sh +80 -0
  311. package/scripts/secret-scan.mjs +168 -0
  312. package/scripts/smoke-dist-bins.mjs +89 -0
  313. package/scripts/verify-dist.mjs +29 -0
  314. package/scripts/verify-v3-venues.mjs +233 -0
  315. package/skills/balance/SKILL.md +176 -0
  316. package/skills/bitcoin-l1.md +33 -0
  317. package/skills/chain-defi-ecosystem-profiling.md +27 -0
  318. package/skills/evm-contract-research.md +27 -0
  319. package/skills/hyperliquid.md +26 -0
  320. package/skills/multichain-exec-desk.md +33 -0
  321. package/skills/oracle-action-semantics/SKILL.md +40 -0
  322. package/skills/oracle-best-execution/SKILL.md +127 -0
  323. package/skills/oracle-best-execution.md +27 -0
  324. package/skills/oracle-bitcoin/SKILL.md +53 -0
  325. package/skills/oracle-chain-graphs-telegram-cards/SKILL.md +59 -0
  326. package/skills/oracle-chat/SKILL.md +61 -0
  327. package/skills/oracle-chat/chain.SKILL.md +31 -0
  328. package/skills/oracle-chat/setup.SKILL.md +37 -0
  329. package/skills/oracle-circuit-breaker/SKILL.md +51 -0
  330. package/skills/oracle-contract-research/SKILL.md +55 -0
  331. package/skills/oracle-desk/SKILL.md +58 -0
  332. package/skills/oracle-desk.md +27 -0
  333. package/skills/oracle-dex-launch/SKILL.md +38 -0
  334. package/skills/oracle-equities/SKILL.md +62 -0
  335. package/skills/oracle-grants/SKILL.md +69 -0
  336. package/skills/oracle-hypercore-staking/SKILL.md +57 -0
  337. package/skills/oracle-hyperliquid/SKILL.md +56 -0
  338. package/skills/oracle-meme-token-sniper/SKILL.md +73 -0
  339. package/skills/oracle-multichain-nft-launch/SKILL.md +338 -0
  340. package/skills/oracle-multichain-token-launch/SKILL.md +300 -0
  341. package/skills/oracle-nft-gacha-launch/SKILL.md +48 -0
  342. package/skills/oracle-nft-mint-gas-war/SKILL.md +63 -0
  343. package/skills/oracle-polymarket/SKILL.md +60 -0
  344. package/skills/oracle-protocol-builder/SKILL.md +59 -0
  345. package/skills/oracle-protocol-security/SKILL.md +60 -0
  346. package/skills/oracle-public-product/SKILL.md +44 -0
  347. package/skills/oracle-receipts/SKILL.md +52 -0
  348. package/skills/oracle-receipts.md +29 -0
  349. package/skills/oracle-rfq-tokenized-assets/SKILL.md +69 -0
  350. package/skills/oracle-smart-wallet-scanner/SKILL.md +49 -0
  351. package/skills/oracle-solana/SKILL.md +65 -0
  352. package/skills/oracle-solana-nft/SKILL.md +54 -0
  353. package/skills/oracle-token-research/SKILL.md +67 -0
  354. package/skills/solana.md +22 -0
  355. package/skins/oracle.yaml +56 -0
  356. package/src/action-receipts.mjs +265 -0
  357. package/src/action-semantics.mjs +62 -0
  358. package/src/address-book.mjs +208 -0
  359. package/src/agent-auth.mjs +206 -0
  360. package/src/approval-guard.mjs +282 -0
  361. package/src/attestation-secret.mjs +94 -0
  362. package/src/audit-log.mjs +196 -0
  363. package/src/auth/oauth.mjs +672 -0
  364. package/src/auto-slippage.mjs +378 -0
  365. package/src/capability-posture.mjs +125 -0
  366. package/src/cards.mjs +422 -0
  367. package/src/chains.mjs +62 -0
  368. package/src/cli/chain-catalog.mjs +215 -0
  369. package/src/cli/chain-state.mjs +74 -0
  370. package/src/cli/commands/auth.mjs +193 -0
  371. package/src/cli/commands/bootstrap.mjs +87 -0
  372. package/src/cli/commands/chain.mjs +143 -0
  373. package/src/cli/commands/chat.mjs +465 -0
  374. package/src/cli/commands/credential.mjs +9 -0
  375. package/src/cli/commands/data-mcp.mjs +18 -0
  376. package/src/cli/commands/data.mjs +75 -0
  377. package/src/cli/commands/doctor.mjs +136 -0
  378. package/src/cli/commands/equities.mjs +41 -0
  379. package/src/cli/commands/farm.mjs +129 -0
  380. package/src/cli/commands/fees.mjs +109 -0
  381. package/src/cli/commands/follow.mjs +130 -0
  382. package/src/cli/commands/harness.mjs +63 -0
  383. package/src/cli/commands/help.mjs +7 -0
  384. package/src/cli/commands/init.mjs +27 -0
  385. package/src/cli/commands/mcp.mjs +154 -0
  386. package/src/cli/commands/model.mjs +106 -0
  387. package/src/cli/commands/plugins.mjs +241 -0
  388. package/src/cli/commands/prepare.mjs +12 -0
  389. package/src/cli/commands/public.mjs +20 -0
  390. package/src/cli/commands/resolve.mjs +64 -0
  391. package/src/cli/commands/route.mjs +12 -0
  392. package/src/cli/commands/runner.mjs +9 -0
  393. package/src/cli/commands/scan.mjs +12 -0
  394. package/src/cli/commands/setup.mjs +294 -0
  395. package/src/cli/commands/sign.mjs +21 -0
  396. package/src/cli/commands/signer.mjs +9 -0
  397. package/src/cli/commands/swap.mjs +102 -0
  398. package/src/cli/commands/upgrade.mjs +12 -0
  399. package/src/cli/commands/vault.mjs +9 -0
  400. package/src/cli/commands/version.mjs +22 -0
  401. package/src/cli/first-run.mjs +23 -0
  402. package/src/cli/kernel.mjs +262 -0
  403. package/src/cli/mcp-targets/chatgpt.mjs +51 -0
  404. package/src/cli/mcp-targets/claude-code.mjs +39 -0
  405. package/src/cli/mcp-targets/claude-desktop.mjs +24 -0
  406. package/src/cli/mcp-targets/codex.mjs +41 -0
  407. package/src/cli/mcp-targets/cursor.mjs +32 -0
  408. package/src/cli/mcp-targets/shared.mjs +71 -0
  409. package/src/cli/mcp-targets/vscode.mjs +39 -0
  410. package/src/cli/messaging-platforms.mjs +217 -0
  411. package/src/cli/model-config.mjs +78 -0
  412. package/src/cli/operator-dispatch.mjs +257 -0
  413. package/src/cli/oracle-harness.py +415 -0
  414. package/src/cli/paths.mjs +107 -0
  415. package/src/cli/runtime.mjs +351 -0
  416. package/src/cli/setup-state.mjs +168 -0
  417. package/src/cli/spawn-child.mjs +43 -0
  418. package/src/data/catalog.mjs +858 -0
  419. package/src/data/desk-data.mjs +877 -0
  420. package/src/data/http.mjs +253 -0
  421. package/src/data/names.mjs +188 -0
  422. package/src/data/provider-endpoint.mjs +94 -0
  423. package/src/data/providers/aave-v3.mjs +139 -0
  424. package/src/data/providers/across-bridge.mjs +41 -0
  425. package/src/data/providers/aerodrome.mjs +245 -0
  426. package/src/data/providers/aevo.mjs +33 -0
  427. package/src/data/providers/approval-indexer.mjs +133 -0
  428. package/src/data/providers/approvals.mjs +594 -0
  429. package/src/data/providers/babylon-staking.mjs +149 -0
  430. package/src/data/providers/balancer.mjs +209 -0
  431. package/src/data/providers/beefy-yields.mjs +45 -0
  432. package/src/data/providers/birdeye-tokens.mjs +33 -0
  433. package/src/data/providers/bisq-markets.mjs +145 -0
  434. package/src/data/providers/bitcoin-esplora.mjs +216 -0
  435. package/src/data/providers/bitcoin-meta.mjs +378 -0
  436. package/src/data/providers/blockscout.mjs +14 -0
  437. package/src/data/providers/bob-rootstock.mjs +198 -0
  438. package/src/data/providers/braiins-insights.mjs +103 -0
  439. package/src/data/providers/bridge-aggregator.mjs +259 -0
  440. package/src/data/providers/bridges.mjs +242 -0
  441. package/src/data/providers/bungee.mjs +29 -0
  442. package/src/data/providers/celestia-da.mjs +38 -0
  443. package/src/data/providers/changenow.mjs +135 -0
  444. package/src/data/providers/compound.mjs +32 -0
  445. package/src/data/providers/connext.mjs +28 -0
  446. package/src/data/providers/convex.mjs +30 -0
  447. package/src/data/providers/cow-protocol.mjs +110 -0
  448. package/src/data/providers/cowswap.mjs +415 -0
  449. package/src/data/providers/curve.mjs +201 -0
  450. package/src/data/providers/das-assets.mjs +59 -0
  451. package/src/data/providers/debridge.mjs +109 -0
  452. package/src/data/providers/defillama.mjs +88 -0
  453. package/src/data/providers/dexscreener.mjs +43 -0
  454. package/src/data/providers/drift.mjs +32 -0
  455. package/src/data/providers/dydx.mjs +41 -0
  456. package/src/data/providers/evm-rpc.mjs +225 -0
  457. package/src/data/providers/farming.mjs +291 -0
  458. package/src/data/providers/geckoterminal.mjs +34 -0
  459. package/src/data/providers/gmx.mjs +496 -0
  460. package/src/data/providers/hiro-stacks.mjs +150 -0
  461. package/src/data/providers/hl-assets.mjs +165 -0
  462. package/src/data/providers/hl-info.mjs +108 -0
  463. package/src/data/providers/hl-markets.mjs +210 -0
  464. package/src/data/providers/hl-outcome.mjs +61 -0
  465. package/src/data/providers/hl-perps.mjs +419 -0
  466. package/src/data/providers/hl-staking.mjs +353 -0
  467. package/src/data/providers/hl-ws.mjs +119 -0
  468. package/src/data/providers/hyperevm-dex.mjs +49 -0
  469. package/src/data/providers/jito-mev.mjs +117 -0
  470. package/src/data/providers/jupiter-venues.mjs +119 -0
  471. package/src/data/providers/jupiter.mjs +315 -0
  472. package/src/data/providers/kamino-strategies.mjs +143 -0
  473. package/src/data/providers/l2beat-tvl.mjs +42 -0
  474. package/src/data/providers/lifi.mjs +166 -0
  475. package/src/data/providers/liquid-esplora.mjs +152 -0
  476. package/src/data/providers/magiceden-ordinals.mjs +141 -0
  477. package/src/data/providers/magiceden-sol.mjs +406 -0
  478. package/src/data/providers/mempool-lightning.mjs +144 -0
  479. package/src/data/providers/mempool-mining.mjs +142 -0
  480. package/src/data/providers/meteora-dlmm.mjs +168 -0
  481. package/src/data/providers/morpho.mjs +177 -0
  482. package/src/data/providers/nft-gallery.mjs +163 -0
  483. package/src/data/providers/nft-portfolio.mjs +494 -0
  484. package/src/data/providers/odos.mjs +156 -0
  485. package/src/data/providers/ondo.mjs +31 -0
  486. package/src/data/providers/oneinch.mjs +174 -0
  487. package/src/data/providers/opensea-multichain.mjs +136 -0
  488. package/src/data/providers/opensea-nft.mjs +371 -0
  489. package/src/data/providers/orca.mjs +29 -0
  490. package/src/data/providers/ordinals-runes.mjs +180 -0
  491. package/src/data/providers/pancakeswap.mjs +28 -0
  492. package/src/data/providers/paraswap.mjs +125 -0
  493. package/src/data/providers/pendle.mjs +188 -0
  494. package/src/data/providers/poly-clob.mjs +283 -0
  495. package/src/data/providers/poly-public.mjs +96 -0
  496. package/src/data/providers/poly-ws.mjs +103 -0
  497. package/src/data/providers/polygon-staking.mjs +227 -0
  498. package/src/data/providers/portfolio-history.mjs +394 -0
  499. package/src/data/providers/portfolio.mjs +600 -0
  500. package/src/data/providers/pyth-price-feeds.mjs +172 -0
  501. package/src/data/providers/raydium.mjs +35 -0
  502. package/src/data/providers/relayscan-mev.mjs +72 -0
  503. package/src/data/providers/rfq.mjs +15 -0
  504. package/src/data/providers/rh-agent.mjs +59 -0
  505. package/src/data/providers/sanctum-lst.mjs +180 -0
  506. package/src/data/providers/satflow.mjs +341 -0
  507. package/src/data/providers/signed-material-guard.mjs +108 -0
  508. package/src/data/providers/solana-rpc.mjs +197 -0
  509. package/src/data/providers/solend-lending.mjs +166 -0
  510. package/src/data/providers/spark-lend.mjs +42 -0
  511. package/src/data/providers/squid-router.mjs +29 -0
  512. package/src/data/providers/stargate.mjs +29 -0
  513. package/src/data/providers/sushiswap.mjs +30 -0
  514. package/src/data/providers/symbiotic-restaking.mjs +41 -0
  515. package/src/data/providers/thorchain.mjs +36 -0
  516. package/src/data/providers/traderjoe.mjs +28 -0
  517. package/src/data/providers/twap.mjs +152 -0
  518. package/src/data/providers/uniswap-v3.mjs +457 -0
  519. package/src/data/providers/uniswap-v4.mjs +414 -0
  520. package/src/data/providers/vertex.mjs +41 -0
  521. package/src/data/providers/wallet-watch.mjs +264 -0
  522. package/src/data/providers/wormhole.mjs +28 -0
  523. package/src/data/providers/yearn.mjs +31 -0
  524. package/src/data/providers/zerox.mjs +167 -0
  525. package/src/data/public-api-scan.mjs +61 -0
  526. package/src/data/quote-placeholder.mjs +31 -0
  527. package/src/desk/swap-prepare.mjs +194 -0
  528. package/src/equities/bridge.mjs +388 -0
  529. package/src/equities/fixtures/bridge_routes.json +159 -0
  530. package/src/equities/fixtures/dst_transitions.json +29 -0
  531. package/src/equities/fixtures/equity_dex_pools.json +154 -0
  532. package/src/equities/fixtures/hip3_l2books.json +2711 -0
  533. package/src/equities/fixtures/nyse_holidays.json +1 -0
  534. package/src/equities/fixtures/oracles.json +100 -0
  535. package/src/equities/fixtures/rh_pool_state.json +244 -0
  536. package/src/equities/fixtures/solana_xstocks.json +704 -0
  537. package/src/equities/fixtures/ton_xstocks.json +35 -0
  538. package/src/equities/fixtures/universe.json +411 -0
  539. package/src/equities/fixtures/venues.json +3542 -0
  540. package/src/equities/fixtures.mjs +405 -0
  541. package/src/equities/funding.mjs +142 -0
  542. package/src/equities/index.mjs +166 -0
  543. package/src/equities/liveness.mjs +148 -0
  544. package/src/equities/marketHours.mjs +249 -0
  545. package/src/equities/normalize.mjs +295 -0
  546. package/src/equities/num.mjs +146 -0
  547. package/src/equities/prepare.mjs +95 -0
  548. package/src/equities/rank.mjs +260 -0
  549. package/src/equities/sourceNum.mjs +69 -0
  550. package/src/equities/types.mjs +220 -0
  551. package/src/equities/venues/arcus-perp.mjs +84 -0
  552. package/src/equities/venues/arcus-spot.mjs +105 -0
  553. package/src/equities/venues/hyperliquid-hip3.mjs +224 -0
  554. package/src/equities/venues/rh-uniswap.mjs +216 -0
  555. package/src/equities/venues/solana-xstocks.mjs +139 -0
  556. package/src/equities/venues/ton-stonfi.mjs +139 -0
  557. package/src/exact-integer.mjs +72 -0
  558. package/src/exec-policy.mjs +419 -0
  559. package/src/flags.mjs +15 -0
  560. package/src/fresh-window.mjs +76 -0
  561. package/src/gmx-attestation.mjs +176 -0
  562. package/src/index.mjs +107 -0
  563. package/src/licensing/locals-only.mjs +25 -0
  564. package/src/nft-gas-war-guard.mjs +139 -0
  565. package/src/onboarding/agent-keys.mjs +161 -0
  566. package/src/onboarding/harness-configs.mjs +102 -0
  567. package/src/onboarding/index.mjs +18 -0
  568. package/src/onboarding/tiers.mjs +139 -0
  569. package/src/oracle-env.mjs +55 -0
  570. package/src/package-manifest.mjs +42 -0
  571. package/src/plugins/agent-plugin-loader.mjs +225 -0
  572. package/src/portfolio-risk.mjs +170 -0
  573. package/src/prepare-envelope.mjs +204 -0
  574. package/src/profile-upgrade.mjs +277 -0
  575. package/src/protocol-execution.mjs +84 -0
  576. package/src/protocol-templates/gate.mjs +179 -0
  577. package/src/protocol-templates/prepare-deploy.mjs +81 -0
  578. package/src/public-api/agent-grants.mjs +57 -0
  579. package/src/public-api/buzz-integration.mjs +267 -0
  580. package/src/public-api/connect-agent.mjs +424 -0
  581. package/src/public-api/grants.mjs +142 -0
  582. package/src/public-api/http.mjs +707 -0
  583. package/src/public-api/metering.mjs +111 -0
  584. package/src/public-control/aa-adapter.mjs +402 -0
  585. package/src/public-control/build-registry.mjs +227 -0
  586. package/src/public-control/bundler-client.mjs +357 -0
  587. package/src/public-control/grant-indexer.mjs +296 -0
  588. package/src/public-control/policy-render.mjs +69 -0
  589. package/src/public-control/policy-schema.mjs +322 -0
  590. package/src/public-control/runtime-config.mjs +275 -0
  591. package/src/public-control/session-key-model.mjs +379 -0
  592. package/src/public-control/session-orchestrator.mjs +418 -0
  593. package/src/rfq/intent.mjs +180 -0
  594. package/src/rfq/sources.mjs +181 -0
  595. package/src/route-attestation.mjs +132 -0
  596. package/src/router/best-execution.mjs +326 -0
  597. package/src/router/index.mjs +250 -0
  598. package/src/router/integrator-fee.mjs +135 -0
  599. package/src/router/prepare-bridge.mjs +293 -0
  600. package/src/router/prepare-route.mjs +398 -0
  601. package/src/router/proposal.mjs +311 -0
  602. package/src/router/risk-classifier.mjs +119 -0
  603. package/src/router/route-sources.mjs +364 -0
  604. package/src/scanner/chains.config.mjs +543 -0
  605. package/src/scanner/contract.mjs +270 -0
  606. package/src/scanner/evm-scanner.mjs +394 -0
  607. package/src/scanner/index.mjs +9 -0
  608. package/src/scanner/v2-venue.mjs +351 -0
  609. package/src/scanner/v3-venue.mjs +308 -0
  610. package/src/scopes.mjs +44 -0
  611. package/src/sell-simulation.mjs +167 -0
  612. package/src/signals/engine.mjs +146 -0
  613. package/src/signals/index.mjs +1 -0
  614. package/src/token-transfer-guard.mjs +188 -0
  615. package/src/tui/app.mjs +438 -0
  616. package/src/tui/backend.mjs +215 -0
  617. package/src/tui/format.mjs +272 -0
  618. package/src/tui/gateway-client.mjs +177 -0
  619. package/src/tui/input.mjs +501 -0
  620. package/src/tui/memory.mjs +105 -0
  621. package/src/tui/meta-learn.mjs +85 -0
  622. package/src/tui/renderer.mjs +443 -0
  623. package/src/tui/scheduler.mjs +205 -0
  624. package/src/tui/skills-loader.mjs +140 -0
  625. package/src/tui/standalone-client.mjs +752 -0
  626. package/src/tui/theme.mjs +81 -0
  627. package/src/vault-attestation.mjs +146 -0
  628. package/src/venues.mjs +206 -0
  629. package/src/watch-preferences.mjs +85 -0
@@ -0,0 +1,105 @@
1
+ // Arcus spot pairs on Robinhood Chain 4663.
2
+ // Tier: quote-only. CRITICAL: bid and ask are passed through UNTOUCHED, including
3
+ // crossed books where bid > ask. Repairing a crossed book here would hide a real
4
+ // data integrity failure from liveness.mjs and let a garbage mid rank as real.
5
+ //
6
+ // Fees are explicitly zero in the fixture capture. A known zero is a fixed point
7
+ // zero with costAccounted true for the fee component alone. Gas and impact are
8
+ // still unknown, so the overall costAccounted claim stays false.
9
+
10
+ import { getVenues } from '../fixtures.mjs';
11
+ import { fromSourceNumber, requireSourceNumber } from '../sourceNum.mjs';
12
+ import { parseDecimal } from '../num.mjs';
13
+ import { validateQuote } from '../types.mjs';
14
+
15
+ export const VENUE = 'arcus_spot';
16
+ export const CHAIN = 'robinhood-4663';
17
+ export const TIER = 'quote-only';
18
+
19
+ function spot() {
20
+ return getVenues().venues.arcus_spot;
21
+ }
22
+
23
+ export function listPairs() {
24
+ return Object.keys(spot().pairs).sort();
25
+ }
26
+
27
+ export function quote({ symbol, side = 'buy', sizeUsd = null } = {}) {
28
+ if (typeof symbol !== 'string' || symbol.length === 0) return null;
29
+ const pair = spot().pairs[symbol];
30
+ if (!pair) return null;
31
+
32
+ // Pass bid and ask through exactly as captured. Do not swap, average, or clamp.
33
+ const bid = pair.bid === undefined || pair.bid === null ? null : requireSourceNumber(pair.bid, `${symbol}.bid`);
34
+ const ask = pair.ask === undefined || pair.ask === null ? null : requireSourceNumber(pair.ask, `${symbol}.ask`);
35
+ const last = fromSourceNumber(pair.last);
36
+
37
+ // Mid is only computed when both sides exist. A crossed book still gets a mid
38
+ // (the arithmetic average of the bad numbers) because mid is evidence, not a
39
+ // filter. Liveness will exclude the whole quote for crossed-book.
40
+ let mid = null;
41
+ if (bid !== null && ask !== null) {
42
+ mid = {
43
+ mantissa: bid.mantissa + ask.mantissa,
44
+ scale: bid.scale === ask.scale ? bid.scale + 1 : Math.max(bid.scale, ask.scale) + 1,
45
+ };
46
+ // Align to a common scale before averaging.
47
+ const scale = Math.max(bid.scale, ask.scale);
48
+ const b = bid.scale === scale ? bid.mantissa : bid.mantissa * 10n ** BigInt(scale - bid.scale);
49
+ const a = ask.scale === scale ? ask.mantissa : ask.mantissa * 10n ** BigInt(scale - ask.scale);
50
+ mid = { mantissa: b + a, scale: scale + 1 };
51
+ // (b+a) at scale+1 is the average at scale, which is what we want.
52
+ // Actually: average = (b+a)/2. With mantissa b+a and scale scale+1 that is
53
+ // (b+a) * 10^-(scale+1) = ((b+a)/10) * 10^-scale, not /2.
54
+ // Correct: mid = (b+a) / 2 at the same scale.
55
+ mid = { mantissa: (b + a) / 2n, scale };
56
+ } else if (last !== null) {
57
+ mid = last;
58
+ }
59
+
60
+ if (bid === null && ask === null && mid === null) return null;
61
+
62
+ const requested = sizeUsd === null ? parseDecimal('0') : sizeUsd;
63
+ // Explicit zero fee. Known measured zero, not unknown.
64
+ const fees = parseDecimal('0');
65
+
66
+ const q = {
67
+ venue: VENUE,
68
+ chain: CHAIN,
69
+ instrument: 'spot',
70
+ tier: TIER,
71
+ symbolRaw: symbol,
72
+ symbol,
73
+ side,
74
+ requestedSize: requested,
75
+ fees,
76
+ gasEstimate: null,
77
+ priceImpact: null,
78
+ fundingHourly: null,
79
+ // Fees known as zero, but gas and impact unknown, so overall claim is false.
80
+ costAccounted: false,
81
+ capturedAt: getVenues().capturedAt * 1000,
82
+ blockOrSeq: null,
83
+ raw: {
84
+ fixture: 'fixtures/venues.json#venues.arcus_spot',
85
+ last: pair.last,
86
+ bid: pair.bid,
87
+ ask: pair.ask,
88
+ vol24h: pair.vol24h,
89
+ feeKnownZero: true,
90
+ reasonCostUnknown: 'gas and impact at size not captured; fee is a known zero',
91
+ },
92
+ };
93
+
94
+ if (bid !== null) q.bid = bid;
95
+ if (ask !== null) q.ask = ask;
96
+ if (mid !== null) q.mid = mid;
97
+
98
+ return validateQuote(q);
99
+ }
100
+
101
+ export function quoteAll({ side = 'buy', sizeUsd = null } = {}) {
102
+ return listPairs()
103
+ .map((symbol) => quote({ symbol, side, sizeUsd }))
104
+ .filter((q) => q !== null);
105
+ }
@@ -0,0 +1,224 @@
1
+ // Hyperliquid HIP-3 builder-deployed equity perp adapter.
2
+ // Tier: quote-only. Adapters report source truth including dormant dexs and
3
+ // markets with zero volume. Exclusion of those is liveness.mjs, not this file.
4
+ //
5
+ // Fixture shape (venues.hyperliquid_hip3.dexs):
6
+ // { abcd: { USA500: { mark, vol24h, oi, fundingHourly, fundingAnnPct, maxLev } }, ... }
7
+ // Symbols are namespaced as dex:TICKER so xyz:NVDA never collides with a cash:NVDA
8
+ // if one ever appears.
9
+ //
10
+ // When fixtures/hip3_l2books.json has a book for the coin, size impact is walked
11
+ // from the book (measured). Fees and gas are still unknown, so overall
12
+ // costAccounted stays false, but priceImpact is no longer null.
13
+
14
+ import { getHip3L2Books, getVenues } from '../fixtures.mjs';
15
+ import { fromSourceNumber, requireSourceNumber } from '../sourceNum.mjs';
16
+ import { div, mul, parseDecimal, sub, toString } from '../num.mjs';
17
+ import { validateQuote } from '../types.mjs';
18
+
19
+ export const VENUE = 'hyperliquid_hip3';
20
+ export const CHAIN = 'hyperliquid';
21
+ export const TIER = 'quote-only';
22
+
23
+ function hip3() {
24
+ return getVenues().venues.hyperliquid_hip3;
25
+ }
26
+
27
+ export function listDexs() {
28
+ return Object.keys(hip3().dexs).sort();
29
+ }
30
+
31
+ export function listMarkets() {
32
+ const out = [];
33
+ for (const [dex, markets] of Object.entries(hip3().dexs)) {
34
+ for (const ticker of Object.keys(markets)) {
35
+ out.push(`${dex}:${ticker}`);
36
+ }
37
+ }
38
+ return out.sort();
39
+ }
40
+
41
+ export function findMarkets(symbol) {
42
+ if (typeof symbol !== 'string' || symbol.length === 0) return [];
43
+ const colon = symbol.indexOf(':');
44
+ if (colon > 0) {
45
+ const dex = symbol.slice(0, colon);
46
+ const ticker = symbol.slice(colon + 1);
47
+ const market = hip3().dexs[dex]?.[ticker];
48
+ if (!market) return [];
49
+ return [{ dex, ticker, market }];
50
+ }
51
+ const hits = [];
52
+ for (const [dex, markets] of Object.entries(hip3().dexs)) {
53
+ if (Object.hasOwn(markets, symbol)) {
54
+ hits.push({ dex, ticker: symbol, market: markets[symbol] });
55
+ }
56
+ }
57
+ return hits;
58
+ }
59
+
60
+ function bookFor(dex, ticker) {
61
+ try {
62
+ const books = getHip3L2Books().books;
63
+ return books[`${dex}:${ticker}`] ?? null;
64
+ } catch {
65
+ return null;
66
+ }
67
+ }
68
+
69
+ // Walk the ask (buy) or bid (sell) side until notional is filled. Returns
70
+ // { vwap, filledUsd, unfilledUsd, levelsUsed } or null if no book.
71
+ function walkBook(book, side, sizeUsd) {
72
+ if (!book || sizeUsd === null || sizeUsd.mantissa <= 0n) return null;
73
+ const levels = side === 'buy' ? book.asks : book.bids;
74
+ if (!levels || levels.length === 0) return null;
75
+
76
+ let remaining = Number(toString(sizeUsd));
77
+ if (!Number.isFinite(remaining) || remaining <= 0) return null;
78
+
79
+ let spent = 0;
80
+ let qty = 0;
81
+ let levelsUsed = 0;
82
+ for (const lvl of levels) {
83
+ const px = Number(lvl.px);
84
+ const sz = Number(lvl.sz);
85
+ if (!(px > 0) || !(sz > 0)) continue;
86
+ const levelNotional = px * sz;
87
+ const take = Math.min(remaining, levelNotional);
88
+ const takeQty = take / px;
89
+ spent += take;
90
+ qty += takeQty;
91
+ remaining -= take;
92
+ levelsUsed += 1;
93
+ if (remaining <= 1e-9) break;
94
+ }
95
+ if (qty <= 0) return null;
96
+ return {
97
+ vwap: spent / qty,
98
+ filledUsd: spent,
99
+ unfilledUsd: Math.max(0, remaining),
100
+ levelsUsed,
101
+ };
102
+ }
103
+
104
+ function impactFromBook(book, side, sizeUsd, mark) {
105
+ const walk = walkBook(book, side, sizeUsd);
106
+ if (!walk) return { impact: null, depth: null };
107
+ const markN = Number(toString(mark));
108
+ if (!(markN > 0)) return { impact: null, depth: walk };
109
+ // Buy impact = (vwap - mark) / mark ; sell impact = (mark - vwap) / mark
110
+ const raw = side === 'buy' ? (walk.vwap - markN) / markN : (markN - walk.vwap) / markN;
111
+ const clamped = Math.max(0, raw);
112
+ // Encode as fixed point via decimal string (source number path).
113
+ const impact = fromSourceNumber(Number(clamped.toPrecision(12)));
114
+ return {
115
+ impact,
116
+ depth: {
117
+ ...walk,
118
+ impactFraction: clamped,
119
+ fullyFilled: walk.unfilledUsd <= 1e-6,
120
+ },
121
+ };
122
+ }
123
+
124
+ function emitQuote({ dex, ticker, market, side, size }) {
125
+ const mark = requireSourceNumber(market.mark, `${dex}:${ticker}.mark`);
126
+ const funding = fromSourceNumber(market.fundingHourly);
127
+ const vol24h = fromSourceNumber(market.vol24h);
128
+ const oi = fromSourceNumber(market.oi);
129
+ const requested = size === null ? parseDecimal('0') : size;
130
+
131
+ const book = bookFor(dex, ticker);
132
+ let priceImpact = null;
133
+ let depthMeta = null;
134
+ let reasonCostUnknown = 'fees and gas not captured';
135
+
136
+ if (requested.mantissa > 0n) {
137
+ if (book) {
138
+ const walked = impactFromBook(book, side, requested, mark);
139
+ priceImpact = walked.impact;
140
+ depthMeta = walked.depth;
141
+ if (!depthMeta?.fullyFilled) {
142
+ reasonCostUnknown =
143
+ 'book walked but size exceeds visible depth; fees and gas not captured';
144
+ } else {
145
+ reasonCostUnknown =
146
+ 'impact measured from l2Book; fees and gas still not captured';
147
+ }
148
+ } else {
149
+ reasonCostUnknown = 'no order book depth wired for this coin; fees and gas not captured';
150
+ }
151
+ } else if (!book) {
152
+ reasonCostUnknown = 'no order book depth wired for this coin; fees and gas not captured';
153
+ } else {
154
+ reasonCostUnknown = 'zero size; fees and gas not captured';
155
+ }
156
+
157
+ // Fees and gas unknown always => costAccounted false. Depth only fills priceImpact.
158
+ const costAccounted = false;
159
+
160
+ const q = {
161
+ venue: VENUE,
162
+ chain: CHAIN,
163
+ instrument: 'perp',
164
+ tier: TIER,
165
+ symbolRaw: `${dex}:${ticker}`,
166
+ symbol: ticker,
167
+ side,
168
+ requestedSize: requested,
169
+ mark,
170
+ fees: null,
171
+ gasEstimate: null,
172
+ priceImpact,
173
+ fundingHourly: funding,
174
+ costAccounted,
175
+ capturedAt: getVenues().capturedAt * 1000,
176
+ blockOrSeq: null,
177
+ raw: {
178
+ fixture: 'fixtures/venues.json#venues.hyperliquid_hip3',
179
+ dex,
180
+ ticker,
181
+ vol24h: market.vol24h,
182
+ oi: market.oi,
183
+ fundingAnnPct: market.fundingAnnPct,
184
+ maxLev: market.maxLev,
185
+ reasonCostUnknown,
186
+ hasL2Book: book !== null,
187
+ l2BookFixture: book ? 'fixtures/hip3_l2books.json' : null,
188
+ depth: depthMeta,
189
+ },
190
+ };
191
+
192
+ if (vol24h !== null) q.raw.vol24hFixed = vol24h;
193
+ if (oi !== null) q.raw.oiFixed = oi;
194
+
195
+ // Attach top of book when present as evidence, not as repaired mid.
196
+ if (book?.bids?.[0] && book?.asks?.[0]) {
197
+ q.bid = parseDecimal(String(book.bids[0].px));
198
+ q.ask = parseDecimal(String(book.asks[0].px));
199
+ }
200
+
201
+ return validateQuote(q);
202
+ }
203
+
204
+ export function quote({ symbol, side = 'buy', sizeUsd = null } = {}) {
205
+ const hits = findMarkets(symbol);
206
+ if (hits.length === 0) return null;
207
+ if (hits.length > 1) return null;
208
+ return emitQuote({ ...hits[0], side, size: sizeUsd });
209
+ }
210
+
211
+ export function quoteAll({ side = 'buy', sizeUsd = null, ticker = null } = {}) {
212
+ const out = [];
213
+ for (const namespaced of listMarkets()) {
214
+ const [dex, t] = namespaced.split(':');
215
+ if (ticker !== null && t !== ticker) continue;
216
+ const market = hip3().dexs[dex][t];
217
+ out.push(emitQuote({ dex, ticker: t, market, side, size: sizeUsd }));
218
+ }
219
+ return out;
220
+ }
221
+
222
+ export function quoteCore(/* ignored */) {
223
+ return [];
224
+ }
@@ -0,0 +1,216 @@
1
+ // Robinhood Chain Uniswap adapter. This is the ONLY prepare tier venue on the desk.
2
+ // Everything else can quote, but this is the one place a user can actually act, which
3
+ // is why bestPreparable exists as a separate pointer from the overall ranking winner.
4
+ //
5
+ // Pricing comes from fixtures/rh_pool_state.json, captured live from chain 4663 via
6
+ // pair.slot0() for Uniswap V3 pools and StateView.getSlot0(poolId) for V4 pools. The
7
+ // original fixture capture recorded only USD liquidity with NO price field, so pool
8
+ // price could not be derived from it at all. That gap is why the state file exists.
9
+ //
10
+ // Chainlink oracle reads are REFERENCE ONLY. They are emitted as referencePrice and
11
+ // are never a rankable route, because nobody can trade at the oracle print.
12
+
13
+ import { getOracles, getRhPoolState } from '../fixtures.mjs';
14
+ import { fromSourceNumber } from '../sourceNum.mjs';
15
+ import {
16
+ div,
17
+ fromScaledInteger,
18
+ mul,
19
+ parseDecimal,
20
+ rescale,
21
+ sub,
22
+ toString as numToString,
23
+ } from '../num.mjs';
24
+ import { validateQuote } from '../types.mjs';
25
+
26
+ export const VENUE = 'rh_uniswap';
27
+ export const CHAIN = 4663;
28
+ export const TIER = 'prepare';
29
+
30
+ // Q96 is the Uniswap fixed point base. sqrtPriceX96 is sqrt(price) * 2^96, so price
31
+ // is (sqrtPriceX96^2) / 2^192. Squaring first in BigInt keeps this exact.
32
+ const Q192 = 1n << 192n;
33
+
34
+ // Working precision for the price ratio. High enough that a sub cent equity price is
35
+ // not truncated away, bounded so the mantissa stays sane.
36
+ const PRICE_SCALE = 18;
37
+
38
+ // Gas units per route shape. These are estimates for a single swap on this chain and
39
+ // are labelled as estimates everywhere they surface. A V4 swap routes through the
40
+ // PoolManager unlock/settle flow and costs materially more than a V3 exactInputSingle.
41
+ const GAS_UNITS = Object.freeze({ v3: 180000n, v4: 240000n });
42
+
43
+ function poolStateFile() {
44
+ return getRhPoolState();
45
+ }
46
+
47
+ // price = sqrtPriceX96^2 / 2^192, expressed as token1 per token0 in RAW base units.
48
+ function rawRatio(sqrtPriceX96) {
49
+ const sq = sqrtPriceX96 * sqrtPriceX96;
50
+ // Scale up before dividing so BigInt truncation does not eat the whole fraction.
51
+ const scaled = (sq * 10n ** BigInt(PRICE_SCALE)) / Q192;
52
+ return { mantissa: scaled, scale: PRICE_SCALE };
53
+ }
54
+
55
+ // Convert the raw token1-per-token0 ratio into quote units per ONE equity token.
56
+ // Decimal correction and orientation are separate concerns and both must be applied.
57
+ function poolPrice(state) {
58
+ const ratio = rawRatio(BigInt(state.sqrtPriceX96));
59
+ const quoteDecimals = state.quote === 'USDG' ? 6 : 18;
60
+ const equityDecimals = 18;
61
+
62
+ if (state.quoteIsToken0) {
63
+ // ratio is equity-per-quote in raw units. Human equity per quote is
64
+ // ratio * 10^quoteDecimals / 10^equityDecimals, and price is its reciprocal.
65
+ const humanEquityPerQuote = div(
66
+ mul(ratio, fromScaledInteger(10n ** BigInt(quoteDecimals), 0)),
67
+ fromScaledInteger(10n ** BigInt(equityDecimals), 0),
68
+ PRICE_SCALE,
69
+ );
70
+ if (humanEquityPerQuote.mantissa === 0n) return null;
71
+ return div(parseDecimal('1'), humanEquityPerQuote, PRICE_SCALE);
72
+ }
73
+
74
+ // ratio is quote-per-equity in raw units, so only the decimal correction applies.
75
+ return div(
76
+ mul(ratio, fromScaledInteger(10n ** BigInt(equityDecimals), 0)),
77
+ fromScaledInteger(10n ** BigInt(quoteDecimals), 0),
78
+ PRICE_SCALE,
79
+ );
80
+ }
81
+
82
+ // Chainlink price() is a scaled integer. The live feed composition on this chain is
83
+ // 36 oracle decimals plus 6 USDG decimals minus 18 equity decimals, giving scale 24.
84
+ export function referencePrice(symbol) {
85
+ const oracles = getOracles();
86
+ const asset = oracles.assets[symbol];
87
+ if (!asset) return null;
88
+ return fromScaledInteger(asset.rawPrice, oracles.oracleScaleExp);
89
+ }
90
+
91
+ // Constant product price impact at a requested notional. A V3 or V4 pool concentrates
92
+ // liquidity, so this xy=k estimate is a MODEL, not a measurement: real impact depends
93
+ // on tick distribution we have not captured. It is therefore reported with
94
+ // costAccounted false so it can never masquerade as a measured cost.
95
+ function modelImpact(liqUsd, notionalUsd) {
96
+ if (liqUsd === null || notionalUsd === null) return null;
97
+ if (liqUsd.mantissa <= 0n || notionalUsd.mantissa <= 0n) return null;
98
+ // impact fraction ~ notional / (liquidity + notional)
99
+ const denom = { ...liqUsd };
100
+ const sum = div(notionalUsd, addFixed(denom, notionalUsd), PRICE_SCALE);
101
+ return sum;
102
+ }
103
+
104
+ function addFixed(left, right) {
105
+ const scale = Math.max(left.scale, right.scale);
106
+ return {
107
+ mantissa: rescale(left, scale).mantissa + rescale(right, scale).mantissa,
108
+ scale,
109
+ };
110
+ }
111
+
112
+ // Gas cost in QUOTE units. gasPriceWei * gasUnits gives wei of native token. This
113
+ // chain's native token is ETH, so converting that to USDG needs an ETH price we did
114
+ // NOT capture. Rather than invent one, gas is returned in native wei alongside an
115
+ // explicit null for its quote denomination, and callers must treat it as unknown.
116
+ export function gasEstimate(version) {
117
+ const state = poolStateFile();
118
+ const units = GAS_UNITS[version];
119
+ if (!units) return null;
120
+ const wei = BigInt(state.gasPriceWei) * units;
121
+ return { wei, units, native: 'ETH' };
122
+ }
123
+
124
+ export function listPools() {
125
+ return Object.keys(poolStateFile().pools).sort();
126
+ }
127
+
128
+ export function quote({ symbol, side = 'buy', sizeUsd = null } = {}) {
129
+ if (typeof symbol !== 'string' || symbol.length === 0) {
130
+ throw new TypeError('symbol must be a nonempty string');
131
+ }
132
+ const state = poolStateFile();
133
+ const pool = state.pools[symbol];
134
+ if (!pool) return null;
135
+
136
+ const price = poolPrice(pool);
137
+ if (price === null) return null;
138
+
139
+ const liqUsd = fromSourceNumber(pool.liqUsd);
140
+ const requested = sizeUsd === null ? parseDecimal('0') : sizeUsd;
141
+
142
+ // Fees: a V3 pool reports its fee tier in ppm and that is a real measured number.
143
+ // A V4 pool's fee can be dynamic via its hook and we did not capture it, so it
144
+ // stays null and forces costAccounted false rather than defaulting to zero.
145
+ const fees =
146
+ pool.feePpm === null || pool.feePpm === undefined
147
+ ? null
148
+ : div(fromScaledInteger(BigInt(pool.feePpm), 0), fromScaledInteger(1000000n, 0), 8);
149
+
150
+ const impact = requested.mantissa === 0n ? parseDecimal('0') : modelImpact(liqUsd, requested);
151
+
152
+ const gas = gasEstimate(pool.version);
153
+ // Gas is known in native wei but NOT convertible to the quote asset without an ETH
154
+ // price we never captured. Unknown is not zero, so this stays null.
155
+ const gasInQuote = null;
156
+
157
+ // costAccounted is a claim that every applicable cost is known. Gas is not
158
+ // denominated, V4 fees are undiscovered, and impact at size is modelled rather than
159
+ // measured. Any one of those is enough to make the claim false.
160
+ const costAccounted = false;
161
+
162
+ const q = {
163
+ venue: VENUE,
164
+ chain: CHAIN,
165
+ instrument: 'spot',
166
+ tier: TIER,
167
+ symbolRaw: symbol,
168
+ symbol,
169
+ side,
170
+ requestedSize: requested,
171
+ mid: price,
172
+ fees,
173
+ gasEstimate: gasInQuote,
174
+ priceImpact: impact,
175
+ fundingHourly: null,
176
+ costAccounted,
177
+ capturedAt: state.capturedAt * 1000,
178
+ blockOrSeq: state.block,
179
+ raw: {
180
+ fixture: 'fixtures/rh_pool_state.json',
181
+ pair: pool.pair,
182
+ version: pool.version,
183
+ sqrtPriceX96: pool.sqrtPriceX96,
184
+ quote: pool.quote,
185
+ quoteIsToken0: pool.quoteIsToken0,
186
+ liqUsd: pool.liqUsd,
187
+ gasNativeWei: gas === null ? null : gas.wei.toString(),
188
+ gasUnits: gas === null ? null : gas.units.toString(),
189
+ impactModel: 'constant-product-estimate',
190
+ notes: [
191
+ 'price read live from chain 4663',
192
+ pool.version === 'v4'
193
+ ? 'v4 fee may be dynamic via hook and was not captured'
194
+ : 'v3 fee tier is the pool static fee',
195
+ 'gas known in native wei only, no ETH price captured to denominate it',
196
+ ],
197
+ },
198
+ };
199
+
200
+ const reference = referencePrice(symbol);
201
+ if (reference !== null) {
202
+ q.referencePrice = reference;
203
+ // Basis versus the oracle print. Useful evidence, never a tradeable route.
204
+ q.referenceBasisBps = numToString(
205
+ div(mul(sub(price, reference), fromScaledInteger(10000n, 0)), reference, 4),
206
+ );
207
+ }
208
+
209
+ return validateQuote(q);
210
+ }
211
+
212
+ export function quoteAll({ side = 'buy', sizeUsd = null } = {}) {
213
+ return listPools()
214
+ .map((symbol) => quote({ symbol, side, sizeUsd }))
215
+ .filter((q) => q !== null);
216
+ }
@@ -0,0 +1,139 @@
1
+ // Solana xStocks adapter (Backed / xStocks SPL tokens).
2
+ // Tier: quote-only. Source is DexScreener-shaped fixture data: priceUsd and
3
+ // liquidityUsd are third-party floats. Converting them to fixed point does NOT
4
+ // make them exact. Impact at size is a model estimate, so any non-trivial size
5
+ // forces costAccounted: false.
6
+ //
7
+ // symbolRaw keeps the x suffix (NVDAx). symbol is the canonical Oracle ticker
8
+ // (NVDA). normalize.mjs already understands the x-suffix rule.
9
+
10
+ import { getSolanaXstocks } from '../fixtures.mjs';
11
+ import { fromSourceNumber, requireSourceNumber } from '../sourceNum.mjs';
12
+ import { div, parseDecimal } from '../num.mjs';
13
+ import { validateQuote } from '../types.mjs';
14
+
15
+ export const VENUE = 'solana_xstocks';
16
+ export const CHAIN = 'solana';
17
+ export const TIER = 'quote-only';
18
+
19
+ // Below this USD liquidity, treat the market as too thin to rank at any size.
20
+ const THIN_LIQ_USD = 25_000;
21
+ // Size above this fraction of reported liq is never cost-accounted.
22
+ const IMPACT_SIZE_FRACTION = 0.02;
23
+
24
+ function data() {
25
+ return getSolanaXstocks();
26
+ }
27
+
28
+ export function listTokens() {
29
+ return Object.keys(data().tokens).sort();
30
+ }
31
+
32
+ function bestPair(symbol) {
33
+ const pairs = data().pairs[symbol];
34
+ if (!pairs || pairs.length === 0) return null;
35
+ // Already sorted by liq desc at capture time; re-sort defensively.
36
+ return [...pairs].sort((a, b) => (b.liquidityUsd ?? 0) - (a.liquidityUsd ?? 0))[0];
37
+ }
38
+
39
+ function modelImpact(liqUsd, sizeUsd) {
40
+ if (liqUsd === null || sizeUsd === null) return null;
41
+ if (liqUsd.mantissa <= 0n || sizeUsd.mantissa <= 0n) return parseDecimal('0');
42
+ // Constant-product-ish: impact fraction ~= size / (liq + size)
43
+ const scale = Math.max(liqUsd.scale, sizeUsd.scale);
44
+ const l =
45
+ liqUsd.scale === scale
46
+ ? liqUsd.mantissa
47
+ : liqUsd.mantissa * 10n ** BigInt(scale - liqUsd.scale);
48
+ const s =
49
+ sizeUsd.scale === scale
50
+ ? sizeUsd.mantissa
51
+ : sizeUsd.mantissa * 10n ** BigInt(scale - sizeUsd.scale);
52
+ // (s / (l+s)) at scale+6 for a bit of room
53
+ const num = s * 10n ** 6n;
54
+ const den = l + s;
55
+ return { mantissa: num / den, scale: 6 };
56
+ }
57
+
58
+ export function quote({ symbol, side = 'buy', sizeUsd = null } = {}) {
59
+ if (typeof symbol !== 'string' || symbol.length === 0) return null;
60
+
61
+ // Accept NVDAx or NVDA.
62
+ let bare = symbol;
63
+ let symbolRaw = symbol;
64
+ const tokens = data().tokens;
65
+ if (Object.hasOwn(tokens, symbol)) {
66
+ bare = symbol;
67
+ symbolRaw = tokens[symbol].symbolRaw;
68
+ } else if (symbol.endsWith('x') || symbol.endsWith('X')) {
69
+ const candidate = symbol.slice(0, -1).toUpperCase();
70
+ if (Object.hasOwn(tokens, candidate)) {
71
+ bare = candidate;
72
+ symbolRaw = tokens[candidate].symbolRaw;
73
+ } else {
74
+ return null;
75
+ }
76
+ } else {
77
+ return null;
78
+ }
79
+
80
+ const token = tokens[bare];
81
+ const pair = bestPair(bare);
82
+ if (!token || !pair) return null;
83
+
84
+ const mid = requireSourceNumber(pair.priceUsd, `${bare}.priceUsd`);
85
+ const liq = fromSourceNumber(pair.liquidityUsd);
86
+ const requested = sizeUsd === null ? parseDecimal('0') : sizeUsd;
87
+
88
+ const impact =
89
+ requested.mantissa === 0n ? parseDecimal('0') : modelImpact(liq, requested);
90
+
91
+ // DexScreener liq is approximate. Any real size is unaccounted for impact quality.
92
+ let costAccounted = false;
93
+ if (requested.mantissa === 0n && (pair.liquidityUsd ?? 0) >= THIN_LIQ_USD) {
94
+ // Even at zero size we do not claim full cost accounting: fees and gas unknown.
95
+ costAccounted = false;
96
+ }
97
+
98
+ const q = {
99
+ venue: VENUE,
100
+ chain: CHAIN,
101
+ instrument: 'spot',
102
+ tier: TIER,
103
+ symbolRaw,
104
+ symbol: bare,
105
+ side,
106
+ requestedSize: requested,
107
+ mid,
108
+ fees: null,
109
+ gasEstimate: null,
110
+ priceImpact: impact,
111
+ fundingHourly: null,
112
+ costAccounted,
113
+ capturedAt: data().capturedAt * 1000,
114
+ blockOrSeq: null,
115
+ raw: {
116
+ fixture: 'fixtures/solana_xstocks.json',
117
+ mint: token.mint,
118
+ pairAddress: pair.pairAddress,
119
+ dexId: pair.dexId,
120
+ quote: pair.quote,
121
+ liquidityUsd: pair.liquidityUsd,
122
+ volume24h: pair.volume24h,
123
+ priceUsd: pair.priceUsd,
124
+ source: 'dexscreener',
125
+ approximate: true,
126
+ reasonCostUnknown:
127
+ 'DexScreener liquidity.usd is a third-party float; fees and SOL gas not captured; impact is modeled',
128
+ thin: (pair.liquidityUsd ?? 0) < THIN_LIQ_USD,
129
+ },
130
+ };
131
+
132
+ return validateQuote(q);
133
+ }
134
+
135
+ export function quoteAll({ side = 'buy', sizeUsd = null } = {}) {
136
+ return listTokens()
137
+ .map((symbol) => quote({ symbol, side, sizeUsd }))
138
+ .filter((q) => q !== null);
139
+ }