@oracle-agent/oracle 0.13.1 → 0.14.1
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.
- package/CONTRIBUTING.md +99 -0
- package/README.md +20 -14
- package/SECURITY.md +6 -8
- package/SETUP.md +25 -27
- package/bin/desk-server.mjs +473 -0
- package/bin/oracle-data-mcp.mjs +1252 -0
- package/bin/oracle-equities.mjs +168 -0
- package/bin/oracle-init.mjs +525 -0
- package/bin/oracle-public-server.mjs +36 -0
- package/bin/oracle-route.mjs +254 -0
- package/bin/oracle-scan.mjs +192 -0
- package/bin/oracle-upgrade.mjs +42 -0
- package/bin/oracle.mjs +34 -0
- package/docs/adding-a-chain.md +229 -0
- package/docs/architecture.md +139 -0
- package/docs/buzz-integration.md +115 -0
- package/docs/cli.md +143 -0
- package/docs/connectors.md +13 -0
- package/docs/hyperliquid-builder-code.md +50 -0
- package/docs/locals-only-fee-waiver.md +34 -0
- package/docs/oracle-pack-standard.md +29 -0
- package/docs/profiles.md +151 -0
- package/docs/public-surface.md +206 -0
- package/examples/add-a-chain.mjs +65 -0
- package/examples/oracle-pack-template.mjs +38 -0
- package/examples/research-a-token.mjs +70 -0
- package/package.json +78 -32
- package/plugins/oracle-owner-gate/__init__.py +288 -0
- package/plugins/oracle-owner-gate/plugin.yaml +9 -0
- package/{dist/assets/profiles → profiles}/oracle/SOUL.md +0 -14
- package/protocols/templates/safe-erc20/SECURITY.md +16 -0
- package/protocols/templates/safe-erc20/foundry.toml +12 -0
- package/protocols/templates/safe-erc20/remappings.txt +2 -0
- package/protocols/templates/safe-erc20/src/SafeERC20.sol +53 -0
- package/protocols/templates/safe-erc20/test/SafeERC20.t.sol +72 -0
- package/public/oracle-splash/_variants/ice.html +3 -3
- package/public/oracle-splash/_variants/ivory.html +3 -3
- package/public/oracle-splash/downloads/index.html +34 -223
- package/public/oracle-splash/index.html +11 -11
- package/scripts/adversarial-bench.mjs +114 -0
- package/scripts/build-dist.mjs +119 -0
- package/scripts/build-inscription.py +230 -0
- package/scripts/check-doc-drift.mjs +123 -0
- package/scripts/check-test-count.mjs +105 -0
- package/scripts/e2e-hl-markets.mjs +21 -0
- package/scripts/e2e-hl-perps.mjs +48 -0
- package/scripts/e2e-hypercore-staking.mjs +128 -0
- package/scripts/e2e-solana-bitcoin.mjs +183 -0
- package/scripts/guard-publish.mjs +22 -0
- package/scripts/protocol-template-gate.mjs +15 -0
- package/scripts/public-api-scan.mjs +23 -0
- package/scripts/publish-dist.mjs +67 -0
- package/scripts/record-hero-cli.sh +80 -0
- package/scripts/secret-scan.mjs +169 -0
- package/scripts/smoke-dist-bins.mjs +89 -0
- package/scripts/verify-dist.mjs +29 -0
- package/scripts/verify-v3-venues.mjs +233 -0
- package/skins/oracle.yaml +56 -0
- package/src/action-receipts.mjs +265 -0
- package/src/action-semantics.mjs +62 -0
- package/src/address-book.mjs +208 -0
- package/src/agent-auth.mjs +206 -0
- package/src/approval-guard.mjs +282 -0
- package/src/attestation-secret.mjs +94 -0
- package/src/audit-log.mjs +196 -0
- package/src/auth/oauth.mjs +672 -0
- package/src/auto-slippage.mjs +378 -0
- package/src/capability-posture.mjs +125 -0
- package/src/cards.mjs +422 -0
- package/src/chains.mjs +62 -0
- package/src/cli/chain-catalog.mjs +215 -0
- package/src/cli/chain-state.mjs +74 -0
- package/src/cli/commands/auth.mjs +193 -0
- package/src/cli/commands/bootstrap.mjs +87 -0
- package/src/cli/commands/chain.mjs +143 -0
- package/src/cli/commands/chat.mjs +465 -0
- package/src/cli/commands/credential.mjs +9 -0
- package/src/cli/commands/data-mcp.mjs +18 -0
- package/src/cli/commands/data.mjs +75 -0
- package/src/cli/commands/doctor.mjs +136 -0
- package/src/cli/commands/equities.mjs +41 -0
- package/src/cli/commands/farm.mjs +129 -0
- package/src/cli/commands/fees.mjs +109 -0
- package/src/cli/commands/follow.mjs +130 -0
- package/src/cli/commands/harness.mjs +63 -0
- package/src/cli/commands/help.mjs +7 -0
- package/src/cli/commands/init.mjs +27 -0
- package/src/cli/commands/mcp.mjs +154 -0
- package/src/cli/commands/model.mjs +106 -0
- package/src/cli/commands/plugins.mjs +275 -0
- package/src/cli/commands/prepare.mjs +12 -0
- package/src/cli/commands/public.mjs +20 -0
- package/src/cli/commands/resolve.mjs +64 -0
- package/src/cli/commands/route.mjs +12 -0
- package/src/cli/commands/runner.mjs +9 -0
- package/src/cli/commands/scan.mjs +12 -0
- package/src/cli/commands/setup.mjs +294 -0
- package/src/cli/commands/sign.mjs +21 -0
- package/src/cli/commands/signer.mjs +9 -0
- package/src/cli/commands/swap.mjs +102 -0
- package/src/cli/commands/upgrade.mjs +12 -0
- package/src/cli/commands/vault.mjs +9 -0
- package/src/cli/commands/version.mjs +22 -0
- package/src/cli/first-run.mjs +23 -0
- package/src/cli/kernel.mjs +262 -0
- package/src/cli/mcp-targets/chatgpt.mjs +51 -0
- package/src/cli/mcp-targets/claude-code.mjs +39 -0
- package/src/cli/mcp-targets/claude-desktop.mjs +24 -0
- package/src/cli/mcp-targets/codex.mjs +41 -0
- package/src/cli/mcp-targets/cursor.mjs +32 -0
- package/src/cli/mcp-targets/shared.mjs +71 -0
- package/src/cli/mcp-targets/vscode.mjs +39 -0
- package/src/cli/messaging-platforms.mjs +217 -0
- package/src/cli/model-config.mjs +78 -0
- package/src/cli/operator-dispatch.mjs +194 -0
- package/src/cli/oracle-harness.py +415 -0
- package/src/cli/paths.mjs +107 -0
- package/src/cli/runtime.mjs +351 -0
- package/src/cli/setup-state.mjs +168 -0
- package/src/cli/spawn-child.mjs +43 -0
- package/src/data/catalog.mjs +858 -0
- package/src/data/desk-data.mjs +877 -0
- package/src/data/http.mjs +253 -0
- package/src/data/names.mjs +188 -0
- package/src/data/provider-endpoint.mjs +94 -0
- package/src/data/providers/aave-v3.mjs +139 -0
- package/src/data/providers/across-bridge.mjs +41 -0
- package/src/data/providers/aerodrome.mjs +245 -0
- package/src/data/providers/aevo.mjs +33 -0
- package/src/data/providers/approval-indexer.mjs +133 -0
- package/src/data/providers/approvals.mjs +594 -0
- package/src/data/providers/babylon-staking.mjs +149 -0
- package/src/data/providers/balancer.mjs +209 -0
- package/src/data/providers/beefy-yields.mjs +45 -0
- package/src/data/providers/birdeye-tokens.mjs +33 -0
- package/src/data/providers/bisq-markets.mjs +145 -0
- package/src/data/providers/bitcoin-esplora.mjs +216 -0
- package/src/data/providers/bitcoin-meta.mjs +378 -0
- package/src/data/providers/blockscout.mjs +14 -0
- package/src/data/providers/bob-rootstock.mjs +198 -0
- package/src/data/providers/braiins-insights.mjs +103 -0
- package/src/data/providers/bridge-aggregator.mjs +259 -0
- package/src/data/providers/bridges.mjs +242 -0
- package/src/data/providers/bungee.mjs +29 -0
- package/src/data/providers/celestia-da.mjs +38 -0
- package/src/data/providers/changenow.mjs +135 -0
- package/src/data/providers/compound.mjs +32 -0
- package/src/data/providers/connext.mjs +28 -0
- package/src/data/providers/convex.mjs +30 -0
- package/src/data/providers/cow-protocol.mjs +110 -0
- package/src/data/providers/cowswap.mjs +415 -0
- package/src/data/providers/curve.mjs +201 -0
- package/src/data/providers/das-assets.mjs +59 -0
- package/src/data/providers/debridge.mjs +109 -0
- package/src/data/providers/defillama.mjs +88 -0
- package/src/data/providers/dexscreener.mjs +43 -0
- package/src/data/providers/drift.mjs +32 -0
- package/src/data/providers/dydx.mjs +41 -0
- package/src/data/providers/evm-rpc.mjs +225 -0
- package/src/data/providers/farming.mjs +291 -0
- package/src/data/providers/geckoterminal.mjs +34 -0
- package/src/data/providers/gmx.mjs +496 -0
- package/src/data/providers/hiro-stacks.mjs +150 -0
- package/src/data/providers/hl-assets.mjs +165 -0
- package/src/data/providers/hl-info.mjs +108 -0
- package/src/data/providers/hl-markets.mjs +210 -0
- package/src/data/providers/hl-outcome.mjs +61 -0
- package/src/data/providers/hl-perps.mjs +419 -0
- package/src/data/providers/hl-staking.mjs +353 -0
- package/src/data/providers/hl-ws.mjs +119 -0
- package/src/data/providers/hyperevm-dex.mjs +49 -0
- package/src/data/providers/jito-mev.mjs +117 -0
- package/src/data/providers/jupiter-venues.mjs +119 -0
- package/src/data/providers/jupiter.mjs +315 -0
- package/src/data/providers/kamino-strategies.mjs +143 -0
- package/src/data/providers/l2beat-tvl.mjs +42 -0
- package/src/data/providers/lifi.mjs +166 -0
- package/src/data/providers/liquid-esplora.mjs +152 -0
- package/src/data/providers/magiceden-ordinals.mjs +141 -0
- package/src/data/providers/magiceden-sol.mjs +406 -0
- package/src/data/providers/mempool-lightning.mjs +144 -0
- package/src/data/providers/mempool-mining.mjs +142 -0
- package/src/data/providers/meteora-dlmm.mjs +168 -0
- package/src/data/providers/morpho.mjs +177 -0
- package/src/data/providers/nft-gallery.mjs +163 -0
- package/src/data/providers/nft-portfolio.mjs +494 -0
- package/src/data/providers/odos.mjs +156 -0
- package/src/data/providers/ondo.mjs +31 -0
- package/src/data/providers/oneinch.mjs +174 -0
- package/src/data/providers/opensea-multichain.mjs +136 -0
- package/src/data/providers/opensea-nft.mjs +371 -0
- package/src/data/providers/orca.mjs +29 -0
- package/src/data/providers/ordinals-runes.mjs +180 -0
- package/src/data/providers/pancakeswap.mjs +28 -0
- package/src/data/providers/paraswap.mjs +125 -0
- package/src/data/providers/pendle.mjs +188 -0
- package/src/data/providers/poly-clob.mjs +283 -0
- package/src/data/providers/poly-public.mjs +96 -0
- package/src/data/providers/poly-ws.mjs +103 -0
- package/src/data/providers/polygon-staking.mjs +227 -0
- package/src/data/providers/portfolio-history.mjs +394 -0
- package/src/data/providers/portfolio.mjs +600 -0
- package/src/data/providers/pyth-price-feeds.mjs +172 -0
- package/src/data/providers/raydium.mjs +35 -0
- package/src/data/providers/relayscan-mev.mjs +72 -0
- package/src/data/providers/rfq.mjs +15 -0
- package/src/data/providers/rh-agent.mjs +59 -0
- package/src/data/providers/sanctum-lst.mjs +180 -0
- package/src/data/providers/satflow.mjs +341 -0
- package/src/data/providers/signed-material-guard.mjs +108 -0
- package/src/data/providers/solana-rpc.mjs +197 -0
- package/src/data/providers/solend-lending.mjs +166 -0
- package/src/data/providers/spark-lend.mjs +42 -0
- package/src/data/providers/squid-router.mjs +29 -0
- package/src/data/providers/stargate.mjs +29 -0
- package/src/data/providers/sushiswap.mjs +30 -0
- package/src/data/providers/symbiotic-restaking.mjs +41 -0
- package/src/data/providers/thorchain.mjs +36 -0
- package/src/data/providers/traderjoe.mjs +28 -0
- package/src/data/providers/twap.mjs +152 -0
- package/src/data/providers/uniswap-v3.mjs +457 -0
- package/src/data/providers/uniswap-v4.mjs +414 -0
- package/src/data/providers/vertex.mjs +41 -0
- package/src/data/providers/wallet-watch.mjs +264 -0
- package/src/data/providers/wormhole.mjs +28 -0
- package/src/data/providers/yearn.mjs +31 -0
- package/src/data/providers/zerox.mjs +167 -0
- package/src/data/public-api-scan.mjs +61 -0
- package/src/data/quote-placeholder.mjs +31 -0
- package/src/desk/swap-prepare.mjs +194 -0
- package/src/equities/bridge.mjs +388 -0
- package/src/equities/fixtures/bridge_routes.json +159 -0
- package/src/equities/fixtures/dst_transitions.json +29 -0
- package/src/equities/fixtures/equity_dex_pools.json +154 -0
- package/src/equities/fixtures/hip3_l2books.json +2711 -0
- package/src/equities/fixtures/nyse_holidays.json +1 -0
- package/src/equities/fixtures/oracles.json +100 -0
- package/src/equities/fixtures/rh_pool_state.json +244 -0
- package/src/equities/fixtures/solana_xstocks.json +704 -0
- package/src/equities/fixtures/ton_xstocks.json +35 -0
- package/src/equities/fixtures/universe.json +411 -0
- package/src/equities/fixtures/venues.json +3542 -0
- package/src/equities/fixtures.mjs +405 -0
- package/src/equities/funding.mjs +142 -0
- package/src/equities/index.mjs +166 -0
- package/src/equities/liveness.mjs +148 -0
- package/src/equities/marketHours.mjs +249 -0
- package/src/equities/normalize.mjs +295 -0
- package/src/equities/num.mjs +146 -0
- package/src/equities/prepare.mjs +95 -0
- package/src/equities/rank.mjs +260 -0
- package/src/equities/sourceNum.mjs +69 -0
- package/src/equities/types.mjs +220 -0
- package/src/equities/venues/arcus-perp.mjs +84 -0
- package/src/equities/venues/arcus-spot.mjs +105 -0
- package/src/equities/venues/hyperliquid-hip3.mjs +224 -0
- package/src/equities/venues/rh-uniswap.mjs +216 -0
- package/src/equities/venues/solana-xstocks.mjs +139 -0
- package/src/equities/venues/ton-stonfi.mjs +139 -0
- package/src/exact-integer.mjs +72 -0
- package/src/exec-policy.mjs +419 -0
- package/src/flags.mjs +15 -0
- package/src/fresh-window.mjs +76 -0
- package/src/gmx-attestation.mjs +176 -0
- package/src/index.mjs +107 -0
- package/src/licensing/locals-only.mjs +25 -0
- package/src/nft-gas-war-guard.mjs +139 -0
- package/src/onboarding/agent-keys.mjs +161 -0
- package/src/onboarding/harness-configs.mjs +102 -0
- package/src/onboarding/index.mjs +18 -0
- package/src/onboarding/tiers.mjs +139 -0
- package/src/oracle-env.mjs +55 -0
- package/src/package-manifest.mjs +42 -0
- package/src/plugins/agent-plugin-loader.mjs +225 -0
- package/src/portfolio-risk.mjs +170 -0
- package/src/prepare-envelope.mjs +204 -0
- package/src/profile-upgrade.mjs +277 -0
- package/src/protocol-execution.mjs +84 -0
- package/src/protocol-templates/gate.mjs +179 -0
- package/src/protocol-templates/prepare-deploy.mjs +81 -0
- package/src/public-api/agent-grants.mjs +57 -0
- package/src/public-api/buzz-integration.mjs +267 -0
- package/src/public-api/connect-agent.mjs +424 -0
- package/src/public-api/grants.mjs +142 -0
- package/src/public-api/http.mjs +707 -0
- package/src/public-api/metering.mjs +111 -0
- package/src/public-control/aa-adapter.mjs +402 -0
- package/src/public-control/build-registry.mjs +227 -0
- package/src/public-control/bundler-client.mjs +357 -0
- package/src/public-control/grant-indexer.mjs +296 -0
- package/src/public-control/policy-render.mjs +69 -0
- package/src/public-control/policy-schema.mjs +322 -0
- package/src/public-control/runtime-config.mjs +275 -0
- package/src/public-control/session-key-model.mjs +379 -0
- package/src/public-control/session-orchestrator.mjs +418 -0
- package/src/rfq/intent.mjs +180 -0
- package/src/rfq/sources.mjs +181 -0
- package/src/route-attestation.mjs +132 -0
- package/src/router/best-execution.mjs +326 -0
- package/src/router/index.mjs +250 -0
- package/src/router/integrator-fee.mjs +135 -0
- package/src/router/prepare-bridge.mjs +293 -0
- package/src/router/prepare-route.mjs +398 -0
- package/src/router/proposal.mjs +311 -0
- package/src/router/risk-classifier.mjs +119 -0
- package/src/router/route-sources.mjs +364 -0
- package/src/scanner/chains.config.mjs +543 -0
- package/src/scanner/contract.mjs +270 -0
- package/src/scanner/evm-scanner.mjs +394 -0
- package/src/scanner/index.mjs +9 -0
- package/src/scanner/v2-venue.mjs +351 -0
- package/src/scanner/v3-venue.mjs +308 -0
- package/src/scopes.mjs +44 -0
- package/src/sell-simulation.mjs +167 -0
- package/src/signals/engine.mjs +146 -0
- package/src/signals/index.mjs +1 -0
- package/src/token-transfer-guard.mjs +188 -0
- package/src/tui/app.mjs +438 -0
- package/src/tui/backend.mjs +215 -0
- package/src/tui/format.mjs +272 -0
- package/src/tui/gateway-client.mjs +177 -0
- package/src/tui/input.mjs +501 -0
- package/src/tui/memory.mjs +105 -0
- package/src/tui/meta-learn.mjs +85 -0
- package/src/tui/renderer.mjs +443 -0
- package/src/tui/scheduler.mjs +205 -0
- package/src/tui/skills-loader.mjs +140 -0
- package/src/tui/standalone-client.mjs +752 -0
- package/src/tui/theme.mjs +81 -0
- package/src/vault-attestation.mjs +146 -0
- package/src/venues.mjs +206 -0
- package/src/watch-preferences.mjs +85 -0
- package/dist/action-receipts.mjs +0 -1
- package/dist/action-semantics.mjs +0 -1
- package/dist/address-book.mjs +0 -2
- package/dist/bin/desk-server.mjs +0 -59
- package/dist/bin/oracle-data-mcp.mjs +0 -8
- package/dist/bin/oracle-equities.mjs +0 -20
- package/dist/bin/oracle-init.mjs +0 -24
- package/dist/bin/oracle-public-server.mjs +0 -5
- package/dist/bin/oracle-route.mjs +0 -22
- package/dist/bin/oracle-scan.mjs +0 -18
- package/dist/bin/oracle-upgrade.mjs +0 -21
- package/dist/bin/oracle.mjs +0 -76
- package/dist/chains.mjs +0 -1
- package/dist/cli/commands/auth.mjs +0 -16
- package/dist/cli/commands/bootstrap.mjs +0 -18
- package/dist/cli/commands/chain.mjs +0 -21
- package/dist/cli/commands/chat.mjs +0 -45
- package/dist/cli/commands/credential.mjs +0 -1
- package/dist/cli/commands/data-mcp.mjs +0 -2
- package/dist/cli/commands/data.mjs +0 -12
- package/dist/cli/commands/doctor.mjs +0 -5
- package/dist/cli/commands/equities.mjs +0 -15
- package/dist/cli/commands/farm.mjs +0 -59
- package/dist/cli/commands/follow.mjs +0 -28
- package/dist/cli/commands/gate.mjs +0 -13
- package/dist/cli/commands/harness.mjs +0 -15
- package/dist/cli/commands/help.mjs +0 -1
- package/dist/cli/commands/init.mjs +0 -3
- package/dist/cli/commands/mcp.mjs +0 -60
- package/dist/cli/commands/model.mjs +0 -54
- package/dist/cli/commands/plugins.mjs +0 -38
- package/dist/cli/commands/prepare.mjs +0 -2
- package/dist/cli/commands/public.mjs +0 -3
- package/dist/cli/commands/resolve.mjs +0 -23
- package/dist/cli/commands/route.mjs +0 -2
- package/dist/cli/commands/runner.mjs +0 -1
- package/dist/cli/commands/scan.mjs +0 -2
- package/dist/cli/commands/setup.mjs +0 -34
- package/dist/cli/commands/sign.mjs +0 -21
- package/dist/cli/commands/signer.mjs +0 -1
- package/dist/cli/commands/swap.mjs +0 -36
- package/dist/cli/commands/upgrade.mjs +0 -2
- package/dist/cli/commands/vault.mjs +0 -1
- package/dist/cli/commands/version.mjs +0 -2
- package/dist/data/desk-data.mjs +0 -55
- package/dist/data/names.mjs +0 -2
- package/dist/data/providers/farming.mjs +0 -2
- package/dist/equities/index.mjs +0 -1
- package/dist/index.mjs +0 -60
- package/dist/nft-gas-war-guard.mjs +0 -1
- package/dist/onboarding/harness-configs.mjs +0 -4
- package/dist/portfolio-risk.mjs +0 -1
- package/dist/prepare-envelope.mjs +0 -1
- package/dist/public-api/agent-grants.mjs +0 -3
- package/dist/public-control/policy-schema.mjs +0 -1
- package/dist/router/index.mjs +0 -2
- package/dist/scanner/index.mjs +0 -4
- package/dist/signals/index.mjs +0 -1
- package/dist/watch-preferences.mjs +0 -1
- /package/{dist/assets/profiles → profiles}/_template/SOUL.md +0 -0
- /package/{dist/assets/profiles → profiles}/_template/profile.json +0 -0
- /package/{dist/assets/profiles → profiles}/bitcoin-agent/SOUL.md +0 -0
- /package/{dist/assets/profiles → profiles}/bitcoin-agent/profile.json +0 -0
- /package/{dist/assets/profiles → profiles}/hyperliquid-agent/SOUL.md +0 -0
- /package/{dist/assets/profiles → profiles}/hyperliquid-agent/profile.json +0 -0
- /package/{dist/assets/profiles → profiles}/oracle/profile.json +0 -0
- /package/{dist/assets/profiles → profiles}/polymarket-agent/SOUL.md +0 -0
- /package/{dist/assets/profiles → profiles}/polymarket-agent/profile.json +0 -0
- /package/{dist/assets/profiles → profiles}/profile.schema.json +0 -0
- /package/{dist/assets/profiles → profiles}/protocol-builder/SOUL.md +0 -0
- /package/{dist/assets/profiles → profiles}/protocol-builder/profile.json +0 -0
- /package/{dist/assets/profiles → profiles}/robinhood-agent/SOUL.md +0 -0
- /package/{dist/assets/profiles → profiles}/robinhood-agent/profile.json +0 -0
- /package/{dist/assets/profiles → profiles}/solana-agent/SOUL.md +0 -0
- /package/{dist/assets/profiles → profiles}/solana-agent/profile.json +0 -0
- /package/{dist/assets/profiles → profiles}/stable-agent/SOUL.md +0 -0
- /package/{dist/assets/profiles → profiles}/stable-agent/profile.json +0 -0
- /package/{dist/assets/skills → skills}/balance/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/bitcoin-l1.md +0 -0
- /package/{dist/assets/skills → skills}/chain-defi-ecosystem-profiling.md +0 -0
- /package/{dist/assets/skills → skills}/evm-contract-research.md +0 -0
- /package/{dist/assets/skills → skills}/hyperliquid.md +0 -0
- /package/{dist/assets/skills → skills}/multichain-exec-desk.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-action-semantics/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-best-execution/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-best-execution.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-bitcoin/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-chain-graphs-telegram-cards/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-chat/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-chat/chain.SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-chat/setup.SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-circuit-breaker/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-contract-research/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-desk/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-desk.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-dex-launch/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-equities/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-grants/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-hypercore-staking/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-hyperliquid/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-meme-token-sniper/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-multichain-nft-launch/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-multichain-token-launch/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-nft-gacha-launch/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-nft-mint-gas-war/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-polymarket/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-protocol-builder/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-protocol-security/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-public-product/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-receipts/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-receipts.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-rfq-tokenized-assets/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-smart-wallet-scanner/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-solana/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-solana-nft/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/oracle-token-research/SKILL.md +0 -0
- /package/{dist/assets/skills → skills}/solana.md +0 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
// Bridge quote pack — Across, Hop, Relay (public, no key).
|
|
2
|
+
|
|
3
|
+
import { httpJson } from "../http.mjs";
|
|
4
|
+
import { attachAutoSlippage, bindAutoSlippageGuardToCall, resolveAutoSlippage } from "../../auto-slippage.mjs";
|
|
5
|
+
import { QUOTE_PLACEHOLDER_ADDRESS, quoteAddress } from "../quote-placeholder.mjs";
|
|
6
|
+
import { stampPrepared } from "../../prepare-envelope.mjs";
|
|
7
|
+
|
|
8
|
+
export const ACROSS_API = "https://across.to/api";
|
|
9
|
+
export const HOP_API = "https://api.hop.exchange/v1";
|
|
10
|
+
export const RELAY_API = "https://api.relay.link";
|
|
11
|
+
|
|
12
|
+
const HOP_CHAIN_IDS = {
|
|
13
|
+
ethereum: 1,
|
|
14
|
+
optimism: 10,
|
|
15
|
+
bsc: 56,
|
|
16
|
+
polygon: 137,
|
|
17
|
+
arbitrum: 42161,
|
|
18
|
+
avalanche: 43114,
|
|
19
|
+
base: 8453,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// ── Across ──────────────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
export async function acrossHealth(opts = {}) {
|
|
25
|
+
try {
|
|
26
|
+
const q = await acrossSuggestedFees(
|
|
27
|
+
{
|
|
28
|
+
token: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
29
|
+
destinationToken: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
30
|
+
originChainId: 1,
|
|
31
|
+
destinationChainId: 42161,
|
|
32
|
+
amount: "1000000000000000",
|
|
33
|
+
},
|
|
34
|
+
opts
|
|
35
|
+
);
|
|
36
|
+
return { ok: true, estimatedFillTimeSec: q.estimatedFillTimeSec };
|
|
37
|
+
} catch (e) {
|
|
38
|
+
return { ok: false, error: String(e.message || e).slice(0, 160) };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function acrossSuggestedFees(q = {}, opts = {}) {
|
|
43
|
+
const {
|
|
44
|
+
token,
|
|
45
|
+
destinationToken = token,
|
|
46
|
+
originChainId,
|
|
47
|
+
destinationChainId,
|
|
48
|
+
amount,
|
|
49
|
+
} = q;
|
|
50
|
+
if (!token || originChainId == null || destinationChainId == null || !amount) {
|
|
51
|
+
throw new Error("acrossSuggestedFees requires token, originChainId, destinationChainId, amount");
|
|
52
|
+
}
|
|
53
|
+
const params = new URLSearchParams({
|
|
54
|
+
token,
|
|
55
|
+
destinationToken,
|
|
56
|
+
originChainId: String(originChainId),
|
|
57
|
+
destinationChainId: String(destinationChainId),
|
|
58
|
+
amount: String(amount),
|
|
59
|
+
});
|
|
60
|
+
const base = (opts.baseUrl || process.env.ACROSS_API_URL || ACROSS_API).replace(/\/$/, "");
|
|
61
|
+
return httpJson(`${base}/suggested-fees?${params}`, {
|
|
62
|
+
fetchImpl: opts.fetchImpl,
|
|
63
|
+
timeoutMs: opts.timeoutMs ?? 15_000,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ── Hop ─────────────────────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
export async function hopHealth(opts = {}) {
|
|
70
|
+
try {
|
|
71
|
+
const q = await hopQuote(
|
|
72
|
+
{
|
|
73
|
+
amount: "1000000000000000",
|
|
74
|
+
token: "ETH",
|
|
75
|
+
fromChain: "ethereum",
|
|
76
|
+
toChain: "arbitrum",
|
|
77
|
+
slippage: 0.5,
|
|
78
|
+
},
|
|
79
|
+
opts
|
|
80
|
+
);
|
|
81
|
+
return { ok: true, estimatedRecieved: q.estimatedRecieved || q.estimatedReceived };
|
|
82
|
+
} catch (e) {
|
|
83
|
+
return { ok: false, error: String(e.message || e).slice(0, 160) };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export async function hopQuote(q = {}, opts = {}) {
|
|
88
|
+
const {
|
|
89
|
+
amount,
|
|
90
|
+
token = "ETH",
|
|
91
|
+
fromChain = "ethereum",
|
|
92
|
+
toChain = "arbitrum",
|
|
93
|
+
} = q;
|
|
94
|
+
if (!amount) throw new Error("hopQuote requires amount");
|
|
95
|
+
const legacyCap = q.slippage == null ? undefined : Math.round(Number(q.slippage) * 100);
|
|
96
|
+
const selected = resolveAutoSlippage({
|
|
97
|
+
liquidityUsd: q.liquidityUsd,
|
|
98
|
+
priceChange5m: q.priceChange5m,
|
|
99
|
+
crossChain: fromChain !== toChain,
|
|
100
|
+
requestedCapBps: q.maxSlippageBps ?? q.slippageBps ?? legacyCap,
|
|
101
|
+
});
|
|
102
|
+
if (!selected.executable) {
|
|
103
|
+
throw new Error(`hop: route requires ${selected.requiredBps} bps above cap ${selected.capBps}`);
|
|
104
|
+
}
|
|
105
|
+
const params = new URLSearchParams({
|
|
106
|
+
amount: String(amount),
|
|
107
|
+
token,
|
|
108
|
+
fromChain,
|
|
109
|
+
toChain,
|
|
110
|
+
// Hop expresses slippage as percentage points: 0.5 = 50 bps.
|
|
111
|
+
slippage: String(selected.selectedBps / 100),
|
|
112
|
+
});
|
|
113
|
+
const base = (opts.baseUrl || process.env.HOP_API_URL || HOP_API).replace(/\/$/, "");
|
|
114
|
+
const result = await httpJson(`${base}/quote?${params}`, {
|
|
115
|
+
fetchImpl: opts.fetchImpl,
|
|
116
|
+
timeoutMs: opts.timeoutMs ?? 15_000,
|
|
117
|
+
});
|
|
118
|
+
const amountOut = result?.estimatedRecieved || result?.estimatedReceived;
|
|
119
|
+
if (!amountOut) return { ...result, autoSlippagePolicy: selected };
|
|
120
|
+
return attachAutoSlippage(result, {
|
|
121
|
+
chainId: Number(q.originChainId || q.chainId || HOP_CHAIN_IDS[fromChain] || 0),
|
|
122
|
+
venue: result?.tx?.to || "hop",
|
|
123
|
+
amountOut,
|
|
124
|
+
liquidityUsd: q.liquidityUsd,
|
|
125
|
+
priceChange5m: q.priceChange5m,
|
|
126
|
+
crossChain: fromChain !== toChain,
|
|
127
|
+
requestedCapBps: q.maxSlippageBps ?? q.slippageBps ?? legacyCap,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ── Relay ───────────────────────────────────────────────────────────────────
|
|
132
|
+
|
|
133
|
+
export async function relayHealth(opts = {}) {
|
|
134
|
+
try {
|
|
135
|
+
const q = await relayQuote(
|
|
136
|
+
{
|
|
137
|
+
user: QUOTE_PLACEHOLDER_ADDRESS,
|
|
138
|
+
originChainId: 1,
|
|
139
|
+
destinationChainId: 8453,
|
|
140
|
+
originCurrency: "0x0000000000000000000000000000000000000000",
|
|
141
|
+
destinationCurrency: "0x0000000000000000000000000000000000000000",
|
|
142
|
+
amount: "1000000000000000",
|
|
143
|
+
tradeType: "EXACT_INPUT",
|
|
144
|
+
},
|
|
145
|
+
opts
|
|
146
|
+
);
|
|
147
|
+
return { ok: true, hasSteps: Array.isArray(q.steps), stepCount: q.steps?.length || 0 };
|
|
148
|
+
} catch (e) {
|
|
149
|
+
return { ok: false, error: String(e.message || e).slice(0, 160) };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export async function relayQuote(q = {}, opts = {}) {
|
|
154
|
+
const {
|
|
155
|
+
user = QUOTE_PLACEHOLDER_ADDRESS,
|
|
156
|
+
originChainId,
|
|
157
|
+
destinationChainId,
|
|
158
|
+
originCurrency = "0x0000000000000000000000000000000000000000",
|
|
159
|
+
destinationCurrency = "0x0000000000000000000000000000000000000000",
|
|
160
|
+
amount,
|
|
161
|
+
tradeType = "EXACT_INPUT",
|
|
162
|
+
} = q;
|
|
163
|
+
if (originChainId == null || destinationChainId == null || !amount) {
|
|
164
|
+
throw new Error("relayQuote requires originChainId, destinationChainId, amount");
|
|
165
|
+
}
|
|
166
|
+
const selected = resolveAutoSlippage({
|
|
167
|
+
liquidityUsd: q.liquidityUsd,
|
|
168
|
+
priceChange5m: q.priceChange5m,
|
|
169
|
+
crossChain: Number(originChainId) !== Number(destinationChainId),
|
|
170
|
+
requestedCapBps: q.maxSlippageBps ?? q.slippageBps,
|
|
171
|
+
});
|
|
172
|
+
if (!selected.executable) {
|
|
173
|
+
throw new Error(`relay: route requires ${selected.requiredBps} bps above cap ${selected.capBps}`);
|
|
174
|
+
}
|
|
175
|
+
const base = (opts.baseUrl || process.env.RELAY_API_URL || RELAY_API).replace(/\/$/, "");
|
|
176
|
+
const result = await httpJson(`${base}/quote`, {
|
|
177
|
+
method: "POST",
|
|
178
|
+
body: {
|
|
179
|
+
user,
|
|
180
|
+
originChainId: Number(originChainId),
|
|
181
|
+
destinationChainId: Number(destinationChainId),
|
|
182
|
+
originCurrency,
|
|
183
|
+
destinationCurrency,
|
|
184
|
+
amount: String(amount),
|
|
185
|
+
tradeType,
|
|
186
|
+
// Relay expects an integer-string in basis points ("50" = 0.50%).
|
|
187
|
+
slippageTolerance: String(selected.selectedBps),
|
|
188
|
+
},
|
|
189
|
+
fetchImpl: opts.fetchImpl,
|
|
190
|
+
timeoutMs: opts.timeoutMs ?? 20_000,
|
|
191
|
+
});
|
|
192
|
+
const amountOut = result?.details?.currencyOut?.amount;
|
|
193
|
+
if (!amountOut || !/^\d+$/.test(String(amountOut))) {
|
|
194
|
+
return { ...result, autoSlippagePolicy: selected };
|
|
195
|
+
}
|
|
196
|
+
return attachAutoSlippage(result, {
|
|
197
|
+
chainId: Number(originChainId),
|
|
198
|
+
venue: result?.steps?.[0]?.items?.[0]?.data?.to || "relay",
|
|
199
|
+
amountOut,
|
|
200
|
+
liquidityUsd: q.liquidityUsd,
|
|
201
|
+
priceChange5m: q.priceChange5m,
|
|
202
|
+
crossChain: Number(originChainId) !== Number(destinationChainId),
|
|
203
|
+
requestedCapBps: q.maxSlippageBps ?? q.slippageBps,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export async function relayPrepare(q = {}, opts = {}) {
|
|
208
|
+
const quote = await relayQuote(q, opts);
|
|
209
|
+
const chainId = Number(q.originChainId);
|
|
210
|
+
const items = (quote.steps || []).flatMap((step) =>
|
|
211
|
+
(step.items || []).filter((item) => item?.data?.to && item?.data?.data).map((item) => ({ stepId: step.id, ...item.data }))
|
|
212
|
+
);
|
|
213
|
+
if (!items.length) throw new Error("relay: quote returned no executable transaction items");
|
|
214
|
+
const venue = String(quote?.autoSlippage?.venue || "").toLowerCase();
|
|
215
|
+
if (items.some((tx) => String(tx.to).toLowerCase() !== venue)) {
|
|
216
|
+
throw new Error("relay: route includes a separate approval/transaction that is not yet safely bound");
|
|
217
|
+
}
|
|
218
|
+
const transactions = items.map((tx) => ({
|
|
219
|
+
chainId,
|
|
220
|
+
from: tx.from || q.user,
|
|
221
|
+
to: tx.to,
|
|
222
|
+
data: tx.data,
|
|
223
|
+
value: tx.value ?? "0x0",
|
|
224
|
+
...(tx.gasLimit != null || tx.gas != null ? { gasLimit: tx.gasLimit ?? tx.gas } : {}),
|
|
225
|
+
slippageGuard: bindAutoSlippageGuardToCall(quote.autoSlippage, { chainId, venue: tx.to, data: tx.data }),
|
|
226
|
+
}));
|
|
227
|
+
return stampPrepared({
|
|
228
|
+
provider: "relay",
|
|
229
|
+
calldataReady: true,
|
|
230
|
+
// NOT executable authority. The bytes are assembled but nothing is signed:
|
|
231
|
+
// the user's wallet is still the only thing that can authorize this. The
|
|
232
|
+
// previous `executionReady: true` read as "cleared to execute" and trained
|
|
233
|
+
// agents to treat a quote as permission.
|
|
234
|
+
requiresUserSignature: true,
|
|
235
|
+
signingReady: false,
|
|
236
|
+
broadcastReady: false,
|
|
237
|
+
chainId,
|
|
238
|
+
quote,
|
|
239
|
+
autoSlippage: quote.autoSlippage,
|
|
240
|
+
transactions,
|
|
241
|
+
}, { provider: "relay", kind: "relay-tx" });
|
|
242
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Bungee/Socket — bridge aggregator with different inventory than LI.FI.
|
|
2
|
+
// https://docs.bungee.exchange — public REST API.
|
|
3
|
+
// Never signs, never broadcasts.
|
|
4
|
+
|
|
5
|
+
import { httpJson } from "../http.mjs";
|
|
6
|
+
|
|
7
|
+
export const BUNGEE_API = "https://api.socket.tech/v2";
|
|
8
|
+
|
|
9
|
+
export async function bungeeQuote({ fromChainId, toChainId, fromToken, toToken, fromAmount, userAddress } = {}) {
|
|
10
|
+
if (!fromChainId || !toChainId || !fromToken || !toToken || !fromAmount || !userAddress) {
|
|
11
|
+
return { error: "bungee quote requires fromChainId, toChainId, fromToken, toToken, fromAmount, userAddress" };
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const params = new URLSearchParams({ fromChainId: String(fromChainId), toChainId: String(toChainId), fromTokenAddress: fromToken, toTokenAddress: toToken, fromAmount: String(fromAmount), userAddress, sort: "output", singleTxOnly: "false" });
|
|
15
|
+
const data = await httpJson(`${BUNGEE_API}/quote?${params}`);
|
|
16
|
+
return { amountOut: data?.result?.toAmount, feeUsd: data?.result?.totalGasFeesInUsd, route: data?.result?.route, estimatedTime: data?.result?.serviceTime ? `${data.result.serviceTime}s` : "unknown" };
|
|
17
|
+
} catch (e) {
|
|
18
|
+
return { error: String(e.message || e).slice(0, 200) };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function bungeeHealth() {
|
|
23
|
+
try {
|
|
24
|
+
const data = await httpJson(`${BUNGEE_API}/supported/chains`);
|
|
25
|
+
return { ok: true, chainCount: data?.result?.length ?? 0 };
|
|
26
|
+
} catch (e) {
|
|
27
|
+
return { ok: false, error: String(e.message || e).slice(0, 160) };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Celestia DA — blob stats and transaction data via Celenium (no API key).
|
|
2
|
+
|
|
3
|
+
import { httpJson } from "../http.mjs";
|
|
4
|
+
|
|
5
|
+
export const CELENIUM_API = "https://api.celenium.io";
|
|
6
|
+
|
|
7
|
+
function base(opts = {}) {
|
|
8
|
+
return (opts.baseUrl || process.env.CELENIUM_API_URL || CELENIUM_API).replace(/\/$/, "");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function celestiaHealth(opts = {}) {
|
|
12
|
+
try {
|
|
13
|
+
const data = await httpJson(`${base(opts)}/v1/stats`, {
|
|
14
|
+
fetchImpl: opts.fetchImpl,
|
|
15
|
+
timeoutMs: opts.timeoutMs ?? 10_000,
|
|
16
|
+
});
|
|
17
|
+
return { ok: data && data.blobs_count != null, provider: "celestia-da" };
|
|
18
|
+
} catch (e) {
|
|
19
|
+
return { ok: false, provider: "celestia-da", error: String(e.message || e).slice(0, 120) };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function celestiaStats(opts = {}) {
|
|
24
|
+
return httpJson(`${base(opts)}/v1/stats`, {
|
|
25
|
+
fetchImpl: opts.fetchImpl,
|
|
26
|
+
timeoutMs: opts.timeoutMs ?? 15_000,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function celestiaBlockStats(args = {}, opts = {}) {
|
|
31
|
+
const height = Number(args.height);
|
|
32
|
+
if (height && (!Number.isFinite(height) || height < 1)) throw new Error("celestia-da: height must be positive");
|
|
33
|
+
const path = height ? `/v1/block/${height}` : "/v1/block";
|
|
34
|
+
return httpJson(`${base(opts)}${path}`, {
|
|
35
|
+
fetchImpl: opts.fetchImpl,
|
|
36
|
+
timeoutMs: opts.timeoutMs ?? 15_000,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// ChangeNOW swap provider.
|
|
2
|
+
//
|
|
3
|
+
// ChangeNOW is a centralized, non-custodial instant swap service that does
|
|
4
|
+
// not require account registration for basic swaps. Different risk model
|
|
5
|
+
// from DEX routes: funds are sent to a ChangeNOW deposit address and the
|
|
6
|
+
// swapped asset is returned to the user's withdrawal address.
|
|
7
|
+
//
|
|
8
|
+
// Public API: https://api.changenow.io/v2
|
|
9
|
+
// Docs: https://documenter.getpostman.com/view/8180765/SVfTPBxP
|
|
10
|
+
//
|
|
11
|
+
// This module is read/prepare only. It quotes routes and provides deposit
|
|
12
|
+
// instructions. The user sends funds themselves; Oracle never holds or moves
|
|
13
|
+
// funds. No API key required for public endpoints.
|
|
14
|
+
//
|
|
15
|
+
// Never signs, never broadcasts, never holds keys.
|
|
16
|
+
|
|
17
|
+
import { httpJson } from "../http.mjs";
|
|
18
|
+
|
|
19
|
+
export const CHANGENOW_API = "https://api.changenow.io/v2";
|
|
20
|
+
|
|
21
|
+
const KNOWN_CURRENCIES_CACHE = new Map();
|
|
22
|
+
let CURRENCIES_LAST_FETCH = 0;
|
|
23
|
+
const CURRENCY_TTL_MS = 600_000; // 10 minutes
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* List available currencies from ChangeNOW.
|
|
27
|
+
* Cached for 10 minutes to avoid rate-limiting on repeated queries.
|
|
28
|
+
*/
|
|
29
|
+
export async function changenowCurrencies({ active = true } = {}) {
|
|
30
|
+
const now = Date.now();
|
|
31
|
+
if (KNOWN_CURRENCIES_CACHE.size && now - CURRENCIES_LAST_FETCH < CURRENCY_TTL_MS) {
|
|
32
|
+
return [...KNOWN_CURRENCIES_CACHE.values()];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const data = await httpJson(`${CHANGENOW_API}/exchange/currencies?active=${active ? "true" : "false"}`);
|
|
37
|
+
KNOWN_CURRENCIES_CACHE.clear();
|
|
38
|
+
for (const c of data ?? []) {
|
|
39
|
+
KNOWN_CURRENCIES_CACHE.set(String(c.ticker).toLowerCase(), c);
|
|
40
|
+
}
|
|
41
|
+
CURRENCIES_LAST_FETCH = now;
|
|
42
|
+
return data ?? [];
|
|
43
|
+
} catch (e) {
|
|
44
|
+
if (KNOWN_CURRENCIES_CACHE.size) return [...KNOWN_CURRENCIES_CACHE.values()];
|
|
45
|
+
return { error: String(e.message || e).slice(0, 200) };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Get the minimum exchangeable amount for a pair.
|
|
51
|
+
*/
|
|
52
|
+
export async function changenowMinAmount(fromTicker, toTicker) {
|
|
53
|
+
if (!fromTicker || !toTicker) return { error: "changenow minAmount requires fromTicker and toTicker" };
|
|
54
|
+
try {
|
|
55
|
+
const data = await httpJson(
|
|
56
|
+
`${CHANGENOW_API}/exchange/min-amount/${encodeURIComponent(fromTicker)}_${encodeURIComponent(toTicker)}`,
|
|
57
|
+
);
|
|
58
|
+
return { minAmount: data?.minAmount ?? "0" };
|
|
59
|
+
} catch (e) {
|
|
60
|
+
return { error: String(e.message || e).slice(0, 200) };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get an estimated exchange amount for a pair.
|
|
66
|
+
*/
|
|
67
|
+
export async function changenowEstimate(fromTicker, toTicker, fromAmount, { flow = "standard" } = {}) {
|
|
68
|
+
if (!fromTicker || !toTicker || !fromAmount) {
|
|
69
|
+
return { error: "changenow estimate requires fromTicker, toTicker, fromAmount" };
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const params = new URLSearchParams({
|
|
73
|
+
fromCurrency: String(fromTicker).toLowerCase(),
|
|
74
|
+
toCurrency: String(toTicker).toLowerCase(),
|
|
75
|
+
fromAmount: String(fromAmount),
|
|
76
|
+
flow,
|
|
77
|
+
});
|
|
78
|
+
const data = await httpJson(`${CHANGENOW_API}/exchange/estimated-amount?${params}`);
|
|
79
|
+
return {
|
|
80
|
+
fromAmount: data?.fromAmount,
|
|
81
|
+
toAmount: data?.toAmount,
|
|
82
|
+
rate: data?.rate,
|
|
83
|
+
flow: data?.flow ?? flow,
|
|
84
|
+
};
|
|
85
|
+
} catch (e) {
|
|
86
|
+
return { error: String(e.message || e).slice(0, 200) };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Full quote: use estimate if fromAmount is provided, otherwise minAmount.
|
|
92
|
+
*/
|
|
93
|
+
export async function changenowQuote({ fromTicker, toTicker, fromAmount, flow } = {}) {
|
|
94
|
+
if (!fromTicker || !toTicker) {
|
|
95
|
+
return { error: "changenow quote requires fromTicker and toTicker" };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const min = await changenowMinAmount(fromTicker, toTicker);
|
|
99
|
+
if (min.error) return min;
|
|
100
|
+
|
|
101
|
+
const amount = fromAmount ?? min.minAmount;
|
|
102
|
+
const est = await changenowEstimate(fromTicker, toTicker, amount, { flow });
|
|
103
|
+
if (est.error) return est;
|
|
104
|
+
|
|
105
|
+
const currencies = await changenowCurrencies();
|
|
106
|
+
const fromInfo = currencies.find(c => String(c?.ticker).toLowerCase() === String(fromTicker).toLowerCase());
|
|
107
|
+
const toInfo = currencies.find(c => String(c?.ticker).toLowerCase() === String(toTicker).toLowerCase());
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
provider: "changenow",
|
|
111
|
+
fromTicker,
|
|
112
|
+
toTicker,
|
|
113
|
+
fromAmount: amount,
|
|
114
|
+
toAmount: est.toAmount,
|
|
115
|
+
estimatedRate: est.rate,
|
|
116
|
+
minAmount: min.minAmount,
|
|
117
|
+
flow: est.flow,
|
|
118
|
+
networkFee: fromInfo?.networkFee ?? null,
|
|
119
|
+
kycRequired: fromInfo?.kycRequired ?? toInfo?.kycRequired ?? false,
|
|
120
|
+
riskDisclosure: "ChangeNOW is a centralized swap service. Funds are sent to a ChangeNOW deposit address. Not self-custodial during the swap window.",
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* ChangeNOW health check.
|
|
126
|
+
*/
|
|
127
|
+
export async function changenowHealth() {
|
|
128
|
+
try {
|
|
129
|
+
const c = await changenowCurrencies();
|
|
130
|
+
if (c?.error) return { ok: false, error: c.error };
|
|
131
|
+
return { ok: true, currencyCount: Array.isArray(c) ? c.length : 0 };
|
|
132
|
+
} catch (e) {
|
|
133
|
+
return { ok: false, error: String(e.message || e).slice(0, 160) };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Compound — OG lending protocol ($2B+ TVL across chains).
|
|
2
|
+
// https://docs.compound.finance — public API.
|
|
3
|
+
// Never signs, never broadcasts.
|
|
4
|
+
|
|
5
|
+
import { httpJson } from "../http.mjs";
|
|
6
|
+
|
|
7
|
+
const COMPOUND_API = "https://api.compound.finance/api/v2";
|
|
8
|
+
|
|
9
|
+
export async function compoundMarkets() {
|
|
10
|
+
try {
|
|
11
|
+
const data = await httpJson(`${COMPOUND_API}/ctoken`);
|
|
12
|
+
return (data?.cToken || []).map(m => ({
|
|
13
|
+
symbol: m?.symbol,
|
|
14
|
+
underlying: m?.underlying_symbol,
|
|
15
|
+
supplyApy: m?.supply_rate?.value ? `${(Number(m.supply_rate.value) * 100).toFixed(2)}%` : null,
|
|
16
|
+
borrowApy: m?.borrow_rate?.value ? `${(Number(m.borrow_rate.value) * 100).toFixed(2)}%` : null,
|
|
17
|
+
totalSupply: m?.total_supply?.value,
|
|
18
|
+
totalBorrow: m?.total_borrows?.value,
|
|
19
|
+
collateralFactor: m?.collateral_factor?.value ? `${(Number(m.collateral_factor.value) * 100).toFixed(0)}%` : null,
|
|
20
|
+
}));
|
|
21
|
+
} catch (e) {
|
|
22
|
+
return { error: String(e.message || e).slice(0, 200) };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function compoundHealth() {
|
|
27
|
+
try {
|
|
28
|
+
return { ok: true, note: "Compound v2 — Ethereum mainnet lending" };
|
|
29
|
+
} catch (e) {
|
|
30
|
+
return { ok: false, error: String(e.message || e).slice(0, 160) };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Connext — canonical cross-chain bridge (xcall).
|
|
2
|
+
// https://docs.connext.network — public REST API.
|
|
3
|
+
// Never signs, never broadcasts.
|
|
4
|
+
|
|
5
|
+
import { httpJson } from "../http.mjs";
|
|
6
|
+
|
|
7
|
+
export const CONNEXT_API = "https://api.connext.network";
|
|
8
|
+
|
|
9
|
+
export async function connextQuote({ originDomain, destinationDomain, originToken, destinationToken, amount } = {}) {
|
|
10
|
+
if (!originDomain || !destinationDomain || !originToken || !destinationToken || !amount) {
|
|
11
|
+
return { error: "connext quote requires originDomain, destinationDomain, originToken, destinationToken, amount" };
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const body = { originDomain: String(originDomain), destinationDomain: String(destinationDomain), originToken, destinationToken, amount: String(amount) };
|
|
15
|
+
const data = await httpJson(`${CONNEXT_API}/estimate`, { method: "POST", body: JSON.stringify(body), headers: { "content-type": "application/json" } });
|
|
16
|
+
return { amountOut: data?.amountOut, fee: data?.fee, estimatedTime: data?.estimatedTransferTime };
|
|
17
|
+
} catch (e) {
|
|
18
|
+
return { error: String(e.message || e).slice(0, 200) };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function connextHealth() {
|
|
23
|
+
try {
|
|
24
|
+
return { ok: true, note: "Connext Amarok — canonical bridge across 20+ chains" };
|
|
25
|
+
} catch (e) {
|
|
26
|
+
return { ok: false, error: String(e.message || e).slice(0, 160) };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Convex Finance — Curve liquidity booster + yield optimizer.
|
|
2
|
+
// https://docs.convexfinance.com — public API.
|
|
3
|
+
// Never signs, never broadcasts.
|
|
4
|
+
|
|
5
|
+
import { httpJson } from "../http.mjs";
|
|
6
|
+
|
|
7
|
+
const CONVEX_API = "https://api.convexfinance.com/api";
|
|
8
|
+
|
|
9
|
+
export async function convexPools() {
|
|
10
|
+
try {
|
|
11
|
+
const data = await httpJson(`${CONVEX_API}/pools`);
|
|
12
|
+
return (data || []).map(p => ({
|
|
13
|
+
name: p?.curvePool?.name || p?.name,
|
|
14
|
+
curveApy: p?.curvePool?.apy ? `${(Number(p.curvePool.apy) * 100).toFixed(2)}%` : null,
|
|
15
|
+
convexApy: p?.apy ? `${(Number(p.apy) * 100).toFixed(2)}%` : null,
|
|
16
|
+
tvl: p?.tvl,
|
|
17
|
+
boosted: p?.boosted || false,
|
|
18
|
+
}));
|
|
19
|
+
} catch (e) {
|
|
20
|
+
return { error: String(e.message || e).slice(0, 200) };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function convexHealth() {
|
|
25
|
+
try {
|
|
26
|
+
return { ok: true, note: "Convex — CRV/CVX yield optimizer on Ethereum" };
|
|
27
|
+
} catch (e) {
|
|
28
|
+
return { ok: false, error: String(e.message || e).slice(0, 160) };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// CoW Protocol public Orderbook API — intent/solver-based DEX reads, no key.
|
|
2
|
+
//
|
|
3
|
+
// Read-only. This module never posts an order: CoW order creation is a signed
|
|
4
|
+
// EIP-712 intent, which belongs on the prepare/exec plane (see cowswap.mjs),
|
|
5
|
+
// not here.
|
|
6
|
+
//
|
|
7
|
+
// Endpoint reality, probed live 2026-08-06:
|
|
8
|
+
// GET /api/v1/version -> 200 (cheap liveness probe)
|
|
9
|
+
// GET /api/v1/account/{owner}/orders -> 200 (owner-scoped order book)
|
|
10
|
+
// GET /api/v1/trades?owner=0x.. -> 200 (owner or orderUid REQUIRED;
|
|
11
|
+
// the unfiltered form returns
|
|
12
|
+
// InvalidTradeFilter)
|
|
13
|
+
// GET /api/v1/auction -> 403 at the CloudFront edge for
|
|
14
|
+
// non-browser clients on EVERY
|
|
15
|
+
// network. Kept as a real call
|
|
16
|
+
// that surfaces the upstream
|
|
17
|
+
// refusal rather than a fake.
|
|
18
|
+
|
|
19
|
+
import { httpJson } from "../http.mjs";
|
|
20
|
+
|
|
21
|
+
export const COW_API = "https://api.cow.fi";
|
|
22
|
+
|
|
23
|
+
/** CoW network path segments keyed by chain id (verified: all return 200 on /version). */
|
|
24
|
+
export const COW_NETWORKS = Object.freeze({
|
|
25
|
+
1: "mainnet",
|
|
26
|
+
100: "xdai",
|
|
27
|
+
42161: "arbitrum_one",
|
|
28
|
+
8453: "base",
|
|
29
|
+
11155111: "sepolia",
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
function base(opts = {}) {
|
|
33
|
+
return (opts.baseUrl || process.env.COW_API_URL || COW_API).replace(/\/$/, "");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function network(args = {}) {
|
|
37
|
+
if (args.network) return String(args.network);
|
|
38
|
+
const chainId = Number(args.chainId ?? 1);
|
|
39
|
+
const net = COW_NETWORKS[chainId];
|
|
40
|
+
if (!net) {
|
|
41
|
+
throw new Error(`cow-protocol: unsupported chainId ${chainId} (have: ${Object.keys(COW_NETWORKS).join(", ")})`);
|
|
42
|
+
}
|
|
43
|
+
return net;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function url(args, path, opts) {
|
|
47
|
+
return `${base(opts)}/${network(args)}/api/v1${path}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function address(value, label) {
|
|
51
|
+
const text = String(value || "").trim();
|
|
52
|
+
if (!/^0x[0-9a-fA-F]{40}$/.test(text)) throw new Error(`cow-protocol: ${label} must be an EVM address`);
|
|
53
|
+
return text;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function limitOf(args, fallback = 10) {
|
|
57
|
+
return Math.min(1000, Math.max(1, Number(args.limit ?? fallback)));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Current batch auction (orders + native prices the solvers compete over).
|
|
62
|
+
*
|
|
63
|
+
* NOTE: the CoW CDN answers 403 to non-browser clients, so this throws with the
|
|
64
|
+
* upstream status. That is the honest result — the alternative would be to
|
|
65
|
+
* advertise data we cannot actually fetch.
|
|
66
|
+
*/
|
|
67
|
+
export async function cowAuction(args = {}, opts = {}) {
|
|
68
|
+
return httpJson(url(args, "/auction", opts), {
|
|
69
|
+
fetchImpl: opts.fetchImpl,
|
|
70
|
+
timeoutMs: opts.timeoutMs ?? 20_000,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Orders for one owner. CoW has no global open-order feed; owner is required. */
|
|
75
|
+
export async function cowOpenOrders(args = {}, opts = {}) {
|
|
76
|
+
const owner = address(args.owner || args.address || args.user, "owner");
|
|
77
|
+
const params = new URLSearchParams({ limit: String(limitOf(args)) });
|
|
78
|
+
if (args.offset != null) params.set("offset", String(Math.max(0, Number(args.offset))));
|
|
79
|
+
const orders = await httpJson(`${url(args, `/account/${owner}/orders`, opts)}?${params}`, {
|
|
80
|
+
fetchImpl: opts.fetchImpl,
|
|
81
|
+
timeoutMs: opts.timeoutMs ?? 20_000,
|
|
82
|
+
});
|
|
83
|
+
const rows = Array.isArray(orders) ? orders : [];
|
|
84
|
+
const open = args.openOnly === false
|
|
85
|
+
? rows
|
|
86
|
+
: rows.filter((o) => String(o?.status || "").toLowerCase() === "open");
|
|
87
|
+
return { owner, count: open.length, total: rows.length, orders: open };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Settled trades. The API demands exactly one of owner or orderUid. */
|
|
91
|
+
export async function cowRecentTrades(args = {}, opts = {}) {
|
|
92
|
+
const params = new URLSearchParams();
|
|
93
|
+
if (args.orderUid) params.set("orderUid", String(args.orderUid));
|
|
94
|
+
else params.set("owner", address(args.owner || args.address || args.user, "owner"));
|
|
95
|
+
const trades = await httpJson(`${url(args, "/trades", opts)}?${params}`, {
|
|
96
|
+
fetchImpl: opts.fetchImpl,
|
|
97
|
+
timeoutMs: opts.timeoutMs ?? 20_000,
|
|
98
|
+
});
|
|
99
|
+
const rows = Array.isArray(trades) ? trades : [];
|
|
100
|
+
return { count: rows.length, trades: rows.slice(0, limitOf(args)) };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export async function cowProtocolHealth(opts = {}) {
|
|
104
|
+
const version = await httpJson(`${base(opts)}/mainnet/api/v1/version`, {
|
|
105
|
+
fetchImpl: opts.fetchImpl,
|
|
106
|
+
timeoutMs: opts.timeoutMs ?? 12_000,
|
|
107
|
+
});
|
|
108
|
+
const text = typeof version === "string" ? version : JSON.stringify(version ?? "");
|
|
109
|
+
return { ok: text.trim().length > 0, provider: "cow-protocol", version: text.trim() || null };
|
|
110
|
+
}
|