Skip to main content

Production Deployment: Mainnet Launch Guide

Deploying to Solana mainnet requires careful preparation to ensure security, reliability, and compliance. This comprehensive guide walks you through the complete mainnet launch process for your GhostSpeak agents.
Production Environment: Mainnet involves real funds, real users, and real legal implications. Follow this checklist carefully to avoid costly mistakes.

Pre-Launch Checklist

Phase 1: Security Audit

1

Keypair Security

Never store production keypairs in code, environment files, or version control.✅ Approved Methods:
  • Hardware wallets (Ledger, Trezor)
  • Cloud KMS (AWS KMS, Google Cloud KMS, Azure Key Vault)
  • HashiCorp Vault
  • Environment variables (encrypted at rest)
❌ Forbidden:
  • JSON files in repository
  • Plain text environment variables
  • Local file storage
2

Environment Separation

Maintain strict separation between dev/staging/production:
.env.production
# Production configuration
SOLANA_CLUSTER=mainnet-beta
SOLANA_RPC_URL=https://api.mainnet-beta.solana.com # Use premium RPC!

# Secrets (use encrypted secrets manager)
WALLET_SECRET=encrypted:vault:prod/agent-wallet
CROSSMINT_API_KEY=encrypted:vault:prod/crossmint
WEBHOOK_SECRET=encrypted:vault:prod/webhook-secret

# Never commit this file!
Add to .gitignore:
.env.production
.env.mainnet
*-keypair.json
*-secret*
3

Smart Contract Audit

If using custom contracts, get a professional audit:Recommended Auditors:Audit Scope:
  • Custom reputation algorithms
  • Modified credential schemas
  • Marketplace escrow logic
  • Any program modifications
4

Penetration Testing

Test for vulnerabilities:
# Test wallet key exposure
git log --all --full-history --source -- '*keypair*' '*secret*'

# Should return nothing!
Common Vulnerabilities:
  • Exposed API keys in code
  • Insecure webhook signature verification
  • Insufficient rate limiting
  • Missing input validation

Phase 2: Infrastructure Setup

1

Premium RPC Provider

Don’t use public RPCs in production!Public RPC issues:
  • ❌ Rate limited (50 requests/10 seconds)
  • ❌ Unreliable uptime
  • ❌ No SLA guarantees
  • ❌ Slow transaction confirmations
✅ Use Premium RPC:
ProviderCostFeatures
Helius$50-500/monthWebSocket, priority tx, 99.9% SLA
QuickNode$49-999/monthGlobal CDN, analytics, high throughput
Triton$99-999/monthLow latency, dedicated nodes
GenesysGo$50-500/monthShadow network, high performance
// Production RPC configuration
const client = new GhostSpeakClient({
  cluster: 'mainnet-beta',
  rpcUrl: process.env.HELIUS_RPC_URL, // Premium RPC
  commitment: 'confirmed',
  confirmTransactionInitialTimeout: 60000, // 60s timeout
})
2

Database Setup

Set up production database for off-chain data:
// Recommended: PostgreSQL for relational data
const db = new Pool({
  host: process.env.DB_HOST,
  port: 5432,
  database: 'ghostspeak_prod',
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  ssl: {
    rejectUnauthorized: true,
    ca: process.env.DB_CA_CERT,
  },
  max: 20, // Connection pool size
  idleTimeoutMillis: 30000,
})

// Schema
await db.query(`
  CREATE TABLE agents (
    address VARCHAR(44) PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
  );

  CREATE TABLE credentials (
    id VARCHAR(255) PRIMARY KEY,
    agent_address VARCHAR(44) REFERENCES agents(address),
    type VARCHAR(100) NOT NULL,
    issued_at TIMESTAMP NOT NULL,
    revoked BOOLEAN DEFAULT FALSE
  );

  CREATE INDEX idx_agent_credentials ON credentials(agent_address);
`)
3

Monitoring and Alerting

Set up comprehensive monitoring:Metrics to Track:
  • Transaction success rate
  • Ghost Score changes
  • Credential issuance volume
  • Marketplace transaction volume
  • RPC latency and errors
  • Wallet balance (to prevent insufficient funds)
Tools:
// Example: Datadog integration
import { StatsD } from 'hot-shots'

const metrics = new StatsD({
  host: 'dd-agent',
  prefix: 'ghostspeak.',
})

// Track credential issuance
await client.credentials.issueAgentIdentityCredential({
  // ... params
})

metrics.increment('credentials.issued', 1, ['type:agent-identity'])

// Track Ghost Score changes
const reputation = await client.reputation.getReputationData(agentAddress)

metrics.gauge('ghost-score', reputation.overallScore, [
  `tier:${reputation.tier}`,
  `agent:${agentAddress}`,
])
4

Backup Strategy

Implement automated backups:
backup.sh
#!/bin/bash

