HUNCH Deployment Guide

Overview

This guide covers deploying HUNCH to production, including frontend deployment, smart contract deployment, and database setup.

Architecture Deployment

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│    Frontend     │    │    Database     │    │   Blockchain    │
│   (Vercel/      │◄──►│   (Supabase)    │◄──►│ (Ethereum/      │
│    Netlify)     │    │                 │    │   Polygon)      │
└─────────────────┘    └─────────────────┘    └─────────────────┘

Prerequisites

Required Accounts

  • Vercel/Netlify account for frontend hosting

  • Supabase account for database

  • Ethereum wallet with deployment funds

  • WalletConnect Cloud account

  • Domain registrar account (optional)

Development Tools

  • Node.js 18+ and npm

  • Hardhat for smart contract deployment

  • Git for version control

Smart Contract Deployment

1. Setup Hardhat Environment

# Install Hardhat dependencies
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox

# Create deployment script
mkdir scripts

2. Configure Network Settings

// hardhat.config.js
require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config();

module.exports = {
  solidity: {
    version: "0.8.19",
    settings: {
      optimizer: {
        enabled: true,
        runs: 200,
      },
    },
  },
  networks: {
    mainnet: {
      url: `https://mainnet.infura.io/v3/${process.env.INFURA_API_KEY}`,
      accounts: [process.env.PRIVATE_KEY],
      gasPrice: 20000000000, // 20 gwei
    },
    polygon: {
      url: `https://polygon-mainnet.infura.io/v3/${process.env.INFURA_API_KEY}`,
      accounts: [process.env.PRIVATE_KEY],
      gasPrice: 30000000000, // 30 gwei
    },
    sepolia: {
      url: `https://sepolia.infura.io/v3/${process.env.INFURA_API_KEY}`,
      accounts: [process.env.PRIVATE_KEY],
    },
  },
  etherscan: {
    apiKey: {
      mainnet: process.env.ETHERSCAN_API_KEY,
      polygon: process.env.POLYGONSCAN_API_KEY,
      sepolia: process.env.ETHERSCAN_API_KEY,
    },
  },
};

3. Create Deployment Script

// scripts/deploy.js
const { ethers } = require("hardhat");

