@polareth/evmstate
Version:
A TypeScript library for tracing, and visualizing EVM state changes with detailed human-readable labeling.
130 lines (112 loc) • 4.3 kB
text/typescript
import { encodeFunctionData } from "tevm";
import { describe, expect, it } from "vitest";
import { ACCOUNTS, CONTRACTS } from "@test/constants.js";
import { getClient } from "@test/utils.js";
import { traceState } from "@/index.js";
const { StoragePacking } = CONTRACTS;
const { caller } = ACCOUNTS;
/**
* Basic storage access tests with storage packing
*
* This test suite verifies:
*
* 1. Basic storage access tracing for both packed and unpacked variables
* 2. Detection of storage reads and writes with proper labeling and typing
* 3. Handling of different data types (uint8/16/32/64/256, bool, bytes32, address)
* 4. Correct tracking of packed storage variables in a single slot
* 5. Individual updates to variables within packed slots
* 6. Mixed operations across packed and unpacked slots
* 7. Account state changes tracking (nonce, balance)
* 8. Large numeric values handling
* 9. Tracer class
*/
describe("Basic slots access and packing", () => {
describe("traceState with contract call", () => {
it("should handle packed storage variables correctly", async () => {
const client = getClient();
// Set packed values in a single storage slot (uint8, uint8, bool, address)
expect(
await traceState({
...StoragePacking.write.setSmallValues(42, 123, true, caller.toString()),
client,
from: caller.toString(),
}),
).toMatchFileSnapshot("./__snapshots__/setSmallValues.shared.snap");
});
it("should handle individual updates to packed variables", async () => {
const client = getClient();
// Now update just one variable in the packed slot
expect(
await traceState({
...StoragePacking.write.setMediumValue1(999),
client,
from: caller.toString(),
}),
).toMatchSnapshot();
});
it("should track updates across multiple slots including packed and non-packed", async () => {
const client = getClient();
// Update values across multiple slots, including both packed and non-packed
// We expect at least 3 slots to be accessed:
// - Slot 0: smallValue1, smallValue2, (packed) (flag & someAddress are not modified)
// - Slot 3: mediumValue1, mediumValue2, mediumValue3 (packed) (mediumValue3 is not modified)
// - Slot 1: largeValue1 (not packed) (written last)
expect(
await traceState({
...StoragePacking.write.updateAllValues(10, 20, 1000, 2000, 12345n),
client,
from: caller.toString(),
}),
).toMatchSnapshot();
});
it("should handle large numeric values correctly", async () => {
const client = getClient();
// Set a large value in a non-packed slot
expect(
await traceState({
...StoragePacking.write.setLargeValue1(123456789012345678901234567890n),
client,
from: caller.toString(),
}),
).toMatchSnapshot();
});
it("should handle bytes32 data correctly", async () => {
const client = getClient();
// Set the bytes32 data
expect(
await traceState({
...StoragePacking.write.setData("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"),
client,
from: caller.toString(),
}),
).toMatchSnapshot();
});
it("should capture storage reads when getting values", async () => {
const client = getClient();
// Read the value and trace the storage access
expect(
await traceState({
client,
from: caller.toString(),
to: StoragePacking.address,
abi: StoragePacking.abi,
functionName: "getLargeValue1",
args: [],
}),
).toMatchSnapshot();
});
});
describe("traceState with transaction calldata", () => {
it("should work similarily to traceState", async () => {
const client = getClient();
expect(
await traceState({
client,
from: caller.toString(),
to: StoragePacking.address,
data: encodeFunctionData(StoragePacking.write.setSmallValues(42, 123, true, caller.toString())),
}),
).toMatchFileSnapshot("./__snapshots__/setSmallValues.shared.snap");
});
});
});