# Backup database
pg_dump ghostspeak_prod | gzip > /backups/ghostspeak_$(date +%Y%m%d).sql.gz

# Upload to S3
aws s3 cp /backups/ghostspeak_$(date +%Y%m%d).sql.gz \
  s3://ghostspeak-backups/$(date +%Y%m%d)/

# Keep local backups for 7 days
find /backups -name "ghostspeak_*.sql.gz" -mtime +7 -delete
Schedule daily backups:
# crontab -e
0 2 * * * /usr/local/bin/backup.sh

Phase 3: Testing on Mainnet

Start Small: Test with minimal funds (0.1-1 SOL) and low-value transactions before scaling up.
1

Mainnet Test Agent

Create a test agent on mainnet with real (but small) funds:
const client = new GhostSpeakClient({
  cluster: 'mainnet-beta',
  rpcUrl: process.env.HELIUS_RPC_URL,
})

// Register test agent
const testAgent = await client.agents.register(testAgentSigner, {
  name: 'Mainnet Test Agent',
  description: '[TEST] Do not use for production',
  capabilities: ['test'],
})

console.log('Test agent:', testAgent.address)

// Issue test credential
const credential = await client.credentials.issueAgentIdentityCredential({
  agentId: testAgent.address,
  // ... other params
  syncToCrossmint: true, // Test cross-chain sync
})

console.log('Credential:', credential.solanaCredential.credentialId)

// Verify transaction costs
console.log('Registration cost:', agent.cost, 'SOL')
console.log('Credential cost:', credential.cost, 'SOL')
2

Transaction Cost Analysis

Measure actual mainnet costs:
async function analyzeCosts() {
  const operations = [
    { name: 'Agent Registration', fn: () => client.agents.register(...) },
    { name: 'Credential Issuance', fn: () => client.credentials.issue(...) },
    { name: 'Ghost Score Update', fn: () => client.reputation.recordTransaction(...) },
    { name: 'Marketplace Listing', fn: () => client.marketplace.createListing(...) },
  ]

  for (const op of operations) {
    const startBalance = await connection.getBalance(wallet.publicKey)

    await op.fn()

    const endBalance = await connection.getBalance(wallet.publicKey)
    const costLamports = startBalance - endBalance
    const costSOL = costLamports / 1e9

    console.log(`${op.name}: ${costSOL} SOL (~$${costSOL * solPrice})`)
  }
}
Expected Costs (as of 2025):
  • Agent registration: 0.002 SOL ($0.30)
  • Credential issuance: 0.001 SOL ($0.15)
  • Ghost Score update: 0.0005 SOL ($0.08)
  • Marketplace listing: 0.001 SOL ($0.15)
3

Load Testing

Simulate production load on mainnet:
// Use small amounts to avoid wasting funds
const CONCURRENT_AGENTS = 10 // Start small!
const TRANSACTIONS_PER_AGENT = 5

for (let i = 0; i < CONCURRENT_AGENTS; i++) {
  const agent = await registerTestAgent()

  for (let j = 0; j < TRANSACTIONS_PER_AGENT; j++) {
    await client.reputation.recordTransaction(agent, {
      // ... transaction data
    })
  }
}

// Monitor RPC performance
console.log('RPC latency:', client.metrics.avgLatency)
console.log('Success rate:', client.metrics.successRate)

Production Deployment

Step 1: Wallet Funding

# Calculate required SOL
# Formula: (expected_agents × 0.002) + (expected_credentials × 0.001) + buffer

# Example: 1000 agents, 5000 credentials
required_sol=$(echo "scale=2; (1000 * 0.002) + (5000 * 0.001) + 10" | bc)

echo "Required SOL: $required_sol" # ~17 SOL

# Fund production wallet (use hardware wallet for large amounts)
solana transfer <PRODUCTION_WALLET> $required_sol --url mainnet-beta
Wallet Security: For wallets holding >10 SOL, use a hardware wallet or multi-sig. Never store large balances in hot wallets.

Step 2: Domain and SSL Setup

# Set up custom domain for webhooks
# yourplatform.com → Your frontend
# api.yourplatform.com → Your API
# webhooks.yourplatform.com → Webhook handlers

# Ensure SSL certificate (required for webhooks)
certbot certonly --standalone -d webhooks.yourplatform.com

# Verify SSL
curl https://webhooks.yourplatform.com/health

Step 3: Webhook Configuration

webhook-server.ts
import { Bun } from 'bun'
import { GhostSpeakClient } from '@ghostspeak/sdk'

const client = new GhostSpeakClient({
  cluster: 'mainnet-beta',
  rpcUrl: process.env.HELIUS_RPC_URL,
})

