├── ftplugin ├── huff │ └── commands.vim └── huff.vim ├── test ├── utils │ ├── Utils.huff │ ├── Ownable.huff │ ├── Address.huff │ └── HashMap.huff └── ERC20.huff ├── ftdetect └── hufffiletype.vim ├── autoload ├── huff.vim └── evm │ └── lookup.vim ├── LICENSE.txt ├── README.md ├── scripts └── gen_evm_asm_table.py └── syntax └── huff.vim /ftplugin/huff/commands.vim: -------------------------------------------------------------------------------- 1 | com! -nargs=1 HuffLookup call evm#lookup#Lookup('') 2 | com! -nargs=0 HuffCompile call huff#Compile() 3 | -------------------------------------------------------------------------------- /ftplugin/huff.vim: -------------------------------------------------------------------------------- 1 | setlocal keywordprg=:HuffLookup 2 | 3 | if get(g:, 'huff_fold_enable', 1) 4 | setlocal foldmethod=syntax 5 | endif 6 | -------------------------------------------------------------------------------- /test/utils/Utils.huff: -------------------------------------------------------------------------------- 1 | /* Macros */ 2 | 3 | #define macro UTILS__NOT_PAYABLE(error_location) = takes(0) returns(0) { 4 | callvalue jumpi 5 | } 6 | -------------------------------------------------------------------------------- /ftdetect/hufffiletype.vim: -------------------------------------------------------------------------------- 1 | " don't spam the user when Vim is started in Vi compatibility mode 2 | let s:cpo_save = &cpo 3 | set cpo&vim 4 | 5 | " Note: should not use augroup in ftdetect (see :help ftdetect) 6 | au BufRead,BufNewFile *.huff setfiletype huff 7 | 8 | " restore Vi compatibility settings 9 | let &cpo = s:cpo_save 10 | unlet s:cpo_save 11 | -------------------------------------------------------------------------------- /autoload/huff.vim: -------------------------------------------------------------------------------- 1 | function! huff#Compile() 2 | let l:huff = get(g:, 'huff_command', 'huffc') 3 | execute "!" . l:huff . " -b " . bufname('%') 4 | endfunction 5 | 6 | function! huff#ShowBytecode() 7 | let l:huff = get(g:, 'huff_command', 'huffc') 8 | let l:bytecode = system(l:huff . " -b " . bufname('%')) 9 | let l:winnr = bufwinnr('EVM_BYTECODE') 10 | if l:winnr ==# -1 11 | vsplit EVM_BYTECODE 12 | else 13 | execute l:winnr . ' wincmd w' 14 | endif 15 | normal! ggdG 16 | setlocal filetype=evm 17 | setlocal buftype=nofile 18 | 19 | call append(0, l:bytecode) 20 | endfunction 21 | -------------------------------------------------------------------------------- /test/utils/Ownable.huff: -------------------------------------------------------------------------------- 1 | /* Storage */ 2 | #define constant OWNER_POINTER = FREE_STORAGE_POINTER() 3 | 4 | /* CONSTRUCTOR */ 5 | #define macro OWNABLE_CONSTRUCTOR() = takes (0) returns (0) { 6 | caller [OWNER_POINTER] sstore 7 | } 8 | 9 | /* Methods */ 10 | #define macro OWNABLE_SET_OWNER() = takes (1) returns (0) { 11 | [OWNER_POINTER] sstore 12 | } 13 | 14 | #define macro OWNABLE_GET_OWNER() = takes (0) returns (1) { 15 | [OWNER_POINTER] sload 16 | } 17 | 18 | #define macro ONLY_OWNER() = takes(0) returns(0) { 19 | [OWNER_POINTER] sload caller eq is_owner jumpi 20 | 0x00 0x00 revert 21 | is_owner: 22 | } -------------------------------------------------------------------------------- /test/utils/Address.huff: -------------------------------------------------------------------------------- 1 | /* Macros */ 2 | 3 | // Identifies whether an address has contract code associated with it. 4 | #define macro IS_CONTRACT() = takes(1) returns (1) { 5 | // Returns 0 if no code is associated with the address. 6 | extcodesize 7 | } 8 | 9 | #define macro SEND_ETH() = takes(2) returns (1) { 10 | 0x00 // [0, amount, address] 11 | 0x00 // [0, 0, amount, address] 12 | 0x00 // [0, 0, 0, amount, address] 13 | 0x00 // [0, 0, 0, 0, amount, address] 14 | dup5 // [amount, 0, 0, 0, 0, amount, address] 15 | dup7 // [address, amount, 0, 0, 0, 0, amount] 16 | } 17 | 18 | #define macro MASK_ADDRESS() = takes(1) returns (1) { 19 | 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff 20 | and 21 | } 22 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2022 wuwe1 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /test/utils/HashMap.huff: -------------------------------------------------------------------------------- 1 | // Given a piece of data (ie an address), hash it, generating the storage slot for a hashmap. 2 | #define macro GET_SLOT_FROM_KEY(mem_ptr) = takes(1) returns (1) { 3 | // Input stack: [key] 4 | // Load the data into memory and hash it, while preserving the memory location. 5 | // [, key] 6 | mstore // [] 7 | 8 | // Hash the data, generating a key. 9 | 0x20 // [32] 10 | // [, 32] 11 | sha3 // [slot] 12 | } 13 | 14 | // Given two keys (ie an address and a number), hash them together, generating a for a secondary hashmap. 15 | // This should only be used if you have multiple maps in your contract. 16 | #define macro GET_SLOT_FROM_KEYS(mem_ptr) = takes(2) returns (1) { 17 | // Input stack: [key1, key2] 18 | // Load the data into memory. 19 | // [, key1, key2] 20 | mstore // [key2] 21 | 0x20 add // [ + 32, key2] 22 | mstore // [] 23 | 24 | // Hash the data, generating a key. 25 | 0x40 // [64] 26 | // [, 64] 27 | sha3 // [key] 28 | } 29 | 30 | #define macro LOAD_ELEMENT(mem_ptr) = takes(1) returns(1) { 31 | // Input stack: [key] 32 | GET_SLOT_FROM_KEY() // [slot] 33 | sload // [value] 34 | } 35 | 36 | #define macro LOAD_ELEMENT_FROM_KEYS(mem_ptr) = takes(2) returns(1) { 37 | // Input stack: [key1, key2] 38 | GET_SLOT_FROM_KEYS() // [slot] 39 | sload // [value] 40 | } 41 | 42 | #define macro STORE_ELEMENT(mem_ptr) = takes(2) returns(0) { 43 | // Input stack: [key, value] 44 | GET_SLOT_FROM_KEY() // [slot, value] 45 | sstore // [] 46 | } 47 | 48 | #define macro STORE_ELEMENT_FROM_KEYS(mem_ptr) = takes(2) returns (0) { 49 | // Input stack: [key1, key2, value] 50 | GET_SLOT_FROM_KEYS() // [slot, value] 51 | sstore // [] 52 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-huff 2 | 3 |

 4 |                                ___           ___           ___           ___         ___   
 5 |       ___        ___          /__/\         /__/\         /__/\         /  /\       /  /\  
 6 |      /__/\      /  /\        |  |::\        \  \:\        \  \:\       /  /:/_     /  /:/_ 
 7 |      \  \:\    /  /:/        |  |:|:\        \__\:\        \  \:\     /  /:/ /\   /  /:/ /\
 8 |       \  \:\  /__/::\      __|__|:|\:\   ___ /  /::\   ___  \  \:\   /  /:/ /:/  /  /:/ /:/
 9 |   ___  \__\:\ \__\/\:\__  /__/::::| \:\ /__/\  /:/\:\ /__/\  \__\:\ /__/:/ /:/  /__/:/ /:/ 
