@oracle-agent/oracle 0.14.1 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/SETUP.md +4 -4
- package/dist/action-receipts.mjs +1 -0
- package/dist/action-semantics.mjs +1 -0
- package/dist/address-book.mjs +2 -0
- package/dist/bin/desk-server.mjs +59 -0
- package/dist/bin/oracle-data-mcp.mjs +8 -0
- package/dist/bin/oracle-equities.mjs +20 -0
- package/dist/bin/oracle-init.mjs +24 -0
- package/dist/bin/oracle-public-server.mjs +5 -0
- package/dist/bin/oracle-route.mjs +22 -0
- package/dist/bin/oracle-scan.mjs +18 -0
- package/dist/bin/oracle-upgrade.mjs +21 -0
- package/dist/bin/oracle.mjs +61 -0
- package/dist/chains.mjs +1 -0
- package/dist/cli/commands/auth.mjs +16 -0
- package/dist/cli/commands/bootstrap.mjs +18 -0
- package/dist/cli/commands/chain.mjs +21 -0
- package/dist/cli/commands/chat.mjs +45 -0
- package/dist/cli/commands/credential.mjs +1 -0
- package/dist/cli/commands/data-mcp.mjs +2 -0
- package/dist/cli/commands/data.mjs +12 -0
- package/dist/cli/commands/doctor.mjs +5 -0
- package/dist/cli/commands/equities.mjs +15 -0
- package/dist/cli/commands/farm.mjs +59 -0
- package/dist/cli/commands/fees.mjs +10 -0
- package/dist/cli/commands/follow.mjs +28 -0
- package/dist/cli/commands/harness.mjs +15 -0
- package/dist/cli/commands/help.mjs +1 -0
- package/dist/cli/commands/init.mjs +3 -0
- package/dist/cli/commands/mcp.mjs +36 -0
- package/dist/cli/commands/model.mjs +54 -0
- package/dist/cli/commands/plugins.mjs +43 -0
- package/dist/cli/commands/prepare.mjs +2 -0
- package/dist/cli/commands/public.mjs +3 -0
- package/dist/cli/commands/resolve.mjs +23 -0
- package/dist/cli/commands/route.mjs +2 -0
- package/dist/cli/commands/runner.mjs +1 -0
- package/dist/cli/commands/scan.mjs +2 -0
- package/dist/cli/commands/setup.mjs +34 -0
- package/dist/cli/commands/sign.mjs +4 -0
- package/dist/cli/commands/signer.mjs +1 -0
- package/dist/cli/commands/swap.mjs +36 -0
- package/dist/cli/commands/upgrade.mjs +2 -0
- package/dist/cli/commands/vault.mjs +1 -0
- package/dist/cli/commands/version.mjs +2 -0
- package/dist/data/desk-data.mjs +55 -0
- package/dist/data/names.mjs +2 -0
- package/dist/data/providers/farming.mjs +2 -0
- package/dist/equities/index.mjs +1 -0
- package/dist/index.mjs +60 -0
- package/dist/nft-gas-war-guard.mjs +1 -0
- package/dist/onboarding/harness-configs.mjs +4 -0
- package/dist/portfolio-risk.mjs +1 -0
- package/dist/prepare-envelope.mjs +1 -0
- package/dist/public-api/agent-grants.mjs +3 -0
- package/dist/public-control/policy-schema.mjs +1 -0
- package/dist/router/index.mjs +2 -0
- package/dist/scanner/index.mjs +4 -0
- package/dist/signals/index.mjs +1 -0
- package/dist/watch-preferences.mjs +1 -0
- package/package.json +32 -78
- package/public/oracle-splash/_variants/ice.html +5 -18
- package/public/oracle-splash/_variants/ivory.html +5 -18
- package/public/oracle-splash/index.html +114 -34
- package/CONTRIBUTING.md +0 -99
- package/bin/desk-server.mjs +0 -473
- package/bin/oracle-data-mcp.mjs +0 -1252
- package/bin/oracle-equities.mjs +0 -168
- package/bin/oracle-init.mjs +0 -525
- package/bin/oracle-public-server.mjs +0 -36
- package/bin/oracle-route.mjs +0 -254
- package/bin/oracle-scan.mjs +0 -192
- package/bin/oracle-upgrade.mjs +0 -42
- package/bin/oracle.mjs +0 -34
- package/docs/adding-a-chain.md +0 -229
- package/docs/architecture.md +0 -139
- package/docs/buzz-integration.md +0 -115
- package/docs/cli.md +0 -143
- package/docs/connectors.md +0 -13
- package/docs/hyperliquid-builder-code.md +0 -50
- package/docs/locals-only-fee-waiver.md +0 -34
- package/docs/oracle-pack-standard.md +0 -29
- package/docs/profiles.md +0 -151
- package/docs/public-surface.md +0 -206
- package/examples/add-a-chain.mjs +0 -65
- package/examples/oracle-pack-template.mjs +0 -38
- package/examples/research-a-token.mjs +0 -70
- package/plugins/oracle-owner-gate/__init__.py +0 -288
- package/plugins/oracle-owner-gate/plugin.yaml +0 -9
- package/protocols/templates/safe-erc20/SECURITY.md +0 -16
- package/protocols/templates/safe-erc20/foundry.toml +0 -12
- package/protocols/templates/safe-erc20/remappings.txt +0 -2
- package/protocols/templates/safe-erc20/src/SafeERC20.sol +0 -53
- package/protocols/templates/safe-erc20/test/SafeERC20.t.sol +0 -72
- package/scripts/adversarial-bench.mjs +0 -114
- package/scripts/build-dist.mjs +0 -119
- package/scripts/build-inscription.py +0 -230
- package/scripts/check-doc-drift.mjs +0 -123
- package/scripts/check-test-count.mjs +0 -105
- package/scripts/e2e-hl-markets.mjs +0 -21
- package/scripts/e2e-hl-perps.mjs +0 -48
- package/scripts/e2e-hypercore-staking.mjs +0 -128
- package/scripts/e2e-solana-bitcoin.mjs +0 -183
- package/scripts/guard-publish.mjs +0 -22
- package/scripts/protocol-template-gate.mjs +0 -15
- package/scripts/public-api-scan.mjs +0 -23
- package/scripts/publish-dist.mjs +0 -67
- package/scripts/record-hero-cli.sh +0 -80
- package/scripts/secret-scan.mjs +0 -169
- package/scripts/smoke-dist-bins.mjs +0 -89
- package/scripts/verify-dist.mjs +0 -29
- package/scripts/verify-v3-venues.mjs +0 -233
- package/skins/oracle.yaml +0 -56
- package/src/action-receipts.mjs +0 -265
- package/src/action-semantics.mjs +0 -62
- package/src/address-book.mjs +0 -208
- package/src/agent-auth.mjs +0 -206
- package/src/approval-guard.mjs +0 -282
- package/src/attestation-secret.mjs +0 -94
- package/src/audit-log.mjs +0 -196
- package/src/auth/oauth.mjs +0 -672
- package/src/auto-slippage.mjs +0 -378
- package/src/capability-posture.mjs +0 -125
- package/src/cards.mjs +0 -422
- package/src/chains.mjs +0 -62
- package/src/cli/chain-catalog.mjs +0 -215
- package/src/cli/chain-state.mjs +0 -74
- package/src/cli/commands/auth.mjs +0 -193
- package/src/cli/commands/bootstrap.mjs +0 -87
- package/src/cli/commands/chain.mjs +0 -143
- package/src/cli/commands/chat.mjs +0 -465
- package/src/cli/commands/credential.mjs +0 -9
- package/src/cli/commands/data-mcp.mjs +0 -18
- package/src/cli/commands/data.mjs +0 -75
- package/src/cli/commands/doctor.mjs +0 -136
- package/src/cli/commands/equities.mjs +0 -41
- package/src/cli/commands/farm.mjs +0 -129
- package/src/cli/commands/fees.mjs +0 -109
- package/src/cli/commands/follow.mjs +0 -130
- package/src/cli/commands/harness.mjs +0 -63
- package/src/cli/commands/help.mjs +0 -7
- package/src/cli/commands/init.mjs +0 -27
- package/src/cli/commands/mcp.mjs +0 -154
- package/src/cli/commands/model.mjs +0 -106
- package/src/cli/commands/plugins.mjs +0 -275
- package/src/cli/commands/prepare.mjs +0 -12
- package/src/cli/commands/public.mjs +0 -20
- package/src/cli/commands/resolve.mjs +0 -64
- package/src/cli/commands/route.mjs +0 -12
- package/src/cli/commands/runner.mjs +0 -9
- package/src/cli/commands/scan.mjs +0 -12
- package/src/cli/commands/setup.mjs +0 -294
- package/src/cli/commands/sign.mjs +0 -21
- package/src/cli/commands/signer.mjs +0 -9
- package/src/cli/commands/swap.mjs +0 -102
- package/src/cli/commands/upgrade.mjs +0 -12
- package/src/cli/commands/vault.mjs +0 -9
- package/src/cli/commands/version.mjs +0 -22
- package/src/cli/first-run.mjs +0 -23
- package/src/cli/kernel.mjs +0 -262
- package/src/cli/mcp-targets/chatgpt.mjs +0 -51
- package/src/cli/mcp-targets/claude-code.mjs +0 -39
- package/src/cli/mcp-targets/claude-desktop.mjs +0 -24
- package/src/cli/mcp-targets/codex.mjs +0 -41
- package/src/cli/mcp-targets/cursor.mjs +0 -32
- package/src/cli/mcp-targets/shared.mjs +0 -71
- package/src/cli/mcp-targets/vscode.mjs +0 -39
- package/src/cli/messaging-platforms.mjs +0 -217
- package/src/cli/model-config.mjs +0 -78
- package/src/cli/operator-dispatch.mjs +0 -194
- package/src/cli/oracle-harness.py +0 -415
- package/src/cli/paths.mjs +0 -107
- package/src/cli/runtime.mjs +0 -351
- package/src/cli/setup-state.mjs +0 -168
- package/src/cli/spawn-child.mjs +0 -43
- package/src/data/catalog.mjs +0 -858
- package/src/data/desk-data.mjs +0 -877
- package/src/data/http.mjs +0 -253
- package/src/data/names.mjs +0 -188
- package/src/data/provider-endpoint.mjs +0 -94
- package/src/data/providers/aave-v3.mjs +0 -139
- package/src/data/providers/across-bridge.mjs +0 -41
- package/src/data/providers/aerodrome.mjs +0 -245
- package/src/data/providers/aevo.mjs +0 -33
- package/src/data/providers/approval-indexer.mjs +0 -133
- package/src/data/providers/approvals.mjs +0 -594
- package/src/data/providers/babylon-staking.mjs +0 -149
- package/src/data/providers/balancer.mjs +0 -209
- package/src/data/providers/beefy-yields.mjs +0 -45
- package/src/data/providers/birdeye-tokens.mjs +0 -33
- package/src/data/providers/bisq-markets.mjs +0 -145
- package/src/data/providers/bitcoin-esplora.mjs +0 -216
- package/src/data/providers/bitcoin-meta.mjs +0 -378
- package/src/data/providers/blockscout.mjs +0 -14
- package/src/data/providers/bob-rootstock.mjs +0 -198
- package/src/data/providers/braiins-insights.mjs +0 -103
- package/src/data/providers/bridge-aggregator.mjs +0 -259
- package/src/data/providers/bridges.mjs +0 -242
- package/src/data/providers/bungee.mjs +0 -29
- package/src/data/providers/celestia-da.mjs +0 -38
- package/src/data/providers/changenow.mjs +0 -135
- package/src/data/providers/compound.mjs +0 -32
- package/src/data/providers/connext.mjs +0 -28
- package/src/data/providers/convex.mjs +0 -30
- package/src/data/providers/cow-protocol.mjs +0 -110
- package/src/data/providers/cowswap.mjs +0 -415
- package/src/data/providers/curve.mjs +0 -201
- package/src/data/providers/das-assets.mjs +0 -59
- package/src/data/providers/debridge.mjs +0 -109
- package/src/data/providers/defillama.mjs +0 -88
- package/src/data/providers/dexscreener.mjs +0 -43
- package/src/data/providers/drift.mjs +0 -32
- package/src/data/providers/dydx.mjs +0 -41
- package/src/data/providers/evm-rpc.mjs +0 -225
- package/src/data/providers/farming.mjs +0 -291
- package/src/data/providers/geckoterminal.mjs +0 -34
- package/src/data/providers/gmx.mjs +0 -496
- package/src/data/providers/hiro-stacks.mjs +0 -150
- package/src/data/providers/hl-assets.mjs +0 -165
- package/src/data/providers/hl-info.mjs +0 -108
- package/src/data/providers/hl-markets.mjs +0 -210
- package/src/data/providers/hl-outcome.mjs +0 -61
- package/src/data/providers/hl-perps.mjs +0 -419
- package/src/data/providers/hl-staking.mjs +0 -353
- package/src/data/providers/hl-ws.mjs +0 -119
- package/src/data/providers/hyperevm-dex.mjs +0 -49
- package/src/data/providers/jito-mev.mjs +0 -117
- package/src/data/providers/jupiter-venues.mjs +0 -119
- package/src/data/providers/jupiter.mjs +0 -315
- package/src/data/providers/kamino-strategies.mjs +0 -143
- package/src/data/providers/l2beat-tvl.mjs +0 -42
- package/src/data/providers/lifi.mjs +0 -166
- package/src/data/providers/liquid-esplora.mjs +0 -152
- package/src/data/providers/magiceden-ordinals.mjs +0 -141
- package/src/data/providers/magiceden-sol.mjs +0 -406
- package/src/data/providers/mempool-lightning.mjs +0 -144
- package/src/data/providers/mempool-mining.mjs +0 -142
- package/src/data/providers/meteora-dlmm.mjs +0 -168
- package/src/data/providers/morpho.mjs +0 -177
- package/src/data/providers/nft-gallery.mjs +0 -163
- package/src/data/providers/nft-portfolio.mjs +0 -494
- package/src/data/providers/odos.mjs +0 -156
- package/src/data/providers/ondo.mjs +0 -31
- package/src/data/providers/oneinch.mjs +0 -174
- package/src/data/providers/opensea-multichain.mjs +0 -136
- package/src/data/providers/opensea-nft.mjs +0 -371
- package/src/data/providers/orca.mjs +0 -29
- package/src/data/providers/ordinals-runes.mjs +0 -180
- package/src/data/providers/pancakeswap.mjs +0 -28
- package/src/data/providers/paraswap.mjs +0 -125
- package/src/data/providers/pendle.mjs +0 -188
- package/src/data/providers/poly-clob.mjs +0 -283
- package/src/data/providers/poly-public.mjs +0 -96
- package/src/data/providers/poly-ws.mjs +0 -103
- package/src/data/providers/polygon-staking.mjs +0 -227
- package/src/data/providers/portfolio-history.mjs +0 -394
- package/src/data/providers/portfolio.mjs +0 -600
- package/src/data/providers/pyth-price-feeds.mjs +0 -172
- package/src/data/providers/raydium.mjs +0 -35
- package/src/data/providers/relayscan-mev.mjs +0 -72
- package/src/data/providers/rfq.mjs +0 -15
- package/src/data/providers/rh-agent.mjs +0 -59
- package/src/data/providers/sanctum-lst.mjs +0 -180
- package/src/data/providers/satflow.mjs +0 -341
- package/src/data/providers/signed-material-guard.mjs +0 -108
- package/src/data/providers/solana-rpc.mjs +0 -197
- package/src/data/providers/solend-lending.mjs +0 -166
- package/src/data/providers/spark-lend.mjs +0 -42
- package/src/data/providers/squid-router.mjs +0 -29
- package/src/data/providers/stargate.mjs +0 -29
- package/src/data/providers/sushiswap.mjs +0 -30
- package/src/data/providers/symbiotic-restaking.mjs +0 -41
- package/src/data/providers/thorchain.mjs +0 -36
- package/src/data/providers/traderjoe.mjs +0 -28
- package/src/data/providers/twap.mjs +0 -152
- package/src/data/providers/uniswap-v3.mjs +0 -457
- package/src/data/providers/uniswap-v4.mjs +0 -414
- package/src/data/providers/vertex.mjs +0 -41
- package/src/data/providers/wallet-watch.mjs +0 -264
- package/src/data/providers/wormhole.mjs +0 -28
- package/src/data/providers/yearn.mjs +0 -31
- package/src/data/providers/zerox.mjs +0 -167
- package/src/data/public-api-scan.mjs +0 -61
- package/src/data/quote-placeholder.mjs +0 -31
- package/src/desk/swap-prepare.mjs +0 -194
- package/src/equities/bridge.mjs +0 -388
- package/src/equities/fixtures/bridge_routes.json +0 -159
- package/src/equities/fixtures/dst_transitions.json +0 -29
- package/src/equities/fixtures/equity_dex_pools.json +0 -154
- package/src/equities/fixtures/hip3_l2books.json +0 -2711
- package/src/equities/fixtures/nyse_holidays.json +0 -1
- package/src/equities/fixtures/oracles.json +0 -100
- package/src/equities/fixtures/rh_pool_state.json +0 -244
- package/src/equities/fixtures/solana_xstocks.json +0 -704
- package/src/equities/fixtures/ton_xstocks.json +0 -35
- package/src/equities/fixtures/universe.json +0 -411
- package/src/equities/fixtures/venues.json +0 -3542
- package/src/equities/fixtures.mjs +0 -405
- package/src/equities/funding.mjs +0 -142
- package/src/equities/index.mjs +0 -166
- package/src/equities/liveness.mjs +0 -148
- package/src/equities/marketHours.mjs +0 -249
- package/src/equities/normalize.mjs +0 -295
- package/src/equities/num.mjs +0 -146
- package/src/equities/prepare.mjs +0 -95
- package/src/equities/rank.mjs +0 -260
- package/src/equities/sourceNum.mjs +0 -69
- package/src/equities/types.mjs +0 -220
- package/src/equities/venues/arcus-perp.mjs +0 -84
- package/src/equities/venues/arcus-spot.mjs +0 -105
- package/src/equities/venues/hyperliquid-hip3.mjs +0 -224
- package/src/equities/venues/rh-uniswap.mjs +0 -216
- package/src/equities/venues/solana-xstocks.mjs +0 -139
- package/src/equities/venues/ton-stonfi.mjs +0 -139
- package/src/exact-integer.mjs +0 -72
- package/src/exec-policy.mjs +0 -419
- package/src/flags.mjs +0 -15
- package/src/fresh-window.mjs +0 -76
- package/src/gmx-attestation.mjs +0 -176
- package/src/index.mjs +0 -107
- package/src/licensing/locals-only.mjs +0 -25
- package/src/nft-gas-war-guard.mjs +0 -139
- package/src/onboarding/agent-keys.mjs +0 -161
- package/src/onboarding/harness-configs.mjs +0 -102
- package/src/onboarding/index.mjs +0 -18
- package/src/onboarding/tiers.mjs +0 -139
- package/src/oracle-env.mjs +0 -55
- package/src/package-manifest.mjs +0 -42
- package/src/plugins/agent-plugin-loader.mjs +0 -225
- package/src/portfolio-risk.mjs +0 -170
- package/src/prepare-envelope.mjs +0 -204
- package/src/profile-upgrade.mjs +0 -277
- package/src/protocol-execution.mjs +0 -84
- package/src/protocol-templates/gate.mjs +0 -179
- package/src/protocol-templates/prepare-deploy.mjs +0 -81
- package/src/public-api/agent-grants.mjs +0 -57
- package/src/public-api/buzz-integration.mjs +0 -267
- package/src/public-api/connect-agent.mjs +0 -424
- package/src/public-api/grants.mjs +0 -142
- package/src/public-api/http.mjs +0 -707
- package/src/public-api/metering.mjs +0 -111
- package/src/public-control/aa-adapter.mjs +0 -402
- package/src/public-control/build-registry.mjs +0 -227
- package/src/public-control/bundler-client.mjs +0 -357
- package/src/public-control/grant-indexer.mjs +0 -296
- package/src/public-control/policy-render.mjs +0 -69
- package/src/public-control/policy-schema.mjs +0 -322
- package/src/public-control/runtime-config.mjs +0 -275
- package/src/public-control/session-key-model.mjs +0 -379
- package/src/public-control/session-orchestrator.mjs +0 -418
- package/src/rfq/intent.mjs +0 -180
- package/src/rfq/sources.mjs +0 -181
- package/src/route-attestation.mjs +0 -132
- package/src/router/best-execution.mjs +0 -326
- package/src/router/index.mjs +0 -250
- package/src/router/integrator-fee.mjs +0 -135
- package/src/router/prepare-bridge.mjs +0 -293
- package/src/router/prepare-route.mjs +0 -398
- package/src/router/proposal.mjs +0 -311
- package/src/router/risk-classifier.mjs +0 -119
- package/src/router/route-sources.mjs +0 -364
- package/src/scanner/chains.config.mjs +0 -543
- package/src/scanner/contract.mjs +0 -270
- package/src/scanner/evm-scanner.mjs +0 -394
- package/src/scanner/index.mjs +0 -9
- package/src/scanner/v2-venue.mjs +0 -351
- package/src/scanner/v3-venue.mjs +0 -308
- package/src/scopes.mjs +0 -44
- package/src/sell-simulation.mjs +0 -167
- package/src/signals/engine.mjs +0 -146
- package/src/signals/index.mjs +0 -1
- package/src/token-transfer-guard.mjs +0 -188
- package/src/tui/app.mjs +0 -438
- package/src/tui/backend.mjs +0 -215
- package/src/tui/format.mjs +0 -272
- package/src/tui/gateway-client.mjs +0 -177
- package/src/tui/input.mjs +0 -501
- package/src/tui/memory.mjs +0 -105
- package/src/tui/meta-learn.mjs +0 -85
- package/src/tui/renderer.mjs +0 -443
- package/src/tui/scheduler.mjs +0 -205
- package/src/tui/skills-loader.mjs +0 -140
- package/src/tui/standalone-client.mjs +0 -752
- package/src/tui/theme.mjs +0 -81
- package/src/vault-attestation.mjs +0 -146
- package/src/venues.mjs +0 -206
- package/src/watch-preferences.mjs +0 -85
- /package/{profiles → dist/assets/profiles}/_template/SOUL.md +0 -0
- /package/{profiles → dist/assets/profiles}/_template/profile.json +0 -0
- /package/{profiles → dist/assets/profiles}/bitcoin-agent/SOUL.md +0 -0
- /package/{profiles → dist/assets/profiles}/bitcoin-agent/profile.json +0 -0
- /package/{profiles → dist/assets/profiles}/hyperliquid-agent/SOUL.md +0 -0
- /package/{profiles → dist/assets/profiles}/hyperliquid-agent/profile.json +0 -0
- /package/{profiles → dist/assets/profiles}/oracle/SOUL.md +0 -0
- /package/{profiles → dist/assets/profiles}/oracle/profile.json +0 -0
- /package/{profiles → dist/assets/profiles}/polymarket-agent/SOUL.md +0 -0
- /package/{profiles → dist/assets/profiles}/polymarket-agent/profile.json +0 -0
- /package/{profiles → dist/assets/profiles}/profile.schema.json +0 -0
- /package/{profiles → dist/assets/profiles}/protocol-builder/SOUL.md +0 -0
- /package/{profiles → dist/assets/profiles}/protocol-builder/profile.json +0 -0
- /package/{profiles → dist/assets/profiles}/robinhood-agent/SOUL.md +0 -0
- /package/{profiles → dist/assets/profiles}/robinhood-agent/profile.json +0 -0
- /package/{profiles → dist/assets/profiles}/solana-agent/SOUL.md +0 -0
- /package/{profiles → dist/assets/profiles}/solana-agent/profile.json +0 -0
- /package/{profiles → dist/assets/profiles}/stable-agent/SOUL.md +0 -0
- /package/{profiles → dist/assets/profiles}/stable-agent/profile.json +0 -0
- /package/{skills → dist/assets/skills}/balance/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/bitcoin-l1.md +0 -0
- /package/{skills → dist/assets/skills}/chain-defi-ecosystem-profiling.md +0 -0
- /package/{skills → dist/assets/skills}/evm-contract-research.md +0 -0
- /package/{skills → dist/assets/skills}/hyperliquid.md +0 -0
- /package/{skills → dist/assets/skills}/multichain-exec-desk.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-action-semantics/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-best-execution/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-best-execution.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-bitcoin/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-chain-graphs-telegram-cards/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-chat/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-chat/chain.SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-chat/setup.SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-circuit-breaker/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-contract-research/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-desk/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-desk.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-dex-launch/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-equities/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-grants/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-hypercore-staking/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-hyperliquid/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-meme-token-sniper/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-multichain-nft-launch/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-multichain-token-launch/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-nft-gacha-launch/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-nft-mint-gas-war/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-polymarket/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-protocol-builder/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-protocol-security/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-public-product/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-receipts/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-receipts.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-rfq-tokenized-assets/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-smart-wallet-scanner/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-solana/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-solana-nft/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/oracle-token-research/SKILL.md +0 -0
- /package/{skills → dist/assets/skills}/solana.md +0 -0
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
// Meteora — Solana AMM pool discovery (dynamic AMM, DLMM-adjacent, LST, farms).
|
|
2
|
-
//
|
|
3
|
-
// This is a POOL INVENTORY surface, not a router: it answers "where is the
|
|
4
|
-
// liquidity and what does it yield", which Jupiter's quote endpoint does not.
|
|
5
|
-
// Read-only — no position or swap preparation.
|
|
6
|
-
//
|
|
7
|
-
// Upstream query-string quirks that are easy to get wrong:
|
|
8
|
-
// - text search is `filter=`, NOT `search_term=`/`q=`/`name=` (those are
|
|
9
|
-
// accepted and then silently IGNORED, returning the unfiltered top pools)
|
|
10
|
-
// - sort_key is an enum: tvl | volume | fee_tvl_ratio | l_m
|
|
11
|
-
// - pool_type is an enum: dynamic | multitoken | lst | farms
|
|
12
|
-
// Anything outside those enums 400s.
|
|
13
|
-
|
|
14
|
-
import { httpJson } from "../http.mjs";
|
|
15
|
-
|
|
16
|
-
export const METEORA_AMM_API = "https://amm-v2.meteora.ag";
|
|
17
|
-
|
|
18
|
-
const SORT_KEYS = new Set(["tvl", "volume", "fee_tvl_ratio", "l_m"]);
|
|
19
|
-
const POOL_TYPES = new Set(["dynamic", "multitoken", "lst", "farms"]);
|
|
20
|
-
const BASE58 = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
|
|
21
|
-
|
|
22
|
-
function base(opts = {}) {
|
|
23
|
-
return String(opts.baseUrl || process.env.METEORA_API_URL || METEORA_AMM_API).replace(/\/$/, "");
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function num(value) {
|
|
27
|
-
const n = Number(value);
|
|
28
|
-
return Number.isFinite(n) ? n : null;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function normalizePool(pool = {}) {
|
|
32
|
-
return {
|
|
33
|
-
address: pool.pool_address || null,
|
|
34
|
-
name: pool.pool_name || null,
|
|
35
|
-
type: pool.pool_type || null,
|
|
36
|
-
version: pool.pool_version ?? null,
|
|
37
|
-
mints: pool.pool_token_mints || [],
|
|
38
|
-
tokenAmounts: pool.pool_token_amounts || [],
|
|
39
|
-
tokenUsdAmounts: pool.pool_token_usd_amounts || [],
|
|
40
|
-
lpMint: pool.lp_mint || null,
|
|
41
|
-
lpDecimals: pool.lp_decimal ?? null,
|
|
42
|
-
lpPriceUsd: num(pool.pool_lp_price_in_usd),
|
|
43
|
-
tvlUsd: num(pool.pool_tvl),
|
|
44
|
-
farmTvlUsd: num(pool.farm_tvl),
|
|
45
|
-
volume24hUsd: num(pool.trading_volume),
|
|
46
|
-
volume7dUsd: num(pool.weekly_trading_volume),
|
|
47
|
-
fee24hUsd: num(pool.fee_volume),
|
|
48
|
-
fee7dUsd: num(pool.weekly_fee_volume),
|
|
49
|
-
// trade_apy is fee yield; farming_apy is emissions. They are additive.
|
|
50
|
-
tradeApyPct: num(pool.trade_apy),
|
|
51
|
-
weeklyTradeApyPct: num(pool.weekly_trade_apy),
|
|
52
|
-
baseApyPct: num(pool.daily_base_apy),
|
|
53
|
-
farmingApyPct: num(pool.farming_apy),
|
|
54
|
-
totalApyPct: (num(pool.trade_apy) ?? 0) + (num(pool.farming_apy) ?? 0),
|
|
55
|
-
aprPct: num(pool.apr),
|
|
56
|
-
feePct: num(pool.total_fee_pct),
|
|
57
|
-
farmingPool: pool.farming_pool || null,
|
|
58
|
-
isLst: Boolean(pool.is_lst),
|
|
59
|
-
isMeme: Boolean(pool.is_meme),
|
|
60
|
-
permissioned: Boolean(pool.permissioned),
|
|
61
|
-
// Meteora's own "we don't recognise these tokens" flag — treat as risk.
|
|
62
|
-
unknownTokens: Boolean(pool.unknown),
|
|
63
|
-
createdAt: pool.created_at ?? null,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function buildSearchUrl(args = {}, opts = {}) {
|
|
68
|
-
const url = new URL(`${base(opts)}/pools/search`);
|
|
69
|
-
const page = Math.max(0, Number(args.page) || 0);
|
|
70
|
-
const size = Math.max(1, Math.min(Number(args.size ?? args.limit) || 20, 100));
|
|
71
|
-
url.searchParams.set("page", String(page));
|
|
72
|
-
url.searchParams.set("size", String(size));
|
|
73
|
-
|
|
74
|
-
if (args.sortKey != null) {
|
|
75
|
-
const key = String(args.sortKey);
|
|
76
|
-
if (!SORT_KEYS.has(key)) {
|
|
77
|
-
throw new Error(`meteora-dlmm: sortKey must be one of ${[...SORT_KEYS].join(", ")}`);
|
|
78
|
-
}
|
|
79
|
-
url.searchParams.set("sort_key", key);
|
|
80
|
-
url.searchParams.set("order_by", args.orderBy === "asc" ? "asc" : "desc");
|
|
81
|
-
}
|
|
82
|
-
if (args.poolType != null) {
|
|
83
|
-
const type = String(args.poolType);
|
|
84
|
-
if (!POOL_TYPES.has(type)) {
|
|
85
|
-
throw new Error(`meteora-dlmm: poolType must be one of ${[...POOL_TYPES].join(", ")}`);
|
|
86
|
-
}
|
|
87
|
-
url.searchParams.set("pool_type", type);
|
|
88
|
-
}
|
|
89
|
-
const filter = args.filter ?? args.query ?? args.search;
|
|
90
|
-
if (filter != null && String(filter).trim()) url.searchParams.set("filter", String(filter).trim());
|
|
91
|
-
const mints = args.mints || args.includeTokenMints;
|
|
92
|
-
if (mints) {
|
|
93
|
-
const list = (Array.isArray(mints) ? mints : [mints]).map((m) => String(m).trim());
|
|
94
|
-
for (const mint of list) {
|
|
95
|
-
if (!BASE58.test(mint)) throw new Error(`meteora-dlmm: mint ${mint} is not a base58 public key`);
|
|
96
|
-
}
|
|
97
|
-
url.searchParams.set("include_token_mints", list.join(","));
|
|
98
|
-
}
|
|
99
|
-
return { url, page, size };
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
async function search(args = {}, opts = {}) {
|
|
103
|
-
const { url, page, size } = buildSearchUrl(args, opts);
|
|
104
|
-
const data = await httpJson(url.toString(), {
|
|
105
|
-
fetchImpl: opts.fetchImpl,
|
|
106
|
-
timeoutMs: opts.timeoutMs ?? 20_000,
|
|
107
|
-
});
|
|
108
|
-
const pools = (Array.isArray(data?.data) ? data.data : []).map(normalizePool);
|
|
109
|
-
return { pools, totalCount: data?.total_count ?? null, page, size };
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export async function meteoraHealth(opts = {}) {
|
|
113
|
-
try {
|
|
114
|
-
const { pools, totalCount } = await search({ size: 3 }, opts);
|
|
115
|
-
return {
|
|
116
|
-
ok: pools.length > 0,
|
|
117
|
-
provider: "meteora-dlmm",
|
|
118
|
-
poolsIndexed: totalCount,
|
|
119
|
-
sample: pools.length,
|
|
120
|
-
exec: false,
|
|
121
|
-
};
|
|
122
|
-
} catch (error) {
|
|
123
|
-
return { ok: false, provider: "meteora-dlmm", error: String(error?.message || error), exec: false };
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/** Top pools, ranked. Defaults to highest TVL. */
|
|
128
|
-
export async function meteoraPools(args = {}, opts = {}) {
|
|
129
|
-
const result = await search({ sortKey: args.sortKey || "tvl", orderBy: args.orderBy || "desc", ...args }, opts);
|
|
130
|
-
let pools = result.pools;
|
|
131
|
-
const minTvl = Number(args.minTvlUsd);
|
|
132
|
-
if (Number.isFinite(minTvl)) pools = pools.filter((p) => (p.tvlUsd ?? 0) >= minTvl);
|
|
133
|
-
if (args.excludeUnknown === true) pools = pools.filter((p) => !p.unknownTokens);
|
|
134
|
-
return {
|
|
135
|
-
provider: "meteora-dlmm",
|
|
136
|
-
chain: "solana-mainnet-beta",
|
|
137
|
-
page: result.page,
|
|
138
|
-
size: result.size,
|
|
139
|
-
totalCount: result.totalCount,
|
|
140
|
-
count: pools.length,
|
|
141
|
-
tvlUsd: pools.reduce((a, p) => a + (p.tvlUsd ?? 0), 0),
|
|
142
|
-
pools,
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Search pools by token symbol/name text or by exact mint.
|
|
148
|
-
* Prefer `mints` — text search matches pool names, which meme tokens spoof.
|
|
149
|
-
*/
|
|
150
|
-
export async function meteoraPoolSearch(args = {}, opts = {}) {
|
|
151
|
-
const filter = args.filter ?? args.query ?? args.search;
|
|
152
|
-
const mints = args.mints || args.includeTokenMints;
|
|
153
|
-
if ((filter == null || !String(filter).trim()) && !mints) {
|
|
154
|
-
throw new Error("meteora-dlmm: poolSearch requires filter text or mints[]");
|
|
155
|
-
}
|
|
156
|
-
const result = await search({ sortKey: args.sortKey || "tvl", orderBy: "desc", ...args }, opts);
|
|
157
|
-
return {
|
|
158
|
-
provider: "meteora-dlmm",
|
|
159
|
-
chain: "solana-mainnet-beta",
|
|
160
|
-
filter: filter ?? null,
|
|
161
|
-
mints: mints ? (Array.isArray(mints) ? mints : [mints]) : [],
|
|
162
|
-
page: result.page,
|
|
163
|
-
size: result.size,
|
|
164
|
-
totalCount: result.totalCount,
|
|
165
|
-
count: result.pools.length,
|
|
166
|
-
pools: result.pools,
|
|
167
|
-
};
|
|
168
|
-
}
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
// Morpho public GraphQL API — markets/vaults, no key. ERC-4626 vault
|
|
2
|
-
// prepare returns a guarded intent only; dynamic vault tx signing/submission is a
|
|
3
|
-
// later, separately gated execution step.
|
|
4
|
-
|
|
5
|
-
import { Interface, getAddress, isAddress, keccak256, toUtf8Bytes } from "ethers";
|
|
6
|
-
import { httpJson } from "../http.mjs";
|
|
7
|
-
import { rpcCall as defaultRpcCall } from "./evm-rpc.mjs";
|
|
8
|
-
import { stampPrepared } from "../../prepare-envelope.mjs";
|
|
9
|
-
|
|
10
|
-
export const MORPHO_API = "https://api.morpho.org/graphql";
|
|
11
|
-
|
|
12
|
-
const ERC4626 = new Interface([
|
|
13
|
-
"function asset() view returns (address)",
|
|
14
|
-
"function maxDeposit(address owner) view returns (uint256)",
|
|
15
|
-
"function previewDeposit(uint256 assets) view returns (uint256)",
|
|
16
|
-
"function deposit(uint256 assets,address receiver) returns (uint256)",
|
|
17
|
-
"function maxWithdraw(address owner) view returns (uint256)",
|
|
18
|
-
"function previewWithdraw(uint256 assets) view returns (uint256)",
|
|
19
|
-
"function withdraw(uint256 assets,address receiver,address owner) returns (uint256)",
|
|
20
|
-
]);
|
|
21
|
-
|
|
22
|
-
const endpoint = (o = {}) => o.baseUrl || process.env.MORPHO_API_URL || MORPHO_API;
|
|
23
|
-
|
|
24
|
-
async function gql(query, variables, opts = {}) {
|
|
25
|
-
return httpJson(endpoint(opts), {
|
|
26
|
-
method: "POST",
|
|
27
|
-
body: { query, variables },
|
|
28
|
-
fetchImpl: opts.fetchImpl,
|
|
29
|
-
timeoutMs: opts.timeoutMs ?? 20_000,
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const MARKET_QUERY = `query Markets($first: Int, $where: MarketFilters) { markets(first: $first, where: $where) { items { marketId lltv listed loanAsset { address symbol decimals } collateralAsset { address symbol decimals } state { supplyAssetsUsd borrowAssetsUsd } } } }`;
|
|
34
|
-
const VAULT_QUERY = `query Vaults($first: Int, $where: VaultFilters) { vaults(first: $first, where: $where) { items { address name symbol listed asset { address symbol decimals } state { totalAssets totalAssetsUsd apy } } } }`;
|
|
35
|
-
|
|
36
|
-
function normalAddress(value, label) {
|
|
37
|
-
const text = String(value || "").trim();
|
|
38
|
-
if (!isAddress(text)) throw new Error(`morpho: ${label} must be an address`);
|
|
39
|
-
return getAddress(text).toLowerCase();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function amountString(value, label = "amount") {
|
|
43
|
-
try {
|
|
44
|
-
const n = BigInt(String(value));
|
|
45
|
-
if (n <= 0n) throw new Error("nonpositive");
|
|
46
|
-
return n.toString();
|
|
47
|
-
} catch {
|
|
48
|
-
throw new Error(`morpho: ${label} must be a positive integer string`);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function canonicalJson(value) {
|
|
53
|
-
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
54
|
-
if (value && typeof value === "object") {
|
|
55
|
-
return `{${Object.keys(value).sort().map((k) => `${JSON.stringify(k)}:${canonicalJson(value[k])}`).join(",")}}`;
|
|
56
|
-
}
|
|
57
|
-
return JSON.stringify(value);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async function callVault(chainId, vault, fn, args, opts = {}) {
|
|
61
|
-
const data = ERC4626.encodeFunctionData(fn, args);
|
|
62
|
-
const call = opts.rpcCall || defaultRpcCall;
|
|
63
|
-
const result = await call(Number(chainId), "eth_call", [{ to: vault, data }, "latest"], opts);
|
|
64
|
-
return ERC4626.decodeFunctionResult(fn, result);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function listedVault(items, vault) {
|
|
68
|
-
const target = vault.toLowerCase();
|
|
69
|
-
return (items || []).find((item) => String(item?.address || "").toLowerCase() === target) || null;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export async function morphoMarkets(args = {}, opts = {}) {
|
|
73
|
-
const first = Math.min(100, Math.max(1, Number(args.first || 20)));
|
|
74
|
-
const chainIds = (args.chainIds || [args.chainId || 1]).map(Number);
|
|
75
|
-
return gql(MARKET_QUERY, { first, chainIds, where: { chainId_in: chainIds } }, opts);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export async function morphoVaults(args = {}, opts = {}) {
|
|
79
|
-
const first = Math.min(100, Math.max(1, Number(args.first || 20)));
|
|
80
|
-
const chainIds = (args.chainIds || [args.chainId || 1]).map(Number);
|
|
81
|
-
return gql(VAULT_QUERY, { first, chainIds, where: { chainId_in: chainIds } }, opts);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export async function morphoHealth(opts = {}) {
|
|
85
|
-
const data = await gql("query { __typename }", {}, opts);
|
|
86
|
-
return { ok: data?.data?.__typename === "Query" };
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export async function morphoPrepareVault(args = {}, opts = {}) {
|
|
90
|
-
const chainId = Number(args.chainId ?? 8453);
|
|
91
|
-
const action = String(args.action || "deposit").toLowerCase();
|
|
92
|
-
if (!["deposit", "withdraw"].includes(action)) throw new Error("morpho: action must be deposit or withdraw");
|
|
93
|
-
const vault = normalAddress(args.vault || args.vaultAddress, "vault");
|
|
94
|
-
const owner = normalAddress(args.owner || args.from || args.sender, "owner");
|
|
95
|
-
const receiver = normalAddress(args.receiver || owner, "receiver");
|
|
96
|
-
const amount = amountString(args.amount || args.assets, "amount");
|
|
97
|
-
const minTotalAssetsUsd = Number(args.minTotalAssetsUsd ?? 100_000);
|
|
98
|
-
|
|
99
|
-
const vaults = await morphoVaults({ chainId, first: 100 }, opts);
|
|
100
|
-
const info = listedVault(vaults?.data?.vaults?.items, vault);
|
|
101
|
-
if (!info) throw new Error("morpho: vault not found in public Morpho vault registry");
|
|
102
|
-
if (info.listed === false) throw new Error("morpho: vault is not listed");
|
|
103
|
-
const totalAssetsUsd = Number(info?.state?.totalAssetsUsd ?? 0);
|
|
104
|
-
if (Number.isFinite(minTotalAssetsUsd) && totalAssetsUsd < minTotalAssetsUsd) {
|
|
105
|
-
throw new Error(`morpho: vault totalAssetsUsd ${totalAssetsUsd} below minimum ${minTotalAssetsUsd}`);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const [assetOnchain] = await callVault(chainId, vault, "asset", [], opts);
|
|
109
|
-
const asset = normalAddress(assetOnchain, "vault asset");
|
|
110
|
-
const apiAsset = info?.asset?.address ? normalAddress(info.asset.address, "api vault asset") : asset;
|
|
111
|
-
if (apiAsset !== asset) throw new Error("morpho: API asset and on-chain asset mismatch");
|
|
112
|
-
|
|
113
|
-
let data;
|
|
114
|
-
let floor;
|
|
115
|
-
if (action === "deposit") {
|
|
116
|
-
const [maxDeposit] = await callVault(chainId, vault, "maxDeposit", [owner], opts);
|
|
117
|
-
if (BigInt(amount) > BigInt(maxDeposit.toString())) throw new Error("morpho: amount exceeds maxDeposit");
|
|
118
|
-
const [sharesOut] = await callVault(chainId, vault, "previewDeposit", [amount], opts);
|
|
119
|
-
if (BigInt(sharesOut.toString()) <= 0n) throw new Error("morpho: previewDeposit returned zero shares");
|
|
120
|
-
floor = { minSharesOut: sharesOut.toString() };
|
|
121
|
-
data = ERC4626.encodeFunctionData("deposit", [amount, receiver]);
|
|
122
|
-
} else {
|
|
123
|
-
const [maxWithdraw] = await callVault(chainId, vault, "maxWithdraw", [owner], opts);
|
|
124
|
-
if (BigInt(amount) > BigInt(maxWithdraw.toString())) throw new Error("morpho: amount exceeds maxWithdraw");
|
|
125
|
-
const [sharesIn] = await callVault(chainId, vault, "previewWithdraw", [amount], opts);
|
|
126
|
-
if (BigInt(sharesIn.toString()) <= 0n) throw new Error("morpho: previewWithdraw returned zero shares");
|
|
127
|
-
floor = { maxSharesIn: sharesIn.toString() };
|
|
128
|
-
data = ERC4626.encodeFunctionData("withdraw", [amount, receiver, owner]);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const vaultGuard = {
|
|
132
|
-
mode: "erc4626-vault",
|
|
133
|
-
version: 1,
|
|
134
|
-
provider: "morpho",
|
|
135
|
-
chainId,
|
|
136
|
-
action,
|
|
137
|
-
vault,
|
|
138
|
-
asset,
|
|
139
|
-
owner,
|
|
140
|
-
receiver,
|
|
141
|
-
amount,
|
|
142
|
-
totalAssetsUsd,
|
|
143
|
-
...floor,
|
|
144
|
-
calldataHash: keccak256(toUtf8Bytes(data)),
|
|
145
|
-
issuedAtMs: Date.now(),
|
|
146
|
-
expiresAtMs: Date.now() + 20_000,
|
|
147
|
-
};
|
|
148
|
-
vaultGuard.guardHash = keccak256(toUtf8Bytes(canonicalJson(vaultGuard)));
|
|
149
|
-
|
|
150
|
-
return stampPrepared({
|
|
151
|
-
provider: "morpho",
|
|
152
|
-
protocol: "erc4626-vault",
|
|
153
|
-
vaultReady: true,
|
|
154
|
-
executionReady: false,
|
|
155
|
-
signingReady: false,
|
|
156
|
-
broadcastReady: false,
|
|
157
|
-
requiresUserSignature: true,
|
|
158
|
-
chainId,
|
|
159
|
-
action,
|
|
160
|
-
vault,
|
|
161
|
-
asset,
|
|
162
|
-
owner,
|
|
163
|
-
receiver,
|
|
164
|
-
amount,
|
|
165
|
-
vaultInfo: info,
|
|
166
|
-
vaultGuard,
|
|
167
|
-
requiresApproval: action === "deposit" ? { token: asset, spender: vault, amount } : null,
|
|
168
|
-
transaction: {
|
|
169
|
-
chainId,
|
|
170
|
-
from: owner,
|
|
171
|
-
to: vault,
|
|
172
|
-
data,
|
|
173
|
-
value: "0x0",
|
|
174
|
-
madVault: vaultGuard,
|
|
175
|
-
},
|
|
176
|
-
}, { provider: "morpho", kind: "erc4626-vault" });
|
|
177
|
-
}
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
// Raster-only NFT contact sheets returned as SVG image content.
|
|
2
|
-
|
|
3
|
-
import { timed } from "../http.mjs";
|
|
4
|
-
|
|
5
|
-
const ALLOWED_IMAGE_HOSTS = Object.freeze([
|
|
6
|
-
"i.seadn.io",
|
|
7
|
-
"openseauserdata.com",
|
|
8
|
-
"arweave.net",
|
|
9
|
-
"ipfs.io",
|
|
10
|
-
"nftstorage.link",
|
|
11
|
-
"dweb.link",
|
|
12
|
-
"cloudflare-ipfs.com",
|
|
13
|
-
"ordinals.com",
|
|
14
|
-
"ordinals.g.com",
|
|
15
|
-
"cdn.helius-rpc.com",
|
|
16
|
-
"shdw-drive.genesysgo.net",
|
|
17
|
-
]);
|
|
18
|
-
|
|
19
|
-
const RASTER_MIME = new Set(["image/jpeg", "image/png", "image/webp"]);
|
|
20
|
-
|
|
21
|
-
function allowedHost(hostname) {
|
|
22
|
-
const host = String(hostname || "").toLowerCase();
|
|
23
|
-
return ALLOWED_IMAGE_HOSTS.some((allowed) => host === allowed || host.endsWith(`.${allowed}`));
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function gatewayUrl(value) {
|
|
27
|
-
const text = String(value || "").trim();
|
|
28
|
-
if (text.startsWith("ipfs://")) return `https://ipfs.io/ipfs/${text.slice(7).replace(/^ipfs\//, "")}`;
|
|
29
|
-
if (text.startsWith("ar://")) return `https://arweave.net/${text.slice(5)}`;
|
|
30
|
-
return text;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function safeImageUrl(value) {
|
|
34
|
-
const text = gatewayUrl(value);
|
|
35
|
-
let url;
|
|
36
|
-
try {
|
|
37
|
-
url = new URL(text);
|
|
38
|
-
} catch {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
if (url.protocol !== "https:" || url.username || url.password || !allowedHost(url.hostname)) return null;
|
|
42
|
-
return url;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async function fetchRaster(value, opts = {}) {
|
|
46
|
-
const fetchImpl = opts.fetchImpl || globalThis.fetch;
|
|
47
|
-
if (typeof fetchImpl !== "function") throw new Error("gallery fetch unavailable");
|
|
48
|
-
let url = safeImageUrl(value);
|
|
49
|
-
if (!url) throw new Error("image host is not on the raster gallery allowlist");
|
|
50
|
-
const maxBytes = Math.min(Math.max(Number(opts.maxImageBytes ?? 1_500_000), 50_000), 4_000_000);
|
|
51
|
-
|
|
52
|
-
for (let redirect = 0; redirect <= 3; redirect += 1) {
|
|
53
|
-
const attempt = await timed(() => fetchImpl(url.toString(), {
|
|
54
|
-
method: "GET",
|
|
55
|
-
redirect: "manual",
|
|
56
|
-
headers: { accept: "image/jpeg,image/png,image/webp" },
|
|
57
|
-
signal: AbortSignal.timeout(opts.timeoutMs ?? 12_000),
|
|
58
|
-
}));
|
|
59
|
-
if (!attempt.ok) throw new Error(attempt.error);
|
|
60
|
-
const response = attempt.data;
|
|
61
|
-
if (response.status >= 300 && response.status < 400) {
|
|
62
|
-
const location = response.headers?.get?.("location");
|
|
63
|
-
if (!location) throw new Error("image redirect missing location");
|
|
64
|
-
const next = safeImageUrl(new URL(location, url).toString());
|
|
65
|
-
if (!next) throw new Error("image redirect left the host allowlist");
|
|
66
|
-
url = next;
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
if (!response.ok) throw new Error(`image HTTP ${response.status}`);
|
|
70
|
-
const mimeType = String(response.headers?.get?.("content-type") || "").split(";", 1)[0].toLowerCase();
|
|
71
|
-
if (!RASTER_MIME.has(mimeType)) throw new Error(`unsafe or unsupported image type ${mimeType || "unknown"}`);
|
|
72
|
-
const length = Number(response.headers?.get?.("content-length") || 0);
|
|
73
|
-
if (length > maxBytes) throw new Error("image exceeds gallery byte cap");
|
|
74
|
-
const bytes = Buffer.from(await response.arrayBuffer());
|
|
75
|
-
if (!bytes.length || bytes.length > maxBytes) throw new Error("image exceeds gallery byte cap");
|
|
76
|
-
return { mimeType, data: bytes.toString("base64"), sourceUrl: url.toString(), bytes: bytes.length };
|
|
77
|
-
}
|
|
78
|
-
throw new Error("too many image redirects");
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function xml(value) {
|
|
82
|
-
return String(value ?? "")
|
|
83
|
-
.replaceAll("&", "&")
|
|
84
|
-
.replaceAll("<", "<")
|
|
85
|
-
.replaceAll(">", ">")
|
|
86
|
-
.replaceAll('"', """)
|
|
87
|
-
.replaceAll("'", "'");
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function label(item, index) {
|
|
91
|
-
return item.name || item.collection || item.tokenId || `NFT ${index + 1}`;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export async function nftGallery(args = {}, opts = {}) {
|
|
95
|
-
const allItems = Array.isArray(args.items) ? args.items : [];
|
|
96
|
-
if (!allItems.length) throw new Error("nft gallery requires inventory items");
|
|
97
|
-
const pageSize = Math.min(Math.max(Number(args.pageSize ?? 12) || 12, 1), 12);
|
|
98
|
-
const page = Math.max(Number(args.page ?? 1) || 1, 1);
|
|
99
|
-
const totalPages = Math.max(Math.ceil(allItems.length / pageSize), 1);
|
|
100
|
-
if (page > totalPages) throw new Error(`nft gallery page ${page} exceeds ${totalPages}`);
|
|
101
|
-
const items = allItems.slice((page - 1) * pageSize, page * pageSize);
|
|
102
|
-
const loaded = [];
|
|
103
|
-
let totalBytes = 0;
|
|
104
|
-
const maxTotalBytes = Math.min(Math.max(Number(args.maxTotalBytes ?? 8_000_000), 250_000), 12_000_000);
|
|
105
|
-
|
|
106
|
-
for (const item of items) {
|
|
107
|
-
if (totalBytes >= maxTotalBytes) {
|
|
108
|
-
loaded.push({ item, image: null, error: "gallery page byte cap reached" });
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
try {
|
|
112
|
-
const image = await fetchRaster(item.imageUrl || item.originalImageUrl, {
|
|
113
|
-
...opts,
|
|
114
|
-
maxImageBytes: Math.min(Number(args.maxImageBytes ?? 1_500_000), maxTotalBytes - totalBytes),
|
|
115
|
-
});
|
|
116
|
-
totalBytes += image.bytes;
|
|
117
|
-
loaded.push({ item, image, error: null });
|
|
118
|
-
} catch (error) {
|
|
119
|
-
loaded.push({ item, image: null, error: String(error?.message || error).slice(0, 180) });
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const columns = 3;
|
|
124
|
-
const tileWidth = 340;
|
|
125
|
-
const tileHeight = 400;
|
|
126
|
-
const headerHeight = 76;
|
|
127
|
-
const rows = Math.ceil(items.length / columns);
|
|
128
|
-
const width = columns * tileWidth;
|
|
129
|
-
const height = headerHeight + rows * tileHeight;
|
|
130
|
-
const body = loaded.map(({ item, image, error }, index) => {
|
|
131
|
-
const column = index % columns;
|
|
132
|
-
const row = Math.floor(index / columns);
|
|
133
|
-
const x = column * tileWidth;
|
|
134
|
-
const y = headerHeight + row * tileHeight;
|
|
135
|
-
const art = image
|
|
136
|
-
? `<image x="${x + 14}" y="${y + 14}" width="312" height="312" preserveAspectRatio="xMidYMid slice" href="data:${image.mimeType};base64,${image.data}"/>`
|
|
137
|
-
: `<rect x="${x + 14}" y="${y + 14}" width="312" height="312" rx="14" fill="#151820"/><text x="${x + 170}" y="${y + 165}" text-anchor="middle" fill="#76808f" font-size="16">image unavailable</text>`;
|
|
138
|
-
const title = xml(label(item, index).slice(0, 34));
|
|
139
|
-
const chain = xml(item.chain || "unknown chain");
|
|
140
|
-
return `${art}<text x="${x + 16}" y="${y + 350}" fill="#f3f5f7" font-size="17" font-weight="600">${title}</text><text x="${x + 16}" y="${y + 376}" fill="#8d98a8" font-size="13">${chain}${error ? " · placeholder" : ""}</text>`;
|
|
141
|
-
}).join("");
|
|
142
|
-
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"><rect width="100%" height="100%" fill="#090b10"/><text x="24" y="34" fill="#ffffff" font-size="24" font-weight="700">NFT INVENTORY</text><text x="24" y="58" fill="#8d98a8" font-size="14">page ${page} of ${totalPages} · ${allItems.length} assets · generated ${xml(new Date().toISOString())}</text>${body}</svg>`;
|
|
143
|
-
|
|
144
|
-
return {
|
|
145
|
-
provider: "nft-portfolio",
|
|
146
|
-
operation: "gallery",
|
|
147
|
-
mimeType: "image/svg+xml",
|
|
148
|
-
dataBase64: Buffer.from(svg).toString("base64"),
|
|
149
|
-
page,
|
|
150
|
-
pageSize,
|
|
151
|
-
totalPages,
|
|
152
|
-
totalItems: allItems.length,
|
|
153
|
-
renderedItems: loaded.filter((row) => row.image).length,
|
|
154
|
-
placeholders: loaded.filter((row) => !row.image).map((row) => ({
|
|
155
|
-
assetKey: row.item.assetKey || null,
|
|
156
|
-
name: row.item.name || null,
|
|
157
|
-
sourceUrl: row.item.imageUrl || null,
|
|
158
|
-
error: row.error,
|
|
159
|
-
})),
|
|
160
|
-
rasterOnly: true,
|
|
161
|
-
externalScripts: false,
|
|
162
|
-
};
|
|
163
|
-
}
|