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 scripts2. 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 mainnet5. 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
Go to Supabase
Create new project
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=false3. Deploy to Vercel
# Install Vercel CLI
npm i -g vercel
# Login to Vercel
vercel login
# Deploy
vercel --prodVercel 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=distNetlify 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 = 200Domain Configuration
1. Custom Domain Setup
For Vercel:
Go to Project Settings → Domains
Add your domain
Configure DNS records as shown
For Netlify:
Go to Site Settings → Domain Management
Add custom domain
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 fix2. 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 rollback2. 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
