UNPKG

@polareth/evmstate

Version:

A TypeScript library for tracing, and visualizing EVM state changes with detailed human-readable labeling.

140 lines (120 loc) 3.88 kB
import { getAddress } 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 { Mappings } = CONTRACTS; const { caller, recipient } = ACCOUNTS; /** * Mappings tests * * This test suite verifies: * * 1. Simple and nested mapping slot access * 2. Mapping with struct values * 3. Complex mapping operations with storage updates * 4. Fixed and dynamic array storage access patterns * 5. Array length slot access and element storage * 6. Struct arrays with complex data storage layout * 7. Nested array storage patterns */ describe("Mappings", () => { it("should trace simple mapping slot access", async () => { const client = getClient(); // Set a value in the balances mapping expect( await traceState({ ...Mappings.write.setBalance(recipient.toString(), 1000n), client, from: caller.toString(), }), ).toMatchSnapshot(); // Run the actual tx await client.tevmContract({ ...Mappings.write.setBalance(recipient.toString(), 1000n), from: caller.toString(), addToBlockchain: true, }); // Read the value and check if the same slot is accessed expect( await traceState({ ...Mappings.read.getBalance(recipient.toString()), client, from: caller.toString(), }), ).toMatchSnapshot(); }); it("should trace nested mapping slot access", async () => { const client = getClient(); // Set an allowance (nested mapping) expect( await traceState({ ...Mappings.write.setAllowance(caller.toString(), recipient.toString(), 1000n), client, from: caller.toString(), }), ).toMatchSnapshot(); }); it("... even with a ridiculously nested mapping", async () => { const client = getClient(); const [a, b, c, d] = Array.from({ length: 4 }, (_, i) => getAddress(`0xad${i.toString().repeat(38)}`.toLowerCase()), ); expect( await traceState({ ...Mappings.write.setRidiculouslyNestedMapping(a, b, c, d, 1000n), client, from: caller.toString(), }), ).toMatchSnapshot(); }); it("should trace mapping with struct values slot access", async () => { const client = getClient(); // Set a struct in the userInfo mapping expect( await traceState({ ...Mappings.write.setUserInfo(recipient.toString(), 1000n, 12345n, true), client, from: caller.toString(), }), ).toMatchSnapshot(); }); it("should trace mapping with struct values slot access across multiple slots", async () => { const client = getClient(); // Update the userInfo mapping at the 3rd slot for the recipient address expect( await traceState({ ...Mappings.write.toggleUserActive(recipient.toString()), client, from: caller.toString(), }), ).toMatchSnapshot(); }); it("should trace complex mapping operations with multiple keys", async () => { const client = getClient(); // First set up the initial struct await client.tevmContract({ ...Mappings.write.setUserInfo(recipient.toString(), 100n, 100n, true), from: caller.toString(), addToBlockchain: true, }); // Now update just the balance field expect( await traceState({ ...Mappings.write.updateUserBalance(recipient.toString(), 300n), client, from: caller.toString(), }), ).toMatchSnapshot(); }); it("should trace mapping to an array", async () => { const client = getClient(); expect( await traceState({ ...Mappings.write.setArrayMapping(1n, 100n), client, from: caller.toString(), }), ).toMatchSnapshot(); }); });