The normal behavior should maintain consistent parameter ordering in event emissions and definitions. Events should follow standard conventions for better code quality and off-chain tracking.
pragma solidity ^0.8.26;
import "forge-std/Test.sol";
import "forge-std/console.sol";
contract EventParameterTest is Test {
event TokensWithdrawn(address indexed token, address indexed to, uint256 amount);
address constant TOKEN = address(0x1111);
address constant RECIPIENT = address(0x2222);
uint256 constant AMOUNT = 1000 ether;
function test_EventParameterOrderBug() public {
console.log("\n=== Event Parameter Order Bug ===");
console.log("Event Definition: TokensWithdrawn(address indexed token, address indexed to, uint256 amount)");
console.log("");
console.log("Function parameters:");
console.log(" token:", TOKEN);
console.log(" to:", RECIPIENT);
console.log(" amount:", AMOUNT);
console.log("\nBuggy emission: emit TokensWithdrawn(to, token, amount);");
console.log(" First indexed param (should be token):", RECIPIENT);
console.log(" Second indexed param (should be to):", TOKEN);
console.log(" Third param (amount):", AMOUNT);
vm.recordLogs();
emit TokensWithdrawn(RECIPIENT, TOKEN, AMOUNT);
Vm.Log[] memory entries = vm.getRecordedLogs();
console.log("\n=== Off-Chain Impact ===");
console.log("Event indexer reads:");
console.log(" token field =", RECIPIENT, "(WRONG - this is actually the recipient)");
console.log(" to field =", TOKEN, "(WRONG - this is actually the token)");
console.log(" amount field =", AMOUNT, "(correct)");
console.log("\n=== Correct Emission ===");
console.log("Correct emission: emit TokensWithdrawn(token, to, amount);");
vm.recordLogs();
emit TokensWithdrawn(TOKEN, RECIPIENT, AMOUNT);
entries = vm.getRecordedLogs();
console.log("Event indexer reads:");
console.log(" token field =", TOKEN, "(correct)");
console.log(" to field =", RECIPIENT, "(correct)");
console.log(" amount field =", AMOUNT, "(correct)");
}
function test_OffChainQueryImpact() public {
console.log("\n=== Off-Chain Query Impact ===");
address targetToken = address(0xABCD);
console.log("\nQuery: Show all withdrawals of token", targetToken);
console.log("\nWith BUGGY emission:");
console.log(" Event emitted as: TokensWithdrawn(recipient, token, amount)");
console.log(" Indexer stores: token=recipient, to=token");
console.log(" Query result: MISS (token field contains recipient, not token)");
console.log(" Impact: Cannot find withdrawals by token address");
console.log("\nWith CORRECT emission:");
console.log(" Event emitted as: TokensWithdrawn(token, recipient, amount)");
console.log(" Indexer stores: token=token, to=recipient");
console.log(" Query result: HIT (token field contains token address)");
console.log(" Impact: Queries work as expected");
}
function test_DashboardDisplayImpact() public {
console.log("\n=== Dashboard Display Impact ===");
address token = address(0x1234);
address recipient = address(0x5678);
uint256 amount = 5000 ether;
console.log("\nActual withdrawal:");
console.log(" Token:", token);
console.log(" Recipient:", recipient);
console.log(" Amount:", amount);
console.log("\nDashboard with BUGGY events:");
console.log(" Displays:");
console.log(" Token: ", recipient, "(WRONG)");
console.log(" Recipient:", token, "(WRONG)");
console.log(" Amount:", amount, "(correct)");
console.log(" Result: Confusing and incorrect information");
console.log("\nDashboard with CORRECT events:");
console.log(" Displays:");
console.log(" Token:", token, "(correct)");
console.log(" Recipient:", recipient, "(correct)");
console.log(" Amount:", amount, "(correct)");
console.log(" Result: Accurate information");
}
}
If there's a reason to keep the emission order, update the event definition instead (not recommended):