A TypeScript type-level EVM (Ethereum Virtual Machine) interpreter. Execute EVM bytecode entirely at compile time using TypeScript's type system!
- ✅ Type-level bytecode parsing and execution
- ✅ Stack operations (PUSH, POP, DUP, SWAP)
- ✅ Arithmetic and logic (ADD, MUL, DIV, MOD, SUB, EQ, ISZERO, LT, GT, SLT, SGT)
- ✅ Bitwise operations (AND, OR, XOR, NOT, BYTE, SHL, SHR, SAR, SIGNEXTEND)
- ✅ Cryptographic operations (SHA3/KECCAK256 via cryptoscript)
- ✅ Control flow opcodes (STOP, RETURN, REVERT, INVALID, JUMPDEST)
- ✅ Memory, Storage, and Context infrastructure
- ✅ Compile-time error detection (stack underflow, invalid opcodes, etc.)
- ✅ Step limit protection (256 steps max)
- ✅ Gas metering with configurable limit
import type { ExecuteEvm } from 'typescript-evm';
// Execute: PUSH1 0x42, RETURN
// This pushes 0x42 onto the stack and returns it
type Result1 = ExecuteEvm<'0x6042F3'>;
// Result1 = {
// status: 'ok';
// stack: ['0x42'];
// returnData: '0x42';
// }
// Execute: PUSH1 0x01, PUSH1 0x01, EQ, RETURN
// Pushes 1 twice, compares for equality, returns result
type Result2 = ExecuteEvm<'0x600160011415F3'>;
// Result2 = {
// status: 'ok';
// stack: ['0x01'];
// returnData: '0x01'; // true (1 == 1)
// }
// Execute: PUSH1 0x01, PUSH1 0x02, SWAP1, POP, RETURN
// Demonstrates stack manipulation
type Result3 = ExecuteEvm<'0x600160029050F3'>;
// Result3 = {
// status: 'ok';
// returnData: '0x02';
// }
// Stack underflow error
type Result4 = ExecuteEvm<'0x50F3'>; // POP on empty stack, then RETURN
// Result4 = {
// status: 'error';
// reason: 'stack_underflow';
// stack: [];
// }
// ISZERO example
type Result5 = ExecuteEvm<'0x600015F3'>; // PUSH1 0x00, ISZERO, RETURN
// Result5 = {
// status: 'ok';
// returnData: '0x01'; // true (0 is zero)
// }
// SHA3/KECCAK256 example - hash of empty input
type Result6 = ExecuteEvm<'0x6000600020F3'>; // PUSH1 0x00, PUSH1 0x00, SHA3, RETURN
// Result6 = {
// status: 'ok';
// returnData: '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470';
// // This is keccak256("") - the hash of empty input
// }Comprehensive list of EVM opcodes with implementation status for TypeVM. Checked items are implemented at the type level today.
-
0x00STOP -
0x01ADD -
0x02MUL -
0x03SUB -
0x04DIV -
0x05SDIV -
0x06MOD -
0x07SMOD -
0x08ADDMOD -
0x09MULMOD -
0x0AEXP -
0x0BSIGNEXTEND -
0x10LT -
0x11GT -
0x12SLT -
0x13SGT -
0x14EQ -
0x15ISZERO -
0x16AND -
0x17OR -
0x18XOR -
0x19NOT -
0x1ABYTE -
0x1BSHL -
0x1CSHR -
0x1DSAR
-
0x20KECCAK256 (SHA3)
-
0x30ADDRESS (returns 0x00: no contract context stub) -
0x31BALANCE -
0x32ORIGIN (returns 0: stub) -
0x33CALLER (returns 0: stub) -
0x34CALLVALUE (returns 0: stub) -
0x35CALLDATALOAD -
0x36CALLDATASIZE -
0x37CALLDATACOPY -
0x38CODESIZE (returns 0: stub) -
0x39CODECOPY -
0x3AGASPRICE (returns 0: stub) -
0x3BEXTCODESIZE -
0x3CEXTCODECOPY -
0x3DRETURNDATASIZE (returns 0: no external call context) -
0x3ERETURNDATACOPY (memory ignored) -
0x3FEXTCODEHASH
-
0x40BLOCKHASH -
0x41COINBASE -
0x42TIMESTAMP (returns 0: stub) -
0x43NUMBER (returns 0: stub) -
0x44PREVRANDAO (formerly DIFFICULTY) -
0x45GASLIMIT -
0x46CHAINID (returns 0: stub) -
0x47SELFBALANCE (returns 0: stub) -
0x48BASEFEE (returns 0: stub) -
0x49BLOBBASEFEE (returns 0: stub)
-
0x50POP -
0x51MLOAD -
0x52MSTORE -
0x53MSTORE8 -
0x54SLOAD -
0x55SSTORE -
0x56JUMP -
0x57JUMPI -
0x58PC (returns 0: PC stub for now) -
0x59MSIZE -
0x5AGAS (returns 0: no gas-left calculation) -
0x5BJUMPDEST -
0x5CTLOAD -
0x5DTSTORE -
0x5EMCOPY -
0x5FPUSH0
-
0x60–0x7FPUSH1–PUSH32
-
0x80–0x8FDUP1–DUP16
-
0x90–0x9FSWAP1–SWAP16
-
0xA0LOG0 (memory ignored) -
0xA1LOG1 (memory ignored) -
0xA2LOG2 (memory ignored) -
0xA3LOG3 (memory ignored) -
0xA4LOG4 (memory ignored)
-
0xF0CREATE -
0xF1CALL -
0xF2CALLCODE -
0xF3RETURN -
0xF4DELEGATECALL -
0xF5CREATE2 -
0xFASTATICCALL -
0xFDREVERT -
0xFEINVALID -
0xFFSELFDESTRUCT
Notes:
- Checklist reflects commonly recognized opcodes up through recent forks (e.g., PUSH0, TLOAD/TSTORE, MCOPY, BLOBBASEFEE). Some opcodes are context-dependent at runtime and are intentionally not implemented in this compile-time interpreter.
- Unknown opcodes result in a type-level
unknown_opcodeerror; unsupported stack effects producestack_underflow.
- Every executed opcode consumes gas per a simple schedule for currently supported instructions:
- Arithmetic/Logic: 3 gas (ADD, MUL, SUB, DIV, MOD, EQ, ISZERO, LT, GT, SLT, SGT, AND, OR, XOR, NOT, SIGNEXTEND, BYTE, SHL, SHR, SAR)
- SHA3/KECCAK256: 30 gas
- Stack ops: POP (2 gas), PUSH0 (2 gas), PUSH1-32/DUP/SWAP (3 gas)
- Control flow: JUMPDEST (1 gas), STOP/RETURN/REVERT/INVALID (0 gas)
- Context stubs: 3 gas (ADDRESS, ORIGIN, CALLER, etc.)
- Default gas limit is
1000. Provide a custom limit via the second generic parameter:ExecuteEvm<'0x6001F3', 64>. - Results expose
gasUsedandgasLimitfields for introspection.
- Maximum 256 execution steps (prevents infinite type recursion)
- SHA3/KECCAK256 supports up to 256-bit inputs (cryptoscript library constraint)
- Memory operations are basic (no dynamic expansion modeling)
- No storage persistence or external calls
- TypeScript's type recursion limits apply
- Compile times increase with bytecode complexity
npm install typescript-evmRun type checks to verify the type tests:
npm run typecheck- The memes
- Educational: Learn EVM opcodes and type-level programming
- Research: Explore capabilities of TypeScript's type system
- Art: Create compile-time smart contract verification tools
- Experimentation: Test EVM bytecode behavior at type-level
MIT
Contributions welcome! This is an experimental project exploring the limits of TypeScript's type system.