Skip to main content

Overview

This guide provides comprehensive instructions for deploying the ZKScore Identity SBT contract to various networks. It covers deployment preparation, configuration, execution, and verification.
Always test your deployment on testnet before deploying to mainnet. Use the testnet deployment addresses provided in the Contract Overview section.

Prerequisites

Required Tools

  1. Node.js: Version 16 or higher
  2. npm/yarn: Package manager
  3. Hardhat/Foundry: Development framework
  4. MetaMask: Wallet for deployment
  5. Etherscan API Key: For contract verification

Environment Setup

# Install dependencies
npm install @openzeppelin/contracts
npm install @nomiclabs/hardhat-ethers
npm install @nomiclabs/hardhat-etherscan
npm install hardhat

# Initialize project
npx hardhat init

Deployment Configuration

Network Configuration

// hardhat.config.js
require("@nomiclabs/hardhat-ethers");
require("@nomiclabs/hardhat-etherscan");

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

Environment Variables

# .env file
PRIVATE_KEY=your_private_key_here
ETHERSCAN_API_KEY=your_etherscan_api_key
POLYGONSCAN_API_KEY=your_polygonscan_api_key
INFURA_KEY=your_infura_key

Contract Deployment

Deployment Script

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

async function main() {
  console.log("Starting Identity SBT deployment...");
  
  // Get the contract factory
  const IdentitySBT = await ethers.getContractFactory("IdentitySBT");
  
  // Deploy the contract
  console.log("Deploying Identity SBT...");
  const identitySBT = await IdentitySBT.deploy(
    "ZKScore Identity", // name
    "ZKSID",           // symbol
    "https://api.onzks.com/metadata/", // baseURI
    "https://api.onzks.com/contract-metadata" // contractURI
  );
  
  await identitySBT.deployed();
  
  console.log("Identity SBT deployed to:", identitySBT.address);
  
  // Grant initial roles
  const [deployer] = await ethers.getSigners();
  console.log("Deployer address:", deployer.address);
  
  // Grant minter role to deployer
  const MINTER_ROLE = await identitySBT.MINTER_ROLE();
  await identitySBT.grantRole(MINTER_ROLE, deployer.address);
  console.log("Minter role granted to deployer");
  
  // Grant admin role to deployer
  const ADMIN_ROLE = await identitySBT.ADMIN_ROLE();
  await identitySBT.grantRole(ADMIN_ROLE, deployer.address);
  console.log("Admin role granted to deployer");
  
  // Grant metadata role to deployer
  const METADATA_ROLE = await identitySBT.METADATA_ROLE();
  await identitySBT.grantRole(METADATA_ROLE, deployer.address);
  console.log("Metadata role granted to deployer");
  
  // Verify deployment
  console.log("Verifying deployment...");
  const name = await identitySBT.name();
  const symbol = await identitySBT.symbol();
  const baseURI = await identitySBT.baseURI();
  
  console.log("Contract name:", name);
  console.log("Contract symbol:", symbol);
  console.log("Base URI:", baseURI);
  
  console.log("Deployment completed successfully!");
  
  return {
    address: identitySBT.address,
    name,
    symbol,
    baseURI
  };
}

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

Deployment Commands

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

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

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

# Deploy to Mumbai
npx hardhat run scripts/deploy.js --network mumbai

Contract Verification

Automatic Verification

// scripts/verify.js
const { run } = require("hardhat");

async function main() {
  const contractAddress = "0x1234567890123456789012345678901234567890";
  
  console.log("Verifying contract on Etherscan...");
  
  try {
    await run("verify:verify", {
      address: contractAddress,
      constructorArguments: [
        "ZKScore Identity",
        "ZKSID",
        "https://api.onzks.com/metadata/",
        "https://api.onzks.com/contract-metadata"
      ]
    });
    
    console.log("Contract verified successfully!");
  } catch (error) {
    if (error.message.includes("Already Verified")) {
      console.log("Contract already verified");
    } else {
      console.error("Verification failed:", error.message);
    }
  }
}

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

Manual Verification

# Verify on Etherscan
npx hardhat verify --network mainnet 0x1234567890123456789012345678901234567890 "ZKScore Identity" "ZKSID" "https://api.onzks.com/metadata/" "https://api.onzks.com/contract-metadata"

# Verify on PolygonScan
npx hardhat verify --network polygon 0x1234567890123456789012345678901234567890 "ZKScore Identity" "ZKSID" "https://api.onzks.com/metadata/" "https://api.onzks.com/contract-metadata"

Deployment Verification

Contract Verification Script

// scripts/verify-deployment.js
const { ethers } = require("hardhat");

