Skip to content

KimlikDAO/EvmScript

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

54 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

 EvmScript

Tests npm version License: MIT

EvmScript is an EVM language embedded in TypeScript. Programs live in .evm.ts modules and compile to lean EVM bytecode, while the surrounding generation, testing, and deployment workflow stays in the TypeScript ecosystem.

It is built around a typed stack algebra: EVM programs are composed from Fragments whose stack effects are checked at compile time, then assembled into compact bytecode. For each statement, EvmScript searches for the minimum-cost stack choreography using a smart and guided combinatorial search instead of relying on hand-written DUP/SWAP sequences.

Why EvmScript?

EvmScript is for EVM-side hot paths where bytecode size, stack choreography, and per-call gas dominate the cost of an operation. It is a good fit for small, specialized verifiers, proxies, payout programs, settlement transactions, liquidation bots, auctions, bridges, and other systems where shaving gas and bytes compounds over many transactions.

The goal is to keep the authoring experience TypeScript-native while giving the compiler room to produce bytecode that is hard to match by hand. Optimal stack dances are often non-obvious even in small programs; EvmScript models that problem directly and searches the state space using advanced combinatorial algorithms.

Install

bun add @kimlikdao/evmscript

Requires Bun and TypeScript. The project currently tests against Bun and TypeScript from the package lockfile.

Authoring Model

EvmScript programs are authored in .evm.ts files. These are TypeScript modules with a small EVM syntax extension: evm (...) => {} functions, typed EVM words, fixed arrays like Data[32], stack-resident local variables, and static for loops.

The model is similar to .tsx: the author-facing syntax is transpiled into regular TypeScript calls before the runtime executes the module. The lowered inline(...), set(...), and staticFor(...) form remains the compiler target, but it is not the normal surface for writing EvmScript programs.

A Merkle verifier, for example, can be expressed in the EVM syntax as:

const verifyMerkle = evm (
  hash: Data,
  index: Uint,
  proof: Data[32]
): Bool => {
  static for (const level in range(32)) {
    hash = hashPair(proof[level], (index & 1) * 32, hash);
    index = index >> 1;
  }
  return hash == sload<Data>(0);
}

The compiler lowers this into regular TypeScript library calls similar to:

const verifyMerkle = inline(
  { hash: Data, index: Uint, proof: array(Data, 32) },
  ({ hash, index, proof }) => [
    staticFor(
      [],
      range(32),
      (level) => [
        set(hash, hashPairAtOffset(
          proof.at(level),
          mul(bitAnd(index, 1), 32),
          hash,
        )),
        set(index, shr(1, index)),
      ],
    ),
    eq(hash, sload(0, Data)),
  ],
);

Because EVM functions are embedded in TypeScript, metaprogramming happens in ordinary TypeScript rather than in a separate macro language. Generation-time code can use functions, loops, arrays, sorting, or any valid TypeScript code. Similarly fixtures, tests, and deployment scripts live side by side in the same language. The batch send and proxy examples use TypeScript helper code to construct EVM functions, while the bytecode bodies remain in evm () => {} syntax.

Core Ideas

  • Typed stack algebra: bytecode fragments carry typed stack signatures, so composition fails early when stack values do not line up.
  • EVM syntax inside TypeScript: .evm.ts files lower expressions, assignments, loops, and function bodies into fragment composition.
  • Solver-guided assembly: the binder converts each statement into an abstract stack problem, then a direct strategy or A* search finds the optimal opcode path for that modeled problem while preserving future-live values.
  • TypeScript-native deployment: compilation produces EVM bytecode as a Uint8Array, ready to deploy with viem, ethers, wagmi, @kimlikdao/lib, or the Ethereum tooling you already use.

Examples

Development

bun install
bunx --no-install tsc -p .
bun test

The GitHub workflow runs both the TypeScript typecheck and the Bun unit tests.

Documentation

The docs in docs/ cover the compiler model in more detail:

About

An EVM language embedded in TypeScript: write, test and deploy EVM programs from TypeScript

Topics

Resources

License

Stars

Watchers

Forks

Contributors