# `Cartouche.Assembly`
[🔗](https://github.com/zenhive/cartouche/blob/main/lib/cartouche/assembly.ex#L1)

A for-fun assembler of EVM assembly code from a simple
lisp-like language used to construct Quark scripts.

This is really for fun and testing, so mostly feel free
to ignore.

## Usage

You can build EVM assembly, via:

```elixir
Cartouche.Assembly.build([
  {:log1, 0, 0, 55}
])
```

That results in the EVM compiled script `0x603760006000a1`.

If you view that here https://ethervm.io/decompile you see
that it decompiles to:

```c
log(memory[0x00:0x00], [0x37]);
```

via the assembly:

```asm
0000    60  PUSH1 0x37
0002    60  PUSH1 0x00
0004    60  PUSH1 0x00
0006    A1  LOG1
```

Overall, scripts can get more complex, e.g. we use a script
to revert if `tx.origin` is zero (e.g. during an `eth_estimateGas`).

```elixir
Cartouche.Assembly.build([
  {:mstore, 0, 0x01020304},
  {:if, :origin, {:revert, 28, 4}, {:return, 0, 0}}
])
```

There's no real goal for this assembler. Just a fun experiment and
useful in testing.

# `opcode`

```elixir
@type opcode() ::
  atom()
  | {:push, non_neg_integer(), binary()}
  | {:dup, non_neg_integer()}
  | {:swap, non_neg_integer()}
  | {:invalid, binary()}
  | {:jump_ptr, integer()}
  | {:jump_dest, integer()}
```

# `assemble`

```elixir
@spec assemble([term()]) :: binary()
```

Assmbles opcodes into raw evm bytecode

## Examples

    iex> [{:push, 0, ""}, {:push, 4, <<0x11, 0x22, 0x33, 0x44>>}, :mstore, {:push, 1, <<4>>}, {:push, 1, <<28>>}, :revert]
    ...> |> Cartouche.Assembly.assemble()
    <<95, 99, 17, 34, 51, 68, 82, 96, 4, 96, 28, 253>>

    iex> [
    ...>   {:push, 2, <<0x01, 0x02>>},
    ...>   {:push, 1, <<0>>},
    ...>   :mstore,
    ...>   :callvalue,
    ...>   {:push, 1, <<0>>},
    ...>   :sub,
    ...>   {:jump_ptr, 0},
    ...>   :jumpi,
    ...>   {:push, 1, <<2>>},
    ...>   {:push, 1, <<30>>},
    ...>   :revert,
    ...>   {:jump_dest, 0},
    ...>   {:push, 1, <<2>>},
    ...>   {:push, 1, <<31>>},
    ...>   :revert
    ...> ]
    ...> |> Cartouche.Assembly.assemble()
    ...> |> Cartouche.Hex.to_hex()
    "0x6101026000523460000362000014576002601efd5b6002601ffd"

    iex> [
    ...>   {:dup, 2},
    ...>   {:swap, 3},
    ...>   {:invalid, ~h[0x010203]}
    ...> ]
    ...> |> Cartouche.Assembly.assemble()
    ...> |> Cartouche.Hex.to_hex()
    "0x8192fe010203"

# `build`

```elixir
@spec build([term()]) :: binary()
```

Compiles and assembles assembly operations.

## Examples

    iex> use Cartouche.Hex
    ...> [
    ...>   {:mstore, 0, ~h[0x11223344]},
    ...>   {:revert, 28, 4}
    ...> ]
    ...> |> Cartouche.Assembly.build()
    ...> |> to_hex()
    "0x63112233446000526004601cfd"

# `compile`

```elixir
@spec compile(term()) :: [term()] | atom()
```

Compiles operations into assembly, which can then be compiled.

## Examples

    iex> use Cartouche.Hex
    ...> [
    ...>   {:mstore, 0, ~h[0x11223344]},
    ...>   {:revert, 4, 28}
    ...> ]
    ...> |> Cartouche.Assembly.compile()
    [{:push, 4, ~h[0x11223344]}, {:push, 1, <<0>>}, :mstore, {:push, 1, <<28>>}, {:push, 1, <<0x04>>}, :revert]

# `constructor`

```elixir
@spec constructor(binary()) :: binary()
```

Returns a simple EVM program that returns the input code
as the output of an Ethereum "initCode" constructor.

## Examples

    iex> use Cartouche.Hex
    ...> Cartouche.Assembly.constructor(~h[0xaabbcc])
    ...> |> to_hex()
    "0x60036200000e60003960036000f3aabbcc"

# `disassemble`

```elixir
@spec disassemble(binary()) :: [term()]
```

Disassembles opcodes from raw evm bytecode to opcodes.

## Examples

    iex> Cartouche.Assembly.disassemble(~h[0x6101026000523460000362000014576002601efd5b6002601ffd])
    [
      {:push, 2, <<0x01, 0x02>>},
      {:push, 1, <<0>>},
      :mstore,
      :callvalue,
      {:push, 1, <<0>>},
      :sub,
      {:push, 3, <<0, 0, 20>>},
      :jumpi,
      {:push, 1, <<2>>},
      {:push, 1, <<30>>},
      :revert,
      :jumpdest,
      {:push, 1, <<2>>},
      {:push, 1, <<31>>},
      :revert
    ]
    
    iex> Cartouche.Assembly.disassemble(~h[0x8192fe010203])
    [
      {:dup, 2},
      {:swap, 3},
      {:invalid, ~h[0x010203]}
    ]

# `show_opcode`

```elixir
@spec show_opcode(term()) :: String.t()
```

Returns a textual representation of the given operation.

## Examples

    iex> Cartouche.Assembly.show_opcode(:add)
    "ADD"

    iex> Cartouche.Assembly.show_opcode({:push, 5, <<1,2,3,4,5>>})
    "PUSH5 0x0102030405"

---

*Consult [api-reference.md](api-reference.md) for complete listing*