10 |  /__/\ |  |:|    \  \:\/\ \  \:\~~\__\/ \  \:\/:/__\/ \  \:\ /  /:/ \  \:\/:/   \  \:\/:/  
11 |  \  \:\|  |:|     \__\::/  \  \:\        \  \::/       \  \:\  /:/   \  \::/     \  \::/   
12 |   \  \:\__|:|     /__/:/    \  \:\        \  \:\        \  \:\/:/     \  \:\      \  \:\   
13 |    \__\::::/      \__\/      \  \:\        \  \:\        \  \::/       \  \:\      \  \:\  
14 |        ~~~~                   \__\/         \__\/         \__\/         \__\/       \__\/  
15 | 
16 | 17 | ## Features 18 | This plugin adds [Huff](https://docs.huff.sh) language support for Vim, with the following main features: 19 | - [x] Compile with `:HuffCompile` 20 | - [x] Syntax highlighting 21 | - [x] Lookup evm opcode with 'K' 22 | - [x] Folding 23 | - [ ] Debug huff program 24 | 25 | ## Install 26 | vim-huff follows the standard runtime path structure. Below are some helper lines for popular package managers: 27 | - [Vim 8 packages](http://vimhelp.appspot.com/repeat.txt.html#packages) 28 | - `git clone https://github.com/wuwe1/vim-huff.git ~/.vim/pack/plugins/start/vim-huff` 29 | - [Neovim packages](https://neovim.io/doc/user/repeat.html#packages) 30 | - `git clone https://github.com/wuwe1/vim-huff.git ~/.local/share/nvim/site/pack/plugins/start/vim-huff` 31 | - [Pathogen](https://github.com/tpope/vim-pathogen) 32 | - `git clone https://github.com/wuwe1/vim-huff.git ~/.vim/bundle/vim-huff` 33 | - [vim-plug](https://github.com/junegunn/vim-plug) 34 | - `Plug 'wuwe1/vim-huff'` 35 | - [Vundle](https://github.com/VundleVim/Vundle.vim) 36 | - `Plugin 'wuwe1/vim-huff'` 37 | -------------------------------------------------------------------------------- /scripts/gen_evm_asm_table.py: -------------------------------------------------------------------------------- 1 | import re 2 | import json 3 | import requests as rq 4 | from typing import Any, List 5 | 6 | 7 | def collect_matches_from_list_until_failed( 8 | pattern: str, 9 | lst: List[Any], 10 | start_idx=0, 11 | cond=lambda m: len(m) == 1, 12 | cons=lambda m: m[0], 13 | ): 14 | idx = start_idx 15 | pat = re.compile(pattern) 16 | collections = [] 17 | matches = pat.findall(lst[idx]) 18 | while cond(matches): 19 | collections.append(cons(matches)) 20 | idx = idx + 1 21 | matches = pat.findall(lst[idx]) 22 | return collections 23 | 24 | 25 | def find_first_match(pattern: str, lst: List[Any]): 26 | pat = re.compile(pattern) 27 | for idx, i in enumerate(lst): 28 | if pat.match(i): 29 | return idx 30 | raise ValueError(f"pattern {pattern} dose not match any line") 31 | 32 | 33 | def collect_opcodes(lines): 34 | idx = find_first_match(r"pub const OPCODES", lines) 35 | return collect_matches_from_list_until_failed( 36 | r'\s+"(\w+)"', lines, start_idx=idx + 1 37 | ) 38 | 39 | 40 | def collect_opcodes_map(lines): 41 | idx = find_first_match(r"pub static OPCODES_MAP", lines) 42 | opcodes_map = {} 43 | opcodes_map_list = collect_matches_from_list_until_failed( 44 | r'"(\w+)" => (Opcode::\w+)', 45 | lines, 46 | start_idx=idx + 1, 47 | cond=lambda m: len(m) == 1 and len(m[0]) == 2, 48 | cons=lambda m: m[0], 49 | ) 50 | for i in opcodes_map_list: 51 | opcodes_map[i[0]] = i[1] 52 | return opcodes_map 53 | 54 | 55 | def collect_opcodes_str(lines): 56 | idx = find_first_match(r"\s+let opcode_str = match self", lines) 57 | opcodes_str = {} 58 | opcodes_str_list = collect_matches_from_list_until_failed( 59 | r'(Opcode::\w+) => "(\w\w)"', 60 | lines, 61 | start_idx=idx + 1, 62 | cond=lambda m: len(m) == 1 and len(m[0]) == 2, 63 | cons=lambda m: m[0], 64 | ) 65 | for i in opcodes_str_list: 66 | opcodes_str[i[0]] = i[1] 67 | return opcodes_str 68 | 69 | 70 | def fetch_evm_rs(): 71 | EVM_RS_URL = "https://raw.githubusercontent.com/huff-language/huff-rs/main/huff_utils/src/evm.rs" 72 | evm_rs = rq.get(EVM_RS_URL).text 73 | return evm_rs.split("\n") 74 | 75 | 76 | def fetch_opcode_meta(): 77 | META_URL = ( 78 | "https://raw.githubusercontent.com/comitylabs/evm.codes/main/opcodes.json" 79 | ) 80 | return rq.get(META_URL).json() 81 | 82 | 83 | def gen_opcode_name_to_hex(evm_rs: List[str]): 84 | opcode_name_to_hex = {} 85 | opcodes = collect_opcodes(evm_rs) 86 | opcodes_map = collect_opcodes_map(evm_rs) 87 | opcodes_str = collect_opcodes_str(evm_rs) 88 | for op in opcodes: 89 | opcode_name_to_hex[op] = opcodes_str[opcodes_map[op]] 90 | return opcode_name_to_hex 91 | 92 | 93 | if __name__ == "__main__": 94 | evm_asm_table = {} 95 | opcode_name_to_hex = gen_opcode_name_to_hex(fetch_evm_rs()) 96 | meta = fetch_opcode_meta() 97 | for op in opcode_name_to_hex: 98 | hx = opcode_name_to_hex[op] 99 | desc = meta[hx]["description"] 100 | input = meta[hx]["input"] 101 | output = meta[hx]["output"] 102 | evm_asm_table[op] = { 103 | "opcode": hx, 104 | "desc": desc, 105 | "input": input, 106 | "output": output, 107 | } 108 | print(json.dumps(evm_asm_table)) 109 | -------------------------------------------------------------------------------- /syntax/huff.vim: -------------------------------------------------------------------------------- 1 | if exists("b:current_syntax") 2 | finish 3 | endif 4 | 5 | " comment 6 | syn region huffComment start="//" end="$" 7 | syn region huffComment start="/\*" end="\*/" 8 | hi def link huffComment Comment 9 | 10 | " natspec 11 | syn match huffNatspecTag "\v\@title>" contained 12 | syn match huffNatspecTag "\v\@author>" contained 13 | syn match huffNatspecTag "\v\@notice>" contained 14 | syn match huffNatspecTag "\v\@dev>" contained 15 | syn match huffNatspecTag "\v\@param>" contained 16 | syn match huffNatspecTag "\v\@return>" contained 17 | syn region huffNatspec start="/\*\*" end="\*/" contains=huffNatspecTag 18 | syn region huffNatspec start="///" end="$" contains=huffNatspecTag 19 | hi def link huffNatspec Comment 20 | hi def link huffNatspecTag Keyword 21 | 22 | " import 23 | syn match huffInclude "\v#include>" 24 | hi def link huffInclude Include 25 | 26 | " number literal 27 | syn match huffNumberDecimal "\v<\d+(\.\d+)?>" 28 | syn match huffNumberHex "\v<0[xX][a-fA-F0-9]+>" 29 | hi def link huffNumberDecimal Number 30 | hi def link huffNumberHex Number 31 | 32 | " define 33 | syn match huffDefine '#define' contained 34 | syn keyword huffMacro macro contained 35 | syn keyword huffFn fn contained 36 | syn keyword huffJumptable jumptable contained 37 | syn keyword huffJumptablePacked jumptable__packed contained 38 | syn keyword huffError error contained 39 | syn keyword huffFunction function contained 40 | syn keyword huffEvent event contained 41 | syn keyword huffConstant constant contained 42 | syn keyword huffTakes takes contained 43 | syn keyword huffReturns returns contained 44 | hi def link huffDefine Define 45 | hi def link huffMacro Keyword 46 | hi def link huffFn Keyword 47 | hi def link huffJumptable Keyword 48 | hi def link huffJumptablePacked Keyword 49 | hi def link huffError Keyword 50 | hi def link huffFunction Keyword 51 | hi def link huffEvent Keyword 52 | hi def link huffConstant Keyword 53 | hi def link huffTakes Keyword 54 | hi def link huffReturns Keyword 55 | 56 | syn match huffIdentifier "\v\i" contained 57 | hi def link huffIdentifier Identifier 58 | 59 | syn match huffInterfacePrimitives "\v<(address|string\d*|bytes\d*|int\d*|uint\d*|bool|hash\d*)>" contained 60 | hi def link huffInterfacePrimitives Type 61 | 62 | syn match huffDeclMacro "\v#define\s+macro\s+\i+\s*\((\i+(,\s*\i+)*)?\)\s*\=\s*takes\s*\(\d+\)\s*returns\s*\(\d+\)" transparent contains=huffDefine,huffMacro,huffIdentifier,huffTakes,huffReturns 63 | syn match huffDeclFn "\v#define\s+fn\s+\i+\s*\((\i+(,\s*\i+)*)?\)\s*\=\s*takes\s*\(\d+\)\s*returns\s*\(\d+\)" transparent contains=huffDefine,huffFn,huffIdentifier,huffTakes,huffReturns 64 | syn match huffDeclJumptable "\v#define\s+jumptable(__packed)?\s+\i+>" transparent contains=huffDefine,huffJumtable,huffJumptablePacked,huffIdentifier 65 | syn match huffConstantDef "\v#define\s+constant\s+[A-Za-z_]\w*" transparent contains=huffDefine,huffConstant,huffIdentifier,huffTakes,huffReturns 66 | syn match huffDefError "\v#define\s+error\s+\i+>" transparent contains=huffDefine,huffError,huffIdentifier 67 | syn match huffInterfaceFunction "\v#define\s+function\s+\i+\(.*\)" transparent contains=huffDefine,huffFunction,huffIdentifier,huffInterfacePrimitives 68 | syn match huffInterfaceEvent "\v#define\s+event\s+\i+\(.*\)" transparent contains=huffDefine,huffEvent,huffIdentifier,huffInterfacePrimitives 69 | 70 | " opcodes 71 | syn keyword huffOpcodesIO sstore sload mstore8 mstore mload pop msize balance address returndatacopy returndatasize extcodecopy extcodesize gasprice caller origin gaslimit difficulty number timestamp coinbase blockhash codecopy codesize calldatacopy calldatasize calldataload callvalue gas 72 | syn keyword huffOpcodesSideEffects log4 log3 log2 log1 log0 jumpdest getpc jumpi jump create2 staticcall delegatecall callcode call create 73 | syn keyword huffOpcodesCalculation not xor or and ror rol sar shr shl keccak sha3 byte iszero eq sgt slt gt lt signextend exp mulmod addmod smod mod sdiv div sub mul add 74 | syn keyword huffOpcodesStop selfdestruct invalid revert return stop 75 | syn match huffOpcodesStack "\v(swap1|dup1)[0-6]" 76 | syn match huffOpcodesStack "\v(swap|dup)[1-9]" 77 | syn match huffOpcodesStack "\vpush3[0-2]|push[1-2][0-9]|push[1-9]" 78 | hi def link huffOpcodesIO Keyword 79 | hi def link huffOpcodesSideEffects Keyword 80 | hi def link huffOpcodesCalculation Keyword 81 | hi def link huffOpcodesStop Keyword 82 | hi def link huffOpcodesStack Keyword 83 | 84 | syn match huffTemplateCall "\v\<\s*\i+\s*\>" transparent contains=huffIdentifier 85 | syn match huffConstantRef "\v\[[A-Z_]+\]" transparent contains=huffIdentifier 86 | 87 | if get(g:, 'huff_fold_enable', 1) 88 | syn region huffBlock start="{" end="}" transparent fold 89 | endif 90 | 91 | let b:current_syntax = "huff" 92 | -------------------------------------------------------------------------------- /test/ERC20.huff: -------------------------------------------------------------------------------- 1 | /// @title ERC20 2 | /// @author Huff Language 3 | /// @notice An exemplary ERC20 token contract written in Huff. 4 | 5 | /* Imports */ 6 | #include "./utils/Ownable.huff" 7 | #include "./utils/Address.huff" 8 | #include "./utils/Utils.huff" 9 | #include "./utils/HashMap.huff" 10 | 11 | /* Interface */ 12 | #define function mint(address,uint256) nonpayable returns () 13 | 14 | #define function transfer(address,uint256) nonpayable returns () 15 | #define function transferFrom(address,address,uint256) nonpayable returns () 16 | #define function approve(address,uint256) nonpayable returns () 17 | 18 | #define function balanceOf(address) view returns (uint256) 19 | #define function allowance(address,address) view returns (uint256) 20 | #define function totalSupply() view returns (uint256) 21 | 22 | #define event Transfer(address,address,uint256) 23 | #define event Approve(address,address,uint256) 24 | 25 | /* Events Signatures */ 26 | #define constant TRANSFER_EVENT_SIGNATURE = 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF 27 | #define constant APPROVAL_EVENT_SIGNATURE = 0x8C5BE1E5EBEC7D5BD14F71427D1E84F3DD0314C0F7B2291E5B200AC8C7C3B925 28 | 29 | /* Storage Slots */ 30 | #define constant BALANCE_LOCATION = FREE_STORAGE_POINTER() 31 | #define constant ALLOWANCE_LOCATION = FREE_STORAGE_POINTER() 32 | #define constant TOTAL_SUPPLY_LOCATION = FREE_STORAGE_POINTER() 33 | 34 | /* Constructor */ 35 | 36 | #define macro CONSTRUCTOR() = takes(0) returns (0) { 37 | // Set msg.sender as the owner of the contract. 38 | OWNABLE_CONSTRUCTOR() 39 | } 40 | 41 | /* Accounting Functions */ 42 | #define macro BALANCE_OF() = takes (0) returns (0) { 43 | 0x04 calldataload // [account] 44 | [BALANCE_LOCATION] LOAD_ELEMENT_FROM_KEYS(0x00) // [balance] 45 | 0x00 mstore // [] 46 | 0x20 0x00 return // [] 47 | } 48 | 49 | #define macro TOTAL_SUPPLY() = takes (0) returns (0) { 50 | [TOTAL_SUPPLY_LOCATION] sload // [supply] 51 | 0x00 mstore // [] 52 | 0x20 0x00 return // [] 53 | } 54 | 55 | #define macro ALLOWANCE() = takes (0) returns (0) { 56 | 0x24 calldataload // [to] 57 | 0x04 calldataload // [from, to] 58 | LOAD_ELEMENT_FROM_KEYS(0x00) // [value] 59 | 60 | 0x00 mstore 61 | 0x20 0x00 return 62 | } 63 | 64 | 65 | /* Transfer Functions */ 66 | #define macro TRANSFER_TAKE_FROM(error) = takes(3) returns (3) { 67 | // Ensure that the sender has a sufficient balance. 68 | // input stack: [value, from, to] 69 | dup2 // [from, value, from, to] 70 | [BALANCE_LOCATION] LOAD_ELEMENT_FROM_KEYS(0x00) // [balance, value, from, to] 71 | dup1 // [balance, balance, value, from, to] 72 | dup3 // [value, balance, balance, value, from, to] 73 | gt // [value>balance, balance, value, from, to] 74 | jumpi // [balance, value, from, to] 75 | 76 | // Update the sender's balance. 77 | // input stack: [balance, value, from, to] 78 | dup2 // [value, balance, value, from, to] 79 | swap1 // [balance, value, value, from, to] 80 | sub // [balance - value, value, from, to] 81 | dup3 // [from, balance-value, value, from, to] 82 | [BALANCE_LOCATION] STORE_ELEMENT_FROM_KEYS(0x00) // [value, from, to] 83 | } 84 | 85 | #define macro TRANSFER_GIVE_TO() = takes(3) returns (0) { 86 | // Update the balance of the recipient. 87 | // input stack: [value, from, to] 88 | dup3 // [to, value, from, to] 89 | dup2 // [value, to, value, from, to] 90 | swap1 // [to, value, value, from, to] 91 | [BALANCE_LOCATION] LOAD_ELEMENT_FROM_KEYS(0x00) // [balance, value, value, from, to] 92 | add // [balance+value, value, from, to] 93 | dup4 // [to, balance+value, value, from, to] 94 | [BALANCE_LOCATION] STORE_ELEMENT_FROM_KEYS(0x00) // [value, from, to] 95 | } 96 | 97 | #define macro APPROVE() = takes (0) returns (0) { 98 | 0x24 calldataload // [value] 99 | 0x04 calldataload // [to, value] 100 | caller // [from, to, value] 101 | 102 | STORE_ELEMENT_FROM_KEYS(0x00) 103 | } 104 | 105 | #define macro TRANSFER() = takes(0) returns(1) { 106 | // Setup the stack for the transfer function. 107 | 0x04 calldataload // [to] 108 | caller // [from, to] 109 | 0x24 calldataload // [value, from, to] 110 | 111 | // Update the balances of the sender and recipient. 112 | TRANSFER_TAKE_FROM(error) // [value, from, to] 113 | TRANSFER_GIVE_TO() // [value, from, to] 114 | 115 | // Emit the transfer event. 116 | 0x00 mstore // [from, to] 117 | [TRANSFER_EVENT_SIGNATURE] // [sig, from, to] 118 | 0x20 0x00 // [0, 32, sig, from, to] 119 | log3 // [] 120 | 121 | // Return "1" to represent a succesful transfer. 122 | 0x01 0x00 mstore 123 | 0x20 0x00 return 124 | 125 | // Error destination. 126 | error: 127 | 0x00 0x00 revert 128 | } 129 | 130 | /* Mint Functions */ 131 | #define macro MINT() = takes(0) returns (0) { 132 | // Ensure that the sender is the owner of the contract. 133 | ONLY_OWNER() 134 | 135 | // Setup the stack for the mint function. 136 | 0x04 calldataload // [to] 137 | 0x00 // [from (0x00), to] 138 | 0x24 calldataload // [value, from, to] 139 | 140 | // Give tokens to the recipient. 141 | TRANSFER_GIVE_TO() // [value, from, to] 142 | 143 | // Update totalSupply 144 | dup1 // [value, value, from, to] 145 | [TOTAL_SUPPLY_LOCATION] sload // [supply,value,value,from,to] 146 | add // [supply+value,value,from,to] 147 | [TOTAL_SUPPLY_LOCATION] sstore // [value,from,to] 148 | 149 | 150 | // Emit the transfer event. 151 | 0x00 mstore // [from, to] 152 | [TRANSFER_EVENT_SIGNATURE] // [sig, from, to] 153 | 0x20 0x00 // [0, 32, sig, from, to] 154 | log3 // [] 155 | } 156 | 157 | // Main Macro 158 | #define macro MAIN() = takes(0) returns (0) { 159 | // Identify which function is being called. 160 | 0x00 calldataload 0xE0 shr 161 | dup1 0xa9059cbb eq transfer jumpi 162 | dup1 0x40c10f19 eq mints jumpi 163 | dup1 0x70a08231 eq balanceOf jumpi 164 | dup1 0x18160ddd eq totalSupply jumpi 165 | dup1 0x095ea7b3 eq approve jumpi 166 | dup1 0xdd62ed3e eq allowance jumpi 167 | 168 | transfer: 169 | TRANSFER() 170 | mints: 171 | MINT() 172 | balanceOf: 173 | BALANCE_OF() 174 | totalSupply: 175 | TOTAL_SUPPLY() 176 | approve: 177 | APPROVE() 178 | allowance: 179 | ALLOWANCE() 180 | 181 | } 182 | -------------------------------------------------------------------------------- /autoload/evm/lookup.vim: -------------------------------------------------------------------------------- 1 | fu! evm#lookup#Lookup(op) 2 | if !exists('g:evm_asm_table.' . a:op) 3 | echom a:op . ' not found' 4 | else 5 | let l:v = get(g:evm_asm_table, a:op) 6 | let l:winnr = bufwinnr('EVM_LOOKUP') 7 | if l:winnr ==# -1 8 | split EVM_LOOKUP 9 | normal! ggdG 10 | setlocal filetype=evmlookup 11 | setlocal buftype=nofile 12 | setlocal bufhidden=delete 13 | setlocal noswapfile 14 | setlocal nobuflisted 15 | setlocal nocursorline nocursorcolumn 16 | syn match evmLookupOpcode '\v^\[\zs0x[A-Fa-f0-9]+\ze\]' 17 | \ nextgroup=evmLookupName 18 | syn match evmLookupName '\v\s+\zs\i+\ze\(' 19 | \ nextgroup=evmLookupInput 20 | syn match evmLookupInput '\v\(\zs.*\ze\)$' 21 | syn match evmlookupOutput '\v^\s+-\>\zs.*\ze$' 22 | hi link evmLookupOpcode Number 23 | hi link evmLookupName Define 24 | hi link evmLookupInput Identifier 25 | hi link evmLookupOutput Type 26 | else 27 | execute l:winnr . 'wincmd w' 28 | endif 29 | 30 | let l:winw = winwidth('.') 31 | 32 | setlocal modifiable 33 | let l:content = [] 34 | call add(l:content, 35 | \ '[0x' . l:v.opcode . '] ' 36 | \ . a:op 37 | \ . '(' . l:v.input . ')') 38 | call add(l:content, ' -> ' . l:v.output) 39 | call add(l:content, l:v.desc) 40 | normal! ggdG 41 | call append(0, l:content) 42 | silent $delete 43 | setlocal nomodifiable 44 | execute 'resize 3' 45 | silent normal! gg 46 | " close easily with enter and q 47 | noremap :close 48 | noremap q :close 49 | endif 50 | endfu 51 | 52 | let g:evm_asm_table = { 53 | \ "lt": { 54 | \ "opcode": "10", 55 | \ "desc": "Less-than comparison", 56 | \ "input": "a | b", 57 | \ "output": "a < b" 58 | \ }, 59 | \ "gt": { 60 | \ "opcode": "11", 61 | \ "desc": "Greater-than comparison", 62 | \ "input": "a | b", 63 | \ "output": "a > b" 64 | \ }, 65 | \ "slt": { 66 | \ "opcode": "12", 67 | \ "desc": "Signed less-than comparison", 68 | \ "input": "a | b", 69 | \ "output": "a < b" 70 | \ }, 71 | \ "sgt": { 72 | \ "opcode": "13", 73 | \ "desc": "Signed greater-than comparison", 74 | \ "input": "a | b", 75 | \ "output": "a > b" 76 | \ }, 77 | \ "eq": { 78 | \ "opcode": "14", 79 | \ "desc": "Equality comparison", 80 | \ "input": "a | b", 81 | \ "output": "a == b" 82 | \ }, 83 | \ "iszero": { 84 | \ "opcode": "15", 85 | \ "desc": "Simple not operator", 86 | \ "input": "a", 87 | \ "output": "a == 0" 88 | \ }, 89 | \ "and": { 90 | \ "opcode": "16", 91 | \ "desc": "Bitwise AND operation", 92 | \ "input": "a | b", 93 | \ "output": "a & b" 94 | \ }, 95 | \ "origin": { 96 | \ "opcode": "32", 97 | \ "desc": "Get execution origination address", 98 | \ "input": "", 99 | \ "output": "address" 100 | \ }, 101 | \ "or": { 102 | \ "opcode": "17", 103 | \ "desc": "Bitwise OR operation", 104 | \ "input": "a | b", 105 | \ "output": "a \\| b" 106 | \ }, 107 | \ "xor": { 108 | \ "opcode": "18", 109 | \ "desc": "Bitwise XOR operation", 110 | \ "input": "a | b", 111 | \ "output": "a ^ b" 112 | \ }, 113 | \ "not": { 114 | \ "opcode": "19", 115 | \ "desc": "Bitwise NOT operation", 116 | \ "input": "a", 117 | \ "output": "~a" 118 | \ }, 119 | \ "sha3": { 120 | \ "opcode": "20", 121 | \ "desc": "Compute Keccak-256 hash", 122 | \ "input": "offset | size", 123 | \ "output": "hash" 124 | \ }, 125 | \ "address": { 126 | \ "opcode": "30", 127 | \ "desc": "Get address of currently executing account", 128 | \ "input": "", 129 | \ "output": "address" 130 | \ }, 131 | \ "balance": { 132 | \ "opcode": "31", 133 | \ "desc": "Get balance of the given account", 134 | \ "input": "address", 135 | \ "output": "balance" 136 | \ }, 137 | \ "caller": { 138 | \ "opcode": "33", 139 | \ "desc": "Get caller address", 140 | \ "input": "", 141 | \ "output": "address" 142 | \ }, 143 | \ "callvalue": { 144 | \ "opcode": "34", 145 | \ "desc": "Get deposited value by the instruction/transaction responsible for this execution", 146 | \ "input": "", 147 | \ "output": "value" 148 | \ }, 149 | \ "calldataload": { 150 | \ "opcode": "35", 151 | \ "desc": "Get input data of current environment", 152 | \ "input": "i", 153 | \ "output": "data[i]" 154 | \ }, 155 | \ "calldatasize": { 156 | \ "opcode": "36", 157 | \ "desc": "Get size of input data in current environment", 158 | \ "input": "", 159 | \ "output": "size" 160 | \ }, 161 | \ "calldatacopy": { 162 | \ "opcode": "37", 163 | \ "desc": "Copy input data in current environment to memory", 164 | \ "input": "destOffset | offset | size", 165 | \ "output": "" 166 | \ }, 167 | \ "codesize": { 168 | \ "opcode": "38", 169 | \ "desc": "Get size of code running in current environment", 170 | \ "input": "", 171 | \ "output": "size" 172 | \ }, 173 | \ "codecopy": { 174 | \ "opcode": "39", 175 | \ "desc": "Copy code running in current environment to memory", 176 | \ "input": "destOffset | offset | size", 177 | \ "output": "" 178 | \ }, 179 | \ "basefee": { 180 | \ "opcode": "48", 181 | \ "desc": "Get the base fee", 182 | \ "input": "", 183 | \ "output": "baseFee" 184 | \ }, 185 | \ "blockhash": { 186 | \ "opcode": "40", 187 | \ "desc": "Get the hash of one of the 256 most recent complete blocks", 188 | \ "input": "blockNumber", 189 | \ "output": "hash" 190 | \ }, 191 | \ "coinbase": { 192 | \ "opcode": "41", 193 | \ "desc": "Get the block’s beneficiary address", 194 | \ "input": "", 195 | \ "output": "address" 196 | \ }, 197 | \ "timestamp": { 198 | \ "opcode": "42", 199 | \ "desc": "Get the block’s timestamp", 200 | \ "input": "", 201 | \ "output": "timestamp" 202 | \ }, 203 | \ "number": { 204 | \ "opcode": "43", 205 | \ "desc": "Get the block’s number", 206 | \ "input": "", 207 | \ "output": "blockNumber" 208 | \ }, 209 | \ "difficulty": { 210 | \ "opcode": "44", 211 | \ "desc": "Get the block’s difficulty", 212 | \ "input": "", 213 | \ "output": "difficulty" 214 | \ }, 215 | \ "prevrandao": { 216 | \ "opcode": "44", 217 | \ "desc": "Get the block’s difficulty", 218 | \ "input": "", 219 | \ "output": "difficulty" 220 | \ }, 221 | \ "gaslimit": { 222 | \ "opcode": "45", 223 | \ "desc": "Get the block’s gas limit", 224 | \ "input": "", 225 | \ "output": "gasLimit" 226 | \ }, 227 | \ "chainid": { 228 | \ "opcode": "46", 229 | \ "desc": "Get the chain ID", 230 | \ "input": "", 231 | \ "output": "chainId" 232 | \ }, 233 | \ "selfbalance": { 234 | \ "opcode": "47", 235 | \ "desc": "Get balance of currently executing account", 236 | \ "input": "", 237 | \ "output": "balance" 238 | \ }, 239 | \ "pop": { 240 | \ "opcode": "50", 241 | \ "desc": "Remove item from stack", 242 | \ "input": "y", 243 | \ "output": "" 244 | \ }, 245 | \ "mload": { 246 | \ "opcode": "51", 247 | \ "desc": "Load word from memory", 248 | \ "input": "offset", 249 | \ "output": "value" 250 | \ }, 251 | \ "mstore8": { 252 | \ "opcode": "53", 253 | \ "desc": "Save byte to memory", 254 | \ "input": "offset | value", 255 | \ "output": "" 256 | \ }, 257 | \ "mstore": { 258 | \ "opcode": "52", 259 | \ "desc": "Save word to memory", 260 | \ "input": "offset | value", 261 | \ "output": "" 262 | \ }, 263 | \ "sload": { 264 | \ "opcode": "54", 265 | \ "desc": "Load word from storage", 266 | \ "input": "key", 267 | \ "output": "value" 268 | \ }, 269 | \ "sstore": { 270 | \ "opcode": "55", 271 | \ "desc": "Save word to storage", 272 | \ "input": "key | value", 273 | \ "output": "" 274 | \ }, 275 | \ "jumpdest": { 276 | \ "opcode": "5b", 277 | \ "desc": "Mark a valid destination for jumps", 278 | \ "input": "", 279 | \ "output": "" 280 | \ }, 281 | \ "jumpi": { 282 | \ "opcode": "57", 283 | \ "desc": "Conditionally alter the program counter", 284 | \ "input": "counter | b", 285 | \ "output": "" 286 | \ }, 287 | \ "jump": { 288 | \ "opcode": "56", 289 | \ "desc": "Alter the program counter", 290 | \ "input": "counter", 291 | \ "output": "" 292 | \ }, 293 | \ "pc": { 294 | \ "opcode": "58", 295 | \ "desc": "Get the value of the program counter prior to the increment corresponding to this instruction", 296 | \ "input": "", 297 | \ "output": "counter" 298 | \ }, 299 | \ "msize": { 300 | \ "opcode": "59", 301 | \ "desc": "Get the size of active memory in bytes", 302 | \ "input": "", 303 | \ "output": "size" 304 | \ }, 305 | \ "stop": { 306 | \ "opcode": "00", 307 | \ "desc": "Halts execution", 308 | \ "input": "", 309 | \ "output": "" 310 | \ }, 311 | \ "addmod": { 312 | \ "opcode": "08", 313 | \ "desc": "Modulo addition operation", 314 | \ "input": "a | b | N", 315 | \ "output": "(a + b) % N" 316 | \ }, 317 | \ "add": { 318 | \ "opcode": "01", 319 | \ "desc": "Addition operation", 320 | \ "input": "a | b", 321 | \ "output": "a + b" 322 | \ }, 323 | \ "mulmod": { 324 | \ "opcode": "09", 325 | \ "desc": "Modulo multiplication operation", 326 | \ "input": "a | b | N", 327 | \ "output": "(a * b) % N" 328 | \ }, 329 | \ "mul": { 330 | \ "opcode": "02", 331 | \ "desc": "Multiplication operation", 332 | \ "input": "a | b", 333 | \ "output": "a * b" 334 | \ }, 335 | \ "sub": { 336 | \ "opcode": "03", 337 | \ "desc": "Subtraction operation", 338 | \ "input": "a | b", 339 | \ "output": "a - b" 340 | \ }, 341 | \ "div": { 342 | \ "opcode": "04", 343 | \ "desc": "Integer division operation", 344 | \ "input": "a | b", 345 | \ "output": "a // b" 346 | \ }, 347 | \ "sdiv": { 348 | \ "opcode": "05", 349 | \ "desc": "Signed integer division operation (truncated)", 350 | \ "input": "a | b", 351 | \ "output": "a // b" 352 | \ }, 353 | \ "mod": { 354 | \ "opcode": "06", 355 | \ "desc": "Modulo remainder operation", 356 | \ "input": "a | b", 357 | \ "output": "a % b" 358 | \ }, 359 | \ "smod": { 360 | \ "opcode": "07", 361 | \ "desc": "Signed modulo remainder operation", 362 | \ "input": "a | b", 363 | \ "output": "a % b" 364 | \ }, 365 | \ "exp": { 366 | \ "opcode": "0a", 367 | \ "desc": "Exponential operation", 368 | \ "input": "a | exponent", 369 | \ "output": "a ** exponent" 370 | \ }, 371 | \ "signextend": { 372 | \ "opcode": "0b", 373 | \ "desc": "Extend length of two’s complement signed integer", 374 | \ "input": "b | x", 375 | \ "output": "y" 376 | \ }, 377 | \ "byte": { 378 | \ "opcode": "1a", 379 | \ "desc": "Retrieve single byte from word", 380 | \ "input": "i | x", 381 | \ "output": "y" 382 | \ }, 383 | \ "shl": { 384 | \ "opcode": "1b", 385 | \ "desc": "Left shift operation", 386 | \ "input": "shift | value", 387 | \ "output": "value << shift" 388 | \ }, 389 | \ "shr": { 390 | \ "opcode": "1c", 391 | \ "desc": "Logical right shift operation", 392 | \ "input": "shift | value", 393 | \ "output": "value >> shift" 394 | \ }, 395 | \ "sar": { 396 | \ "opcode": "1d", 397 | \ "desc": "Arithmetic (signed) right shift operation", 398 | \ "input": "shift | value", 399 | \ "output": "value >> shift" 400 | \ }, 401 | \ "gasprice": { 402 | \ "opcode": "3a", 403 | \ "desc": "Get price of gas in current environment", 404 | \ "input": "", 405 | \ "output": "price" 406 | \ }, 407 | \ "extcodesize": { 408 | \ "opcode": "3b", 409 | \ "desc": "Get size of an account’s code", 410 | \ "input": "address", 411 | \ "output": "size" 412 | \ }, 413 | \ "extcodecopy": { 414 | \ "opcode": "3c", 415 | \ "desc": "Copy an account’s code to memory", 416 | \ "input": "address | destOffset | offset | size", 417 | \ "output": "" 418 | \ }, 419 | \ "returndatasize": { 420 | \ "opcode": "3d", 421 | \ "desc": "Get size of output data from the previous call from the current environment", 422 | \ "input": "", 423 | \ "output": "size" 424 | \ }, 425 | \ "returndatacopy": { 426 | \ "opcode": "3e", 427 | \ "desc": "Copy output data from the previous call to memory", 428 | \ "input": "destOffset | offset | size", 429 | \ "output": "" 430 | \ }, 431 | \ "extcodehash": { 432 | \ "opcode": "3f", 433 | \ "desc": "Get hash of an account’s code", 434 | \ "input": "address", 435 | \ "output": "hash" 436 | \ }, 437 | \ "gas": { 438 | \ "opcode": "5a", 439 | \ "desc": "Get the amount of available gas, including the corresponding reduction for the cost of this instruction", 440 | \ "input": "", 441 | \ "output": "gas" 442 | \ }, 443 | \ "log0": { 444 | \ "opcode": "a0", 445 | \ "desc": "Append log record with no topics", 446 | \ "input": "offset | size", 447 | \ "output": "" 448 | \ }, 449 | \ "log1": { 450 | \ "opcode": "a1", 451 | \ "desc": "Append log record with one topic", 452 | \ "input": "offset | size | topic", 453 | \ "output": "" 454 | \ }, 455 | \ "log2": { 456 | \ "opcode": "a2", 457 | \ "desc": "Append log record with two topics", 458 | \ "input": "offset | size | topic1 | topic2", 459 | \ "output": "" 460 | \ }, 461 | \ "log3": { 462 | \ "opcode": "a3", 463 | \ "desc": "Append log record with three topics", 464 | \ "input": "offset | size | topic1 | topic2 | topic3", 465 | \ "output": "" 466 | \ }, 467 | \ "log4": { 468 | \ "opcode": "a4", 469 | \ "desc": "Append log record with four topics", 470 | \ "input": "offset | size | topic1 | topic2 | topic3 | topic4", 471 | \ "output": "" 472 | \ }, 473 | \ "create2": { 474 | \ "opcode": "f5", 475 | \ "desc": "Create a new account with associated code at a predictable address", 476 | \ "input": "value | offset | size | salt", 477 | \ "output": "address" 478 | \ }, 479 | \ "create": { 480 | \ "opcode": "f0", 481 | \ "desc": "Create a new account with associated code", 482 | \ "input": "value | offset | size", 483 | \ "output": "address" 484 | \ }, 485 | \ "callcode": { 486 | \ "opcode": "f2", 487 | \ "desc": "Message-call into this account with alternative account’s code", 488 | \ "input": "gas | address | value | argsOffset | argsSize | retOffset | retSize", 489 | \ "output": "success" 490 | \ }, 491 | \ "call": { 492 | \ "opcode": "f1", 493 | \ "desc": "Message-call into an account", 494 | \ "input": "gas | address | value | argsOffset | argsSize | retOffset | retSize", 495 | \ "output": "success" 496 | \ }, 497 | \ "return": { 498 | \ "opcode": "f3", 499 | \ "desc": "Halt execution returning output data", 500 | \ "input": "offset | size", 501 | \ "output": "" 502 | \ }, 503 | \ "delegatecall": { 504 | \ "opcode": "f4", 505 | \ "desc": "Message-call into this account with an alternative account’s code, but persisting the current values for sender and value", 506 | \ "input": "gas | address | argsOffset | argsSize | retOffset | retSize", 507 | \ "output": "success" 508 | \ }, 509 | \ "staticcall": { 510 | \ "opcode": "fa", 511 | \ "desc": "Static message-call into an account", 512 | \ "input": "gas | address | argsOffset | argsSize | retOffset | retSize", 513 | \ "output": "success" 514 | \ }, 515 | \ "revert": { 516 | \ "opcode": "fd", 517 | \ "desc": "Halt execution reverting state changes but returning data and remaining gas", 518 | \ "input": "offset | size", 519 | \ "output": "" 520 | \ }, 521 | \ "invalid": { 522 | \ "opcode": "fe", 523 | \ "desc": "Designated invalid instruction", 524 | \ "input": "", 525 | \ "output": "" 526 | \ }, 527 | \ "selfdestruct": { 528 | \ "opcode": "ff", 529 | \ "desc": "Halt execution and register account for later deletion", 530 | \ "input": "address", 531 | \ "output": "" 532 | \ }, 533 | \ "push32": { 534 | \ "opcode": "7f", 535 | \ "desc": "Place 32 byte (full word) item on stack", 536 | \ "input": "", 537 | \ "output": "value" 538 | \ }, 539 | \ "push31": { 540 | \ "opcode": "7e", 541 | \ "desc": "Place 31 byte item on stack", 542 | \ "input": "", 543 | \ "output": "value" 544 | \ }, 545 | \ "push30": { 546 | \ "opcode": "7d", 547 | \ "desc": "Place 30 byte item on stack", 548 | \ "input": "", 549 | \ "output": "value" 550 | \ }, 551 | \ "push29": { 552 | \ "opcode": "7c", 553 | \ "desc": "Place 29 byte item on stack", 554 | \ "input": "", 555 | \ "output": "value" 556 | \ }, 557 | \ "push28": { 558 | \ "opcode": "7b", 559 | \ "desc": "Place 28 byte item on stack", 560 | \ "input": "", 561 | \ "output": "value" 562 | \ }, 563 | \ "push27": { 564 | \ "opcode": "7a", 565 | \ "desc": "Place 27 byte item on stack", 566 | \ "input": "", 567 | \ "output": "value" 568 | \ }, 569 | \ "push26": { 570 | \ "opcode": "79", 571 | \ "desc": "Place 26 byte item on stack", 572 | \ "input": "", 573 | \ "output": "value" 574 | \ }, 575 | \ "push25": { 576 | \ "opcode": "78", 577 | \ "desc": "Place 25 byte item on stack", 578 | \ "input": "", 579 | \ "output": "value" 580 | \ }, 581 | \ "push24": { 582 | \ "opcode": "77", 583 | \ "desc": "Place 24 byte item on stack", 584 | \ "input": "", 585 | \ "output": "value" 586 | \ }, 587 | \ "push23": { 588 | \ "opcode": "76", 589 | \ "desc": "Place 23 byte item on stack", 590 | \ "input": "", 591 | \ "output": "value" 592 | \ }, 593 | \ "push22": { 594 | \ "opcode": "75", 595 | \ "desc": "Place 22 byte item on stack", 596 | \ "input": "", 597 | \ "output": "value" 598 | \ }, 599 | \ "push21": { 600 | \ "opcode": "74", 601 | \ "desc": "Place 21 byte item on stack", 602 | \ "input": "", 603 | \ "output": "value" 604 | \ }, 605 | \ "push20": { 606 | \ "opcode": "73", 607 | \ "desc": "Place 20 byte item on stack", 608 | \ "input": "", 609 | \ "output": "value" 610 | \ }, 611 | \ "push19": { 612 | \ "opcode": "72", 613 | \ "desc": "Place 19 byte item on stack", 614 | \ "input": "", 615 | \ "output": "value" 616 | \ }, 617 | \ "push18": { 618 | \ "opcode": "71", 619 | \ "desc": "Place 18 byte item on stack", 620 | \ "input": "", 621 | \ "output": "value" 622 | \ }, 623 | \ "push17": { 624 | \ "opcode": "70", 625 | \ "desc": "Place 17 byte item on stack", 626 | \ "input": "", 627 | \ "output": "value" 628 | \ }, 629 | \ "push16": { 630 | \ "opcode": "6f", 631 | \ "desc": "Place 16 byte item on stack", 632 | \ "input": "", 633 | \ "output": "value" 634 | \ }, 635 | \ "push15": { 636 | \ "opcode": "6e", 637 | \ "desc": "Place 15 byte item on stack", 638 | \ "input": "", 639 | \ "output": "value" 640 | \ }, 641 | \ "push14": { 642 | \ "opcode": "6d", 643 | \ "desc": "Place 14 byte item on stack", 644 | \ "input": "", 645 | \ "output": "value" 646 | \ }, 647 | \ "push13": { 648 | \ "opcode": "6c", 649 | \ "desc": "Place 13 byte item on stack", 650 | \ "input": "", 651 | \ "output": "value" 652 | \ }, 653 | \ "push12": { 654 | \ "opcode": "6b", 655 | \ "desc": "Place 12 byte item on stack", 656 | \ "input": "", 657 | \ "output": "value" 658 | \ }, 659 | \ "push11": { 660 | \ "opcode": "6a", 661 | \ "desc": "Place 11 byte item on stack", 662 | \ "input": "", 663 | \ "output": "value" 664 | \ }, 665 | \ "push10": { 666 | \ "opcode": "69", 667 | \ "desc": "Place 10 byte item on stack", 668 | \ "input": "", 669 | \ "output": "value" 670 | \ }, 671 | \ "push9": { 672 | \ "opcode": "68", 673 | \ "desc": "Place 9 byte item on stack", 674 | \ "input": "", 675 | \ "output": "value" 676 | \ }, 677 | \ "push8": { 678 | \ "opcode": "67", 679 | \ "desc": "Place 8 byte item on stack", 680 | \ "input": "", 681 | \ "output": "value" 682 | \ }, 683 | \ "push7": { 684 | \ "opcode": "66", 685 | \ "desc": "Place 7 byte item on stack", 686 | \ "input": "", 687 | \ "output": "value" 688 | \ }, 689 | \ "push6": { 690 | \ "opcode": "65", 691 | \ "desc": "Place 6 byte item on stack", 692 | \ "input": "", 693 | \ "output": "value" 694 | \ }, 695 | \ "push5": { 696 | \ "opcode": "64", 697 | \ "desc": "Place 5 byte item on stack", 698 | \ "input": "", 699 | \ "output": "value" 700 | \ }, 701 | \ "push4": { 702 | \ "opcode": "63", 703 | \ "desc": "Place 4 byte item on stack", 704 | \ "input": "", 705 | \ "output": "value" 706 | \ }, 707 | \ "push3": { 708 | \ "opcode": "62", 709 | \ "desc": "Place 3 byte item on stack", 710 | \ "input": "", 711 | \ "output": "value" 712 | \ }, 713 | \ "push2": { 714 | \ "opcode": "61", 715 | \ "desc": "Place 2 byte item on stack", 716 | \ "input": "", 717 | \ "output": "value" 718 | \ }, 719 | \ "push1": { 720 | \ "opcode": "60", 721 | \ "desc": "Place 1 byte item on stack", 722 | \ "input": "", 723 | \ "output": "value" 724 | \ }, 725 | \ "swap16": { 726 | \ "opcode": "9f", 727 | \ "desc": "Exchange 1st and 17th stack items", 728 | \ "input": "a | ... | b", 729 | \ "output": "b | ... | a" 730 | \ }, 731 | \ "swap15": { 732 | \ "opcode": "9e", 733 | \ "desc": "Exchange 1st and 16th stack items", 734 | \ "input": "a | ... | b", 735 | \ "output": "b | ... | a" 736 | \ }, 737 | \ "swap14": { 738 | \ "opcode": "9d", 739 | \ "desc": "Exchange 1st and 15th stack items", 740 | \ "input": "a | ... | b", 741 | \ "output": "b | ... | a" 742 | \ }, 743 | \ "swap13": { 744 | \ "opcode": "9c", 745 | \ "desc": "Exchange 1st and 14th stack items", 746 | \ "input": "a | ... | b", 747 | \ "output": "b | ... | a" 748 | \ }, 749 | \ "swap12": { 750 | \ "opcode": "9b", 751 | \ "desc": "Exchange 1st and 13th stack items", 752 | \ "input": "a | ... | b", 753 | \ "output": "b | ... | a" 754 | \ }, 755 | \ "swap11": { 756 | \ "opcode": "9a", 757 | \ "desc": "Exchange 1st and 12th stack items", 758 | \ "input": "a | ... | b", 759 | \ "output": "b | ... | a" 760 | \ }, 761 | \ "swap10": { 762 | \ "opcode": "99", 763 | \ "desc": "Exchange 1st and 11th stack items", 764 | \ "input": "a | ... | b", 765 | \ "output": "b | ... | a" 766 | \ }, 767 | \ "swap9": { 768 | \ "opcode": "98", 769 | \ "desc": "Exchange 1st and 10th stack items", 770 | \ "input": "a | ... | b", 771 | \ "output": "b | ... | a" 772 | \ }, 773 | \ "swap8": { 774 | \ "opcode": "97", 775 | \ "desc": "Exchange 1st and 9th stack items", 776 | \ "input": "a | ... | b", 777 | \ "output": "b | ... | a" 778 | \ }, 779 | \ "swap7": { 780 | \ "opcode": "96", 781 | \ "desc": "Exchange 1st and 8th stack items", 782 | \ "input": "a | ... | b", 783 | \ "output": "b | ... | a" 784 | \ }, 785 | \ "swap6": { 786 | \ "opcode": "95", 787 | \ "desc": "Exchange 1st and 7th stack items", 788 | \ "input": "a | ... | b", 789 | \ "output": "b | ... | a" 790 | \ }, 791 | \ "swap5": { 792 | \ "opcode": "94", 793 | \ "desc": "Exchange 1st and 6th stack items", 794 | \ "input": "a | ... | b", 795 | \ "output": "b | ... | a" 796 | \ }, 797 | \ "swap4": { 798 | \ "opcode": "93", 799 | \ "desc": "Exchange 1st and 5th stack items", 800 | \ "input": "a | ... | b", 801 | \ "output": "b | ... | a" 802 | \ }, 803 | \ "swap3": { 804 | \ "opcode": "92", 805 | \ "desc": "Exchange 1st and 4th stack items", 806 | \ "input": "a | ... | b", 807 | \ "output": "b | ... | a" 808 | \ }, 809 | \ "swap2": { 810 | \ "opcode": "91", 811 | \ "desc": "Exchange 1st and 3rd stack items", 812 | \ "input": "a | b | c", 813 | \ "output": "c | b | a" 814 | \ }, 815 | \ "swap1": { 816 | \ "opcode": "90", 817 | \ "desc": "Exchange 1st and 2nd stack items", 818 | \ "input": "a | b", 819 | \ "output": "b | a" 820 | \ }, 821 | \ "dup16": { 822 | \ "opcode": "8f", 823 | \ "desc": "Duplicate 16th stack item", 824 | \ "input": "... | value", 825 | \ "output": "value | ... | value" 826 | \ }, 827 | \ "dup15": { 828 | \ "opcode": "8e", 829 | \ "desc": "Duplicate 15th stack item", 830 | \ "input": "... | value", 831 | \ "output": "value | ... | value" 832 | \ }, 833 | \ "dup14": { 834 | \ "opcode": "8d", 835 | \ "desc": "Duplicate 14th stack item", 836 | \ "input": "... | value", 837 | \ "output": "value | ... | value" 838 | \ }, 839 | \ "dup13": { 840 | \ "opcode": "8c", 841 | \ "desc": "Duplicate 13th stack item", 842 | \ "input": "... | value", 843 | \ "output": "value | ... | value" 844 | \ }, 845 | \ "dup12": { 846 | \ "opcode": "8b", 847 | \ "desc": "Duplicate 12th stack item", 848 | \ "input": "... | value", 849 | \ "output": "value | ... | value" 850 | \ }, 851 | \ "dup11": { 852 | \ "opcode": "8a", 853 | \ "desc": "Duplicate 11th stack item", 854 | \ "input": "... | value", 855 | \ "output": "value | ... | value" 856 | \ }, 857 | \ "dup10": { 858 | \ "opcode": "89", 859 | \ "desc": "Duplicate 10th stack item", 860 | \ "input": "... | value", 861 | \ "output": "value | ... | value" 862 | \ }, 863 | \ "dup9": { 864 | \ "opcode": "88", 865 | \ "desc": "Duplicate 9th stack item", 866 | \ "input": "... | value", 867 | \ "output": "value | ... | value" 868 | \ }, 869 | \ "dup8": { 870 | \ "opcode": "87", 871 | \ "desc": "Duplicate 8th stack item", 872 | \ "input": "... | value", 873 | \ "output": "value | ... | value" 874 | \ }, 875 | \ "dup7": { 876 | \ "opcode": "86", 877 | \ "desc": "Duplicate 7th stack item", 878 | \ "input": "... | value", 879 | \ "output": "value | ... | value" 880 | \ }, 881 | \ "dup6": { 882 | \ "opcode": "85", 883 | \ "desc": "Duplicate 6th stack item", 884 | \ "input": "... | value", 885 | \ "output": "value | ... | value" 886 | \ }, 887 | \ "dup5": { 888 | \ "opcode": "84", 889 | \ "desc": "Duplicate 5th stack item", 890 | \ "input": "... | value", 891 | \ "output": "value | ... | value" 892 | \ }, 893 | \ "dup4": { 894 | \ "opcode": "83", 895 | \ "desc": "Duplicate 4th stack item", 896 | \ "input": "... | value", 897 | \ "output": "value | ... | value" 898 | \ }, 899 | \ "dup3": { 900 | \ "opcode": "82", 901 | \ "desc": "Duplicate 3rd stack item", 902 | \ "input": "a | b | c", 903 | \ "output": "c | a | b | c" 904 | \ }, 905 | \ "dup2": { 906 | \ "opcode": "81", 907 | \ "desc": "Duplicate 2nd stack item", 908 | \ "input": "a | b", 909 | \ "output": "b | a | b" 910 | \ }, 911 | \ "dup1": { 912 | \ "opcode": "80", 913 | \ "desc": "Duplicate 1st stack item", 914 | \ "input": "value", 915 | \ "output": "value | value" 916 | \ } 917 | \} 918 | --------------------------------------------------------------------------------