# Hardhat Guide Setup & Workflows

> A guide to setting up and using the Hardhat development environment for building, testing, and deploying on Ontomir EVM.

Hardhat is a flexible and extensible Ethereum development environment that is fully compatible with Ontomir EVM. It's an excellent choice for teams with JavaScript/TypeScript expertise or those who need complex deployment and testing workflows.

### Project Setup and Configuration <a href="#project-setup-and-configuration" id="project-setup-and-configuration"></a>

Initialize and configure a new Hardhat project for Ontomir EVM development.

#### 1. Installation <a href="#id-1-installation" id="id-1-installation"></a>

```
mkdir Ontomir-evm-hardhat
cd Ontomir-evm-hardhat
npm init -y
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox @openzeppelin/contracts
npx hardhat init # Select "Create a TypeScript project"
```

#### 2. Configuration <a href="#id-2-configuration" id="id-2-configuration"></a>

Modify `hardhat.config.ts` to include networks and settings for Ontomir EVM.

```
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
import "dotenv/config";

const config: HardhatUserConfig = {
  solidity: {
    version: "0.8.24",
    settings: {
      optimizer: {
        enabled: true,
        runs: 200,
      },
      evmVersion: "istanbul"
    },
  },
  networks: {
    local: {
      url: "http://127.0.0.1:8545",
      chainId: 4321, // Your EVM chain ID
      accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
      gasPrice: 20000000000,
    },
    testnet: {
      url: "<evm_rpc_url>",
      chainId: 4321, // Your EVM chain ID
      accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
    }
  },
  gasReporter: {
    enabled: process.env.REPORT_GAS !== undefined,
    currency: "USD",
  },
  etherscan: {
    apiKey: {
      OntomirEvmTestnet: process.env.ETHERSCAN_API_KEY || "dummy_key"
    },
    customChains: [
      {
        network: "OntomirEvmTestnet",
        chainId: 4321, // Your EVM chain ID
        urls: {
          apiURL: "",
          browserURL: ""
        }
      }
    ]
  }
};

export default config;
```

### TypeScript Integration <a href="#typescript-integration" id="typescript-integration"></a>

Hardhat's first-class TypeScript support enables type-safe contract interactions and tests.

#### 1. Writing a Contract <a href="#id-1-writing-a-contract" id="id-1-writing-a-contract"></a>

Create a contract in the `contracts/` directory. For this example, we'll use a simple `LiquidStakingVault`.

```
// contracts/LiquidStakingVault.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/access/Ownable.sol";

// Interface for the staking precompile
interface IStaking {
    function delegate(address validator, uint256 amount) external returns (bool);
    function undelegate(address validator, uint256 amount) external returns (bool, uint64);
}

contract LiquidStakingVault is Ownable {
    IStaking constant STAKING = IStaking(0x0000000000000000000000000000000000000800);

    mapping(address => uint256) public stakedBalance;
    address public primaryValidator;
    uint256 public totalStaked;

    event Staked(address indexed user, uint256 amount);

    constructor(address _primaryValidator) Ownable(msg.sender) {
        primaryValidator = _primaryValidator;
    }

    function stake() external payable {
        require(msg.value > 0, "Must stake positive amount");
        bool success = STAKING.delegate(primaryValidator, msg.value);
        require(success, "Delegation failed");
        stakedBalance[msg.sender] += msg.value;
        totalStaked += msg.value;
        emit Staked(msg.sender, msg.value);
    }
}
```

#### 2. Writing Tests <a href="#id-2-writing-tests" id="id-2-writing-tests"></a>

Create type-safe tests in the `test/` directory.

```
// test/LiquidStakingVault.test.ts
import { expect } from "chai";
import { ethers } from "hardhat";
import { LiquidStakingVault } from "../typechain-types";
import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers";

describe("LiquidStakingVault", function () {
  let vault: LiquidStakingVault;
  let owner: SignerWithAddress;
  let user1: SignerWithAddress;

  const STAKING_PRECOMPILE = "0x0000000000000000000000000000000000000800";
  const VALIDATOR_ADDRESS = "0x1234567890123456789012345678901234567890";

  beforeEach(async function () {
    [owner, user1] = await ethers.getSigners();

    const VaultFactory = await ethers.getContractFactory("LiquidStakingVault");
    vault = await VaultFactory.deploy(VALIDATOR_ADDRESS);
    await vault.waitForDeployment();

    // Mock the staking precompile's delegate function to always return true
    // This bytecode is a minimal contract that returns true for any call
    const successBytecode = "0x6080604052348015600f57600080fd5b50600160005560016000f3";
    await ethers.provider.send("hardhat_setCode", [
      STAKING_PRECOMPILE,
      successBytecode,
    ]);
  });

  it("Should allow a user to stake tokens", async function () {
    const stakeAmount = ethers.parseEther("1.0");

    await expect(vault.connect(user1).stake({ value: stakeAmount }))
      .to.emit(vault, "Staked")
      .withArgs(user1.address, stakeAmount);

    expect(await vault.stakedBalance(user1.address)).to.equal(stakeAmount);
    expect(await vault.totalStaked()).to.equal(stakeAmount);
  });
});
```

Run your tests:

```
npx hardhat test
```

### Deployment Scripts <a href="#deployment-scripts" id="deployment-scripts"></a>

Create a deployment script in the `scripts/` directory to deploy your contract to a live network.

```
// scripts/deploy.ts
import { ethers, network } from "hardhat";
import { writeFileSync } from "fs";

async function main() {
  const [deployer] = await ethers.getSigners();

  console.log("Deploying contracts with the account:", deployer.address);

  const validatorAddress = process.env.VALIDATOR_ADDRESS || "0x0000000000000000000000000000000000000000";

  const VaultFactory = await ethers.getContractFactory("LiquidStakingVault");
  const vault = await VaultFactory.deploy(validatorAddress);
  await vault.waitForDeployment();

  const vaultAddress = await vault.getAddress();
  console.log("LiquidStakingVault deployed to:", vaultAddress);

  // Save deployment information
  const deploymentInfo = {
    contractAddress: vaultAddress,
    deployer: deployer.address,
    network: network.name,
    chainId: network.config.chainId,
  };

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

  // Optional: Verify contract on Etherscan-compatible explorer
  if (network.name !== "local" && process.env.ETHERSCAN_API_KEY) {
    console.log("Waiting for block confirmations before verification...");
    // await vault.deploymentTransaction()?.wait(5); // Wait for 5 blocks
    await new Promise(resolve => setTimeout(resolve, 30000)); // Or wait 30 seconds

    await hre.run("verify:verify", {
        address: vaultAddress,
        constructorArguments: [validatorAddress],
    });
  }
}

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

Run the deployment script:

```
npx hardhat run scripts/deploy.ts --network testnet
```
