From ba3654b45d9cfb5f2c1c6b79ed12ab62f2d21316 Mon Sep 17 00:00:00 2001 From: Andile Sizophila Mchunu Date: Sat, 21 Mar 2026 22:59:20 +0200 Subject: [PATCH 1/3] fix: correct bytecode prefix check for contract creation detection Changed the contract creation bytecode prefix check from 0x60e06040 to 0x6080604 to match the standard Solidity init code. Standard Solidity init code starts with PUSH1 0x80 PUSH1 0x40 MSTORE (0x60806040), not 0x60e06040. This fixes the block explorer showing contract creation transactions as 'Unknown' instead of properly detecting them. Closes #1246 --- packages/nextjs/utils/scaffold-eth/decodeTxData.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nextjs/utils/scaffold-eth/decodeTxData.ts b/packages/nextjs/utils/scaffold-eth/decodeTxData.ts index 86eac35e8e..eceaa46846 100644 --- a/packages/nextjs/utils/scaffold-eth/decodeTxData.ts +++ b/packages/nextjs/utils/scaffold-eth/decodeTxData.ts @@ -17,7 +17,7 @@ const interfaces = chainMetaData : {}; export const decodeTransactionData = (tx: TransactionWithFunction) => { - if (tx.input.length >= 10 && !tx.input.startsWith("0x60e06040")) { + if (tx.input.length >= 10 && !tx.input.startsWith("0x6080604")) { let foundInterface = false; for (const [, contractAbi] of Object.entries(interfaces)) { try { From bb374e5d35d3cb1c1a00bf34572108adf181837c Mon Sep 17 00:00:00 2001 From: Andile Sizophila Mchunu Date: Sat, 21 Mar 2026 23:20:28 +0200 Subject: [PATCH 2/3] test: improve test coverage and isolation for YourContract - Refactored to use loadFixture pattern for test isolation - Added tests for: premium, totalCounter, userGreetingCounter - Added tests for withdraw() with owner/non-owner - Added tests for receive() function - Added event emission tests for GreetingChange - Total: 12 tests covering all contract functions Closes #1206 --- packages/hardhat/test/YourContract.ts | 123 ++++++++++++++++++++++++-- 1 file changed, 114 insertions(+), 9 deletions(-) diff --git a/packages/hardhat/test/YourContract.ts b/packages/hardhat/test/YourContract.ts index a44cf04e1d..893472a199 100644 --- a/packages/hardhat/test/YourContract.ts +++ b/packages/hardhat/test/YourContract.ts @@ -1,28 +1,133 @@ import { expect } from "chai"; import { ethers } from "hardhat"; +import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; import { YourContract } from "../typechain-types"; describe("YourContract", function () { - // We define a fixture to reuse the same setup in every test. - - let yourContract: YourContract; - before(async () => { - const [owner] = await ethers.getSigners(); + async function deployYourContractFixture() { + const [owner, otherAccount] = await ethers.getSigners(); const yourContractFactory = await ethers.getContractFactory("YourContract"); - yourContract = (await yourContractFactory.deploy(owner.address)) as YourContract; + const yourContract = (await yourContractFactory.deploy(owner.address)) as YourContract; await yourContract.waitForDeployment(); - }); + return { yourContract, owner, otherAccount }; + } describe("Deployment", function () { - it("Should have the right message on deploy", async function () { + it("Should have the right owner", async function () { + const { yourContract, owner } = await loadFixture(deployYourContractFixture); + expect(await yourContract.owner()).to.equal(owner.address); + }); + + it("Should have the default greeting", async function () { + const { yourContract } = await loadFixture(deployYourContractFixture); expect(await yourContract.greeting()).to.equal("Building Unstoppable Apps!!!"); }); + it("Should have premium set to false", async function () { + const { yourContract } = await loadFixture(deployYourContractFixture); + expect(await yourContract.premium()).to.equal(false); + }); + + it("Should have totalCounter at zero", async function () { + const { yourContract } = await loadFixture(deployYourContractFixture); + expect(await yourContract.totalCounter()).to.equal(0); + }); + }); + + describe("setGreeting", function () { it("Should allow setting a new message", async function () { + const { yourContract } = await loadFixture(deployYourContractFixture); const newGreeting = "Learn Scaffold-ETH 2! :)"; - await yourContract.setGreeting(newGreeting); expect(await yourContract.greeting()).to.equal(newGreeting); }); + + it("Should increment totalCounter", async function () { + const { yourContract } = await loadFixture(deployYourContractFixture); + await yourContract.setGreeting("First"); + expect(await yourContract.totalCounter()).to.equal(1); + await yourContract.setGreeting("Second"); + expect(await yourContract.totalCounter()).to.equal(2); + }); + + it("Should track user greeting count", async function () { + const { yourContract, owner, otherAccount } = await loadFixture(deployYourContractFixture); + await yourContract.setGreeting("Owner message"); + expect(await yourContract.userGreetingCounter(owner.address)).to.equal(1); + + await yourContract.connect(otherAccount).setGreeting("Other message"); + expect(await yourContract.userGreetingCounter(otherAccount.address)).to.equal(1); + expect(await yourContract.userGreetingCounter(owner.address)).to.equal(1); + }); + + it("Should set premium to true when ETH is sent", async function () { + const { yourContract } = await loadFixture(deployYourContractFixture); + await yourContract.setGreeting("Premium message", { value: ethers.parseEther("0.01") }); + expect(await yourContract.premium()).to.equal(true); + }); + + it("Should set premium to false when no ETH is sent", async function () { + const { yourContract } = await loadFixture(deployYourContractFixture); + // First send with ETH + await yourContract.setGreeting("Premium message", { value: ethers.parseEther("0.01") }); + expect(await yourContract.premium()).to.equal(true); + // Then send without ETH + await yourContract.setGreeting("Free message"); + expect(await yourContract.premium()).to.equal(false); + }); + + it("Should emit GreetingChange event", async function () { + const { yourContract, owner } = await loadFixture(deployYourContractFixture); + const newGreeting = "Event test"; + await expect(yourContract.setGreeting(newGreeting)) + .to.emit(yourContract, "GreetingChange") + .withArgs(owner.address, newGreeting, false, 0); + }); + + it("Should emit GreetingChange event with premium when ETH sent", async function () { + const { yourContract, owner } = await loadFixture(deployYourContractFixture); + const newGreeting = "Premium event test"; + const value = ethers.parseEther("0.01"); + await expect(yourContract.setGreeting(newGreeting, { value })) + .to.emit(yourContract, "GreetingChange") + .withArgs(owner.address, newGreeting, true, value); + }); + }); + + describe("withdraw", function () { + it("Should allow owner to withdraw", async function () { + const { yourContract, owner } = await loadFixture(deployYourContractFixture); + // Send ETH to contract + await yourContract.setGreeting("Fund me", { value: ethers.parseEther("1") }); + const contractBalance = await ethers.provider.getBalance(yourContract.target); + expect(contractBalance).to.equal(ethers.parseEther("1")); + + // Withdraw + const ownerBalanceBefore = await ethers.provider.getBalance(owner.address); + const tx = await yourContract.withdraw(); + const receipt = await tx.wait(); + const gasUsed = receipt!.gasUsed * receipt!.gasPrice; + + const contractBalanceAfter = await ethers.provider.getBalance(yourContract.target); + expect(contractBalanceAfter).to.equal(0); + + const ownerBalanceAfter = await ethers.provider.getBalance(owner.address); + expect(ownerBalanceAfter).to.equal(ownerBalanceBefore + ethers.parseEther("1n") - gasUsed); + }); + + it("Should revert if non-owner tries to withdraw", async function () { + const { yourContract, otherAccount } = await loadFixture(deployYourContractFixture); + await yourContract.setGreeting("Fund me", { value: ethers.parseEther("1") }); + await expect(yourContract.connect(otherAccount).withdraw()).to.be.revertedWith("Not the Owner"); + }); + }); + + describe("receive", function () { + it("Should accept ETH via receive", async function () { + const { yourContract, owner } = await loadFixture(deployYourContractFixture); + await owner.sendTransaction({ to: yourContract.target, value: ethers.parseEther("0.5") }); + const balance = await ethers.provider.getBalance(yourContract.target); + expect(balance).to.equal(ethers.parseEther("0.5")); + }); }); }); From 6e8796ef20d8c652d5e8df7185a4c9c5a4278889 Mon Sep 17 00:00:00 2001 From: Andile Sizophila Mchunu Date: Sat, 21 Mar 2026 23:31:22 +0200 Subject: [PATCH 3/3] fix: add --no-compile to account scripts to skip unnecessary compilation Account-related scripts (account, account:generate, account:import, account:reveal-pk) were triggering full Hardhat compilation every time. Added --no-compile flag since these scripts don't need compilation. Closes #1127 --- packages/hardhat/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/hardhat/package.json b/packages/hardhat/package.json index ae9565a343..fb9724b154 100644 --- a/packages/hardhat/package.json +++ b/packages/hardhat/package.json @@ -2,10 +2,10 @@ "name": "@se-2/hardhat", "version": "0.0.1", "scripts": { - "account": "hardhat run scripts/listAccount.ts", - "account:generate": "hardhat run scripts/generateAccount.ts", - "account:import": "hardhat run scripts/importAccount.ts", - "account:reveal-pk": "hardhat run scripts/revealPK.ts", + "account": "hardhat run --no-compile scripts/listAccount.ts", + "account:generate": "hardhat run --no-compile scripts/generateAccount.ts", + "account:import": "hardhat run --no-compile scripts/importAccount.ts", + "account:reveal-pk": "hardhat run --no-compile scripts/revealPK.ts", "chain": "hardhat node --network hardhat --no-deploy", "check-types": "tsc --noEmit --incremental", "clean": "hardhat clean",