@oracle-agent/oracle 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +99 -0
- package/README.md +531 -13
- package/SECURITY.md +112 -0
- package/SETUP.md +317 -0
- package/artifacts/inscription/oracle-was-here-preview.png +0 -0
- package/artifacts/inscription/oracle-was-here.svg +1 -0
- package/artifacts/specialist-packs/oracle-full-crypto.json +298 -0
- 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 +28 -19
- 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 +110 -14
- package/plugins/oracle-owner-gate/__init__.py +288 -0
- package/plugins/oracle-owner-gate/plugin.yaml +9 -0
- package/profiles/_template/SOUL.md +54 -0
- package/profiles/_template/profile.json +22 -0
- package/profiles/bitcoin-agent/SOUL.md +31 -0
- package/profiles/bitcoin-agent/profile.json +32 -0
- package/profiles/hyperliquid-agent/SOUL.md +34 -0
- package/profiles/hyperliquid-agent/profile.json +38 -0
- package/profiles/oracle/SOUL.md +120 -0
- package/profiles/oracle/profile.json +40 -0
- package/profiles/polymarket-agent/SOUL.md +35 -0
- package/profiles/polymarket-agent/profile.json +34 -0
- package/profiles/profile.schema.json +90 -0
- package/profiles/protocol-builder/SOUL.md +57 -0
- package/profiles/protocol-builder/profile.json +39 -0
- package/profiles/robinhood-agent/SOUL.md +53 -0
- package/profiles/robinhood-agent/profile.json +41 -0
- package/profiles/solana-agent/SOUL.md +37 -0
- package/profiles/solana-agent/profile.json +38 -0
- package/profiles/stable-agent/SOUL.md +43 -0
- package/profiles/stable-agent/profile.json +38 -0
- 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/agent-connect/app.js +84 -0
- package/public/agent-connect/index.html +83 -0
- package/public/agent-connect/styles.css +70 -0
- package/public/index.html +12 -0
- package/public/oracle-console/app.js +272 -0
- package/public/oracle-console/bitcoin-wallets.js +206 -0
- package/public/oracle-console/index.html +91 -0
- package/public/oracle-console/styles.css +239 -0
- package/public/oracle-splash/_variants/ice.html +2073 -0
- package/public/oracle-splash/_variants/ivory.html +2075 -0
- package/public/oracle-splash/assets/agents/claude.png +0 -0
- package/public/oracle-splash/assets/agents/codex.png +0 -0
- package/public/oracle-splash/assets/cli-chain-hyperliquid.jpg +0 -0
- package/public/oracle-splash/assets/desktop-app.jpg +0 -0
- package/public/oracle-splash/assets/hero/cli-session-poster.jpg +0 -0
- package/public/oracle-splash/assets/hero/cli-session.mp4 +0 -0
- package/public/oracle-splash/assets/hero/cli-session.webm +0 -0
- package/public/oracle-splash/assets/hero/orb-poster.jpg +0 -0
- package/public/oracle-splash/assets/hero/orb.avif +0 -0
- package/public/oracle-splash/assets/hero/orb.webm +0 -0
- package/public/oracle-splash/assets/hero/risk-session-poster.jpg +0 -0
- package/public/oracle-splash/assets/hero/risk-session.mp4 +0 -0
- package/public/oracle-splash/assets/hero/risk-session.webm +0 -0
- package/public/oracle-splash/assets/hero/route-session-poster.jpg +0 -0
- package/public/oracle-splash/assets/hero/route-session.mp4 +0 -0
- package/public/oracle-splash/assets/hero/route-session.webm +0 -0
- package/public/oracle-splash/assets/llms/claude.svg +1 -0
- package/public/oracle-splash/assets/llms/codex-icon.svg +1 -0
- package/public/oracle-splash/assets/llms/codex.svg +1 -0
- package/public/oracle-splash/assets/llms/cursor-icon.svg +12 -0
- package/public/oracle-splash/assets/llms/cursor.svg +17 -0
- package/public/oracle-splash/assets/llms/deepseek.svg +1 -0
- package/public/oracle-splash/assets/llms/gemini-icon.svg +1 -0
- package/public/oracle-splash/assets/llms/gemini.svg +1 -0
- package/public/oracle-splash/assets/llms/grok.svg +8 -0
- package/public/oracle-splash/assets/llms/hermes.png +0 -0
- package/public/oracle-splash/assets/llms/kimi-icon.svg +1 -0
- package/public/oracle-splash/assets/llms/kimi.svg +1 -0
- package/public/oracle-splash/assets/llms/manus.svg +18 -0
- package/public/oracle-splash/assets/llms/openclaw.svg +22 -0
- package/public/oracle-splash/assets/llms/perplexity.svg +1 -0
- package/public/oracle-splash/assets/llms/qwen.svg +1 -0
- package/public/oracle-splash/assets/llms/windsurf.svg +1 -0
- package/public/oracle-splash/assets/protocols/abcdex.png +0 -0
- package/public/oracle-splash/assets/protocols/across.png +0 -0
- package/public/oracle-splash/assets/protocols/aerodrome.png +0 -0
- package/public/oracle-splash/assets/protocols/balancer.png +0 -0
- package/public/oracle-splash/assets/protocols/cowswap.png +0 -0
- package/public/oracle-splash/assets/protocols/curve.png +0 -0
- package/public/oracle-splash/assets/protocols/dreamcash.png +0 -0
- package/public/oracle-splash/assets/protocols/felix.png +0 -0
- package/public/oracle-splash/assets/protocols/gmx.png +0 -0
- package/public/oracle-splash/assets/protocols/hyena.png +0 -0
- package/public/oracle-splash/assets/protocols/hyperbeat.png +0 -0
- package/public/oracle-splash/assets/protocols/hyperliquid.png +0 -0
- package/public/oracle-splash/assets/protocols/hyperswap.png +0 -0
- package/public/oracle-splash/assets/protocols/jupiter.png +0 -0
- package/public/oracle-splash/assets/protocols/kinetiq.png +0 -0
- package/public/oracle-splash/assets/protocols/lfj.png +0 -0
- package/public/oracle-splash/assets/protocols/lifi.png +0 -0
- package/public/oracle-splash/assets/protocols/magic-eden.png +0 -0
- package/public/oracle-splash/assets/protocols/morpho.png +0 -0
- package/public/oracle-splash/assets/protocols/odos.png +0 -0
- package/public/oracle-splash/assets/protocols/oneinch.png +0 -0
- package/public/oracle-splash/assets/protocols/opensea.png +0 -0
- package/public/oracle-splash/assets/protocols/pancakeswap.png +0 -0
- package/public/oracle-splash/assets/protocols/paragon.png +0 -0
- package/public/oracle-splash/assets/protocols/paraswap.png +0 -0
- package/public/oracle-splash/assets/protocols/pendle.png +0 -0
- package/public/oracle-splash/assets/protocols/polymarket.png +0 -0
- package/public/oracle-splash/assets/protocols/quickswap.png +0 -0
- package/public/oracle-splash/assets/protocols/relay.png +0 -0
- package/public/oracle-splash/assets/protocols/stargate.png +0 -0
- package/public/oracle-splash/assets/protocols/tradexyz.png +0 -0
- package/public/oracle-splash/assets/protocols/uniswap.png +0 -0
- package/public/oracle-splash/assets/protocols/velodrome.png +0 -0
- package/public/oracle-splash/assets/protocols/ventuals.png +0 -0
- package/public/oracle-splash/assets/wordmarks/across-icon.webp +0 -0
- package/public/oracle-splash/assets/wordmarks/across.svg +4 -0
- package/public/oracle-splash/assets/wordmarks/aerodrome.svg +23 -0
- package/public/oracle-splash/assets/wordmarks/balancer.svg +3 -0
- package/public/oracle-splash/assets/wordmarks/cowswap.svg +1 -0
- package/public/oracle-splash/assets/wordmarks/curve.png +0 -0
- package/public/oracle-splash/assets/wordmarks/gmx.svg +13 -0
- package/public/oracle-splash/assets/wordmarks/hop-icon.webp +0 -0
- package/public/oracle-splash/assets/wordmarks/hyena.svg +7 -0
- package/public/oracle-splash/assets/wordmarks/hyperliquid.svg +21 -0
- package/public/oracle-splash/assets/wordmarks/hyperswap.svg +13 -0
- package/public/oracle-splash/assets/wordmarks/jupiter.svg +35 -0
- package/public/oracle-splash/assets/wordmarks/kinetiq.svg +1 -0
- package/public/oracle-splash/assets/wordmarks/lfj.webp +0 -0
- package/public/oracle-splash/assets/wordmarks/lifi.png +0 -0
- package/public/oracle-splash/assets/wordmarks/magic-eden.svg +1 -0
- package/public/oracle-splash/assets/wordmarks/markets.svg +1 -0
- package/public/oracle-splash/assets/wordmarks/morpho.svg +1 -0
- package/public/oracle-splash/assets/wordmarks/odos.svg +3 -0
- package/public/oracle-splash/assets/wordmarks/oneinch-icon.webp +0 -0
- package/public/oracle-splash/assets/wordmarks/oneinch.svg +6 -0
- package/public/oracle-splash/assets/wordmarks/opensea-icon.svg +17 -0
- package/public/oracle-splash/assets/wordmarks/opensea.svg +1 -0
- package/public/oracle-splash/assets/wordmarks/outcome.svg +16 -0
- package/public/oracle-splash/assets/wordmarks/pancakeswap.svg +18 -0
- package/public/oracle-splash/assets/wordmarks/paragon.svg +9 -0
- package/public/oracle-splash/assets/wordmarks/paraswap.svg +16 -0
- package/public/oracle-splash/assets/wordmarks/pendle.png +0 -0
- package/public/oracle-splash/assets/wordmarks/polymarket.png +0 -0
- package/public/oracle-splash/assets/wordmarks/quickswap.png +0 -0
- package/public/oracle-splash/assets/wordmarks/relay.svg +8 -0
- package/public/oracle-splash/assets/wordmarks/satflow-icon.png +0 -0
- package/public/oracle-splash/assets/wordmarks/stargate-icon.webp +0 -0
- package/public/oracle-splash/assets/wordmarks/stargate.svg +15 -0
- package/public/oracle-splash/assets/wordmarks/uniswap.svg +18 -0
- package/public/oracle-splash/assets/wordmarks/velodrome.svg +84 -0
- package/public/oracle-splash/assets/wordmarks/xyz.svg +12 -0
- package/public/oracle-splash/assets/wordmarks/zerox-icon.webp +0 -0
- package/public/oracle-splash/brand/aave.webp +0 -0
- package/public/oracle-splash/brand/aavev2.webp +0 -0
- package/public/oracle-splash/brand/aborean.webp +0 -0
- package/public/oracle-splash/brand/across.webp +0 -0
- package/public/oracle-splash/brand/aerodrome.webp +0 -0
- package/public/oracle-splash/brand/afi.webp +0 -0
- package/public/oracle-splash/brand/arcus.webp +0 -0
- package/public/oracle-splash/brand/aster.webp +0 -0
- package/public/oracle-splash/brand/avant.webp +0 -0
- package/public/oracle-splash/brand/balancer.webp +0 -0
- package/public/oracle-splash/brand/beefy.webp +0 -0
- package/public/oracle-splash/brand/benqi.webp +0 -0
- package/public/oracle-splash/brand/bestinslot.ico +0 -0
- package/public/oracle-splash/brand/bitfi.webp +0 -0
- package/public/oracle-splash/brand/bonkswap.webp +0 -0
- package/public/oracle-splash/brand/bouncebit.webp +0 -0
- package/public/oracle-splash/brand/camelot.webp +0 -0
- package/public/oracle-splash/brand/compound.webp +0 -0
- package/public/oracle-splash/brand/concrete.webp +0 -0
- package/public/oracle-splash/brand/cow.webp +0 -0
- package/public/oracle-splash/brand/curve.webp +0 -0
- package/public/oracle-splash/brand/derive.webp +0 -0
- package/public/oracle-splash/brand/dolomite.webp +0 -0
- package/public/oracle-splash/brand/eigenlayer.webp +0 -0
- package/public/oracle-splash/brand/ekubo.webp +0 -0
- package/public/oracle-splash/brand/ethena.webp +0 -0
- package/public/oracle-splash/brand/etherfi.webp +0 -0
- package/public/oracle-splash/brand/etherfiborrow.webp +0 -0
- package/public/oracle-splash/brand/felix.webp +0 -0
- package/public/oracle-splash/brand/fluid.webp +0 -0
- package/public/oracle-splash/brand/fluxbeam.webp +0 -0
- package/public/oracle-splash/brand/folks.webp +0 -0
- package/public/oracle-splash/brand/fortyacres.webp +0 -0
- package/public/oracle-splash/brand/gainsnetwork.webp +0 -0
- package/public/oracle-splash/brand/gassss.webp +0 -0
- package/public/oracle-splash/brand/gmx.webp +0 -0
- package/public/oracle-splash/brand/harmonix.webp +0 -0
- package/public/oracle-splash/brand/hlorderbook.webp +0 -0
- package/public/oracle-splash/brand/hlp.webp +0 -0
- package/public/oracle-splash/brand/hop.webp +0 -0
- package/public/oracle-splash/brand/hyperbeat.webp +0 -0
- package/public/oracle-splash/brand/hyperlend.webp +0 -0
- package/public/oracle-splash/brand/hyperliquid.webp +0 -0
- package/public/oracle-splash/brand/hyperliquidhpl.webp +0 -0
- package/public/oracle-splash/brand/hyperliquidspot.webp +0 -0
- package/public/oracle-splash/brand/hyperswap.webp +0 -0
- package/public/oracle-splash/brand/hypha.webp +0 -0
- package/public/oracle-splash/brand/joedex.webp +0 -0
- package/public/oracle-splash/brand/jupiter.webp +0 -0
- package/public/oracle-splash/brand/kelp.webp +0 -0
- package/public/oracle-splash/brand/kinetiq.webp +0 -0
- package/public/oracle-splash/brand/kmhype.webp +0 -0
- package/public/oracle-splash/brand/kona.webp +0 -0
- package/public/oracle-splash/brand/konalend.webp +0 -0
- package/public/oracle-splash/brand/lfj.webp +0 -0
- package/public/oracle-splash/brand/lido.webp +0 -0
- package/public/oracle-splash/brand/lifi.webp +0 -0
- package/public/oracle-splash/brand/lighter.webp +0 -0
- package/public/oracle-splash/brand/lista.webp +0 -0
- package/public/oracle-splash/brand/loopedhype.webp +0 -0
- package/public/oracle-splash/brand/lorenzo.webp +0 -0
- package/public/oracle-splash/brand/magic-eden.webp +0 -0
- package/public/oracle-splash/brand/magiceden.webp +0 -0
- package/public/oracle-splash/brand/mempool.png +0 -0
- package/public/oracle-splash/brand/meteora.webp +0 -0
- package/public/oracle-splash/brand/morpho.webp +0 -0
- package/public/oracle-splash/brand/myriad.webp +0 -0
- package/public/oracle-splash/brand/noxa.webp +0 -0
- package/public/oracle-splash/brand/odos.webp +0 -0
- package/public/oracle-splash/brand/oneinch.webp +0 -0
- package/public/oracle-splash/brand/openbook.webp +0 -0
- package/public/oracle-splash/brand/opensea.webp +0 -0
- package/public/oracle-splash/brand/orca.webp +0 -0
- package/public/oracle-splash/brand/ordinals.png +0 -0
- package/public/oracle-splash/brand/ostium.webp +0 -0
- package/public/oracle-splash/brand/pancakeswap.webp +0 -0
- package/public/oracle-splash/brand/pendle.webp +0 -0
- package/public/oracle-splash/brand/perena.webp +0 -0
- package/public/oracle-splash/brand/pharaoh.webp +0 -0
- package/public/oracle-splash/brand/phoenix.webp +0 -0
- package/public/oracle-splash/brand/polymarket.webp +0 -0
- package/public/oracle-splash/brand/polynomial.webp +0 -0
- package/public/oracle-splash/brand/projectx.webp +0 -0
- package/public/oracle-splash/brand/pumpfun.webp +0 -0
- package/public/oracle-splash/brand/quickswap.webp +0 -0
- package/public/oracle-splash/brand/rain.webp +0 -0
- package/public/oracle-splash/brand/raydium.webp +0 -0
- package/public/oracle-splash/brand/relay.webp +0 -0
- package/public/oracle-splash/brand/rocketpool.webp +0 -0
- package/public/oracle-splash/brand/saber.webp +0 -0
- package/public/oracle-splash/brand/sakuraswap.webp +0 -0
- package/public/oracle-splash/brand/sanctum.webp +0 -0
- package/public/oracle-splash/brand/satflow.png +0 -0
- package/public/oracle-splash/brand/sierra.webp +0 -0
- package/public/oracle-splash/brand/sky.webp +0 -0
- package/public/oracle-splash/brand/solv.webp +0 -0
- package/public/oracle-splash/brand/spark.webp +0 -0
- package/public/oracle-splash/brand/sparksavings.webp +0 -0
- package/public/oracle-splash/brand/sphere.webp +0 -0
- package/public/oracle-splash/brand/ssv.webp +0 -0
- package/public/oracle-splash/brand/stabble.webp +0 -0
- package/public/oracle-splash/brand/stableswap.webp +0 -0
- package/public/oracle-splash/brand/stakewise.webp +0 -0
- package/public/oracle-splash/brand/stargate.webp +0 -0
- package/public/oracle-splash/brand/sthype.webp +0 -0
- package/public/oracle-splash/brand/sushiswap.webp +0 -0
- package/public/oracle-splash/brand/unisat.png +0 -0
- package/public/oracle-splash/brand/uniswap.webp +0 -0
- package/public/oracle-splash/brand/uniswapv2.webp +0 -0
- package/public/oracle-splash/brand/uniswapv4.webp +0 -0
- package/public/oracle-splash/brand/unit.webp +0 -0
- package/public/oracle-splash/brand/velodrome.webp +0 -0
- package/public/oracle-splash/brand/velora.webp +0 -0
- package/public/oracle-splash/brand/venus.webp +0 -0
- package/public/oracle-splash/brand/wbeth.webp +0 -0
- package/public/oracle-splash/brand/xsy.webp +0 -0
- package/public/oracle-splash/brand/yieldyak.webp +0 -0
- package/public/oracle-splash/brand/zerobase.webp +0 -0
- package/public/oracle-splash/brand/zerox.webp +0 -0
- package/public/oracle-splash/downloads/index.html +52 -0
- package/public/oracle-splash/favicon.ico +0 -0
- package/public/oracle-splash/favicon.svg +6 -0
- package/public/oracle-splash/index.html +2537 -0
- package/public/oracle-splash/mesh-graph.png +0 -0
- package/public/oracle-splash/mesh-graph.svg +216 -0
- 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 +168 -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/skills/balance/SKILL.md +176 -0
- package/skills/bitcoin-l1.md +33 -0
- package/skills/chain-defi-ecosystem-profiling.md +27 -0
- package/skills/evm-contract-research.md +27 -0
- package/skills/hyperliquid.md +26 -0
- package/skills/multichain-exec-desk.md +33 -0
- package/skills/oracle-action-semantics/SKILL.md +40 -0
- package/skills/oracle-best-execution/SKILL.md +127 -0
- package/skills/oracle-best-execution.md +27 -0
- package/skills/oracle-bitcoin/SKILL.md +53 -0
- package/skills/oracle-chain-graphs-telegram-cards/SKILL.md +59 -0
- package/skills/oracle-chat/SKILL.md +61 -0
- package/skills/oracle-chat/chain.SKILL.md +31 -0
- package/skills/oracle-chat/setup.SKILL.md +37 -0
- package/skills/oracle-circuit-breaker/SKILL.md +51 -0
- package/skills/oracle-contract-research/SKILL.md +55 -0
- package/skills/oracle-desk/SKILL.md +58 -0
- package/skills/oracle-desk.md +27 -0
- package/skills/oracle-dex-launch/SKILL.md +38 -0
- package/skills/oracle-equities/SKILL.md +62 -0
- package/skills/oracle-grants/SKILL.md +69 -0
- package/skills/oracle-hypercore-staking/SKILL.md +57 -0
- package/skills/oracle-hyperliquid/SKILL.md +56 -0
- package/skills/oracle-meme-token-sniper/SKILL.md +73 -0
- package/skills/oracle-multichain-nft-launch/SKILL.md +338 -0
- package/skills/oracle-multichain-token-launch/SKILL.md +300 -0
- package/skills/oracle-nft-gacha-launch/SKILL.md +48 -0
- package/skills/oracle-nft-mint-gas-war/SKILL.md +63 -0
- package/skills/oracle-polymarket/SKILL.md +60 -0
- package/skills/oracle-protocol-builder/SKILL.md +59 -0
- package/skills/oracle-protocol-security/SKILL.md +60 -0
- package/skills/oracle-public-product/SKILL.md +44 -0
- package/skills/oracle-receipts/SKILL.md +52 -0
- package/skills/oracle-receipts.md +29 -0
- package/skills/oracle-rfq-tokenized-assets/SKILL.md +69 -0
- package/skills/oracle-smart-wallet-scanner/SKILL.md +49 -0
- package/skills/oracle-solana/SKILL.md +65 -0
- package/skills/oracle-solana-nft/SKILL.md +54 -0
- package/skills/oracle-token-research/SKILL.md +67 -0
- package/skills/solana.md +22 -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 +241 -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 +257 -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
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: oracle-receipts
|
|
3
|
+
description: Use whenever reporting the outcome of any on-chain action (swap, bridge, mint, send, list, accept-offer).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Receipt format
|
|
7
|
+
|
|
8
|
+
## Required fields
|
|
9
|
+
- tx hash (full, with chain explorer link)
|
|
10
|
+
- chain + chainId
|
|
11
|
+
- action (swap/bridge/mint/send/list/accept-offer)
|
|
12
|
+
- from → to (addresses)
|
|
13
|
+
- amount in → amount out (with token symbols)
|
|
14
|
+
- gas used + gas cost in USD
|
|
15
|
+
- status: confirmed / pending / failed
|
|
16
|
+
|
|
17
|
+
## Explorer links
|
|
18
|
+
- Ethereum: https://etherscan.io/tx/{hash}
|
|
19
|
+
- Base: https://basescan.org/tx/{hash}
|
|
20
|
+
- Arbitrum: https://arbiscan.io/tx/{hash}
|
|
21
|
+
- Optimism: https://optimistic.etherscan.io/tx/{hash}
|
|
22
|
+
- Polygon: https://polygonscan.com/tx/{hash}
|
|
23
|
+
- BSC: https://bscscan.com/tx/{hash}
|
|
24
|
+
- HyperEVM: https://www.hyperscan.com/tx/{hash}
|
|
25
|
+
|
|
26
|
+
## Never claim
|
|
27
|
+
- "submitted" = confirmed. Only tx receipt with status=1 is confirmed.
|
|
28
|
+
- A prepare is not a fill. Report prepare as "prepared, unsigned."
|
|
29
|
+
- A sign is not a send. Report sign as "signed, not broadcast."
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: oracle-rfq-tokenized-assets
|
|
3
|
+
description: RFQ/intent routing across supported chains and guarded buys for tokenized Robinhood assets when user keys/routes are configured.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Oracle RFQ + tokenized asset routing
|
|
7
|
+
|
|
8
|
+
Use when a user asks for RFQ, solver/intent quotes, request-for-quote execution,
|
|
9
|
+
or buying tokenized Robinhood-style assets/stocks on supported chains.
|
|
10
|
+
|
|
11
|
+
## RFQ scope
|
|
12
|
+
|
|
13
|
+
Oracle should treat RFQ as another best-execution source, not a bypass:
|
|
14
|
+
|
|
15
|
+
- Query RFQ/intent venues where the chain and token pair are supported and the
|
|
16
|
+
user has configured any required API keys.
|
|
17
|
+
- Compare RFQ quotes against AMM/aggregator routes on net received after gas,
|
|
18
|
+
fees, solver spread, and settlement assumptions.
|
|
19
|
+
- Return `artifactKind` precisely: signed typed-data order vs unsigned tx vs
|
|
20
|
+
wallet-provider action.
|
|
21
|
+
- Re-quote immediately before prepare/signing. RFQ expiry/nonce is short-lived.
|
|
22
|
+
- Do not fabricate RFQ support for a chain without a configured venue.
|
|
23
|
+
|
|
24
|
+
## Every-chain rule
|
|
25
|
+
|
|
26
|
+
"Across all chains" means every configured chain is attempted and capability-labeled:
|
|
27
|
+
|
|
28
|
+
- `RFQ_READY`: venue configured, quote live, prepare path verified.
|
|
29
|
+
- `QUOTE_ONLY`: quote available, but no reviewed prepare path.
|
|
30
|
+
- `UNCONFIGURED`: needs user API key or venue credentials.
|
|
31
|
+
- `UNAVAILABLE`: no RFQ venue for that chain/token pair.
|
|
32
|
+
- `BLOCKED`: policy, unsupported asset, compliance, or route guard rejected.
|
|
33
|
+
|
|
34
|
+
Unsupported is an honest result, not a failure to hide.
|
|
35
|
+
|
|
36
|
+
## Tokenized Robinhood assets
|
|
37
|
+
|
|
38
|
+
Treat tokenized Robinhood assets as normal on-chain assets plus extra identity/risk
|
|
39
|
+
checks:
|
|
40
|
+
|
|
41
|
+
1. Resolve the exact chain and contract/mint from the official issuer/venue or a
|
|
42
|
+
user-provided contract. Never infer from ticker alone.
|
|
43
|
+
2. Check asset metadata, decimals, supply, issuer/proxy/admin controls, transfer
|
|
44
|
+
restrictions, and redeemability/custody disclosures when public.
|
|
45
|
+
3. Verify the venue/router can quote and prepare the asset on that chain.
|
|
46
|
+
4. For buys, run the same route and slippage guard as any ERC-20/SPL swap.
|
|
47
|
+
5. For sells, run sellability/reverse route first; tokenized assets may trade like
|
|
48
|
+
wrappers and can have restricted-transfer or allowlist rules.
|
|
49
|
+
6. User signs; Oracle does not custody or guarantee redemption.
|
|
50
|
+
|
|
51
|
+
## Output contract
|
|
52
|
+
|
|
53
|
+
Return a table per chain/venue:
|
|
54
|
+
|
|
55
|
+
- chain / venue / asset id
|
|
56
|
+
- RFQ status and expiry
|
|
57
|
+
- gross quote, estimated gas/fees, net output
|
|
58
|
+
- artifact kind and signing path
|
|
59
|
+
- policy blockers
|
|
60
|
+
- confidence and data timestamp
|
|
61
|
+
|
|
62
|
+
## Pitfalls
|
|
63
|
+
|
|
64
|
+
- Calling a solver/RFQ quote "gasless" when the cost is hidden in spread.
|
|
65
|
+
- Using an RFQ quote after expiry.
|
|
66
|
+
- Treating a tokenized stock ticker as identity without contract provenance.
|
|
67
|
+
- Ignoring transfer restrictions that make buys possible but exits blocked.
|
|
68
|
+
- Routing tokenized Robinhood assets through DEMI/RH private executor by default;
|
|
69
|
+
public users must use their own wallet/key/API setup.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: oracle-smart-wallet-scanner
|
|
3
|
+
description: Use when finding, scoring, or monitoring smart wallets from on-chain behavior across tokens, NFTs, and venues.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Smart-wallet scanner
|
|
7
|
+
|
|
8
|
+
Use this for on-chain wallet intelligence: early buyers, profitable exits, repeat
|
|
9
|
+
edge, copy-radar, cabal detection candidates, and wallet boards.
|
|
10
|
+
|
|
11
|
+
## Smart wallet definition
|
|
12
|
+
|
|
13
|
+
A wallet is not smart because it bought one winner. Require repeatable evidence:
|
|
14
|
+
|
|
15
|
+
- early across multiple unrelated assets
|
|
16
|
+
- profitable realized exits, not just mark-to-market bags
|
|
17
|
+
- enough trade count and not only one ticker
|
|
18
|
+
- entry before broad social consensus
|
|
19
|
+
- exits before liquidity drain or sell imbalance
|
|
20
|
+
- behavior survives fees, gas, and failed trades
|
|
21
|
+
|
|
22
|
+
## Scan pattern
|
|
23
|
+
|
|
24
|
+
1. Start from live events: pair creates, swaps, mint transfers, order fills,
|
|
25
|
+
marketplace sales, bridge inflows.
|
|
26
|
+
2. Normalize wallet, chain, token/NFT, time, size, and realized PnL.
|
|
27
|
+
3. Cluster funding and common recipients separately; do not call it a bundle
|
|
28
|
+
without launch-block clustering and common-funder evidence.
|
|
29
|
+
4. Score wallets by multi-asset repeatability and drawdown, not raw largest win.
|
|
30
|
+
5. Track holds vs exits. A smart buyer becoming a smart seller changes the signal.
|
|
31
|
+
6. Emit confidence and evidence window with every wallet label.
|
|
32
|
+
|
|
33
|
+
## Output standard
|
|
34
|
+
|
|
35
|
+
For each wallet surface:
|
|
36
|
+
|
|
37
|
+
- address and chain
|
|
38
|
+
- sample wins/losses
|
|
39
|
+
- realized PnL basis and limitations
|
|
40
|
+
- first-seen timing vs launch/volume
|
|
41
|
+
- current holdings/exit state if known
|
|
42
|
+
- confidence: high / moderate / low / unknown
|
|
43
|
+
|
|
44
|
+
## Hard rules
|
|
45
|
+
|
|
46
|
+
- Never expose a private operator wallet as a public smart-wallet seed.
|
|
47
|
+
- Never use one-token PnL as a primary smart label.
|
|
48
|
+
- Cabal candidates are seeds for deeper analysis, not proof of manipulation.
|
|
49
|
+
- If sell data is unavailable, label PnL `UNKNOWN`, not profitable.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: oracle-solana
|
|
3
|
+
description: Use for Solana research and swap preparation — Jupiter routes, SPL accounts, simulation, blockhash expiry.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Solana
|
|
7
|
+
|
|
8
|
+
Read and prepare through Oracle's data plane (`solana-rpc`, `jupiter`). No key
|
|
9
|
+
required. Signing happens in the user's wallet; Oracle returns unsigned
|
|
10
|
+
transactions.
|
|
11
|
+
|
|
12
|
+
## Ops
|
|
13
|
+
|
|
14
|
+
| Need | Op |
|
|
15
|
+
|---|---|
|
|
16
|
+
| SOL balance | `getBalance` |
|
|
17
|
+
| SPL accounts | `tokenAccounts` |
|
|
18
|
+
| fresh blockhash | `latestBlockhash` |
|
|
19
|
+
| dry run | `simulate` |
|
|
20
|
+
| route price | `jupiter.quote` |
|
|
21
|
+
| unsigned swap tx | `jupiter.prepare` |
|
|
22
|
+
|
|
23
|
+
## Blockhash expiry is the trap
|
|
24
|
+
|
|
25
|
+
A Solana transaction carries a recent blockhash and dies in roughly 60–90 seconds.
|
|
26
|
+
|
|
27
|
+
Consequences that catch people:
|
|
28
|
+
|
|
29
|
+
- a transaction prepared two minutes ago is **dead** — re-prepare, don't retry
|
|
30
|
+
- do not prepare, go do other tool work, then hand it over
|
|
31
|
+
- if the user takes a while to approve, prepare again
|
|
32
|
+
|
|
33
|
+
An expired transaction fails with a confusing error that looks like a routing bug.
|
|
34
|
+
It isn't.
|
|
35
|
+
|
|
36
|
+
## Simulate every time
|
|
37
|
+
|
|
38
|
+
`simulateTransaction` is cheap and tells you the actual failure before the user
|
|
39
|
+
signs. There is no reason to skip it. Check:
|
|
40
|
+
|
|
41
|
+
- does it succeed at all
|
|
42
|
+
- compute units consumed (near the limit → it will fail under load)
|
|
43
|
+
- logs for the real revert reason
|
|
44
|
+
|
|
45
|
+
## Account creation costs rent
|
|
46
|
+
|
|
47
|
+
Swapping into a token the wallet has never held requires creating an associated
|
|
48
|
+
token account, which costs SOL rent. Budget it, and say so — a wallet with exactly
|
|
49
|
+
enough SOL for the swap will fail on the account creation.
|
|
50
|
+
|
|
51
|
+
## Decimals are not standard
|
|
52
|
+
|
|
53
|
+
Nine is common, six is common, others exist. Read the mint. Assuming decimals is how
|
|
54
|
+
an amount ends up 1000x off.
|
|
55
|
+
|
|
56
|
+
## Hard rules
|
|
57
|
+
|
|
58
|
+
1. **Simulate before returning any transaction for signature.**
|
|
59
|
+
2. **Never relay a caller-supplied RPC** — a hostile endpoint can lie about
|
|
60
|
+
simulation.
|
|
61
|
+
3. **Return unsigned only.** Never a fully-signed transaction.
|
|
62
|
+
4. **Solana authority is separate from EVM authority.** No EVM key satisfies a
|
|
63
|
+
Solana grant.
|
|
64
|
+
5. Name the **mint address**, not just the ticker.
|
|
65
|
+
6. Receipts or it didn't happen — confirmed signature or it failed.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: oracle-solana-nft
|
|
3
|
+
description: Research Solana NFT collections and prepare unsigned Magic Eden buy, list, and mint transactions.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Solana NFT lane (Magic Eden)
|
|
7
|
+
|
|
8
|
+
Use when someone asks Oracle to check a Solana NFT collection's floor, find
|
|
9
|
+
listings, buy an NFT, list one they hold, or mint from a launchpad drop.
|
|
10
|
+
|
|
11
|
+
## Tiers
|
|
12
|
+
|
|
13
|
+
| Op | Key needed | What it returns |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| `stats` | none | floor in SOL, listed count, 24h volume |
|
|
16
|
+
| `listings` | none | mint, seller, auctionHouse, tokenATA, price |
|
|
17
|
+
| `tokenListings` | none | listings for one specific mint |
|
|
18
|
+
| `prepareBuy` | `MAGICEDEN_API_KEY` | unsigned base64 transaction |
|
|
19
|
+
| `prepareList` | `MAGICEDEN_API_KEY` | unsigned base64 transaction |
|
|
20
|
+
| `prepareMint` | `MAGICEDEN_API_KEY` | unsigned base64 transaction |
|
|
21
|
+
|
|
22
|
+
Reads are keyless. Instruction builders need the user's own Magic Eden key. If
|
|
23
|
+
the key is missing, say so plainly and stop; do not fake a ticket.
|
|
24
|
+
|
|
25
|
+
## Flow for a buy
|
|
26
|
+
|
|
27
|
+
1. `desk.solana.nftStats({ symbol })` - confirm the collection is real and get
|
|
28
|
+
the floor.
|
|
29
|
+
2. `desk.solana.nftListings({ symbol, limit })` - pull live listings. The
|
|
30
|
+
cheapest listing is the first one when sorted by price.
|
|
31
|
+
3. Set `maxPriceSol` from the user's stated ceiling, not from the floor. The cap
|
|
32
|
+
is checked before any network call, so a listing that moved above the ceiling
|
|
33
|
+
is rejected without touching the API.
|
|
34
|
+
4. `desk.solana.nftPrepareBuy({ buyer, seller, auctionHouse, tokenMint, tokenATA, priceSol, maxPriceSol })`.
|
|
35
|
+
5. Simulate the returned base64 through `desk.solana.simulate` before handing it
|
|
36
|
+
over. A prepared transaction that fails simulation is a prepared loss.
|
|
37
|
+
6. Hand the user the unsigned transaction. Their wallet signs and sends.
|
|
38
|
+
|
|
39
|
+
## Rules
|
|
40
|
+
|
|
41
|
+
- Floor price is not a bid. Buying fills at the listing price, which can move
|
|
42
|
+
between the read and the signature.
|
|
43
|
+
- Always pass `maxPriceSol`. Without it there is no ceiling on a mint or buy.
|
|
44
|
+
- Collection symbols are validated as slugs. `../` and empty strings are
|
|
45
|
+
rejected, not encoded into a URL.
|
|
46
|
+
- Every prepare returns `signingReady: false` and `broadcastReady: false`. Oracle
|
|
47
|
+
never signs a Solana transaction and never sends one.
|
|
48
|
+
- Solana lamports are integers. `priceSol` is decimal SOL; the module converts.
|
|
49
|
+
|
|
50
|
+
## Verification
|
|
51
|
+
|
|
52
|
+
`npm run e2e:solana-bitcoin` hits live Magic Eden reads, a live Jupiter quote,
|
|
53
|
+
a live prepared swap, and a live simulation, then asserts the prepare posture
|
|
54
|
+
held.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: oracle-token-research
|
|
3
|
+
description: Use when researching any token, especially low-cap or newly launched. The sell-side-first checklist that catches honeypots.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Token research
|
|
7
|
+
|
|
8
|
+
The default assumption for a new token is **hostile**. Research exists to disprove
|
|
9
|
+
that, not to confirm a story.
|
|
10
|
+
|
|
11
|
+
## Sell side first
|
|
12
|
+
|
|
13
|
+
Most losses here are not bad entries. They are tokens that **buy cleanly and cannot
|
|
14
|
+
be sold**. So the first question is never "will it go up" — it is "can I get out."
|
|
15
|
+
|
|
16
|
+
Run a **round-trip simulation** in one state-free call: wrap native → buy token →
|
|
17
|
+
sell token back → require a minimum return. Treat any of these as FAIL:
|
|
18
|
+
|
|
19
|
+
- quote failure in either direction
|
|
20
|
+
- transfer failure
|
|
21
|
+
- router revert
|
|
22
|
+
- round-trip return below the no-tax reverse quote by more than a small tolerance
|
|
23
|
+
|
|
24
|
+
A successful **buy** quote proves nothing about the sell.
|
|
25
|
+
|
|
26
|
+
## Price against the real pool
|
|
27
|
+
|
|
28
|
+
A launchpad or bonding-curve token often exposes its **own** `getReserves()`
|
|
29
|
+
returning zero or virtual values. The tradeable market is a *different* pair.
|
|
30
|
+
|
|
31
|
+
- `blockTimestampLast == 0` → not a live pool. Do not size against it.
|
|
32
|
+
- Find the real pair via `factory.getPair(a, b)` or a live swap's decoded target
|
|
33
|
+
- A pair with `kLast`, `price0CumulativeLast`, `MINIMUM_LIQUIDITY` is standard V2
|
|
34
|
+
even when the router in front of it is a custom fork
|
|
35
|
+
|
|
36
|
+
Sizing against stale reserves is how a "0.4% impact" trade becomes 3%.
|
|
37
|
+
|
|
38
|
+
## Identity before action
|
|
39
|
+
|
|
40
|
+
Tickers collide and get squatted. A fuzzy name match is a **candidate**, never
|
|
41
|
+
confirmation.
|
|
42
|
+
|
|
43
|
+
Always surface the **contract address** and require explicit confirmation before
|
|
44
|
+
anything that moves value. `FEFUR` vs `FEFER` is a real class of loss.
|
|
45
|
+
|
|
46
|
+
## The rest of the checklist
|
|
47
|
+
|
|
48
|
+
| Check | Red flag |
|
|
49
|
+
|---|---|
|
|
50
|
+
| holder concentration | top 5 hold most of supply |
|
|
51
|
+
| liquidity depth | thin relative to your size |
|
|
52
|
+
| LP status | unlocked or removable |
|
|
53
|
+
| age | hours old with heavy volume |
|
|
54
|
+
| router | non-canonical clone with a familiar name |
|
|
55
|
+
| mint authority | still open |
|
|
56
|
+
| transfer logic | fees or blocks that change post-launch |
|
|
57
|
+
|
|
58
|
+
## Label your evidence
|
|
59
|
+
|
|
60
|
+
Mark every finding `LIVE`, `STALE`, `UNKNOWN`, or `UNAVAILABLE` with a timestamp.
|
|
61
|
+
Do not call holder-concentration analysis "bundle detection" — bundles require
|
|
62
|
+
launch-block clustering and common-funder evidence, which is a different query.
|
|
63
|
+
|
|
64
|
+
## Honest output
|
|
65
|
+
|
|
66
|
+
`unknown` is a correct and frequent answer about a two-hour-old token. Say it.
|
|
67
|
+
Never let narrative quality substitute for a passing sell simulation.
|
package/skills/solana.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: solana
|
|
3
|
+
description: Use for Solana reads and swap preparation.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Solana
|
|
7
|
+
|
|
8
|
+
## Read
|
|
9
|
+
- `data solana_balance <pubkey>` — SOL balance
|
|
10
|
+
- `data solana_token_accounts <pubkey>` — SPL token accounts
|
|
11
|
+
- `data dex_search <symbol>` → resolve to Solana token
|
|
12
|
+
|
|
13
|
+
## Swap
|
|
14
|
+
- `data jupiter_quote` — get best swap route (≤100 bps slippage)
|
|
15
|
+
- `data jupiter_prepare` — build unsigned swap tx
|
|
16
|
+
- `data solana_simulate` — simulate before signing
|
|
17
|
+
|
|
18
|
+
## Key facts
|
|
19
|
+
- No EVM — separate address format, separate tools
|
|
20
|
+
- Jupiter is the primary aggregator
|
|
21
|
+
- Never sign a Solana tx without simulating first
|
|
22
|
+
- Read/prepare only on this plane — signing uses operator package
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: oracle
|
|
2
|
+
description: filled lowercase oracle in the classic boxed layout
|
|
3
|
+
colors:
|
|
4
|
+
banner_border: "#455867"
|
|
5
|
+
banner_title: "#B8F0FF"
|
|
6
|
+
banner_accent: "#91C2D7"
|
|
7
|
+
banner_dim: "#60717F"
|
|
8
|
+
banner_text: "#EAF2F8"
|
|
9
|
+
ui_accent: "#B8F0FF"
|
|
10
|
+
ui_label: "#A5D9EB"
|
|
11
|
+
ui_ok: "#7EE7B5"
|
|
12
|
+
ui_error: "#FF7B7B"
|
|
13
|
+
ui_warn: "#F0C674"
|
|
14
|
+
prompt: "#B8F0FF"
|
|
15
|
+
input_rule: "#455867"
|
|
16
|
+
response_border: "#91C2D7"
|
|
17
|
+
status_bar_bg: "#11161B"
|
|
18
|
+
status_bar_text: "#91A2B1"
|
|
19
|
+
status_bar_strong: "#EAF2F8"
|
|
20
|
+
status_bar_dim: "#60717F"
|
|
21
|
+
status_bar_good: "#7EE7B5"
|
|
22
|
+
status_bar_warn: "#F0C674"
|
|
23
|
+
status_bar_bad: "#FF9B71"
|
|
24
|
+
status_bar_critical: "#FF7B7B"
|
|
25
|
+
session_label: "#B8F0FF"
|
|
26
|
+
session_border: "#455867"
|
|
27
|
+
voice_status_bg: "#11161B"
|
|
28
|
+
selection_bg: "#23313B"
|
|
29
|
+
completion_menu_bg: "#11161B"
|
|
30
|
+
completion_menu_current_bg: "#23313B"
|
|
31
|
+
completion_menu_meta_bg: "#11161B"
|
|
32
|
+
completion_menu_meta_current_bg: "#23313B"
|
|
33
|
+
spinner:
|
|
34
|
+
waiting_faces: ["·", "··", "···"]
|
|
35
|
+
thinking_faces: ["◇", "◈", "◆", "◈"]
|
|
36
|
+
thinking_verbs: ["thinking", "reading", "checking", "routing"]
|
|
37
|
+
wings: [["", ""]]
|
|
38
|
+
branding:
|
|
39
|
+
agent_name: "oracle"
|
|
40
|
+
welcome: ""
|
|
41
|
+
goodbye: "exit"
|
|
42
|
+
response_label: " oracle "
|
|
43
|
+
prompt_symbol: "›"
|
|
44
|
+
help_header: "oracle"
|
|
45
|
+
tool_prefix: "│"
|
|
46
|
+
banner_logo: |
|
|
47
|
+
[bold #B8F0FF] ████[/]
|
|
48
|
+
[bold #B8F0FF] ░░███[/]
|
|
49
|
+
[bold #ACDEEF] ██████ ████████ ██████ ██████ ░███ ██████[/]
|
|
50
|
+
[bold #A5D9EB] ███░░███░░███░░███ ░░░░░███ ███░░███ ░███ ███░░███[/]
|
|
51
|
+
[bold #9FCBDD]░███ ░███ ░███ ░░░ ███████ ░███ ░░░ ░███ ░███████[/]
|
|
52
|
+
[bold #9FCBDD]░███ ░███ ░███ ███░░███ ░███ ███ ░███ ░███░░░[/]
|
|
53
|
+
[bold #ACDEEF]░░██████ █████ ░░████████░░██████ █████░░██████[/]
|
|
54
|
+
[bold #B8F0FF] ░░░░░░ ░░░░░ ░░░░░░░░ ░░░░░░ ░░░░░ ░░░░░░[/]
|
|
55
|
+
banner_hero: |
|
|
56
|
+
[bold #EAF2F8]THE FUTURE IS AGENTIC[/]
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
// Deterministic, public-only receipts for prepared and executed actions.
|
|
2
|
+
//
|
|
3
|
+
// This module deliberately has no authority and no I/O: it does not authorize,
|
|
4
|
+
// sign, broadcast, or fetch. It only records facts supplied by its caller.
|
|
5
|
+
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
import { wordlists } from "ethers";
|
|
8
|
+
|
|
9
|
+
export const ACTION_RECEIPT_VERSION = 1;
|
|
10
|
+
|
|
11
|
+
// Key-name matching was exact-ish and only covered five words, so every wallet
|
|
12
|
+
// export alias (secretKey, seedPhrase, wif, keyMaterial, privKey, xprv, seed,
|
|
13
|
+
// keystore) sailed through. There was also NO value-shape rule, so a raw key or
|
|
14
|
+
// a BIP-39 phrase pasted into a benign field like `memo` was recorded verbatim.
|
|
15
|
+
//
|
|
16
|
+
// Both concerns were already solved in src/address-book.mjs; this module simply
|
|
17
|
+
// did not use the hardened list. Found by the opus lane of the 2026-08-03
|
|
18
|
+
// four-model review, and verified to PERSIST: unknown top-level props are
|
|
19
|
+
// dropped by the schema whitelist, but a secret nested inside a RETAINED field
|
|
20
|
+
// (intent, route, decodedAction) survives into the frozen receipt.
|
|
21
|
+
const SECRET_KEYS = new Set([
|
|
22
|
+
"privatekey",
|
|
23
|
+
"privkey",
|
|
24
|
+
"secretkey",
|
|
25
|
+
"seedphrase",
|
|
26
|
+
"seed",
|
|
27
|
+
"mnemonic",
|
|
28
|
+
"passphrase",
|
|
29
|
+
"password",
|
|
30
|
+
"keystore",
|
|
31
|
+
"keymaterial",
|
|
32
|
+
"wif",
|
|
33
|
+
"xprv",
|
|
34
|
+
"xpriv",
|
|
35
|
+
"bearer",
|
|
36
|
+
"authorization",
|
|
37
|
+
"signature",
|
|
38
|
+
"apikey",
|
|
39
|
+
"credential",
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
// Unambiguous key shapes: WIF, extended private key, BIP-39 word run. These are
|
|
43
|
+
// refused wherever they appear.
|
|
44
|
+
//
|
|
45
|
+
// A bare 64-hex string is deliberately NOT in this list. A raw EVM private key
|
|
46
|
+
// and a bytes32 tx hash are byte-identical, and receipts legitimately carry
|
|
47
|
+
// txHash / orderHash / salt / merkleRoot / nonce. Blanket-refusing 64-hex would
|
|
48
|
+
// break real receipts — an over-tight filter is its own bug. It is instead
|
|
49
|
+
// gated on the field name below.
|
|
50
|
+
const KEY_SHAPED_VALUE = [
|
|
51
|
+
/\b[5KL][1-9A-HJ-NP-Za-km-z]{50,51}\b/,
|
|
52
|
+
/\bxprv[0-9A-Za-z]{50,}\b/,
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
const BIP39_WORD_COUNTS = new Set([12, 15, 18, 21, 24]);
|
|
56
|
+
|
|
57
|
+
function isBip39EnglishPhrase(value) {
|
|
58
|
+
const words = String(value).trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
59
|
+
return BIP39_WORD_COUNTS.has(words.length) && words.every((word) => wordlists.en.getWordIndex(word) >= 0);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const BARE_32_BYTE_HEX = /^\s*(?:0x)?[0-9a-fA-F]{64}\s*$/;
|
|
63
|
+
|
|
64
|
+
// Field names whose whole value is EXPECTED to be a 32-byte digest.
|
|
65
|
+
//
|
|
66
|
+
// The trailing `(?:e?s)?` matters: `publicValue` scans array leaves using the
|
|
67
|
+
// PARENT key, so a batched route's `orderHashes` / `proofs` / `commitments`
|
|
68
|
+
// arrives here in its plural form (English pluralizes `hash` as `hashes`).
|
|
69
|
+
// Without it a digest LIST is refused while the exact same digest in singular
|
|
70
|
+
// form is accepted — an over-tight filter that breaks real receipts and blocks
|
|
71
|
+
// no secret (key-SHAPED values are refused by KEY_SHAPED_VALUE / BIP-39
|
|
72
|
+
// regardless of field name).
|
|
73
|
+
const DIGEST_FIELD = /(hash|digest|root|salt|nonce|proof|commitment|sig|id)(?:e?s)?$/i;
|
|
74
|
+
const PROTOCOL_HEX_FIELDS = new Set([
|
|
75
|
+
"calldata",
|
|
76
|
+
"data",
|
|
77
|
+
"publickey",
|
|
78
|
+
"pubkey",
|
|
79
|
+
"message",
|
|
80
|
+
"payload",
|
|
81
|
+
"input",
|
|
82
|
+
"extradata",
|
|
83
|
+
]);
|
|
84
|
+
|
|
85
|
+
function allows32ByteHex(key) {
|
|
86
|
+
const normalized = normalizedKey(key);
|
|
87
|
+
return PROTOCOL_HEX_FIELDS.has(normalized) || DIGEST_FIELD.test(normalized);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export class ActionReceiptSecretError extends Error {
|
|
91
|
+
constructor(path) {
|
|
92
|
+
super(`action receipt refused: secret-bearing field at ${path}`);
|
|
93
|
+
this.name = "ActionReceiptSecretError";
|
|
94
|
+
this.code = "ACTION_RECEIPT_SECRET";
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function normalizedKey(key) {
|
|
99
|
+
return String(key).replace(/[^a-z0-9]/gi, "").toLowerCase();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function isSecretKey(key) {
|
|
103
|
+
const normalized = normalizedKey(key);
|
|
104
|
+
return [...SECRET_KEYS].some((secret) => normalized.includes(secret));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Refuse a key-material-shaped VALUE, so a secret pasted into a benign field
|
|
109
|
+
* name (memo, note, label) cannot be recorded verbatim.
|
|
110
|
+
*
|
|
111
|
+
* Bare 64-hex is only refused when the field name is NOT digest-shaped: a raw
|
|
112
|
+
* EVM private key and a bytes32 hash are byte-identical, and receipts carry
|
|
113
|
+
* txHash / orderHash / salt / nonce legitimately.
|
|
114
|
+
*/
|
|
115
|
+
function assertNoSecretValue(key, value, path) {
|
|
116
|
+
if (typeof value !== "string") return;
|
|
117
|
+
if (KEY_SHAPED_VALUE.some((re) => re.test(value)) || isBip39EnglishPhrase(value)) {
|
|
118
|
+
throw new ActionReceiptSecretError(path);
|
|
119
|
+
}
|
|
120
|
+
if (BARE_32_BYTE_HEX.test(value) && !allows32ByteHex(key)) {
|
|
121
|
+
throw new ActionReceiptSecretError(path);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function publicValue(value, path = "$", key = "") {
|
|
126
|
+
if (value == null || typeof value === "boolean") return value;
|
|
127
|
+
if (typeof value === "string") {
|
|
128
|
+
assertNoSecretValue(key, value, path);
|
|
129
|
+
return value;
|
|
130
|
+
}
|
|
131
|
+
if (typeof value === "number") {
|
|
132
|
+
if (!Number.isFinite(value)) throw new TypeError(`action receipt: non-finite number at ${path}`);
|
|
133
|
+
return value;
|
|
134
|
+
}
|
|
135
|
+
if (typeof value === "bigint") return value.toString();
|
|
136
|
+
if (Array.isArray(value)) return value.map((item, index) => publicValue(item, `${path}[${index}]`, key));
|
|
137
|
+
if (typeof value !== "object" || Object.getPrototypeOf(value) !== Object.prototype) {
|
|
138
|
+
throw new TypeError(`action receipt: JSON-like value required at ${path}`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const out = {};
|
|
142
|
+
for (const childKey of Object.keys(value).sort()) {
|
|
143
|
+
const childPath = `${path}.${childKey}`;
|
|
144
|
+
if (isSecretKey(childKey)) throw new ActionReceiptSecretError(childPath);
|
|
145
|
+
if (value[childKey] !== undefined) out[childKey] = publicValue(value[childKey], childPath, childKey);
|
|
146
|
+
}
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Recursively reject secret-bearing fields and return a detached public copy. */
|
|
151
|
+
export function assertNoReceiptSecrets(value) {
|
|
152
|
+
return publicValue(value);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function canonicalPublicJson(value) {
|
|
156
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
157
|
+
if (Array.isArray(value)) return `[${value.map(canonicalPublicJson).join(",")}]`;
|
|
158
|
+
return `{${Object.keys(value).map((key) => `${JSON.stringify(key)}:${canonicalPublicJson(value[key])}`).join(",")}}`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Canonical JSON with recursively sorted object keys. */
|
|
162
|
+
export function canonicalReceiptJson(value) {
|
|
163
|
+
return canonicalPublicJson(publicValue(value));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Hash exactly the public receipt fields, excluding the self-referential id. */
|
|
167
|
+
export function computeReceiptId(receipt) {
|
|
168
|
+
if (!receipt || typeof receipt !== "object" || Array.isArray(receipt)) {
|
|
169
|
+
throw new TypeError("action receipt: object required");
|
|
170
|
+
}
|
|
171
|
+
const { receiptId: _ignored, summary: _derived, ...publicFields } = receipt;
|
|
172
|
+
return createHash("sha256").update(canonicalReceiptJson(publicFields)).digest("hex");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function supplied(input, ...keys) {
|
|
176
|
+
for (const key of keys) if (input[key] !== undefined) return input[key];
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function required(input, keys, label) {
|
|
181
|
+
const value = supplied(input, ...keys);
|
|
182
|
+
if (value === undefined || value === null) throw new TypeError(`action receipt: ${label} required`);
|
|
183
|
+
return value;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function balanceFields(input) {
|
|
187
|
+
const balances = supplied(input, "balances", "balanceChanges");
|
|
188
|
+
const before = supplied(input, "beforeBalances", "balancesBefore", "before");
|
|
189
|
+
const after = supplied(input, "afterBalances", "balancesAfter", "after");
|
|
190
|
+
if (balances !== undefined) return { balances };
|
|
191
|
+
if (before === undefined && after === undefined) return {};
|
|
192
|
+
return { balances: { ...(before === undefined ? {} : { before }), ...(after === undefined ? {} : { after }) } };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Normalize caller-supplied prepare/execute facts into the versioned schema.
|
|
197
|
+
* Unknown input fields are intentionally omitted from the receipt.
|
|
198
|
+
*/
|
|
199
|
+
export function normalizeActionReceipt(input = {}) {
|
|
200
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
201
|
+
throw new TypeError("action receipt: input object required");
|
|
202
|
+
}
|
|
203
|
+
// Scan the complete input before selecting fields so a secret cannot be
|
|
204
|
+
// hidden in an otherwise unknown property and accidentally appear later.
|
|
205
|
+
publicValue(input);
|
|
206
|
+
|
|
207
|
+
const txHash = supplied(input, "txHash", "transactionHash");
|
|
208
|
+
const phase = supplied(input, "phase", "stage", "resultType") ?? (txHash == null ? "prepare" : "execute");
|
|
209
|
+
if (phase !== "prepare" && phase !== "execute") {
|
|
210
|
+
throw new TypeError('action receipt: phase must be "prepare" or "execute"');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const fields = {
|
|
214
|
+
receiptVersion: ACTION_RECEIPT_VERSION,
|
|
215
|
+
phase,
|
|
216
|
+
intent: required(input, ["intent"], "intent"),
|
|
217
|
+
route: required(input, ["route"], "route"),
|
|
218
|
+
decodedAction: required(input, ["decodedAction", "action"], "decodedAction"),
|
|
219
|
+
policyChecks: required(input, ["policyChecks", "checks"], "policyChecks"),
|
|
220
|
+
allowlistHits: required(input, ["allowlistHits", "allowlistMatches"], "allowlistHits"),
|
|
221
|
+
prepareHash: required(input, ["prepareHash"], "prepareHash"),
|
|
222
|
+
...(txHash == null ? {} : { txHash }),
|
|
223
|
+
...balanceFields(input),
|
|
224
|
+
};
|
|
225
|
+
const receipt = publicValue(fields);
|
|
226
|
+
return Object.freeze({ ...receipt, receiptId: computeReceiptId(receipt) });
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export const createActionReceipt = normalizeActionReceipt;
|
|
230
|
+
|
|
231
|
+
function label(value, preferred = []) {
|
|
232
|
+
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
233
|
+
for (const key of preferred) if (value?.[key] != null) return String(value[key]);
|
|
234
|
+
return "recorded";
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function checkResult(check) {
|
|
238
|
+
if (typeof check === "boolean") return check;
|
|
239
|
+
if (check && typeof check === "object") {
|
|
240
|
+
if (typeof check.ok === "boolean") return check.ok;
|
|
241
|
+
if (typeof check.allowed === "boolean") return check.allowed;
|
|
242
|
+
if (typeof check.passed === "boolean") return check.passed;
|
|
243
|
+
}
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/** Produce a compact human-readable statement without changing the receipt. */
|
|
248
|
+
export function summarizeActionReceipt(receipt) {
|
|
249
|
+
if (!receipt || typeof receipt !== "object") throw new TypeError("action receipt: object required");
|
|
250
|
+
const action = label(receipt.decodedAction, ["type", "action", "method", "name"]);
|
|
251
|
+
const route = label(receipt.route, ["name", "provider", "venue", "id"]);
|
|
252
|
+
const checks = Array.isArray(receipt.policyChecks)
|
|
253
|
+
? receipt.policyChecks
|
|
254
|
+
: Object.values(receipt.policyChecks || {});
|
|
255
|
+
const passed = checks.filter((check) => checkResult(check) === true).length;
|
|
256
|
+
const failed = checks.filter((check) => checkResult(check) === false).length;
|
|
257
|
+
const hits = Array.isArray(receipt.allowlistHits)
|
|
258
|
+
? receipt.allowlistHits.length
|
|
259
|
+
: Object.keys(receipt.allowlistHits || {}).length;
|
|
260
|
+
const tx = receipt.txHash == null ? "no transaction hash" : `tx ${receipt.txHash}`;
|
|
261
|
+
const balances = receipt.balances == null ? "balances not provided" : "before/after balances recorded";
|
|
262
|
+
return `${receipt.phase} ${action} via ${route}; policy ${passed} passed, ${failed} failed; ${hits} allowlist hit${hits === 1 ? "" : "s"}; ${tx}; ${balances}; receipt ${receipt.receiptId}`;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export const formatActionReceipt = summarizeActionReceipt;
|