Testnet Deployment

Deploy the full Cortex stack (contracts + offchain services) to a public testnet.

Current Hosted Deployment

Frontend: https://cortex.projectaegis.ai

API: https://cortex-api.projectaegis.ai

Network: Base Sepolia, chain ID 84532

Indexer start block: 42716484

Live Contract Addresses

ContractBase Sepolia Address
AgentRegistry0x39e3a043532187af2ffe308154375fb662ccb0d6
IntentBook0x16f7e7c4856bad4dcbE61400630087Dab75B229E
PolicyModule0x7120d45cbd6b5d079f39418e4f84880c634ef614
AttestationRegistry0x62631b3f111424831Daa61beCB2E7A4bB0f71D2f
SolverRegistry0x21cf04BC864953DA4C79160f820F38eF74213EeA
AttestorRegistry0x40f2623F177a400a5928C99F107500049a884da0
CommerceRegistry0xc4c014d9eb2d07ff6f7d2b8625e8cf3bc1150574

Recommended testnet: Base Sepolia — an OP Stack L2 with fast blocks (~2s), free faucets, and a good block explorer.

Base SepoliaOP Sepolia
Chain ID8453211155420
RPChttps://sepolia.base.orghttps://sepolia.optimism.io
Explorersepolia.basescan.orgsepolia-optimistic.etherscan.io

Prerequisites

  • Foundryforge, cast
  • Node.js >= 18
  • PostgreSQL client toolspsql
  • Three wallets — deployer, solver, agent (each needs testnet ETH)

1. Get Testnet ETH

Fund your deployer wallet with Base Sepolia ETH from any of these faucets:

2. Configure Environment

cp ops/.env.testnet.example ops/.env.testnet

Edit ops/.env.testnet with your values:

RPC_URL=https://sepolia.base.org
DATABASE_URL=postgres://user:pass@host:5432/cortex
DEPLOYER_KEY=0x<your-deployer-private-key>
SOLVER_PRIVATE_KEY=0x<your-solver-private-key>
AGENT_PRIVATE_KEY=0x<your-agent-private-key>

Never commit private keys. The .env.testnet file is gitignored.

3. Deploy Contracts

source ops/.env.testnet
./ops/deploy-testnet.sh

Deploys AgentRegistry, IntentBook, PolicyModule, AttestationRegistry, SolverRegistry, AttestorRegistry, and CommerceRegistry to Base Sepolia. Contract addresses are written to ops/.env.testnet.

4. Set Up Postgres

You need a Postgres instance accessible from wherever you run the services.

  • Railway — simplest option, supports Node.js + Postgres in one platform
  • Neon — serverless Postgres with a free tier
  • Supabase — managed Postgres with a generous free tier

Copy the connection string and update DATABASE_URL in ops/.env.testnet.

5. Start Services Locally

source ops/.env.testnet
ENV_FILE=ops/.env.testnet ./ops/start-services.sh

Builds services, runs idempotent migrations, and starts the indexer, solver, and API.

6. Manual Service Commands

Source the testnet env and start each service:

source ops/.env.testnet

# Indexer — polls Base Sepolia for events, writes to Postgres
cd indexer && npm run build && node dist/src/index.js

# Solver — watches IntentSubmitted, simulates, fills
cd solver && npm run build && node dist/src/index.js

# API — REST server on port 3001
cd api && npm run build && node dist/src/index.js

Or as background processes:

source ops/.env.testnet

cd indexer && npm run build && nohup node dist/src/index.js > ../ops/indexer.log 2>&1 &
cd ../solver && npm run build && nohup node dist/src/index.js > ../ops/solver.log 2>&1 &
cd ../api && npm run build && nohup node dist/src/index.js > ../ops/api.log 2>&1 &

7. Verify

Check the block explorer

Visit https://sepolia.basescan.org/address/<AGENT_REGISTRY_ADDRESS> to confirm the contract is deployed.

Hit the API

# Health check
curl http://localhost:3001/health
curl http://localhost:3001/analytics/commerce

# List agents
curl http://localhost:3001/agents?owner=0x0000000000000000000000000000000000000000

# List open intents
curl http://localhost:3001/intents?status=open

Hosted API checks:

curl https://cortex-api.projectaegis.ai/health
curl https://cortex-api.projectaegis.ai/analytics/commerce

Start the dashboard

cd web
NEXT_PUBLIC_API_URL=http://localhost:3001 npm run dev

Open http://localhost:3000/dashboard. Protocol fees should show 0until a future fee switch is intentionally added.

Hosted dashboard: https://cortex.projectaegis.ai/dashboard.

8. AWS Deployment

The hosted deployment runs on AWS account 159077623001 (SSO profile node.admin,us-east-2): the API and indexer run on the shared sre-adara EKS cluster behind a dedicated cortex ALB at cortex-api.projectaegis.ai, the web app is a static export on S3 + CloudFront at cortex.projectaegis.ai, and Postgres is RDS cortex-postgres. K8s manifests live in infra/k8s/; the web stack is infra/aws-web/.

aws sso login --profile node.admin
aws eks update-kubeconfig --name sre-adara --region us-east-2 --profile node.admin

# Build + push ARM64 images, then deploy to EKS
export AWS_PROFILE=node.admin AWS_REGION=us-east-2
REG=159077623001.dkr.ecr.us-east-2.amazonaws.com
aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin "$REG"
docker buildx build --platform linux/arm64 -f api/Dockerfile     -t "$REG/cortex-api:latest"     --push .
docker buildx build --platform linux/arm64 -f indexer/Dockerfile -t "$REG/cortex-indexer:latest" --push .
kubectl apply -f infra/k8s/
kubectl rollout restart deployment/cortex-api deployment/cortex-indexer -n cortex

# Web (S3 + CloudFront)
cd infra/aws-web && terraform init && terraform apply && cd ../..
cd web && NEXT_PUBLIC_API_URL=https://cortex-api.projectaegis.ai npm run build && cd ..
aws s3 sync web/out s3://cortex-web-159077623001 --delete

The cortex-secrets Secret (DATABASE_URL) is created once — see infra/k8s/README.md. On Apple Silicon, Terraform must be a native darwin_arm64 build; an x86_64 binary under Rosetta times out loading the AWS provider.

Register a test agent

source ops/.env.testnet

cast send "$AGENT_REGISTRY_ADDRESS" \
  "registerAgent(string,bytes,bytes32)" \
  "ipfs://test-agent" \
  "0xaabb" \
  "0x0000000000000000000000000000000000000000000000000000000000000001" \
  --rpc-url "$RPC_URL" \
  --private-key "$AGENT_PRIVATE_KEY"

Wait a few seconds for the indexer, then query curl http://localhost:3001/agents/1.

Alternative: OP Sepolia

The same steps apply to OP Sepolia. Change:

RPC_URL=https://sepolia.optimism.io

The deploy script auto-detects the chain ID. Use the OP Sepolia explorer at sepolia-optimistic.etherscan.io.

Troubleshooting

  • Deploy fails with “insufficient funds”: Get more testnet ETH from a faucet. Deployment costs ~0.01 ETH.
  • Indexer not picking up events: Check that RPC_URL and contract addresses match. The indexer may take 5-10 seconds.
  • Solver not filling intents: Verify SOLVER_PRIVATE_KEY has testnet ETH. Check ops/solver.log.
  • Database connection refused: Ensure Postgres is accessible and DATABASE_URL is correct. Test with psql "$DATABASE_URL" -c "SELECT 1".