Perp-driven basket vaults backed by a shared perpetual liquidity pool, built on a GMX v1 fork.
Hub-and-spoke topology: One hub chain runs the full perp stack (VaultAccounting, GMX pool, OracleAdapter, etc.). Spoke chains are deposit-only with StateRelay for routing weights and NAV adjustments; the layout can scale to many spokes as configured in config/chains.json. A keeper service posts state to all chains each epoch.
┌─── Spoke ───────────────────────────────┐
│ Investor ──► BasketVault ──► StateRelay │
│ │ (deposit-only) │
│ mint shares RedemptionReceiver ◄─┐ │
└─────────────────────────────────────┼───┘
│ CCIP
┌─── Hub ────────────────────────────────────────────────┼───┐
│ Investor ──► BasketVault ──► VaultAccounting ──► GMX Pool │
│ │ │ │ │
│ mint shares StateRelay position PnL │
│ (NAV-priced) (tracked per vault) │
│ │
│ Keeper ──► StateRelay.updateState() (routing + PnL) │
└────────────────────────────────────────────────────────────┘
- BasketVault -- GLP-style vault: deposit USDC, receive shares priced from vault NAV (including perp PnL)
- BasketShareToken -- ERC20 shares (6 decimals)
- BasketFactory -- Deploy new baskets (name + fees), then register assets explicitly
- OracleAdapter -- Unified oracle for equities + commodities (Chainlink + custom relayer)
- PricingEngine -- Oracle price + deterministic size-based slippage
- VaultAccounting -- Per-vault capital tracking, PnL attribution, position management
- FundingRateManager -- Oracle-anchored, imbalance-based funding rates
- PerpReader -- Read-only aggregator for off-chain monitoring
- StateRelay -- Keeper-posted routing weights and per-vault global PnL adjustments; deposit routing guard via
getLocalWeight() - RedemptionReceiver -- CCIP receiver on spoke chains for keeper-bridged USDC redemption fills
- PoolReserveRegistry -- TWAP-style pool depth tracking (hub, legacy)
- CCIPReserveMessenger -- Delta-triggered reserve state sync over Chainlink CCIP (hub, legacy)
- IntentRouter -- Deposit/redeem intent routing with escrow (hub only)
- CrossChainIntentBridge, OracleConfigQuorum -- CCIP relay and quorum-based oracle config consensus (hub only)
- Off-chain Node.js epoch loop: reads all chains, computes inverse-proportional routing weights and per-spoke PnL adjustments, posts
StateRelay.updateState()to every chain each epoch
Exact hub/spoke rollout is defined in config/chains.json.
| Contract | Hub | Spoke | Notes |
|---|---|---|---|
BasketFactory |
Yes | Yes (no oracle) | Spoke factory passes address(0) for oracle |
BasketVault |
Yes | Yes | Spoke vaults have vaultAccounting = address(0) |
BasketShareToken |
Yes | Yes | Created by factory per basket |
VaultAccounting |
Yes | No | Perp capital tracking, hub only |
OracleAdapter |
Yes | No | Price feeds, hub only |
PricingEngine |
Yes | No | Execution quotes, hub only |
FundingRateManager |
Yes | No | GMX funding, hub only |
PriceSync |
Yes | No | Oracle→GMX sync, hub only |
PerpReader |
Yes | No | Read aggregation, hub only |
AssetWiring |
Yes | No | Asset bootstrap, hub only |
GMX fork |
Yes | No | Shared liquidity pool, hub only |
StateRelay |
Yes | Yes | Routing weights + PnL adjustments |
RedemptionReceiver |
No | Yes | CCIP inbound for redemption fills |
PoolReserveRegistry |
Yes (legacy) | No | Superseded by StateRelay |
USDC (or MockUSDC) |
Yes | Yes | Deposit/redemption token |
Hub deployments use script/Deploy.s.sol. Spoke deployments use script/DeploySpoke.s.sol (deploys only USDC, BasketFactory, and StateRelay). The scripts/deploy-all.sh script reads config/chains.json and selects the correct script per chain role.
Forked GMX v1 contracts (Solidity 0.6.12) providing the core position engine: Vault, VaultUtils, Router, ShortsTracker, BasePositionManager.
- Engage audit firm (BasketVault, VaultAccounting, OracleAdapter, GMX integration, PriceSync, FundingRateManager, PricingEngine)
- Address audit findings and re-verify fixes
- Write mainnet deploy script (
DeployMainnet.s.solor chain-specific variant) - Deploy Gnosis Safe multi-sig as protocol owner
- Deploy OpenZeppelin TimelockController for admin actions
- Transfer all module ownership to multi-sig + timelock
- Migrate oracle from Yahoo Finance relayer to Chainlink / Pyth / RedStone
- Incorporate Foundation entity (Cayman Foundation Company)
- Formalize Labs company
- Execute Labs-Foundation services agreement and IP license
- Draft and publish Terms of Service
- Draft and publish risk disclosures
- Implement frontend geo-blocking (U.S. + OFAC-sanctioned jurisdictions)
- Integrate OFAC / sanctions wallet screening
- Production oracle integration (Chainlink / Pyth for all mainnet assets)
- Monitoring and alerting (oracle staleness, reserve levels, pool utilization, position health)
- Keeper redundancy (at least 2 independent operators)
- Incident response runbook
- Bug bounty program (Immunefi)
- Foundation multi-sig (3-of-5 Gnosis Safe) deployed and funded
- Security council members identified for Stage 1 expansion (4-of-7)
- Progressive decentralization plan documented (see docs/TECHNICAL_ARCHITECTURE_AND_ROADMAP.md)
- Governance token design (deferred to post-launch, design begins in Phase 2)
- Update deployment registry for mainnet (docs/DEPLOYMENTS.md)
- Finalize whitepaper (docs/WHITEPAPER_DRAFT.md)
- Publish audit report
- Update regulatory roadmap post-foundation setup (docs/REGULATORY_ROADMAP_DRAFT.md)
Two parallel raises feeding mainnet readiness. Strategic priorities are tracked in COMPANY.md §Strategic priorities (vc-outreach and lp-seed-liquidity); operational playbooks live in growth/.
Equity / token-warrant round for IndexFlow Labs. Gated on Foundation + Labs incorporation (see §Legal/Entity above). Playbook: growth/VC_OUTREACH_PLAYBOOK.md. Detailed checklist below under Growth › VC Pipeline.
- Foundation + Labs incorporated (prerequisite — see §Legal/Entity)
- Trackable deck hosted (Docsend / Notion) and risk-disclosure section reviewed
- Tier 1 list validated against current portfolio activity (see playbook §Stage 1)
- First Tier 1 outreach batch sent
- First monthly investor update sent
- First term sheet received
- Round closed
Product-viability gate, not a growth nice-to-have: without LP capital in the shared perp OI pool, baskets cannot run their long/short hedge legs and the redeemable-NAV guarantee weakens. Playbook: growth/LP_OUTREACH_PLAYBOOK.md. Detailed checklist below under Growth › LP Outreach.
- Per-LP risk-parameter envelope finalised in
docs/PERP_RISK_MATH.md+docs/GLOBAL_POOL_MANAGEMENT_FLOW.md - Anchor-LP first-look terms decided (revshare % vs equity warrant vs service-fee credit — pick one primary mechanism)
- Risk memo hosted (Docsend / Notion) — separate from the VC deck
- Track A (perp-layer LPs) Tier 1 list of 10–20 MM/desk contacts built
- Track B (basket-vault depositors) Tier 1 list of 30–50 DAO/treasury contacts built
- First Tier 1 risk-walkthrough call scheduled
- First perp-pool USDC deposit live onchain
- First basket-vault deposit > $100k live onchain
- Monthly pool-update email cadence established
IndexFlow runs as an Agent Company: every employee — human or AI — has a manifest entry in COMPANY.md, a monthly USD budget cap, and a human-gated approval for any public statement. The contracts are permissionless; the company that operates around them is auditable.
What is public, today, in git:
- Manifest + governance —
COMPANY.md(schema: agentcompanies/v1) declares active employees, brainstorm slate, board, budgets, sync contract, and fourgovernance.hardConstraintsenforced on every heartbeat (no auto-commit, deployment-memory allowlist, public-channel human gate, scope boundary). - Trading agent state —
agents/memory/<agent>/paperclip-heartbeat.json(per-run thesis, write actions, risk-officer verdicts),state.json(vault binding, fingerprint), andrun-log.<network>.jsonl(full turn-by-turn audit trail) for every vault-managing agent. Pushed by thecommit-resultsjob in.github/workflows/vault-agent.yml. - Per-vault AI Operator panel —
apps/web/public/agent-metadata/<vault>.jsonfeeds the "AI Activity" card on each/baskets/<vault>page (thesis, plus collapsed-by-default run details including no-action runs, reasoning summaries, tool-call traces, decisions, and tx justifications). - Deployment ledger —
AGENT_DEPLOYMENT_MEMORY.mdis the allowlist for every cloud / on-chain resource an agent may touch. Resources not listed there are read-only. - Growth pipeline — date-slotted Season 1 schedule in
growth/X_CONTENT_CALENDAR.md, per-partner files ingrowth/partnerships/, and the basket concepts queue atgrowth/basket-concepts/queue/.
The public surface is indexflow.app/ops (apps/web/src/app/ops/page.tsx) — a server-rendered mirror that reads every file above and renders an org chart, live heartbeats, governance constraints, budgets, the CMO surface (calendar + partnerships + concepts), and a deployment ledger. The data source is git pull; no extra DB, no hosted control plane.
Permissionless protocol on-chain. Transparent operating company in git. No black boxes.
The local Paperclip dashboard (docs/PAPERCLIP_RUNBOOK.md) is an optional founder-only UI for tickets, budgets, and manual re-runs — not part of the public mirror. See docs/AGENTS_FRAMEWORK.md §Paperclip Integration for the architecture.
Progress tracker for the IndexFlow growth engine. Strategy, templates, and playbooks live in growth/.
- Growth strategy and 4-layer framework (growth/README.md)
- Content calendar with layer-tagged backlog (growth/CONTENT_CALENDAR.md)
- VC outreach playbook (growth/VC_OUTREACH_PLAYBOOK.md)
- Content templates (blog, tweet thread, tweet standalone, Substack, LinkedIn, podcast pitch, Farcaster)
- Drafts workflow and naming conventions (growth/drafts/README.md)
- In-app SEO blog (
/blog,/blog/[slug]) with frontmatter, JSON-LD, sitemap, reading time - X growth plan with 4-week activation sequence (growth/X_GROWTH_PLAN.md)
- X content calendar (Season 1, date-slotted) (growth/X_CONTENT_CALENDAR.md)
- Galxe campaign plan (Operator Trials, Option C scope) (growth/GALXE_CAMPAIGN_PLAN.md)
- Partnerships tracker (active partners + per-partner files) (growth/partnerships/README.md)
- Season 1 X drafts seeded (Mon May 25 → Sat Jun 20, 26 drafts in
growth/drafts/) - Boost.xyz campaign plan (high-value onchain actions, separate from Galxe scope) (
growth/BOOST_CAMPAIGN_PLAN.md)
- X / Twitter account live (@indexflowDAO)
- Set up Discord server
- Telegram community live
- Public Agent Company mirror live at
/ops(apps/web/src/app/ops/page.tsx) — server-rendered fromCOMPANY.md,agents/memory/,growth/,AGENT_DEPLOYMENT_MEMORY.md. Surfaces hard constraints, budgets, content calendar, partnerships, basket concepts.
- First blog post published (cross-chain liquidity routing)
- Second blog post published (five waves of on-chain exposure)
- TradFi asset manager blog post published (
/blog/if-you-run-money-the-old-way-crypto-question) - First X post live (Mon May 25 standalone, @indexflowDAO)
- First X thread published
- First LinkedIn post published
- First Substack issue published
- First YouTube video published
- First podcast pitch sent
- First Farcaster cast published
- Cross-chain coordination layer content added to content calendar (blog, X threads, LinkedIn, Substack, YouTube)
- Technical breakdown blog draft: cross-chain coordination layer (
growth/drafts/2026-04-15-blog-cross-chain-coordination-layer.md) - X thread draft: cross-chain coordination layer (
growth/drafts/2026-04-15-thread-cross-chain-coordination.md) - Autonomous-AI-agents-managing-vaults blog refreshed for OpenAI-powered agents with git-committed memory and static
/agent-metadata/<vault>.json(content/blog/autonomous-ai-agents-managing-vaults.md) - Testnet live agents blog draft seeded (
growth/drafts/2026-05-26-blog-two-ai-agents-live-on-testnet.md) - Testnet live agents blog published (
/blog/two-ai-agents-live-on-testnet) - Theseus priority teaser draft seeded (
growth/drafts/2026-06-11-tweet-theseus-priority-primer.md)
Galxe-only Curators Guild soft launch. Full design in growth/GALXE_CAMPAIGN_PLAN.md. Other guilds (Educators, Allocators, Engineers) deferred to Season 2.
- Galxe space created (Operator Trials) and 4 Curator OATs uploaded (Genesis, Champion, Consistent, Veteran)
- Galxe REST credential endpoint implemented (
apps/web/src/app/api/galxe/credential/route.ts— deploy to Vercel) - Curator leaderboard GitHub Actions workflow (
.github/workflows/curator-leaderboard.yml— weekly snapshot + commit toapps/web/public/) - Curator leaderboard worker scaffolded (
services/leaderboard-worker/) - Curator weekly USDC pool funded ($200/month = $50/week)
- Run first snapshot manually via Actions → Curator Leaderboard Snapshot → Run workflow
-
/operatorspage shows weekly rankings and OAT badges
Active partner relationships are tracked in growth/partnerships/ with YAML-frontmatter per-partner files (counterpart, status, co-marketing confirmation, funding intros, next milestone, co-branded surfaces, guilds touched). The master comparison table in growth/partnerships/README.md lists all partners in one view. The Season 1 partner slots concentrate in Week 2 (Mantle spoke demo) and Week 3 (the confidential-infra trinity: iExec compute, Secret state, Nox signing). Non-chain partners also include Theseus (vault-deploy-gated co-marketing; founders engaged). Chain partnerships (counterparts IndexFlow may deploy a hub or spoke onto — currently Mantle, Avalanche, BNB, Alephium, Sui) are tracked separately under growth/partnerships/chains/ because they have a deployment lifecycle (testnet → mainnet) on top of the usual co-tweet / Galxe / Boost surfaces; the chain-partner rows double as the index into AGENT_DEPLOYMENT_MEMORY.md.
- Partnerships index + per-partner files (growth/partnerships/README.md)
- Secret Network — Confidential State leg, Week 3 trinity (growth/partnerships/secret-network.md)
- Mantle — Spoke demo, Week 2 (growth/partnerships/chains/mantle.md)
- iExec — Confidential Compute leg, Week 3 trinity (growth/partnerships/iexec.md)
- Nox — MPC Signing leg, Week 3 trinity (canonical X handle TBD) (growth/partnerships/nox.md)
- Envio — data plane for IndexFlow (
/operators, UTM attribution, multichain Hasura endpoint); co-marketing agreed, Thu Jun 18 16:30 UTC standalone slot anchored (growth/partnerships/envio.md, growth/partnerships/envio-proposal.md) - Chain partnerships tracker (chains/ subfolder + per-chain files + deployment-status legend) (growth/partnerships/chains/README.md)
- Avalanche chain partnership — Fuji spoke live; mainnet C-Chain in discussion (growth/partnerships/chains/avalanche.md)
- Mantle chain partnership — Mantle Sepolia spoke deploy pending (hackathon target) (growth/partnerships/chains/mantle.md)
- BNB chain partnership — BNB Smart Chain Testnet spoke deploy pending (hackathon target; CCIP lane verification prerequisite) (growth/partnerships/chains/bnb.md)
- Alephium chain partnership — non-EVM (UTXO + Ralph); hackathon target; scope decision pending (real Ralph spoke vs. wrapped/co-marketing-only) (growth/partnerships/chains/alephium.md)
- Theseus — vault-deploy-gated co-marketing partner (founders engaged) (growth/partnerships/theseus.md)
- Sui chain partnership — non-EVM (Move); communications opened, no agreement yet (growth/partnerships/chains/sui.md)
- Testnet gated pilot pathway (email capture at vault creation)
- Operator waitlist for mainnet early access
- Lead magnet PDF: "The Asset Manager's Playbook"
- Lead magnet PDF: "From TradFi Funds to DeFi Vaults"
- Video Sales Letter (VSL) recorded and hosted
- Email nurture platform selected (Customer.io or similar)
- Welcome email sequence configured
- Behavioral trigger sequences configured
- Lead scoring model implemented (Clay / HubSpot)
Strategic priority: COMPANY.md §vc-outreach. Playbook: growth/VC_OUTREACH_PLAYBOOK.md.
- Clay workspace set up with enriched VC list
- Sending domains configured and warmed (Instantly.ai)
- LinkedIn automation configured (Expandi / HeyReach)
- Signal monitoring live (Trigify / Midbound)
- Trackable deck hosted (Docsend / Notion)
- First Tier 1 outreach batch sent
- First monthly investor update sent
Strategic priority: COMPANY.md §lp-seed-liquidity. Playbook: growth/LP_OUTREACH_PLAYBOOK.md. Two-track audience — perp-layer LPs (market makers) and basket-vault depositors (DAO treasuries + family offices).
- Minestarters strategic audit + liquidity seed board proposal drafted (growth/MINESTARTERS_INDEXFLOW_AUDIT_LIQUIDITY_PROPOSAL.md)
- Clay workspace configured with
outreach_track: lp_perp | lp_baskettagging (shared with VC pipeline) - Track A list build: 10–20 Tier 1 market-maker contacts enriched (Wintermute, GSR, Amber, Selini, Auros, Cumberland, etc.)
- Track B list build: 30–50 Tier 1 DAO treasury / fintech contacts enriched (via Defillama + Dune)
- Onchain enrichment pipeline live (idle USDC balances per target wallet)
- Risk memo hosted (Docsend / Notion) — counterparty-class variant for MM teams + DAOs
- Live perp-pool stats dashboard ready to embed in outreach (Envio query → public URL)
- Anchor-LP negotiation envelope documented (deposit caps, funding-rate floor, withdrawal queue, term mechanism)
- Telegram/Discord outreach tracker (DAO treasuries — separate from LinkedIn rail)
- First Tier 1 risk-walkthrough call scheduled
- Monthly pool-update email cadence established
- First perp-pool USDC deposit live onchain
- First basket-vault deposit > $100k live onchain
- Grant blurb written (growth/grants/blurb.md)
- 0x Labs grant draft: Strategy KPIs distinguish chain-local vs protocol-level metrics (growth/grants/0xlabs-grant-application.md)
- 0xLabs grant application submitted (growth/grants/0xlabs-grant-application.md)
- Solidity -- 0.6.12 (GMX fork) + ^0.8.24 (new contracts)
- Foundry -- Build, test, deploy
- OpenZeppelin 5.x -- ERC20, Ownable, ReentrancyGuard
- Chainlink CCIP -- Cross-chain messaging for coordination layer (StateRelay sync, RedemptionReceiver fills, oracle config quorum)
- Keeper service -- Node.js/TypeScript epoch loop for routing weights and PnL adjustments (
services/keeper/) - Hub chain — public testnet (or equivalent) with the full perp stack; see
config/chains.json - Spoke chains — additional networks, deposit-only with
StateRelay; roles and RPC aliases are configured alongside the hub
# Install dependencies
forge install
npm install
# Formatting and lint checks run in CI (no local git hooks).
# See .github/workflows/test.yml for the full CI pipeline.
# Build
forge build
# Test
forge test -vvEnvironment templates (all variables documented with comments):
- Repo root: copy
.env.exampleto.envfor Foundry RPC URLs, explorer keys, deploy overrides, agents, and scripts that read the root.env/.env.local. - Web app: copy
apps/web/.env.exampletoapps/web/.env.localforNEXT_PUBLIC_*and Playwright/E2E vars.
For Forge scripts and root-level tooling, set RPC URLs and explorer API keys in .env using .env.example as the template; variable names align with foundry.toml [rpc_endpoints] and [etherscan].
The Next.js web app reads apps/web/.env.local (or shell). Required and optional variables:
| Variable | Required | Description |
|---|---|---|
NEXT_PUBLIC_PRIVY_APP_ID |
Yes | Privy app ID from dashboard.privy.io |
NEXT_PUBLIC_ENVIO_URL |
Yes (for indexer-backed views) | Envio HyperIndex GraphQL (Hasura) endpoint serving all chains, e.g. http://127.0.0.1:8080/v1/graphql locally or the deployed Envio Cloud URL. When unset, indexer-backed views fall back to RPC reads. |
NEXT_PUBLIC_PUSH_SERVICE_URL |
No | Cloud Run push-worker base URL used by /settings for preferences/subscription APIs |
NEXT_PUBLIC_E2E_TEST_MODE |
No | Set to 1 for deterministic E2E mock wallet |
The push worker service (Cloud Run) requires:
| Variable | Required | Description |
|---|---|---|
VAPID_PUBLIC_KEY |
Yes | Web Push VAPID public key (base64url) |
VAPID_PRIVATE_KEY |
Yes | Web Push VAPID private key (base64url) |
VAPID_CONTACT_EMAIL |
Yes | Contact identity passed to push services (for example mailto:ops@indexflow.app) |
ENVIO_URL |
Yes | Envio HyperIndex GraphQL endpoint for dispatch signal scans (Hasura). |
DISPATCH_AUTH_TOKEN |
Yes | Bearer token required by POST /v1/push/dispatch |
OPEN_INTEREST_NEAR_CAP_BPS |
No | Threshold for open-interest alerting (default 9000) |
ORACLE_STALE_THRESHOLD_SECONDS |
No | Oracle staleness threshold in seconds (default 2700) |
LARGE_PNL_THRESHOLD_USD |
No | Realized PnL threshold for large-PnL alerts (default 5000) |
RESERVE_BREACH_COOLDOWN_MS |
No | Cooldown window for reserve-breach repeat alerts (default 1800000) |
PORT |
No | HTTP listen port (default 8080) |
Hub vs spoke: Hub chains deploy the full perp stack via Deploy.s.sol. Spoke chains deploy deposit-only infrastructure via DeploySpoke.s.sol. The deploy-all.sh script reads config/chains.json and selects the correct script per chain role.
Deploy scripts pull a live Yahoo Finance quote for BHP.AX (8-decimal USD raw) via Node (scripts/fetch-yf-asset-price.js and Foundry ffi). The script writes cache/yf-seed-price.txt (gitignored); Solidity reads it with vm.readFile so the seed is not passed through ffi stdout (which can mis-decode decimal ASCII). Node must be on PATH, and the machine needs outbound network access unless you pin a seed.
- Offline / no Yahoo: set
SEED_PRICE_RAWto the 8-decimal raw integer (e.g.4500000000for $45.00) so deploy skips FFI.
# Deploy all chains (reads config/chains.json, picks Deploy.s.sol or DeploySpoke.s.sol per role)
./scripts/deploy-all.sh
# Deploy a single chain (<key> is the network id in config/chains.json)
./scripts/deploy-all.sh --chain <key>
# Local (Anvil, hub role)
npm run deploy:local
# Hub public testnet (writes apps/web/src/config/<target>-deployment.json for the hub key)
CHAIN=<hubKey> forge script script/Deploy.s.sol:Deploy --rpc-url <rpcAlias> --broadcast -vvv
# Additional deploy:* shortcuts (per configured network) live in package.json<hubKey> must match the chain field for the hub entry in config/chains.json. <rpcAlias> must match an endpoint name in foundry.toml [rpc_endpoints] (the same alias you pass to forge script --rpc-url).
Docker Compose runs the local chain (Anvil). Contracts deploy from the host, the Envio HyperIndex indexer runs on the host, and the UI runs on the host -- everything outside of Docker for native hot reload.
- Docker / Docker Compose
- Node.js
- Foundry (
forge,cast) onPATH
# 1. Start Anvil + deploy contracts (writes local-deployment.json)
npm run local:up
# 2. Start the Envio HyperIndex indexer (separate terminal)
npm run --prefix apps/envio dev:local
# 3. Start the UI dev server (separate terminal, hot reloads on file changes)
NEXT_PUBLIC_ENVIO_URL=http://127.0.0.1:8080/v1/graphql npm run local:devOpen http://localhost:3000, log in via Privy (or connect MetaMask), and switch the deployment target to Anvil.
After changing Solidity contracts:
npm run redeploy:localThis re-deploys contracts to the running Anvil and updates apps/web/src/config/local-deployment.json. The Next.js dev server picks up new contract addresses via HMR -- no restart needed. If the Envio indexer is running, restart it so it picks up the new contract addresses from apps/envio/config.local.generated.yaml.
# Stream Docker service logs (Anvil)
npm run local:logs
# Stop Anvil and wipe its volumes
npm run local:down| Service | URL |
|---|---|
| Anvil RPC | http://127.0.0.1:8545 |
| Envio GraphQL (Hasura) | http://127.0.0.1:8080/v1/graphql |
| Envio playground | http://127.0.0.1:8080 |
| Web UI | http://127.0.0.1:3000 |
docker-compose.local.ymlruns Anvil only.scripts/local/redeploy.shdeploys contracts from the host to Docker Anvil over localhost.apps/envioruns the indexer on the host (managing its own Postgres + Hasura) vianpm run --prefix apps/envio dev:local.- The UI runs on the host via
npm run local:dev; passNEXT_PUBLIC_ENVIO_URLso the app reads from the local Hasura endpoint. apps/web/src/config/local-deployment.jsonis written by the deploy script and imported by the Next.js app at build/dev time. File changes trigger HMR.
- Deployment target persists in
localStorageand follows the network selector. - For each deployment target key, the app loads
apps/web/src/config/<target>-deployment.jsonwhen that target is selected (see deploy script outputs underapps/web/src/config/). apps/web/src/config/local-deployment.jsonis used when target isanvil.- Authentication uses Privy (email, Google, or external wallets like MetaMask). Set
NEXT_PUBLIC_PRIVY_APP_IDfrom dashboard.privy.io. - The app is installable as a PWA (
/manifest.webmanifest,public/sw.js). Notification preferences are managed in Settings (/settings). - iOS install note: use Safari → Share → Add to Home Screen. iOS Web Push requires Home Screen install.
- For local Anvil testing, connect MetaMask through Privy with the pre-funded Anvil account (
0xf39Fd6...). - In E2E mode (
NEXT_PUBLIC_E2E_TEST_MODE=1), deployment target is locked toanviland the deterministic mock wallet connector remains enabled for CI-stable signing. - When a wallet is connected on the wrong network, the app auto-requests a switch to the selected deployment chain.
The Envio HyperIndex indexer lives at apps/envio and is the single indexer for every chain. It indexes BasketFactory, BasketVault (dynamically registered), VaultAccounting, OracleAdapter, and StateRelay across Sepolia, Fuji, and Anvil (locally) into one Hasura GraphQL endpoint.
# install + codegen
npm install --prefix apps/envio
npm run --prefix apps/envio codegen
# run against the multichain config (Sepolia + Fuji)
npm run --prefix apps/envio dev
# run against the local dual-Anvil generated config
npm run --prefix apps/envio dev:localProduction indexing runs on Envio Cloud (or a self-hosted Envio). See apps/envio/README.md for the current deploy flow.
Set NEXT_PUBLIC_ENVIO_URL in Vercel (or apps/web/.env.local) to the Hasura endpoint -- the same URL is used for every deployment target because Envio is multichain.
Set ENVIO_URL on the push-worker (Cloud Run) to the same endpoint.
Runtime note:
- The web app and push-worker both read from one Envio endpoint. When
NEXT_PUBLIC_ENVIO_URLis unset, indexer-backed UI views fall back to RPC data paths; the push-worker/v1/push/dispatchendpoint returns500untilENVIO_URLis configured. - The "All Chains" view aggregates data from all chains the indexer covers, served by the same endpoint.
- If "All Chains" shows no indexed baskets while baskets exist onchain (for example on Mantle Sepolia), verify the active Envio deployment has that network enabled with correct addresses/start blocks and required RPC env vars.
The GMX vault reads prices from SimplePriceFeed, not from OracleAdapter directly. After deploy, wire PriceSync as a keeper on SimplePriceFeed (setKeeper(address(priceSync), true)) and add PriceSync mappings (addMapping(assetId, gmxToken)) for each asset the pool trades.
Keeping perp prices aligned with the oracle
- Chainlink-backed assets —
OracleAdapter.getPricereads the feed when called. Push that value into the vault feed by callingPriceSync.syncAll()orPriceSync.syncPrices(assetIds)on whatever cadence you need (anyone can send these txs). - Custom relayer assets — A keeper must call
OracleAdapter.submitPrice/submitPricesfirst (requiressetKeeperon the adapter), then runPriceSync.sync*as above.
Basket configuration still validates asset ids through OracleAdapter, but share mint/redeem pricing is NAV-based and perp-driven. The perp path only updates GMX on-chain feed storage when PriceSync runs.
For basket/perp operator responsibilities (capital allocation, position management controls, and investor liquidity implications), see docs/ASSET_MANAGER_FLOW.md.
Perp leverage risk
- Effective leverage is approximately
size / collateralfor each opened leg. - Example:
size = 10,000andcollateral = 2,000is about5x, so an approximately10%favorable/adverse move is about+/-50%on collateral before fees/funding and execution effects. - For full mechanics and operator caveats, see docs/SHARE_PRICE_AND_OPERATIONS.md and docs/ASSET_MANAGER_FLOW.md.
Funding — Keepers authorized on FundingRateManager call updateFundingRate so the GMX vault’s funding parameters stay in line with your policy (often on a schedule tied to fundingInterval).
Automation (e.g. cron, Gelato, Chainlink Automation) is optional: it only replaces manually sending the same transactions.
Cross-chain keeper service
The keeper service (services/keeper/) is required for hub-and-spoke operation:
# Start the keeper (reads all chains from config/chains.json)
# Set PRIVATE_KEY and the RPC env vars from .env.example for every network the keeper touches.
PRIVATE_KEY=0x... npm run keeper:start
# Configure epoch interval (default 60s)
EPOCH_INTERVAL_MS=30000 npm run keeper:startEach epoch the keeper:
- Reads vault reserves and hub PnL across all deployed chains.
- Computes routing weights (inverse-proportional to idle USDC per chain).
- Computes per-vault global PnL adjustments (hub PnL distributed pro-rata).
- Posts
StateRelay.updateState()to every chain.
The keeper also monitors pending redemptions on spoke chains and bridges USDC from the hub via CCIP to fill them through RedemptionReceiver.
Reserve liquidity controls
- Basket owners can set a reserve target via
setMinReserveBpsto keep idle USDC available for redemptions. allocateToPerpis reserve-aware and only allows allocations up togetAvailableForPerpUsdc().- Anyone can add non-dilutive reserve cash via
topUpReserve(amount)(USDC transfer, no share mint).
GMX bufferAmounts policy (this repo)
bufferAmountsremains in the fork for compatibility.- This integration treats it as mostly unused and expects values to remain
0unless you intentionally adopt swap-buffer constraints. - Local deploy now seeds a USDC buffer (
200,000 USDC) inDeployLocal.s.solto keep explicit swap headroom during testing. - Web admin exposes global pool controls in Admin → Pool:
setBufferAmount(gov-only, per whitelisted token)- direct pool funding via token
transfer(gmxVault, amount)thendirectPoolDeposit(token)(per whitelisted token)
Run one-shot sync for all supported assets (local deployment config)
forge script script/SyncAllOraclePrices.s.sol:SyncAllOraclePrices --rpc-url local --broadcastHub deployment sync helpers — use the sync:* and submit-sync:* scripts in package.json; each sets DEPLOYMENT_CONFIG to the matching apps/web/src/config/<target>-deployment.json and --rpc-url for that target.
Default oracle profile (greenfield DeployLocal / hub testnet deploy)
- Only
BHP.AXis registered, asFeedType.CustomRelayer(stalenessThreshold=86400,deviationBps=2000), for the Yahoo Finance relayer path. - Add more symbols (including
FeedType.Chainlinkfeeds on your hub network) via Admin → Assets or a customized deploy script; see docs/ORACLE_SUPPORTED_ASSETS.md.
Yahoo Finance price relayer (config-free, on-chain driven)
scripts/update-yahoo-finance-prices.js enumerates all active CustomRelayer assets from the OracleAdapter contract on-chain, reads their stored assetSymbols, fetches Yahoo Finance quotes, converts non-USD currencies via FX rates, and submits 8-decimal USD prices to submitPrices + syncAll. No local config file is needed.
Public testnets (hub / spoke)
Use the matching update-prices:* and update-prices:*:dry scripts in package.json; each wires DEPLOYMENT_CONFIG and RPC_URL for its target.
Local Anvil
npm run update-prices:local:dry
PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 npm run update-prices:localConfig/env overrides: DEPLOYMENT_CONFIG, RPC_URL.
GitHub automation: .github/workflows/update-prices.yml runs every 15 minutes and serializes overlapping runs per network using Actions concurrency (queue policy, no in-progress cancellation).
Registering new assets via admin UI
The admin assets page (/admin/oracle) includes a Yahoo Finance search that lets operators discover any publicly-traded equity and register it on-chain as a CustomRelayer asset with an initial price seed. Ambiguous unsuffixed equities (for example BHP) are rejected and must be registered with an explicit exchange suffix (for example BHP.AX). Unique unsuffixed equities (for example AAPL) and non-equity symbols remain valid. Registered assets automatically appear in basket asset pickers.
Multi-Agent Framework
Agents are defined as markdown files in agents/ -- each file is a system prompt + YAML config specifying which MCP servers to use. No JavaScript required to create a new agent. Seven trading agents ship today and run in a CI round-robin against the Mantle Sepolia hub (one agent per hourly tick, indexed by HOUR_UTC % 7):
agents/mining-manager.md— mining long/short vault driven by the Atlas ML engine (vaultMinestarters ML Picks).agents/quality-matrix-manager.md— parallel mining long/short vault driven by the analyst's 8-category Quality Matrix (vaultMinestarters Quality Matrix).agents/rwa-treasurer.md— RWA reserve treasurer; sizes USDY/mUSD/mETH allocation againstrwaTargetBps.agents/meth-carry-manager.md— delta-neutral mETH carry vault (long mETH spot + synthetic ETH short).agents/rwa-yield-router.md— rotates the configured reserve token when a competing primitive offers ≥75 bps annualised net advantage.agents/funding-rate-harvester.md— cross-venue funding-rate harvester; uses Bybit as a read-only sentiment input.agents/smart-money-mirror-manager.md— Mantle ecosystem smart-money mirror; reads Nansen (or an Envio-only degraded fallback).
agents/vault-manager.md is retired from the CI matrix and remains available for local runs only (node scripts/agent-runner.mjs vault-manager).
All three use OpenAI (or any OpenAI-compatible chat-completions endpoint) for inference and sign transactions directly with PRIVATE_KEY. For deterministic behavior, agents can also define policy frontmatter (for example autoAllocateTargetBps, entryMode, entryMomentumPctMin, entryVolumeMin, entryMlScoreMin, entryQualityScoreMin, entryDirection, maxNewPositionsPerRun, rebalanceMode).
Atlas-backed agents read ATLAS_API_URL and ATLAS_API_KEY through atlas-ml-mcp / atlas-quality-mcp. Both MCPs support the same auth overrides: ATLAS_AUTH_MODE=basic with ATLAS_BASIC_AUTH or ATLAS_USERNAME / ATLAS_PASSWORD for nginx-protected Atlas deployments (with https://atlas.minestarters.com defaulting to a built-in Basic auth fallback), plus ATLAS_AUTH_MODE=header with ATLAS_AUTH_HEADER_NAME / ATLAS_AUTH_HEADER_VALUE for custom gateways. The mining manager can inspect historical ML runs and horizon experiments through the Atlas ML MCP; horizon evaluation is intentionally explicit/operator-driven because it can be expensive.
# Install MCP server deps (one-time)
npm --prefix apps/mcps/vault-manager install
npm --prefix apps/mcps/yfinance install
npm --prefix apps/mcps/atlas-ml install
# Uses repo-root .env / .env.local if present (see Configuration above)
# Run the vault manager agent (shortcut)
npm run agent:vault
# Dry-run mode (skips all on-chain writes)
npm run agent:vault:dry
# Run any agent by name
npm run agent:run -- vault-manager
npm run agent:run -- mining-manager
npm run agent:run -- quality-matrix-manager
# Write confirmations are ON by default (interactive TTY prompts before on-chain writes)
LLM_API_KEY=sk-... PRIVATE_KEY=0x... npm run agent:run -- vault-manager
# Non-interactive auto-execute override (off by default)
AGENT_NON_INTERACTIVE_WRITE_EXECUTE=1 LLM_API_KEY=sk-... PRIVATE_KEY=0x... npm run agent:run -- vault-managerA GitHub Actions cron (.github/workflows/vault-agent.yml) fires hourly at minute :18 and picks one trading agent per tick via HOUR_UTC % 7 (each agent therefore runs every seven hours, ~3.4×/day). A workflow_dispatch event accepts any single agent slug for ad-hoc runs plus a dry_run toggle. A follow-up commit-results job in the same workflow pushes the updated agents/memory/ + apps/web/public/agent-metadata/ files back to the default branch under the vault-agent[bot] identity, so the next scheduled run starts from the prior state. See docs/AGENTS_FRAMEWORK.md for the full guide (creating agents, MCP tool reference, vault lifecycle, memory) and the slot-by-slot rotation table.
After run logs are committed, the self-improver issues channel scans hard errors[] entries; fresh runtime failures such as ATLAS_HTTP_ERROR become dedupe-friendly agent-finding investigations before broader speculative ideas.
Agent run history is network-scoped to avoid cross-network context bleed: each agent writes/reads agents/memory/<agent>/run-log.<network>.jsonl. Override with AGENT_NETWORK if needed. Dry runs (AGENT_DRY_RUN=1) do not update run logs.
Agent memory is deployment-aware: the runner fingerprints the active deployment context (network key + DEPLOYMENT_CONFIG content + RPC_URL). When that fingerprint changes (for example after redeploying contracts), it automatically invalidates stale memory for that network by rotating state.json and run-log.<network>.jsonl into agents/memory/<agent>/archive/, then starts from a fresh vault context.
Editing an agent markdown file does not, by itself, force a new vault. The runner updates the stored agent file hash for bookkeeping, but if the remembered vault address is still present and the deployment fingerprint is unchanged, subsequent runs keep managing the same vault.
Paperclip operator dashboard (optional, narrow scope). This repo is the canonical source of truth for the IndexFlow agent fleet. COMPANY.md (schema agentcompanies/v1, name: IndexFlow, scope: meta_and_growth_agents) declares the IndexFlow company identity, the engineering meta-agents Paperclip manages today (issue-implementer, self-improver-issues, plus their two prompt-only risk officers), and a brainstorm slate of growth/ops agents (content-publisher, partnership-tracker, broadcast-bot, docs-syncer, basket-ideator) that activate once their agents/<id>.md prompt files are authored. Trading agents (the seven vault-agent.yml rotation slugs plus their risk-officer) and the Minestarters vault family stay repo-managed via this very vault-agent.yml CI flow — Paperclip does not schedule or budget them. The boundary holds even for new vaults: basket-ideator proposes themes (growth/basket-concepts/queue/); the repo-managed trading-agent flow deploys them. A self-hosted Paperclip install plus the paperclip-agent-companies-plugin discovers and daily-auto-syncs COMPANY.md, schedules active employees via a shell adapter that invokes npm run agent:run -- <agent>, enforces per-employee monthly budgets, and surfaces tickets / approvals from a web UI. The runner writes agents/memory/<agent>/paperclip-heartbeat.json (schema paperclip.heartbeat/v1) on every run; the existing commit-results job in .github/workflows/vault-agent.yml pushes it back to main automatically. See docs/AGENTS_FRAMEWORK.md §Paperclip Integration for the architecture diagram and setup runbook.
The agent framework uses OpenAI (or any OpenAI-compatible chat-completions endpoint) for inference, signs transactions directly with the keeper PRIVATE_KEY via cast send, and persists state to the git repository so every run is auditable from git log.
Architecture:
┌─────────────────────────────────────────────────────────────────────────┐
│ Agent Runner (agent-runner.mjs) │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────────┐ │
│ │ OpenAI │ │ MCP Servers │ │ Memory │ │
│ │ (LLM Inference) │ │ │ │ │ │
│ │ │ │ vault-manager │ │ agents/memory/<agent>/ │ │
│ │ gpt-4o (default)│ │ yfinance │ │ + per-network run-log │ │
│ │ via LLM_API_KEY │ │ │ │ (committed to git by CI)│ │
│ └────────┬────────┘ └────────┬────────┘ └─────────────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Transaction Execution │ │
│ │ cast send --private-key $PRIVATE_KEY --rpc-url $RPC_URL ... │ │
│ └─────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
Required environment variables:
LLM_API_KEY=sk-... # OpenAI (or compatible) API key
PRIVATE_KEY=0x... # Keeper wallet that signs vault writes
RPC_URL=sepolia # RPC alias or full URL
DEPLOYMENT_CONFIG=apps/web/src/config/sepolia-deployment.json
# Optional:
LLM_BASE_URL=https://api.openai.com/v1
LLM_MODEL=gpt-4o- Pitch deck (Google Slides) — investor and partner overview.
/primer— visual long-scroll explainer page distilling the whitepaper and pitch deck into animated sections with inline SVG diagrams.- In-app wiki (web app):
/docs— searchable index sourced directly from repository markdown underdocs/*.md.- Canonical routes:
/docs/readme/docs/technical-architecture-roadmap/docs/investor-flow/docs/asset-manager-flow/docs/perp-risk-math/docs/operator-interactions/docs/price-feed-flow/docs/oracle-supported-assets/docs/global-pool-management-flow/docs/deployments/docs/e2e-testing/docs/share-price-and-operations/docs/pwa-push-notifications/docs/regulatory-roadmap-draft
- Legacy wiki slugs remain supported as compatibility aliases and redirect to canonical routes.
- AI docs assistant: a floating chat widget on
/docspages lets users ask questions about the protocol. Powered bygpt-4o-mini, it ingests all docs and blog posts as context. RequiresLLM_API_KEYinapps/web/.env.local.
- Operator monitoring surfaces (web app):
/prices— live oracle status and current per-asset prices, with dynamic source badges (ChainlinkorCustom Oracle)./prices/[assetId]— per-asset historicalPriceUpdatedtimeline + chart with 24H/7D/30D windows.
- MODIFICATIONS.md — Detailed changes vs upstream GMX.
- docs/TECHNICAL_ARCHITECTURE_AND_ROADMAP.md — Canonical IndexFlow technical architecture and roadmap document for basket-vault, shared-perp, oracle, monitoring, governance, and tokenomics design.
- docs/INVESTOR_FLOW.md — Basket share holder journey, mint/redeem vs NAV, perp allocation, and what investors do not control.
- docs/ASSET_MANAGER_FLOW.md — Basket/perp manager flow: setup, capital allocation, positions, risk controls, and implementation caveats.
- docs/PERP_RISK_MATH.md — Leverage formulas, unit conventions, and liquidation caveats for operator sizing decisions.
- docs/OPERATOR_INTERACTIONS.md — Per-contract interaction matrix with inputs, checks, state deltas, and post-tx verification steps.
- docs/GLOBAL_POOL_MANAGEMENT_FLOW.md — Global GMX pool operations in Admin → Pool: buffer management and direct pool funding flow.
- docs/PRICE_FEED_FLOW.md — OracleAdapter → PriceSync → SimplePriceFeed lifecycle, GMX vault reads, and admin wiring (Mermaid sequence diagrams).
- docs/ORACLE_SUPPORTED_ASSETS.md — Asset registry for the current public testnet deployment: each supported symbol and its oracle source (Chainlink feed or Yahoo Finance relayer).
- docs/DEPLOYMENTS.md — Deployment registry for live contracts, Subgraph indexing, and Google Cloud push-worker infrastructure (push notifications only).
- docs/E2E_TESTING.md — Playwright + Anvil E2E runbook, CI wiring, and lifecycle scope.
- docs/PWA_PUSH_NOTIFICATIONS.md — PWA install behavior, push worker architecture, notification categories, and staging verification runbook.
- docs/REGULATORY_ROADMAP_DRAFT.md — Permissionless protocol launch pathway, foundation structure, progressive decentralization, and compliance requirements (draft).
- docs/README.md — Maintainer-facing map of canonical
/docs/*routes and legacy alias redirects. - Basket trade flows in the web app include icon-based Deposit/Redeem tabs, a stable quote area, and inline transaction feedback so users can verify what will happen before they submit.
# Start an Anvil node
anvil --host 127.0.0.1 --port 8545
# Deploy local contracts to the running node
PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 npm run deploy:local
# Run Playwright suite in deterministic E2E mode
NEXT_PUBLIC_E2E_TEST_MODE=1 E2E_RPC_URL=http://127.0.0.1:8545 npm run test:e2e:ciFor a local report, run forge coverage (use --ir-minimum if the compiler reports stack-too-deep). CI uploads Foundry LCOV to Codecov for the badge above, with Codecov project status scoped to Solidity paths (**/*.sol) and upload search disabled so only lcov.info is processed. The upload step is best-effort (non-blocking) and retried once on transient failure so Codecov outages do not fail overall CI. During Codecov incidents, the badge can remain stale until a later successful upload. CI also pins foundry-rs/foundry-toolchain to Foundry v1.5.1 (instead of floating stable) to keep forge/cast/anvil/chisel installs deterministic across runs. Local-anvil broadcast steps (deploy:local and friends) rely on the explicit [etherscan].local = { chain = 31337, url = ... } entry in foundry.toml so Foundry's Etherscan trace identifier doesn't bail with "No known Etherscan API URL for chain anvil-hardhat" (foundry-rs/foundry#11351); no placeholder explorer API key env vars are needed in CI.