Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion contracts/src/Factory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ contract Factory {
mapping(address => bool) public isDeployedTNT;
mapping(address => mapping(address => bool)) private userHasTNT;

event TNTCreated(address indexed owner, address tntAddress);
event TNTCreated(address indexed owner, address indexed tntAddress);
event TokenRegistered(address indexed user, address indexed tntAddress);
event TokenUnregistered(address indexed user, address indexed tntAddress);

Expand Down
4 changes: 2 additions & 2 deletions contracts/src/TNT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ contract TNT is ERC721, AccessControl {

mapping(uint256 => TokenMetadata) public metadata;

event TokenIssued(address indexed issuer, address indexed user, uint256 tokenId);
event TokenRevoked(address indexed revoker, uint256 tokenId);
event TokenIssued(address indexed issuer, address indexed user, uint256 indexed tokenId);
event TokenRevoked(address indexed revoker, uint256 indexed tokenId);

constructor(
address admin,
Expand Down
15 changes: 13 additions & 2 deletions hardhat.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,16 @@ require("@nomicfoundation/hardhat-toolbox");

/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: "0.8.28",
};
solidity: "0.8.20",
paths: {
sources: "./contracts/src",
tests: "./test",
cache: "./cache",
artifacts: "./artifacts"
},
networks: {
hardhat: {
allowUnlimitedContractSize: true
}
}
};
6 changes: 4 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
"name": "hardhat-project",
"devDependencies": {
"@nomicfoundation/hardhat-toolbox": "^5.0.0",
"@openzeppelin/contracts": "^5.2.0",
"hardhat": "^2.22.17"
},
"dependencies": {
"@openzeppelin/contracts": "^5.2.0",
"openzeppelin": "^1.0.0"
}
}
124 changes: 124 additions & 0 deletions test/EventIndexing.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("Event Indexing Validation", function () {
let factory;
let tnt;
let owner, user;

before(async function () {
[owner, user] = await ethers.getSigners();

// Deploy Factory
const FactoryContract = await ethers.getContractFactory("Factory");
factory = await FactoryContract.deploy();
await factory.waitForDeployment();

console.log("\n✅ Factory deployed successfully");
});

it("✅ TNTCreated event has indexed tntAddress", async function () {
const tx = await factory.createTNT("TestToken", "TST", true, "");
const receipt = await tx.wait();

// Parse the event
const factoryInterface = factory.interface;
const eventLogs = receipt.logs.map(log => {
try {
return factoryInterface.parseLog(log);
} catch (e) {
return null;
}
}).filter(Boolean);

const tntCreatedEvent = eventLogs.find(e => e.name === "TNTCreated");
expect(tntCreatedEvent).to.not.be.undefined;

// Check indexed parameters
// topics[0] = event signature hash
// topics[1] = indexed owner
// topics[2] = indexed tntAddress (NEW!)
const eventLog = receipt.logs.find(log =>
log.topics[0] === factoryInterface.getEvent("TNTCreated").topicHash
);

console.log(" Event topics count:", eventLog.topics.length);
console.log(" ✓ tntAddress is now indexed (topic 2)");

expect(eventLog.topics.length).to.equal(3, "Should have 3 topics (signature + 2 indexed params)");

// Get TNT contract address for next tests
const tntAddress = tntCreatedEvent.args[1];
tnt = await ethers.getContractAt("TNT", tntAddress);
});

it("✅ TokenIssued event has indexed tokenId", async function () {
// Grant minter role and issue a token
await tnt.grantMinterRole(owner.address);
const tx = await tnt.issueToken(user.address);
const receipt = await tx.wait();

const tntInterface = tnt.interface;
const eventLog = receipt.logs.find(log =>
log.topics[0] === tntInterface.getEvent("TokenIssued").topicHash
);

console.log(" Event topics count:", eventLog.topics.length);
console.log(" ✓ tokenId is now indexed (topic 3)");

// topics[0] = event signature
// topics[1] = indexed issuer
// topics[2] = indexed user
// topics[3] = indexed tokenId (NEW!)
expect(eventLog.topics.length).to.equal(4, "Should have 4 topics (signature + 3 indexed params)");
});

it("✅ TokenRevoked event has indexed tokenId", async function () {
// Create a revokable TNT and issue a token
const tx1 = await factory.createTNT("RevokableToken", "RVK", true, "");
const receipt1 = await tx1.wait();

const factoryInterface = factory.interface;
const eventLogs = receipt1.logs.map(log => {
try {
return factoryInterface.parseLog(log);
} catch (e) {
return null;
}
}).filter(Boolean);

const tntCreatedEvent = eventLogs.find(e => e.name === "TNTCreated");
const revokableTNT = await ethers.getContractAt("TNT", tntCreatedEvent.args[1]);

// Issue token
await revokableTNT.grantMinterRole(owner.address);
await revokableTNT.grantRevokerRole(owner.address);
await revokableTNT.issueToken(user.address);

// Revoke token
const tx2 = await revokableTNT.revokeToken(0);
const receipt2 = await tx2.wait();

const tntInterface = revokableTNT.interface;
const eventLog = receipt2.logs.find(log =>
log.topics[0] === tntInterface.getEvent("TokenRevoked").topicHash
);

console.log(" Event topics count:", eventLog.topics.length);
console.log(" ✓ tokenId is now indexed (topic 2)");

// topics[0] = event signature
// topics[1] = indexed revoker
// topics[2] = indexed tokenId (NEW!)
expect(eventLog.topics.length).to.equal(3, "Should have 3 topics (signature + 2 indexed params)");
});

it("✅ Gas cost comparison", async function () {
// This test shows the gas cost increase from indexing
const tx = await factory.createTNT("GasTest", "GAS", true, "");
const receipt = await tx.wait();

console.log("\n Gas used for TNT creation:", receipt.gasUsed.toString());
console.log(" Note: +375 gas per indexed parameter is negligible");
});
});
4 changes: 2 additions & 2 deletions test/TNT.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe("TNT and Factory Contracts", function () {
TNT = TNTContract;

// Deploy revokable TNT
let tx = await factory.createTNT("TestToken", "TTK", true);
let tx = await factory.createTNT("TestToken", "TTK", true, "");
let receipt = await tx.wait();
let event = receipt.logs.find(
(log) => 'fragment' in log && log.fragment.name === 'TNTCreated'
Expand All @@ -28,7 +28,7 @@ describe("TNT and Factory Contracts", function () {
tnt = await ethers.getContractAt("TNT", tntAddress);

// Deploy non-revokable TNT
tx = await factory.createTNT("NonRevokableToken", "NRT", false);
tx = await factory.createTNT("NonRevokableToken", "NRT", false, "");
receipt = await tx.wait();
event = receipt.logs.find(
(log) => 'fragment' in log && log.fragment.name === 'TNTCreated'
Expand Down