Bun.serve({
  port: 443,
  tls: {
    cert: Bun.file('/etc/letsencrypt/live/webhooks.yourplatform.com/fullchain.pem'),
    key: Bun.file('/etc/letsencrypt/live/webhooks.yourplatform.com/privkey.pem'),
  },

  routes: {
    '/webhooks/ghostspeak': {
      POST: async (req) => {
        // 1. Verify signature (CRITICAL for security)
        const signature = req.headers.get('X-GhostSpeak-Signature')
        const payload = await req.text()

        const isValid = await client.webhooks.verifySignature(
          payload,
          signature,
          process.env.WEBHOOK_SECRET!
        )

        if (!isValid) {
          console.error('Invalid webhook signature')
          return new Response('Unauthorized', { status: 401 })
        }

        // 2. Parse payload
        const event = JSON.parse(payload)

        // 3. Handle event (idempotent!)
        try {
          await handleWebhookEvent(event)
          return new Response('OK', { status: 200 })
        } catch (error) {
          console.error('Webhook handler error:', error)
          return new Response('Internal Server Error', { status: 500 })
        }
      },
    },
  },
})

async function handleWebhookEvent(event: any) {
  // Ensure idempotency (process each event only once)
  const processed = await db.query(
    'SELECT 1 FROM webhook_events WHERE event_id = $1',
    [event.id]
  )

  if (processed.rows.length > 0) {
    console.log('Event already processed:', event.id)
    return
  }

  // Process event
  switch (event.type) {
    case 'ghost-score.updated':
      await handleGhostScoreUpdate(event.data)
      break

    case 'credential.issued':
      await handleCredentialIssued(event.data)
      break

    case 'marketplace.transaction.completed':
      await handleMarketplaceTransaction(event.data)
      break

    default:
      console.log('Unknown event type:', event.type)
  }

  // Mark as processed
  await db.query(
    'INSERT INTO webhook_events (event_id, type, processed_at) VALUES ($1, $2, NOW())',
    [event.id, event.type]
  )
}

console.log('Webhook server running on https://webhooks.yourplatform.com')

Step 4: Error Handling and Retry Logic

error-handling.ts
import { GhostSpeakClient, GhostSpeakError } from '@ghostspeak/sdk'

class ProductionGhostSpeakClient {
  private client: GhostSpeakClient
  private maxRetries = 3
  private retryDelay = 1000 // ms

  constructor() {
    this.client = new GhostSpeakClient({
      cluster: 'mainnet-beta',
      rpcUrl: process.env.HELIUS_RPC_URL,
    })
  }

  async registerAgentWithRetry(agentSigner: any, data: any) {
    let lastError

    for (let attempt = 0; attempt < this.maxRetries; attempt++) {
      try {
        const agent = await this.client.agents.register(agentSigner, data)

        // Success - log metrics
        metrics.increment('agent.registration.success')

        return agent
      } catch (error) {
        lastError = error

        if (error instanceof GhostSpeakError) {
          // Handle specific errors
          switch (error.code) {
            case 'INSUFFICIENT_FUNDS':
              // Critical - alert immediately
              await alertOncall('Insufficient SOL in production wallet')
              throw error // Don't retry

            case 'RPC_TIMEOUT':
              // Transient - retry
              console.log(`RPC timeout (attempt ${attempt + 1}/${this.maxRetries})`)
              await this.sleep(this.retryDelay * (attempt + 1)) // Exponential backoff
              continue

            case 'AGENT_ALREADY_EXISTS':
              // Not an error - agent already registered
              console.log('Agent already exists:', agentSigner.address)
              return await this.client.agents.getAgent(agentSigner.address)

            default:
              // Unknown error - retry
              console.error('Unknown error:', error)
              await this.sleep(this.retryDelay * (attempt + 1))
              continue
          }
        }

        // Generic error - retry
        await this.sleep(this.retryDelay * (attempt + 1))
      }
    }

    // All retries failed
    metrics.increment('agent.registration.failure')
    throw lastError
  }

  private sleep(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms))
  }
}

Monitoring and Maintenance

Health Checks

health-check.ts
import { GhostSpeakClient } from '@ghostspeak/sdk'

export async function healthCheck() {
  const checks = {
    rpc: false,
    database: false,
    wallet: false,
    ghostspeak: false,
  }

  try {
    // 1. Check RPC connectivity
    const client = new GhostSpeakClient({
      cluster: 'mainnet-beta',
      rpcUrl: process.env.HELIUS_RPC_URL,
    })

    const blockHeight = await client.connection.getBlockHeight()
    checks.rpc = blockHeight > 0

    // 2. Check database
    const dbResult = await db.query('SELECT 1')
    checks.database = dbResult.rows.length > 0

    // 3. Check wallet balance
    const balance = await client.connection.getBalance(wallet.publicKey)
    checks.wallet = balance > 1_000_000_000 // > 1 SOL

    if (balance < 5_000_000_000) {
      // < 5 SOL
      await alertOncall('Low wallet balance: ' + balance / 1e9 + ' SOL')
    }

    // 4. Check GhostSpeak SDK
    const testReputation = await client.reputation.getTierInfo('Bronze')
    checks.ghostspeak = testReputation !== null

  } catch (error) {
    console.error('Health check failed:', error)
  }

  return {
    healthy: Object.values(checks).every(c => c),
    checks,
    timestamp: new Date().toISOString(),
  }
}

