npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@hackerdao/trim

v0.9.2

Published

Trim is a opcode-oriented programming language for the Ethereum Virtual Machine (EVM). It offers syntax for writing highly optimized code in a more readable manner, without introducing mental or complexity overhead.

Downloads

8

Readme

Trim

Trim is a opcode-oriented programming language for the Ethereum Virtual Machine (EVM). It offers syntax for writing highly optimized code in a more readable manner, without introducing mental or complexity overhead.

Getting Started

First install Trim (and ethereumjs/vm as you'll probably use its opcode definitions)

npm install @hackerdao/trim @ethereumjs/vm

Then just import and compile:

import { compileTrim, getOpcodesForTrim } from '@hackerdao/trim'
import { getOpcodesForHF } from '@ethereumjs/vm/dist/evm/opcodes'
import Common, { Chain, Hardfork } from '@ethereumjs/common'

const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Berlin })
const opcodes = getOpcodesForTrim(getOpcodesForHF(common))

const bytecode = compileTrim('(ADD 0x00 0x01)', { opcodes })

console.log("Compile success! Resulting bytecode:", bytecode)

Sample

Here's a template to get started writing a full smart contract with Trim:

(SUB CODESIZE #runtime)
DUP1
(CODECOPY 0x00 #runtime _)
(RETURN 0x00 _)

#runtime
(CALLDATACOPY 0x1c 0x00 0x04)
(MLOAD 0x00) ; copy function id onto the stack

(EQ (abi/fn-selector "hello()") DUP1)
(JUMPI #hello _)

REVERT ; No matching function id

#hello
(MSTORE 0x00 "Hello, world!")
(RETURN 0x00 0x20)

Syntax

First and foremost, Trim is a superset of bare assembly. You can always write opcodes in a plain manner. For example, this is valid Trim:

PUSH1 0x20
PUSH2 0x1000
ADD
MLOAD

What Trim introduces is s-expressions. An s-expression allows you to write in opcode-arguments notation:

(MLOAD (ADD 0x1000 0x20))

This code is equivalent to the previous example.

You can also use the top operator (_) to refer to the top of the stack. The following examples are all equivalent:

; Example A
PUSH1 0x20
(ADD 0x1000 _)
(MLOAD _)

; Example B
(ADD 0x1000 0x20)
(MLOAD _)

; Example C
(ADD 0x1000 0x20)
MLOAD

Note how you don't have to write all your code in s-expressions.

Features

When you write a Trim s-expression, you gain access to a few features. Aside from defining a label, these features are only accessible within s-expressions.

Strings

Trim allows you to write double-quoted string literals. For example:

; Old way
PUSH12 0x48656c6c6f2c205472696d21
EQ

; New way
(EQ "Hello, Trim!" _)

Labels

When deploying an EVM smart contract, you deploy both the initialization code and the runtime code as one long sequence of bytes. During this deployment transaction, the EVM will run this code, take its return value, and then persist this return value to the block chain. In other words, the value returned is the bytecode that will always run when future transactions are made to the new contract's address.

Unfortunately, writing in plain opcodes for this task is a big hassle, as it involves manually counting bytes and hardcoding those numbers into your code. Worse, if you add or remove lines of code during development, you will have to recount and update these hardcoded numbers before testing it again.

Trim solves this by introducing labels:

(SUB CODESIZE #runtime)
DUP1
(CODECOPY 0x00 #runtime _)
(RETURN 0x00 _)

#runtime
(MSTORE 0x00 "Hello, world!")
(RETURN 0x00 0x20)

In the above code, line 6 is a label definition, which ends up being 15 bytes:

  • 3 bytes for each #runtime reference (each get compiled to a PUSH2 statement)
  • 2 bytes for each 0x00 (each get compiled to a PUSH1 statement)
  • 1 byte for each other opcode before the #runtime definition.

The #runtime label

Trim treats a label named #runtime as a special case. If it's present, all labels defined after #runtime will automatically be offset by that amount. This is necessary to correct runtime label offsets, compensating for the removal of the init code.

Macros

Trim has some built-in macros. In the future it will have user-defined macros too.

push

Normally when you want to push literal value, you just simply write it, e.g. (ADD 0x01 0x02) or (EQ "abc" _).

But what if you want to push a string onto the stack? Just use the push macro:

("Hi")      ; Error, invalid token
(push "Hi") ; Works!

abi/fn-selector

A convenience macro to output function selector (also known an "function id") segment of an ABI encoded function call. Useful for running function-specific code.

(EQ (abi/fn-selector "foo()") DUP1)
(JUMPI #foo _)

; ...

#foo
; More code here

Roadmap

These are some features we're considering adding to Trim. Create an issue to discuss or suggest more!

  • [x] User-defined macros
  • [ ] Defining labels with macros
  • [ ] Hardhat integration
  • [ ] More standard ABI macros
  • [ ] Imports