async function main() {
  console.log("Starting HUNCH deployment...");

  // Get deployer account
  const [deployer] = await ethers.getSigners();
  console.log("Deploying with account:", deployer.address);
  console.log("Account balance:", (await deployer.getBalance()).toString());

  // Deploy Oracle first
  console.log("\n1. Deploying Oracle...");
  const Oracle = await ethers.getContractFactory("Oracle");
  const oracle = await Oracle.deploy();
  await oracle.deployed();
  console.log("Oracle deployed to:", oracle.address);

  // Deploy MarketFactory
  console.log("\n2. Deploying MarketFactory...");
  const MarketFactory = await ethers.getContractFactory("MarketFactory");
  const marketFactory = await MarketFactory.deploy(oracle.address);
  await marketFactory.deployed();
  console.log("MarketFactory deployed to:", marketFactory.address);

  // Deploy MultiOptionMarketFactory
  console.log("\n3. Deploying MultiOptionMarketFactory...");
  const MultiOptionMarketFactory = await ethers.getContractFactory("MultiOptionMarketFactory");
  const multiOptionMarketFactory = await MultiOptionMarketFactory.deploy(oracle.address);
  await multiOptionMarketFactory.deployed();
  console.log("MultiOptionMarketFactory deployed to:", multiOptionMarketFactory.address);

  // Configure Oracle with factories
  console.log("\n4. Configuring Oracle...");
  await oracle.addResolver(deployer.address);
  console.log("Added deployer as resolver");

  // Verification info
  console.log("\n=== DEPLOYMENT SUMMARY ===");
  console.log("Network:", network.name);
  console.log("Oracle:", oracle.address);
  console.log("MarketFactory:", marketFactory.address);
  console.log("MultiOptionMarketFactory:", multiOptionMarketFactory.address);
  
  // Save deployment info
  const deploymentInfo = {
    network: network.name,
    oracle: oracle.address,
    marketFactory: marketFactory.address,
    multiOptionMarketFactory: multiOptionMarketFactory.address,
    deployer: deployer.address,
    timestamp: new Date().toISOString(),
  };

  require("fs").writeFileSync(
    `deployments/${network.name}.json`,
    JSON.stringify(deploymentInfo, null, 2)
  );

  console.log(`\nDeployment info saved to deployments/${network.name}.json`);
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

4. Deploy to Networks

# Create deployments directory
mkdir deployments

# Deploy to Sepolia testnet
npx hardhat run scripts/deploy.js --network sepolia

# Deploy to Polygon
npx hardhat run scripts/deploy.js --network polygon

# Deploy to Mainnet (when ready)
npx hardhat run scripts/deploy.js --network mainnet

5. Verify Contracts

# Verify Oracle
npx hardhat verify --network polygon <ORACLE_ADDRESS>

# Verify MarketFactory
npx hardhat verify --network polygon <MARKET_FACTORY_ADDRESS> <ORACLE_ADDRESS>

# Verify MultiOptionMarketFactory
npx hardhat verify --network polygon <MULTI_OPTION_FACTORY_ADDRESS> <ORACLE_ADDRESS>

Database Setup

1. Create Supabase Project

  1. Go to Supabase

  2. Create new project

  3. Note down project URL and anon key

2. Run Database Migrations

-- Create markets_enhanced table
CREATE TABLE public.markets_enhanced (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    market_id TEXT NOT NULL UNIQUE,
    question TEXT NOT NULL,
    description TEXT,
    category TEXT,
    market_type TEXT DEFAULT 'binary',
    creator_address TEXT NOT NULL,
    end_time TIMESTAMP WITH TIME ZONE NOT NULL,
    resolved BOOLEAN DEFAULT false,
    winning_option_index INTEGER,
    total_volume BIGINT DEFAULT 0,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);

-- Create market_options table
CREATE TABLE public.market_options (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    market_id TEXT NOT NULL,
    option_index INTEGER NOT NULL,
    option_text TEXT NOT NULL,
    shares_outstanding BIGINT DEFAULT 0,
    total_volume BIGINT DEFAULT 0,
    current_price BIGINT DEFAULT 0,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);

-- Create x_connections table
CREATE TABLE public.x_connections (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_address TEXT NOT NULL UNIQUE,
    x_user_id TEXT NOT NULL,
    x_username TEXT NOT NULL,
    x_display_name TEXT,
    x_profile_image_url TEXT,
    x_follower_count INTEGER DEFAULT 0,
    x_verified BOOLEAN DEFAULT false,
    access_token TEXT NOT NULL,
    access_token_secret TEXT NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);

3. Setup Row Level Security

-- Enable RLS
ALTER TABLE public.markets_enhanced ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.market_options ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.x_connections ENABLE ROW LEVEL SECURITY;

-- Markets policies
CREATE POLICY "Anyone can view enhanced markets" ON markets_enhanced FOR SELECT USING (true);
CREATE POLICY "Anyone can create markets" ON markets_enhanced FOR INSERT WITH CHECK (true);
CREATE POLICY "Market creators can update their markets" ON markets_enhanced FOR UPDATE USING (creator_address = current_setting('request.jwt.claims', true)::json->>'wallet_address');

-- Market options policies
CREATE POLICY "Anyone can view market options" ON market_options FOR SELECT USING (true);
CREATE POLICY "Market creators can insert options" ON market_options FOR INSERT WITH CHECK (true);
CREATE POLICY "Market creators can update options" ON market_options FOR UPDATE USING (true);

-- X connections policies
CREATE POLICY "Users can view their own X connections" ON x_connections FOR SELECT USING (user_address = current_setting('request.jwt.claims', true)::json->>'wallet_address');
CREATE POLICY "Users can create their own X connections" ON x_connections FOR INSERT WITH CHECK (user_address = current_setting('request.jwt.claims', true)::json->>'wallet_address');
CREATE POLICY "Users can update their own X connections" ON x_connections FOR UPDATE USING (user_address = current_setting('request.jwt.claims', true)::json->>'wallet_address');
CREATE POLICY "Users can delete their own X connections" ON x_connections FOR DELETE USING (user_address = current_setting('request.jwt.claims', true)::json->>'wallet_address');

Frontend Deployment

1. Update Contract Addresses

// src/config/wagmi.ts
export const CONTRACT_ADDRESSES = {
  [mainnet.id]: {
    marketFactory: '0xYourMainnetMarketFactoryAddress',
    outcomeToken: '0xYourMainnetTokenAddress',
    oracle: '0xYourMainnetOracleAddress',
  },
  [polygon.id]: {
    marketFactory: '0xYourPolygonMarketFactoryAddress',
    outcomeToken: '0xYourPolygonTokenAddress',
    oracle: '0xYourPolygonOracleAddress',
  },
  [sepolia.id]: {
    marketFactory: '0xYourSepoliaMarketFactoryAddress',
    outcomeToken: '0xYourSepoliaTokenAddress',
    oracle: '0xYourSepoliaOracleAddress',
  },
};

2. Configure Environment Variables

# Production .env
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=your-supabase-anon-key
VITE_WALLETCONNECT_PROJECT_ID=your-walletconnect-project-id
VITE_NETWORK=mainnet
VITE_ENABLE_TESTNETS=false

3. Deploy to Vercel

# Install Vercel CLI
npm i -g vercel

# Login to Vercel
vercel login

# Deploy
vercel --prod

Vercel Configuration (vercel.json):

{
  "framework": "vite",
  "buildCommand": "npm run build",
  "outputDirectory": "dist",
  "installCommand": "npm install",
  "env": {
    "VITE_SUPABASE_URL": "@supabase-url",
    "VITE_SUPABASE_ANON_KEY": "@supabase-anon-key",
    "VITE_WALLETCONNECT_PROJECT_ID": "@walletconnect-project-id"
  },
  "rewrites": [
    {
      "source": "/api/(.*)",
      "destination": "/api/$1"
    }
  ]
}

4. Deploy to Netlify (Alternative)

# Install Netlify CLI
npm i -g netlify-cli

# Login to Netlify
netlify login

# Deploy
netlify deploy --prod --dir=dist

Netlify Configuration (netlify.toml):

[build]
  publish = "dist"
  command = "npm run build"

[build.environment]
  VITE_SUPABASE_URL = "https://your-project.supabase.co"
  VITE_SUPABASE_ANON_KEY = "your-supabase-anon-key"
  VITE_WALLETCONNECT_PROJECT_ID = "your-walletconnect-project-id"

[[redirects]]
  from = "/api/*"
  to = "/.netlify/functions/:splat"
  status = 200

Domain Configuration

1. Custom Domain Setup

For Vercel:

  1. Go to Project Settings → Domains

  2. Add your domain

  3. Configure DNS records as shown

For Netlify:

  1. Go to Site Settings → Domain Management

  2. Add custom domain

  3. Update DNS records

2. SSL Certificate

Both Vercel and Netlify provide automatic SSL certificates for custom domains.

Environment-Specific Configuration

Development

// config/environments/development.ts
export const config = {
  network: 'sepolia',
  enableTestnets: true,
  logLevel: 'debug',
  enableMockData: true,
};

Staging

// config/environments/staging.ts
export const config = {
  network: 'polygon',
  enableTestnets: true,
  logLevel: 'info',
  enableMockData: false,
};

Production

// config/environments/production.ts
export const config = {
  network: 'mainnet',
  enableTestnets: false,
  logLevel: 'error',
  enableMockData: false,
};

Monitoring and Analytics

1. Error Tracking

# Install Sentry
npm install @sentry/react @sentry/tracing
// src/lib/sentry.ts
import * as Sentry from "@sentry/react";

Sentry.init({
  dsn: "YOUR_SENTRY_DSN",
  integrations: [
    new Sentry.BrowserTracing(),
  ],
  tracesSampleRate: 0.1,
  environment: process.env.NODE_ENV,
});

2. Performance Monitoring

// src/lib/analytics.ts
import { Analytics } from '@vercel/analytics/react';

export function AnalyticsProvider({ children }) {
  return (
    <>
      {children}
      <Analytics />
    </>
  );
}

3. Uptime Monitoring

Setup monitoring for:

  • Frontend availability

  • API response times

  • Smart contract interaction success rates

  • Database performance

Security Considerations

1. Environment Variables

  • Never commit sensitive keys to Git

  • Use different keys for each environment

  • Rotate keys regularly

2. Smart Contract Security

  • Get contracts audited before mainnet deployment

  • Use multisig wallets for admin functions

  • Implement emergency pause mechanisms

3. Frontend Security

  • Enable CSP headers

  • Use HTTPS only

  • Implement rate limiting

  • Validate all user inputs

Maintenance

1. Regular Updates

# Update dependencies monthly
npm update

# Security audit
npm audit fix

2. Database Maintenance

  • Monitor query performance

  • Setup automated backups

  • Archive old data periodically

3. Smart Contract Upgrades

  • Plan upgrade strategy

  • Test thoroughly on testnets

  • Communicate changes to users

Rollback Strategy

1. Frontend Rollback

# Vercel
vercel rollback [deployment-url]

# Netlify
netlify rollback

2. Database Rollback

  • Use Supabase point-in-time recovery

  • Restore from scheduled backups

  • Re-run specific migrations

3. Smart Contract Rollback

  • Deploy new contract versions

  • Update frontend to use new addresses

  • Migrate user funds if necessary

Cost Optimization

1. Frontend Costs

  • Use CDN for static assets

  • Optimize bundle size

  • Implement code splitting

2. Database Costs

  • Monitor query usage

  • Optimize expensive queries

  • Implement data archiving

3. Blockchain Costs

  • Batch transactions when possible

  • Use Layer 2 solutions

  • Optimize contract gas usage

Backup and Recovery

1. Database Backups

  • Daily automated backups

  • Cross-region replication

  • Test restore procedures

2. Code Backups

  • Git repository mirroring

  • Regular code exports

  • Documentation backups

3. Smart Contract Recovery

  • Keep deployment keys secure

  • Document all contract addresses

  • Maintain upgrade paths

Last updated