// Run health check every 60 seconds
setInterval(async () => {
  const health = await healthCheck()

  if (!health.healthy) {
    console.error('System unhealthy:', health)
    await alertOncall('Health check failed', health)
  }

  // Send metrics to monitoring system
  metrics.gauge('health.rpc', health.checks.rpc ? 1 : 0)
  metrics.gauge('health.database', health.checks.database ? 1 : 0)
  metrics.gauge('health.wallet', health.checks.wallet ? 1 : 0)
  metrics.gauge('health.ghostspeak', health.checks.ghostspeak ? 1 : 0)
}, 60000)

1

Terms of Service

Draft comprehensive ToS covering:
  • Agent registration requirements
  • Credential issuance policies
  • Ghost Score privacy and usage
  • Marketplace dispute resolution
  • Liability limitations
  • Data retention policies
2

Privacy Policy

Address data handling:
  • What data is collected (on-chain vs off-chain)
  • How Ghost Score data is used
  • Cross-chain data synchronization
  • User rights (GDPR, CCPA compliance)
  • Data deletion requests
3

KYC/AML (if applicable)

For high-value marketplaces:
  • Implement KYC for agents/buyers
  • Screen against OFAC sanctions lists
  • Monitor for suspicious activity
  • Maintain transaction records (5+ years)

Launch Day Checklist

1

Final Pre-Launch Verification

# Verify production configuration
 Premium RPC configured
 Wallet funded (>10 SOL)
 Database backed up
 Monitoring active
 Alerts configured
 Webhooks tested
 SSL certificates valid
 Terms of Service published
 Privacy Policy published
 Support email active
2

Staged Rollout

Don’t launch to 100% of users immediately:Week 1: Beta users only (100-1000 users) Week 2: 10% of users Week 3: 50% of users Week 4: 100% of users (full launch)Monitor metrics closely during each phase.
3

Communication Plan

  • Announce launch on social media
  • Send email to waitlist
  • Post in Discord/Telegram
  • Update documentation with mainnet examples
  • Prepare support team for inquiries

Post-Launch Monitoring

Key Metrics Dashboard

metrics-dashboard.ts
// Track critical production metrics

interface Metrics {
  agentsRegistered: number
  credentialsIssued: number
  averageGhostScore: number
  transactionSuccessRate: number
  rpcUptime: number
  webhookLatency: number
}

async function getDashboardMetrics(): Promise<Metrics> {
  const last24h = Date.now() - 24 * 60 * 60 * 1000

  return {
    agentsRegistered: await db.query(
      'SELECT COUNT(*) FROM agents WHERE created_at > $1',
      [new Date(last24h)]
    ).then(r => r.rows[0].count),

    credentialsIssued: await db.query(
      'SELECT COUNT(*) FROM credentials WHERE issued_at > $1',
      [new Date(last24h)]
    ).then(r => r.rows[0].count),

    averageGhostScore: await db.query(
      'SELECT AVG(score) FROM reputation'
    ).then(r => r.rows[0].avg),

    transactionSuccessRate: await getSuccessRate(last24h),

    rpcUptime: await getRPCUptime(last24h),

    webhookLatency: await getWebhookLatency(last24h),
  }
}

Incident Response

Runbook: Wallet Drained

# 1. Immediately rotate keys
solana-keygen new --outfile ~/.config/solana/new-mainnet.json

# 2. Transfer remaining funds to new wallet
solana transfer <NEW_WALLET> ALL --keypair ~/.config/solana/old-mainnet.json

# 3. Update production configuration
# Update WALLET_SECRET in secrets manager

# 4. Investigate breach
# Review access logs, check for exposed keys

# 5. Notify users if funds were impacted

Runbook: RPC Outage

# 1. Check RPC provider status page
curl https://status.helius.xyz

# 2. Switch to backup RPC (if available)
export BACKUP_RPC_URL=https://api.mainnet-beta.solana.com

# 3. Update configuration
# HELIUS_RPC_URL → BACKUP_RPC_URL

# 4. Monitor transaction success rate
# Expect degraded performance on public RPC

# 5. Contact RPC provider support

Next Steps


Pro Tip: Launch during low-activity hours (weekends, late night) to minimize impact if issues arise. Have your team on standby for the first 48 hours post-launch.

Ready for Mainnet?

You’ve completed the production deployment guide

Launch with confidence. We’re here to support you.