A Symbolic Ethereum Virtual Machine (EVM) interpreter and decompiler, along with several other utils for programmatically extracting information from bytecode.
Forked from MrLuit/evm. For more info, see Detached Fork.
- Lightweight with no dependencies
- Embedded signature database WIP
- Convert bytecode to opcodes
- Read information like events or functions from either bytecode or TX data
- Extract the IPFS or swarm hash (when present) from bytecode
- Check whether an opcode exists and is reachable within bytecode execution
- Detect whether contracts are compliant to certain ERCs
Install using your package manager or Browser's script
tag
yarn add @acuarica/evm
npm install @acuarica/evm
<script src="https://cdn.jsdelivr.net/gh/acuarica/evm@f88b20a/lib/EVM.js"></script>
bytecode
- Get raw bytecode (not really useful; same as input)metadata
- Get IPFS or Swarm hash (if present) for contract metadataevm.opcodes
- Returns opcodes including pc and pushData (if included)evm.jumpdests
- Get map of program counters from JUMPDEST opcodesgetFunctions()
- Parse functions from their signatures in bytecodegetEvents()
- Parse events from their signatures in bytecodecontainsOpcode(opcode)
- Check whether an opcode exists and is reachable within bytecodedecompile()
- Decompile bytecode into readable Solidity-like pseudocodeisERC165()
- Detect whether contract is ERC165-compliant
const { EVM } = require('evm');
const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider('https://api.mycryptoapi.com/eth'));
web3.eth.getCode('0x06012c8cf97BEaD5deAe237070F9587f8E7A266d').then(code => {
/* CryptoKitties contract */
const evm = new EVM(code);
console.log(evm.getOpcodes()); /* Get opcodes */
});
const { EVM } = window.EVM_Utils;
const web3 = new Web3(window.web3.currentProvider);
web3.eth.getCode('0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359', function (err, code) {
/* DAI contract */ if (err) throw err;
const evm = new EVM(code);
console.log(evm.getOpcodes()); /* Get opcodes */
});
const { EVM } = require('evm');
const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider('https://api.mycryptoapi.com/eth'));
web3.eth.getCode('0x06012c8cf97BEaD5deAe237070F9587f8E7A266d').then(code => {
/* CryptoKitties contract */
const evm = new EVM(code);
console.log(evm.getFunctions()); /* Get functions */
console.log(evm.getEvents()); /* Get events */
console.log(evm.decompile()); /* Decompile bytecode */
console.log(
evm.containsOpcode('SELFDESTRUCT')
); /* Check whether contract contains a SELFDESTRUCT */
console.log(evm.isERC165()); /* Detect whether contract is ERC165-compliant */
});
const { EVM } = window.EVM;
const web3 = new Web3(window.web3.currentProvider);
web3.eth.getCode('0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359', function (err, code) {
/* DAI contract */ if (err) throw err;
const evm = new EVM(code);
console.log(evm.getFunctions()); /* Get functions */
console.log(evm.getEvents()); /* Get events */
console.log(evm.decompile()); /* Decompile bytecode */
console.log(
evm.containsOpcode('SELFDESTRUCT')
); /* Check whether contract contains a SELFDESTRUCT */
console.log(evm.isERC165()); /* Detect whether contract is ERC165-compliant */
});
const { Transaction } = require('evm');
const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider('https://api.mycryptoapi.com/eth'));
web3.eth
.getTransaction('0xd20a8d888a3f29471ea41ea77cc2d95ccd79ade1eaad059e83524e72b9adf962')
.then(transactionData => {
const transaction = new Transaction();
transaction.setInput(transactionData.input);
console.log(transaction.getFunction()); /* Get function */
});
const { Transaction } = window.EVM;
const web3 = new Web3(window.web3.currentProvider);
web3.eth.getTransaction(
'0xd20a8d888a3f29471ea41ea77cc2d95ccd79ade1eaad059e83524e72b9adf962',
function (err, transactionData) {
if (err) throw err;
const transaction = new Transaction();
transaction.setInput(transactionData.input);
console.log(transaction.getFunction()); /* Get function */
}
);
This GitHub repo was originally a fork of https://github.com/MrLuit/evm. It served as a great starting point for this project. The fact that it is lightweight and written in TypeScript, make it ideal for embedding in other applications.
However, as we started to support and decompile newer contracts, we realize it was quite outdated. Besides not being able to process newer smart contracts, for some, the bytecode analysis algorithm did not terminate. That's the reason we forked that repo.
We did a major overhaul of the codebase, adding new features, refactoring the whole project and adding both testing and documentation.
As we added changes, we realized it did not make sense to keep it a forked repo.
Moreover, when sending new PRs, the default base
repo is the upstream repo, which is not what we want in our case.
This behavior is both error prone and annoying.
That's why, as of Apr 17, 2023, this project is no longer a fork of MrLuit/evm.