const { loadFixture } = require("@nomicfoundation/hardhat-network-helpers");
const { expect } = require("chai");
const path = require("path");
const fs = require("fs");

describe("attack arithmetic/integer_overflow_1.sol", function () {
  async function deployContracts() {
    const codePath = path.join(
      __dirname,
      "../../artifacts/contracts/dataset/arithmetic/integer_overflow_1.sol/Overflow.json",
    );
    const json = JSON.parse(fs.readFileSync(codePath));
    const Overflow = await ethers.getContractFactory(json.abi, json.bytecode);
    const overflow = await Overflow.deploy();
    await overflow.waitForDeployment();
    const address = await overflow.getAddress();

    const OverflowAttacker = await ethers.getContractFactory(
      "contracts/arithmetic/integer_overflow_1_attack.sol:OverflowAttacker",
    );
    const attacker = await OverflowAttacker.deploy(address);
    await attacker.waitForDeployment();

    return { overflow, attacker };
  }

  it("functional check: arithmetic/integer_overflow_1.sol", async function () {
    const { overflow } = await loadFixture(deployContracts);
    let storage = await ethers.provider.getStorage(overflow.target, 0);
    let value = Number(storage);
    expect(value).to.be.equal(0);
    const [v, a] = await ethers.getSigners();
    await overflow.connect(a).add(1);
    storage = await ethers.provider.getStorage(overflow.target, 0);
    value = Number(storage);
    expect(value).to.be.equal(1);
  });

  it("exploit overflow vulnerability", async function () {
    const { overflow, attacker } = await loadFixture(deployContracts);
    let storage = await ethers.provider.getStorage(overflow.target, 0);
    let value = Number(storage);
    expect(value).to.be.equal(0);
    const max = 2 ** 256 - 1;
    // make the sellerBalance to be the maximum value
    await attacker.addMax();
    storage = await ethers.provider.getStorage(overflow.target, 0);
    value = Number(storage);
    expect(value).to.be.equal(max);

    // cause the overflow
    await overflow.add(1);
    storage = await ethers.provider.getStorage(overflow.target, 0);
    value = Number(storage);
    expect(value).to.be.equal(0);
  });
});
