Skip to main content

Environment Variables

Tornado Nova uses environment variables for sensitive configuration. Create a .env file in the project root based on .env.example:
.env
PRIVATE_KEY=your_private_key_here
ETH_RPC=https://eth-mainnet.alchemyapi.io/v2/your_key
XDAI_RPC=https://rpc.gnosischain.com
BSC_RPC=https://bsc-dataseed.binance.org/
MINIMUM_WITHDRAWAL_AMOUNT=0.05
MAXIMUM_DEPOSIT_AMOUNT=1
ALCHEMY_KEY=your_alchemy_api_key
INFURA_API_KEY=your_infura_api_key
ETHERSCAN_KEY=your_etherscan_api_key
Never commit your .env file to version control. It contains sensitive private keys and API credentials.

Environment Variable Descriptions

# Private key for deployment and transactions
PRIVATE_KEY=

# RPC endpoints for different networks
ETH_RPC=https://
XDAI_RPC=https://
BSC_RPC=https://

Hardhat Configuration

The hardhat.config.js file configures network connections, compiler settings, and plugins.

Solidity Compiler Settings

hardhat.config.js
solidity: {
  compilers: [
    {
      version: '0.4.24',
      settings: {
        optimizer: {
          enabled: true,
          runs: 200,
        },
      },
    },
    {
      version: '0.6.2',
      settings: {
        optimizer: {
          enabled: true,
          runs: 200,
        },
      },
    },
    {
      version: '0.7.5',
      settings: {
        optimizer: {
          enabled: true,
          runs: 200,
        },
      },
    },
    {
      version: '0.7.6',
      settings: {
        optimizer: {
          enabled: true,
          runs: 200,
        },
      },
    },
  ],
},
Multiple compiler versions are configured to support different contract dependencies.

Network Configuration

networks: {
  hardhat: {
    forking: {
      url: `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_KEY}`,
      blockNumber: 13685625,
    },
    chainId: 1,
    initialBaseFeePerGas: 5,
    loggingEnabled: false,
    allowUnlimitedContractSize: false,
    blockGasLimit: 50000000,
  },
}

Additional Settings

hardhat.config.js
config = {
  // ... networks and compiler config
  
  etherscan: {
    apiKey: process.env.ETHERSCAN_KEY,
  },
  
  mocha: {
    timeout: 600000000, // 10 minutes for ZK proof tests
  },
  
  typechain: {
    outDir: 'src/types', // TypeScript type generation
  },
}

Application Configuration

The config.js file contains deployment addresses and protocol parameters:

Layer 1 Configuration (Ethereum Mainnet)

config.js
module.exports = {
  // L1 Configuration
  multisig: '0xb04E030140b30C27bcdfaafFFA98C57d80eDa7B4',
  omniBridge: '0x88ad09518695c6c3712AC10a214bE5109a655671',
  weth: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
  singletonFactory: '0xce0042B868300000d44A59004Da54A005ffdcf9f',
  salt: '0x0000000000000000000000000000000000000000000000000000000047941987',
}
The salt value is used for deterministic contract deployment via CREATE2.

Layer 2 Configuration (Gnosis Chain)

config.js
module.exports = {
  // L2 Configuration (Gnosis Chain)
  verifier2: '0xdf3a408c53e5078af6e8fb2a85088d46ee09a61b',
  verifier16: '0x743494b60097a2230018079c02fe21a7b687eaa5',
  MERKLE_TREE_HEIGHT: 23,
  hasher: '0x94c92f096437ab9958fc0a37f09348f30389ae79',
  gcWeth: '0x6a023ccd1ff6f2045c3309768ead9e68f978f6e1',
  gcOmniBridge: '0xf6a78083ca3e2a662d6dd1703c939c8ace2e268d',
  l1Unwrapper: '0x3F615bA21Bc6Cc5D4a6D798c5950cc5c42937fbd',
  govAddress: '0x5efda50f22d34f262c29268506c5fa42cb56a1ce',
  l1ChainId: 1,
  gcMultisig: '0x1f727de610030a88863d7da45bdea4eb84655b52',
}

Configuration Parameters

ParameterDescription
verifier2Address of Transaction2 verifier contract
verifier16Address of Transaction16 verifier contract
MERKLE_TREE_HEIGHTMaximum tree depth (23 = 8.3M deposits)
hasherPoseidon hash function contract address
gcWethWrapped ETH token on Gnosis Chain
gcOmniBridgeBridge contract for L1↔L2 communication
l1UnwrapperL1 contract for unwrapping deposits
govAddressTornado Cash governance address
l1ChainIdEthereum mainnet chain ID (1)

Network-Specific Notes

Ethereum Mainnet

  • Used for L1 operations and governance
  • Requires ALCHEMY_KEY for RPC access
  • Higher gas costs - optimize transaction batching

Gnosis Chain (formerly xDai)

  • Primary network for Tornado Pool operations
  • Lower gas costs (fixed at 25 Gwei)
  • Bridge connection to Ethereum mainnet
  • Fast block times (~5 seconds)

Binance Smart Chain

  • Alternative L1 configuration available
  • Requires updating bridge and token addresses in config.js
  • Commented out by default

Deployment Configuration

To verify expected contract addresses with current config:
yarn compile
node -e 'require("./src/0_generateAddresses").generateWithLog()'
Expected addresses with salt 0x0000000000000000000000000000000000000000000000000000000047941987:
  • L1Unwrapper: 0x3F615bA21Bc6Cc5D4a6D798c5950cc5c42937fbd
  • TornadoPool: 0x0CDD3705aF7979fBe80A64288Ebf8A9Fe1151cE1

Running Different Networks

npx hardhat run scripts/deployL1Unwrapper.js --network mainnet
Always test deployment scripts on testnets (e.g., Rinkeby) before deploying to mainnet.

Verifying Contracts

After deployment, verify contracts on Etherscan:
npx hardhat verify --network mainnet <CONTRACT_ADDRESS>
Ensure ETHERSCAN_KEY is set in your .env file.

Next Steps

  • Review Installation if you haven’t set up the project
  • Build circuits following Building Circuits
  • Run tests to verify configuration: yarn test
  • Deploy contracts using the configured networks

Build docs developers (and LLMs) love