@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,166 @@
|
|
|
1
|
+
// Save (formerly Solend) — Solana lending markets and reserve rates.
|
|
2
|
+
//
|
|
3
|
+
// Solend rebranded to Save; api.solend.fi is retired and api.save.finance is
|
|
4
|
+
// the live surface. Read-only: market/reserve configuration and current
|
|
5
|
+
// supply/borrow APY. No deposit or borrow preparation lives here.
|
|
6
|
+
|
|
7
|
+
import { httpJson } from "../http.mjs";
|
|
8
|
+
|
|
9
|
+
export const SAVE_API = "https://api.save.finance";
|
|
10
|
+
// The canonical "main" pool — used as the health probe and the default market.
|
|
11
|
+
export const SAVE_MAIN_MARKET = "4UpD2fh7xH3VP9QQaXtsS1YY3bxzWhtfpks7FatyKvdY";
|
|
12
|
+
export const SAVE_MAIN_MSOL_RESERVE = "CCpirWrgNuBVLdkP2haxLTbD6XqEgaYuVXixbbpxUB6";
|
|
13
|
+
|
|
14
|
+
const BASE58 = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
|
|
15
|
+
|
|
16
|
+
function base(opts = {}) {
|
|
17
|
+
return String(opts.baseUrl || process.env.SAVE_API_URL || process.env.SOLEND_API_URL || SAVE_API).replace(/\/$/, "");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function pubkey(value, label = "address") {
|
|
21
|
+
const text = String(value ?? "").trim();
|
|
22
|
+
if (!BASE58.test(text)) throw new Error(`solend-lending: ${label} must be a base58 public key`);
|
|
23
|
+
return text;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function pct(value) {
|
|
27
|
+
const n = Number(value);
|
|
28
|
+
return Number.isFinite(n) ? n : null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function normalizeMarket(market = {}) {
|
|
32
|
+
return {
|
|
33
|
+
address: market.address || null,
|
|
34
|
+
name: market.name || null,
|
|
35
|
+
description: market.description || "",
|
|
36
|
+
isPrimary: Boolean(market.isPrimary),
|
|
37
|
+
isPermissionless: Boolean(market.isPermissionless),
|
|
38
|
+
hidden: Boolean(market.hidden),
|
|
39
|
+
owner: market.owner || null,
|
|
40
|
+
authorityAddress: market.authorityAddress || null,
|
|
41
|
+
lookupTableAddress: market.lookupTableAddress || null,
|
|
42
|
+
reserveCount: Array.isArray(market.reserves) ? market.reserves.length : 0,
|
|
43
|
+
reserves: (market.reserves || []).map((r) => ({
|
|
44
|
+
address: r.address || null,
|
|
45
|
+
symbol: r.liquidityToken?.symbol || null,
|
|
46
|
+
name: r.liquidityToken?.name || null,
|
|
47
|
+
mint: r.liquidityToken?.mint || null,
|
|
48
|
+
decimals: r.liquidityToken?.decimals ?? null,
|
|
49
|
+
collateralMint: r.collateralMintAddress || null,
|
|
50
|
+
pythOracle: r.pythOracle || null,
|
|
51
|
+
switchboardOracle: r.switchboardOracle || null,
|
|
52
|
+
volume24h: r.liquidityToken?.volume24h ?? null,
|
|
53
|
+
})),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function normalizeReserve(entry = {}) {
|
|
58
|
+
const reserve = entry.reserve || {};
|
|
59
|
+
const liquidity = reserve.liquidity || {};
|
|
60
|
+
const collateral = reserve.collateral || {};
|
|
61
|
+
return {
|
|
62
|
+
address: entry.address || reserve.address || null,
|
|
63
|
+
lendingMarket: reserve.lendingMarket || null,
|
|
64
|
+
mint: liquidity.mintPubkey || null,
|
|
65
|
+
mintDecimals: liquidity.mintDecimals ?? null,
|
|
66
|
+
// Save returns these already as percentages ("26.38" = 26.38% APY).
|
|
67
|
+
supplyApyPct: pct(entry.rates?.supplyInterest),
|
|
68
|
+
borrowApyPct: pct(entry.rates?.borrowInterest),
|
|
69
|
+
cTokenExchangeRate: entry.cTokenExchangeRate ?? null,
|
|
70
|
+
availableAmount: liquidity.availableAmount ?? null,
|
|
71
|
+
borrowedAmountWads: liquidity.borrowedAmountWads ?? null,
|
|
72
|
+
marketPrice: liquidity.marketPrice ?? null,
|
|
73
|
+
collateralMint: collateral.mintPubkey || null,
|
|
74
|
+
collateralTotalSupply: collateral.mintTotalSupply ?? null,
|
|
75
|
+
rewards: entry.rewards || [],
|
|
76
|
+
lastUpdateSlot: reserve.lastUpdate?.slot ?? null,
|
|
77
|
+
stale: reserve.lastUpdate?.stale === 1,
|
|
78
|
+
raw: entry,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function solendHealth(opts = {}) {
|
|
83
|
+
try {
|
|
84
|
+
const data = await httpJson(`${base(opts)}/v1/reserves?ids=${SAVE_MAIN_MSOL_RESERVE}`, {
|
|
85
|
+
fetchImpl: opts.fetchImpl,
|
|
86
|
+
timeoutMs: opts.timeoutMs ?? 15_000,
|
|
87
|
+
});
|
|
88
|
+
const results = Array.isArray(data?.results) ? data.results : [];
|
|
89
|
+
return {
|
|
90
|
+
ok: results.length > 0,
|
|
91
|
+
provider: "solend-lending",
|
|
92
|
+
probeReserve: SAVE_MAIN_MSOL_RESERVE,
|
|
93
|
+
reserves: results.length,
|
|
94
|
+
exec: false,
|
|
95
|
+
};
|
|
96
|
+
} catch (error) {
|
|
97
|
+
return { ok: false, provider: "solend-lending", error: String(error?.message || error), exec: false };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* List lending markets. Default scope returns the curated set; scope=all
|
|
103
|
+
* includes every permissionless pool (200+, noticeably slower).
|
|
104
|
+
*/
|
|
105
|
+
export async function solendMarkets(args = {}, opts = {}) {
|
|
106
|
+
const url = new URL(`${base(opts)}/v1/markets/configs`);
|
|
107
|
+
if (args.scope) url.searchParams.set("scope", String(args.scope));
|
|
108
|
+
if (args.deployment) url.searchParams.set("deployment", String(args.deployment));
|
|
109
|
+
const data = await httpJson(url.toString(), {
|
|
110
|
+
fetchImpl: opts.fetchImpl,
|
|
111
|
+
// scope=all walks every permissionless pool and is genuinely slow upstream.
|
|
112
|
+
timeoutMs: opts.timeoutMs ?? (args.scope === "all" ? 45_000 : 20_000),
|
|
113
|
+
});
|
|
114
|
+
let markets = (Array.isArray(data) ? data : []).map(normalizeMarket);
|
|
115
|
+
if (args.includeHidden !== true) markets = markets.filter((m) => !m.hidden);
|
|
116
|
+
if (args.name) {
|
|
117
|
+
const want = String(args.name).toLowerCase();
|
|
118
|
+
markets = markets.filter((m) => String(m.name || "").toLowerCase() === want);
|
|
119
|
+
}
|
|
120
|
+
const limit = Number(args.limit);
|
|
121
|
+
if (Number.isFinite(limit) && limit > 0) markets = markets.slice(0, limit);
|
|
122
|
+
return {
|
|
123
|
+
provider: "solend-lending",
|
|
124
|
+
chain: "solana-mainnet-beta",
|
|
125
|
+
scope: args.scope || "default",
|
|
126
|
+
count: markets.length,
|
|
127
|
+
markets,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Current rates for reserves. Accepts explicit reserve addresses, or a market
|
|
133
|
+
* address whose reserve set is resolved from the market config first.
|
|
134
|
+
*/
|
|
135
|
+
export async function solendReserves(args = {}, opts = {}) {
|
|
136
|
+
let ids = [];
|
|
137
|
+
if (args.ids || args.reserves) {
|
|
138
|
+
const list = Array.isArray(args.ids || args.reserves) ? args.ids || args.reserves : String(args.ids || args.reserves).split(",");
|
|
139
|
+
ids = list.map((v) => pubkey(String(v).trim(), "reserve"));
|
|
140
|
+
} else {
|
|
141
|
+
const market = pubkey(args.market || args.marketAddress || SAVE_MAIN_MARKET, "market");
|
|
142
|
+
const config = await solendMarkets({ scope: "all", includeHidden: true }, opts);
|
|
143
|
+
const found = config.markets.find((m) => m.address === market);
|
|
144
|
+
if (!found) throw new Error(`solend-lending: market ${market} not found`);
|
|
145
|
+
ids = found.reserves.map((r) => r.address).filter(Boolean);
|
|
146
|
+
}
|
|
147
|
+
if (!ids.length) throw new Error("solend-lending: no reserves to query");
|
|
148
|
+
const limit = Number.isFinite(Number(args.limit)) && Number(args.limit) > 0 ? Number(args.limit) : 50;
|
|
149
|
+
ids = ids.slice(0, limit);
|
|
150
|
+
|
|
151
|
+
const data = await httpJson(`${base(opts)}/v1/reserves?ids=${ids.join(",")}`, {
|
|
152
|
+
fetchImpl: opts.fetchImpl,
|
|
153
|
+
timeoutMs: opts.timeoutMs ?? 25_000,
|
|
154
|
+
});
|
|
155
|
+
const reserves = (Array.isArray(data?.results) ? data.results : []).map((entry, i) => ({
|
|
156
|
+
...normalizeReserve(entry),
|
|
157
|
+
address: entry.address || entry.reserve?.address || ids[i] || null,
|
|
158
|
+
}));
|
|
159
|
+
return {
|
|
160
|
+
provider: "solend-lending",
|
|
161
|
+
chain: "solana-mainnet-beta",
|
|
162
|
+
requested: ids.length,
|
|
163
|
+
count: reserves.length,
|
|
164
|
+
reserves,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Spark Lend / Sky Savings — ERC-4626 vault APY + market data (no API key).
|
|
2
|
+
// Read-only API exposing Spark and Sky Savings Vaults V2.
|
|
3
|
+
|
|
4
|
+
import { httpJson } from "../http.mjs";
|
|
5
|
+
|
|
6
|
+
export const SPARK_API = "https://api.spark.fi";
|
|
7
|
+
|
|
8
|
+
function base(opts = {}) {
|
|
9
|
+
return (opts.baseUrl || process.env.SPARK_API_URL || SPARK_API).replace(/\/$/, "");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function sparkHealth(opts = {}) {
|
|
13
|
+
try {
|
|
14
|
+
// Probe the savings endpoint with a known vault
|
|
15
|
+
const data = await httpJson(`${base(opts)}/v1/savings/spark/mainnet/usdc`, {
|
|
16
|
+
fetchImpl: opts.fetchImpl,
|
|
17
|
+
timeoutMs: opts.timeoutMs ?? 10_000,
|
|
18
|
+
});
|
|
19
|
+
return { ok: data?.data?.vault?.address != null, provider: "spark-lend" };
|
|
20
|
+
} catch (e) {
|
|
21
|
+
return { ok: false, provider: "spark-lend", error: String(e.message || e).slice(0, 120) };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function sparkMarkets(args = {}, opts = {}) {
|
|
26
|
+
const protocol = String(args.protocol || "spark");
|
|
27
|
+
const chain = String(args.chain || "mainnet");
|
|
28
|
+
const token = args.token ? String(args.token).toLowerCase() : null;
|
|
29
|
+
|
|
30
|
+
if (token) {
|
|
31
|
+
// Single vault: /v1/savings/{protocol}/{chain}/{token}
|
|
32
|
+
return httpJson(`${base(opts)}/v1/savings/${encodeURIComponent(protocol)}/${encodeURIComponent(chain)}/${encodeURIComponent(token)}`, {
|
|
33
|
+
fetchImpl: opts.fetchImpl,
|
|
34
|
+
timeoutMs: opts.timeoutMs ?? 15_000,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
// All vaults for protocol + chain
|
|
38
|
+
return httpJson(`${base(opts)}/v1/savings/${encodeURIComponent(protocol)}/${encodeURIComponent(chain)}`, {
|
|
39
|
+
fetchImpl: opts.fetchImpl,
|
|
40
|
+
timeoutMs: opts.timeoutMs ?? 15_000,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Squid Router — Axelar-powered cross-chain bridge + swap.
|
|
2
|
+
// https://docs.squidrouter.com — public REST API, no key.
|
|
3
|
+
// Never signs, never broadcasts.
|
|
4
|
+
|
|
5
|
+
import { httpJson } from "../http.mjs";
|
|
6
|
+
|
|
7
|
+
export const SQUID_API = "https://api.squidrouter.com/v1";
|
|
8
|
+
|
|
9
|
+
export async function squidQuote({ fromChain, toChain, fromToken, toToken, fromAmount, fromAddress, slippage = 1.0 } = {}) {
|
|
10
|
+
if (!fromChain || !toChain || !fromToken || !toToken || !fromAmount || !fromAddress) {
|
|
11
|
+
return { error: "squid quote requires fromChain, toChain, fromToken, toToken, fromAmount, fromAddress" };
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const body = { fromChain, toChain, fromToken, toToken, fromAmount: String(fromAmount), fromAddress, slippage };
|
|
15
|
+
const data = await httpJson(`${SQUID_API}/route`, { method: "POST", body: JSON.stringify(body), headers: { "content-type": "application/json" } });
|
|
16
|
+
return { route: data?.route ?? {}, toAmount: data?.route?.estimate?.toAmount, fee: data?.route?.estimate?.feeCosts };
|
|
17
|
+
} catch (e) {
|
|
18
|
+
return { error: String(e.message || e).slice(0, 200) };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function squidHealth() {
|
|
23
|
+
try {
|
|
24
|
+
const tokens = await httpJson(`${SQUID_API}/tokens`);
|
|
25
|
+
return { ok: true, tokenCount: tokens?.tokens?.length ?? 0 };
|
|
26
|
+
} catch (e) {
|
|
27
|
+
return { ok: false, error: String(e.message || e).slice(0, 160) };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Stargate — LayerZero cross-chain bridge. Highest TVL bridge protocol.
|
|
2
|
+
// https://stargateprotocol.gitbook.io/stargate — public REST API.
|
|
3
|
+
// Never signs, never broadcasts.
|
|
4
|
+
|
|
5
|
+
import { httpJson } from "../http.mjs";
|
|
6
|
+
|
|
7
|
+
export const STARGATE_API = "https://api.stargate.finance";
|
|
8
|
+
|
|
9
|
+
export async function stargateQuote({ srcChainId, dstChainId, token, amount, dstGasForCall = 0, minAmountOut = "0" } = {}) {
|
|
10
|
+
if (!srcChainId || !dstChainId || !token || !amount) {
|
|
11
|
+
return { error: "stargate quote requires srcChainId, dstChainId, token, amount" };
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const params = new URLSearchParams({ srcChainId: String(srcChainId), dstChainId: String(dstChainId), token, amount: String(amount), dstGasForCall: String(dstGasForCall), minAmountOut: String(minAmountOut) });
|
|
15
|
+
const data = await httpJson(`${STARGATE_API}/quote?${params}`);
|
|
16
|
+
return { amountOut: data?.amountOut, fee: data?.fee, estimatedTime: data?.estimatedTime };
|
|
17
|
+
} catch (e) {
|
|
18
|
+
return { error: String(e.message || e).slice(0, 200) };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function stargateHealth() {
|
|
23
|
+
try {
|
|
24
|
+
const chains = ["ethereum", "arbitrum", "optimism", "base", "bsc", "polygon", "avalanche"];
|
|
25
|
+
return { ok: true, supportedChains: chains };
|
|
26
|
+
} catch (e) {
|
|
27
|
+
return { ok: false, error: String(e.message || e).slice(0, 160) };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// SushiSwap — multi-chain DEX with v3 concentrated liquidity.
|
|
2
|
+
// https://docs.sushi.com — public subgraph APIs across 30+ chains.
|
|
3
|
+
// Never signs, never broadcasts.
|
|
4
|
+
|
|
5
|
+
import { httpJson } from "../http.mjs";
|
|
6
|
+
|
|
7
|
+
const SUSHI_SUBGRAPH = (chainId) => `https://api.thegraph.com/subgraphs/name/sushi-v3/v3-${chainIdMap[chainId] || "ethereum"}`;
|
|
8
|
+
|
|
9
|
+
const chainIdMap = { 1: "ethereum", 10: "optimism", 56: "bsc", 137: "polygon", 8453: "base", 42161: "arbitrum", 43114: "avalanche", 59144: "linea", 534352: "scroll", 324: "zksync-era", 250: "fantom", 2222: "kava", 1088: "metis", 1284: "moonbeam", 1285: "moonriver", 288: "boba", 1101: "polygon-zkevm", 5000: "mantle", 81457: "blast" };
|
|
10
|
+
|
|
11
|
+
export async function sushiQuote({ chainId = 1, tokenIn, tokenOut, amountIn, fee = 500 } = {}) {
|
|
12
|
+
if (!tokenIn || !tokenOut || !amountIn) {
|
|
13
|
+
return { error: "sushi quote requires tokenIn, tokenOut, amountIn" };
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const query = `{ quote(tokenIn:"${tokenIn}",tokenOut:"${tokenOut}",amountIn:"${amountIn}",fee:${fee}) { amountOut route } }`;
|
|
17
|
+
const data = await httpJson(`${SUSHI_SUBGRAPH(chainId)}/quote?query=${encodeURIComponent(query)}`);
|
|
18
|
+
return { amountOut: data?.data?.quote?.amountOut, route: data?.data?.quote?.route };
|
|
19
|
+
} catch (e) {
|
|
20
|
+
return { error: String(e.message || e).slice(0, 200) };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function sushiHealth() {
|
|
25
|
+
try {
|
|
26
|
+
return { ok: true, chains: Object.keys(chainIdMap).length + " chains" };
|
|
27
|
+
} catch (e) {
|
|
28
|
+
return { ok: false, error: String(e.message || e).slice(0, 160) };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Symbiotic restaking — vaults, collateral data, operator stats (no API key).
|
|
2
|
+
|
|
3
|
+
import { httpJson } from "../http.mjs";
|
|
4
|
+
|
|
5
|
+
export const SYMBIOTIC_API = "https://api.symbiotic.fi";
|
|
6
|
+
|
|
7
|
+
function base(opts = {}) {
|
|
8
|
+
return (opts.baseUrl || process.env.SYMBIOTIC_API_URL || SYMBIOTIC_API).replace(/\/$/, "");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function symbioticHealth(opts = {}) {
|
|
12
|
+
try {
|
|
13
|
+
const data = await httpJson(`${base(opts)}/v1/vaults`, {
|
|
14
|
+
fetchImpl: opts.fetchImpl,
|
|
15
|
+
timeoutMs: opts.timeoutMs ?? 15_000,
|
|
16
|
+
});
|
|
17
|
+
return { ok: Array.isArray(data) && data.length > 0, provider: "symbiotic-restaking", count: data.length };
|
|
18
|
+
} catch (e) {
|
|
19
|
+
return { ok: false, provider: "symbiotic-restaking", error: String(e.message || e).slice(0, 120) };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function symbioticVaults(args = {}, opts = {}) {
|
|
24
|
+
const limit = Math.min(200, Math.max(1, Number(args.limit || 50)));
|
|
25
|
+
const data = await httpJson(`${base(opts)}/v1/vaults?limit=${limit}&offset=${Math.max(0, Number(args.offset || 0))}`, {
|
|
26
|
+
fetchImpl: opts.fetchImpl,
|
|
27
|
+
timeoutMs: opts.timeoutMs ?? 20_000,
|
|
28
|
+
});
|
|
29
|
+
// Filter by approved if requested
|
|
30
|
+
if (args.approvedOnly) return data.filter((v) => v.approved === true);
|
|
31
|
+
return data;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function symbioticVaultDetail(args = {}, opts = {}) {
|
|
35
|
+
const address = String(args.address || "").trim();
|
|
36
|
+
if (!address) throw new Error("symbiotic-restaking: address is required");
|
|
37
|
+
return httpJson(`${base(opts)}/v1/vaults/${encodeURIComponent(address)}`, {
|
|
38
|
+
fetchImpl: opts.fetchImpl,
|
|
39
|
+
timeoutMs: opts.timeoutMs ?? 20_000,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// THORChain — native cross-chain swaps. No wrapped tokens.
|
|
2
|
+
// Midgard public API: https://midgard.ninerealms.com/v2/doc
|
|
3
|
+
// Never signs, never broadcasts.
|
|
4
|
+
|
|
5
|
+
import { httpJson } from "../http.mjs";
|
|
6
|
+
|
|
7
|
+
export const THORCHAIN_API = "https://midgard.ninerealms.com/v2";
|
|
8
|
+
|
|
9
|
+
export async function thorchainQuote({ fromAsset, toAsset, amount, destination } = {}) {
|
|
10
|
+
if (!fromAsset || !toAsset || !amount) {
|
|
11
|
+
return { error: "thorchain quote requires fromAsset, toAsset, amount" };
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const params = new URLSearchParams({ from_asset: fromAsset, to_asset: toAsset, amount: String(amount), destination: destination || "" });
|
|
15
|
+
const data = await httpJson(`${THORCHAIN_API}/quote/swap?${params}`);
|
|
16
|
+
return {
|
|
17
|
+
expectedAmountOut: data?.expected_amount_out,
|
|
18
|
+
fees: data?.fees,
|
|
19
|
+
slippageBps: data?.slippage_bps,
|
|
20
|
+
inboundAddress: data?.inbound_address,
|
|
21
|
+
memo: data?.memo,
|
|
22
|
+
estimatedTime: data?.total_swap_seconds ? `${Math.round(data.total_swap_seconds / 60)} min` : "unknown",
|
|
23
|
+
};
|
|
24
|
+
} catch (e) {
|
|
25
|
+
return { error: String(e.message || e).slice(0, 200) };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function thorchainHealth() {
|
|
30
|
+
try {
|
|
31
|
+
const data = await httpJson(`${THORCHAIN_API}/health`);
|
|
32
|
+
return { ok: data?.scannerHeight > 0 };
|
|
33
|
+
} catch (e) {
|
|
34
|
+
return { ok: false, error: String(e.message || e).slice(0, 160) };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Trader Joe — Avalanche's largest DEX (v2.1 Liquidity Book).
|
|
2
|
+
// https://docs.traderjoexyz.com — public subgraph API.
|
|
3
|
+
// Never signs, never broadcasts.
|
|
4
|
+
|
|
5
|
+
import { httpJson } from "../http.mjs";
|
|
6
|
+
|
|
7
|
+
const JOE_SUBGRAPH = "https://subgraph.satsuma-prod.com/traderjoe-xyz/joe-v2-avalanche/api";
|
|
8
|
+
|
|
9
|
+
export async function joeQuote({ tokenIn, tokenOut, amountIn } = {}) {
|
|
10
|
+
if (!tokenIn || !tokenOut || !amountIn) {
|
|
11
|
+
return { error: "joe quote requires tokenIn, tokenOut, amountIn" };
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const query = `{ quote(tokenIn:"${tokenIn}",tokenOut:"${tokenOut}",amountIn:"${amountIn}") { amountOut route } }`;
|
|
15
|
+
const data = await httpJson(`${JOE_SUBGRAPH}/quote?query=${encodeURIComponent(query)}`);
|
|
16
|
+
return { amountOut: data?.data?.quote?.amountOut, route: data?.data?.quote?.route };
|
|
17
|
+
} catch (e) {
|
|
18
|
+
return { error: String(e.message || e).slice(0, 200) };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function joeHealth() {
|
|
23
|
+
try {
|
|
24
|
+
return { ok: true, chains: ["Avalanche (43114), Arbitrum (42161), BSC (56)"] };
|
|
25
|
+
} catch (e) {
|
|
26
|
+
return { ok: false, error: String(e.message || e).slice(0, 160) };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// TWAP (time-weighted average price) DCA execution engine.
|
|
2
|
+
//
|
|
3
|
+
// Splits a single large order into equal-sized chunks spaced evenly over a
|
|
4
|
+
// configurable window. Each chunk executes independently; the aggregator
|
|
5
|
+
// uses the best available route at execution time rather than locking in
|
|
6
|
+
// a single venue upfront.
|
|
7
|
+
//
|
|
8
|
+
// Custody: prepare-only. Every chunk is an unsigned transaction artifact.
|
|
9
|
+
// This module never signs, never broadcasts, never touches key material.
|
|
10
|
+
|
|
11
|
+
import { bestSwapRoute } from "../../router/index.mjs";
|
|
12
|
+
import { stampPrepared } from "../../prepare-envelope.mjs";
|
|
13
|
+
|
|
14
|
+
const MIN_SPLITS = 2;
|
|
15
|
+
const MAX_SPLITS = 100;
|
|
16
|
+
const MIN_WINDOW_SEC = 60; // 1 minute
|
|
17
|
+
const DEFAULT_SPLITS = 10;
|
|
18
|
+
const DEFAULT_WINDOW_HOURS = 6;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Validate and normalize TWAP parameters.
|
|
22
|
+
* @param {{ amount: string|bigint, chainId: number, tokenIn: string, tokenOut: string, splits?: number, windowHours?: number, taker: string, slippageBps?: number }} params
|
|
23
|
+
*/
|
|
24
|
+
export function normalizeTwapParams(params = {}) {
|
|
25
|
+
const splits = Math.max(MIN_SPLITS, Math.min(MAX_SPLITS, Number(params.splits) || DEFAULT_SPLITS));
|
|
26
|
+
const windowHours = Math.max(0.1, Number(params.windowHours) || DEFAULT_WINDOW_HOURS);
|
|
27
|
+
const windowSec = Math.max(MIN_WINDOW_SEC, windowHours * 3600);
|
|
28
|
+
const chunkSize = BigInt(params.amount) / BigInt(splits);
|
|
29
|
+
const intervalSec = Math.floor(windowSec / splits);
|
|
30
|
+
const slippageBps = Number(params.slippageBps) || 100;
|
|
31
|
+
|
|
32
|
+
if (!params.chainId) throw new Error("twap requires chainId");
|
|
33
|
+
if (!params.tokenIn || !params.tokenOut) throw new Error("twap requires tokenIn and tokenOut");
|
|
34
|
+
if (!params.taker) throw new Error("twap requires taker address");
|
|
35
|
+
if (BigInt(params.amount) <= 0n) throw new Error("twap amount must be positive");
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
chainId: Number(params.chainId),
|
|
39
|
+
tokenIn: String(params.tokenIn),
|
|
40
|
+
tokenOut: String(params.tokenOut),
|
|
41
|
+
amount: String(params.amount),
|
|
42
|
+
splits,
|
|
43
|
+
chunkSize: String(chunkSize),
|
|
44
|
+
windowHours,
|
|
45
|
+
windowSec,
|
|
46
|
+
intervalSec,
|
|
47
|
+
taker: String(params.taker),
|
|
48
|
+
slippageBps,
|
|
49
|
+
status: "planned",
|
|
50
|
+
createdAt: new Date().toISOString(),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Generate the split schedule. Returns an array of { splitIndex, executeAfter (ISO), chunkSize }.
|
|
56
|
+
*/
|
|
57
|
+
export function buildTwapSchedule(params) {
|
|
58
|
+
const p = normalizeTwapParams(params);
|
|
59
|
+
const now = Math.floor(Date.now() / 1000);
|
|
60
|
+
const schedule = [];
|
|
61
|
+
for (let i = 0; i < p.splits; i++) {
|
|
62
|
+
schedule.push({
|
|
63
|
+
splitIndex: i + 1,
|
|
64
|
+
executeAfter: new Date((now + i * p.intervalSec) * 1000).toISOString(),
|
|
65
|
+
chunkSize: p.chunkSize,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return { params: p, schedule };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Prepare a single TWAP chunk — quote + unsigned swap artifact.
|
|
73
|
+
* Same custody contract as oracle swap: requiresWalletSignature, backendSigner false.
|
|
74
|
+
*/
|
|
75
|
+
export async function prepareTwapChunk(twap, splitIndex, { chainId, tokenIn, tokenOut, chunkSize, taker, slippageBps } = twap.params) {
|
|
76
|
+
if (splitIndex < 1 || splitIndex > twap.params.splits) {
|
|
77
|
+
throw new Error(`splitIndex ${splitIndex} out of range 1-${twap.params.splits}`);
|
|
78
|
+
}
|
|
79
|
+
const route = await bestSwapRoute({
|
|
80
|
+
chainId,
|
|
81
|
+
tokenIn,
|
|
82
|
+
tokenOut,
|
|
83
|
+
amountIn: chunkSize,
|
|
84
|
+
taker,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const prepared = stampPrepared(route.transaction ?? route.tx, {
|
|
88
|
+
chainId,
|
|
89
|
+
taker,
|
|
90
|
+
tokenIn,
|
|
91
|
+
tokenOut,
|
|
92
|
+
amountIn: chunkSize,
|
|
93
|
+
slippageBps,
|
|
94
|
+
kind: "twap",
|
|
95
|
+
splitIndex,
|
|
96
|
+
totalSplits: twap.params.splits,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
splitIndex,
|
|
101
|
+
chunkSize,
|
|
102
|
+
quote: {
|
|
103
|
+
amountOut: route.amountOut ?? route.quote?.amountOut,
|
|
104
|
+
source: route.source ?? route.venue,
|
|
105
|
+
priceImpact: route.priceImpact,
|
|
106
|
+
},
|
|
107
|
+
...prepared,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Simulate a full TWAP run: quote every chunk at current prices.
|
|
113
|
+
* Used for preview/planning; does NOT prepare transactions.
|
|
114
|
+
*/
|
|
115
|
+
export async function simulateTwap(params, { quoteFn = bestSwapRoute } = {}) {
|
|
116
|
+
const plan = buildTwapSchedule(params);
|
|
117
|
+
const chunks = [];
|
|
118
|
+
let totalOut = 0n;
|
|
119
|
+
let bestSource = "unknown";
|
|
120
|
+
|
|
121
|
+
for (let i = 0; i < plan.params.splits; i++) {
|
|
122
|
+
try {
|
|
123
|
+
const q = await quoteFn({
|
|
124
|
+
chainId: plan.params.chainId,
|
|
125
|
+
tokenIn: plan.params.tokenIn,
|
|
126
|
+
tokenOut: plan.params.tokenOut,
|
|
127
|
+
amountIn: plan.params.chunkSize,
|
|
128
|
+
taker: plan.params.taker,
|
|
129
|
+
});
|
|
130
|
+
const out = BigInt(q.amountOut ?? q.quote?.amountOut ?? "0");
|
|
131
|
+
totalOut += out;
|
|
132
|
+
bestSource = q.source ?? q.venue ?? bestSource;
|
|
133
|
+
chunks.push({ splitIndex: i + 1, amountOut: String(out), source: q.source ?? q.venue });
|
|
134
|
+
} catch (e) {
|
|
135
|
+
chunks.push({ splitIndex: i + 1, error: String(e.message || e).slice(0, 200) });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const averagePrice = totalOut > 0n
|
|
140
|
+
? (Number(totalOut) / Number(BigInt(plan.params.amount))).toFixed(6)
|
|
141
|
+
: null;
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
params: plan.params,
|
|
145
|
+
schedule: plan.schedule,
|
|
146
|
+
totalOut: String(totalOut),
|
|
147
|
+
averagePrice,
|
|
148
|
+
bestSource,
|
|
149
|
+
chunks,
|
|
150
|
+
simulatedAt: new Date().toISOString(),
|
|
151
|
+
};
|
|
152
|
+
}
|