async function main() {
  const contractAddress = "0x1234567890123456789012345678901234567890";
  
  console.log("Verifying deployment...");
  
  // Get contract instance
  const IdentitySBT = await ethers.getContractFactory("IdentitySBT");
  const identitySBT = IdentitySBT.attach(contractAddress);
  
  // Verify basic properties
  const name = await identitySBT.name();
  const symbol = await identitySBT.symbol();
  const baseURI = await identitySBT.baseURI();
  
  console.log("Contract name:", name);
  console.log("Contract symbol:", symbol);
  console.log("Base URI:", baseURI);
  
  // Verify roles
  const [deployer] = await ethers.getSigners();
  const MINTER_ROLE = await identitySBT.MINTER_ROLE();
  const ADMIN_ROLE = await identitySBT.ADMIN_ROLE();
  const METADATA_ROLE = await identitySBT.METADATA_ROLE();
  
  const hasMinterRole = await identitySBT.hasRole(MINTER_ROLE, deployer.address);
  const hasAdminRole = await identitySBT.hasRole(ADMIN_ROLE, deployer.address);
  const hasMetadataRole = await identitySBT.hasRole(METADATA_ROLE, deployer.address);
  
  console.log("Deployer has minter role:", hasMinterRole);
  console.log("Deployer has admin role:", hasAdminRole);
  console.log("Deployer has metadata role:", hasMetadataRole);
  
  // Test minting
  console.log("Testing minting...");
  try {
    const tx = await identitySBT.mint(
      deployer.address,
      "test.zks",
      "https://api.onzks.com/metadata/test.zks"
    );
    const receipt = await tx.wait();
    
    const event = receipt.events.find(e => e.event === 'IdentityMinted');
    const tokenId = event.args.tokenId;
    
    console.log("Test mint successful, token ID:", tokenId.toString());
    
    // Test activation
    console.log("Testing activation...");
    const activateTx = await identitySBT.activate(tokenId);
    await activateTx.wait();
    
    console.log("Test activation successful");
    
    // Verify activation
    const isActivated = await identitySBT.isActivated(tokenId);
    console.log("Token is activated:", isActivated);
    
  } catch (error) {
    console.error("Test failed:", error.message);
  }
  
  console.log("Deployment verification completed!");
}

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

Network-Specific Deployment

Ethereum Mainnet

# Deploy to Ethereum mainnet
npx hardhat run scripts/deploy.js --network mainnet

# Verify on Etherscan
npx hardhat verify --network mainnet 0x1234567890123456789012345678901234567890 "ZKScore Identity" "ZKSID" "https://api.onzks.com/metadata/" "https://api.onzks.com/contract-metadata"

Polygon

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

# Verify on PolygonScan
npx hardhat verify --network polygon 0x1234567890123456789012345678901234567890 "ZKScore Identity" "ZKSID" "https://api.onzks.com/metadata/" "https://api.onzks.com/contract-metadata"

Arbitrum

# Deploy to Arbitrum
npx hardhat run scripts/deploy.js --network arbitrum

# Verify on Arbitrum Explorer
npx hardhat verify --network arbitrum 0x1234567890123456789012345678901234567890 "ZKScore Identity" "ZKSID" "https://api.onzks.com/metadata/" "https://api.onzks.com/contract-metadata"

Deployment Checklist

Pre-Deployment

  • Test on testnet
  • Verify contract code
  • Check gas estimates
  • Prepare deployment script
  • Set up environment variables
  • Backup private keys

During Deployment

  • Monitor gas prices
  • Check network status
  • Verify transaction status
  • Save deployment addresses
  • Record transaction hashes

Post-Deployment

  • Verify contract on explorer
  • Test basic functions
  • Grant necessary roles
  • Update documentation
  • Notify team members

Troubleshooting

Common Issues

Gas Limit Exceeded

# Increase gas limit
npx hardhat run scripts/deploy.js --network mainnet --gas-limit 10000000

Verification Failed

# Try manual verification
npx hardhat verify --network mainnet 0x1234567890123456789012345678901234567890 "ZKScore Identity" "ZKSID" "https://api.onzks.com/metadata/" "https://api.onzks.com/contract-metadata"

Network Connection Issues

# Check network status
npx hardhat run scripts/deploy.js --network mainnet --verbose

Error Handling

// Enhanced deployment script with error handling
async function main() {
  try {
    console.log("Starting deployment...");
    
    const IdentitySBT = await ethers.getContractFactory("IdentitySBT");
    
    // Estimate gas
    const gasEstimate = await IdentitySBT.getDeployTransaction(
      "ZKScore Identity",
      "ZKSID",
      "https://api.onzks.com/metadata/",
      "https://api.onzks.com/contract-metadata"
    ).gasLimit;
    
    console.log("Estimated gas:", gasEstimate.toString());
    
    // Deploy with gas limit
    const identitySBT = await IdentitySBT.deploy(
      "ZKScore Identity",
      "ZKSID",
      "https://api.onzks.com/metadata/",
      "https://api.onzks.com/contract-metadata",
      {
        gasLimit: gasEstimate.mul(120).div(100) // 20% buffer
      }
    );
    
    await identitySBT.deployed();
    console.log("Deployment successful:", identitySBT.address);
    
  } catch (error) {
    console.error("Deployment failed:", error.message);
    
    if (error.message.includes("gas limit exceeded")) {
      console.error("Try increasing gas limit");
    } else if (error.message.includes("insufficient funds")) {
      console.error("Insufficient funds for deployment");
    } else if (error.message.includes("network")) {
      console.error("Network connection issue");
    }
    
    process.exit(1);
  }
}

Best Practices

Security

  1. Use Hardware Wallets: Use hardware wallets for deployment
  2. Secure Private Keys: Store private keys securely
  3. Test on Testnet: Always test on testnet first
  4. Verify Contracts: Verify contracts on explorers
  5. Monitor Deployments: Monitor deployment transactions

Performance

  1. Optimize Gas: Use gas optimization techniques
  2. Batch Operations: Batch multiple operations
  3. Monitor Gas Prices: Deploy during low gas periods
  4. Use Efficient Networks: Choose appropriate networks
  5. Monitor Performance: Monitor contract performance

Maintenance

  1. Regular Updates: Keep dependencies updated
  2. Monitor Events: Monitor contract events
  3. Backup Data: Backup important data
  4. Document Changes: Document all changes
  5. Version Control: Use version control for deployments