11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/DebugTrace.ts:
--------------------------------------------------------------------------------
1 | export interface DebugTrace {
2 | id: number
3 | jsonrpc: number
4 | result: {
5 | gas: number
6 | returnValue: string
7 | structLogs: {
8 | depth: number
9 | error: string
10 | gas: number
11 | gasCost: number
12 | memory: string[]
13 | op: string
14 | pc: number
15 | stack: string[]
16 | storage: any
17 | }[]
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/EVM.ts:
--------------------------------------------------------------------------------
1 | import { EVMStack } from './EVMStack'
2 | import { EVMStorage } from './EVMStorage'
3 | import { EVMMemory } from './EVMMemory'
4 | import { Word } from './Word'
5 |
6 | export class EVM {
7 | stack: EVMStack
8 | storage: EVMStorage
9 | memory: EVMMemory
10 | nextJumpLocation: Word
11 |
12 | constructor() {
13 | this.stack = new EVMStack()
14 | this.storage = new EVMStorage()
15 | this.memory = new EVMMemory(64)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/EVMStack.test.ts:
--------------------------------------------------------------------------------
1 | import { EVMStack } from './EVMStack'
2 | import { Word } from './Word'
3 |
4 | describe('EVMStack', () => {
5 | let stack: EVMStack
6 |
7 | beforeEach(() => {
8 | stack = new EVMStack()
9 | })
10 |
11 | it('test push', () => {
12 | stack.push(Word.createLiteral('80'))
13 | stack.push(Word.createLiteral('81'))
14 | expect(stack.length()).toEqual(2)
15 | })
16 |
17 | it('Test pop', () => {
18 | stack.push(Word.createLiteral('80'))
19 | stack.push(Word.createLiteral('81'))
20 | const pop = stack.pop()
21 | expect(pop).toEqual(Word.createLiteral('81'))
22 | expect(stack.length()).toEqual(1)
23 | })
24 |
25 | it('Test peek', () => {
26 | stack.push(Word.createLiteral('80'))
27 | stack.push(Word.createLiteral('81'))
28 | const pop = stack.peek()
29 | expect(pop).toEqual(Word.createLiteral('81'))
30 | expect(stack.length()).toEqual(2)
31 | })
32 |
33 | it('Test get', () => {
34 | stack.push(Word.createLiteral('80'))
35 | stack.push(Word.createLiteral('81'))
36 | stack.push(Word.createLiteral('82'))
37 | const get0 = stack.get(0)
38 | const get1 = stack.get(1)
39 | const get2 = stack.get(2)
40 | expect(get0).toEqual(Word.createLiteral('82'))
41 | expect(get1).toEqual(Word.createLiteral('81'))
42 | expect(get2).toEqual(Word.createLiteral('80'))
43 | expect(stack.length()).toEqual(3)
44 | })
45 |
46 | it('Test put', () => {
47 | stack.push(Word.createLiteral('01'))
48 | stack.push(Word.createLiteral('02'))
49 | stack.push(Word.createLiteral('03'))
50 | stack.put(2, Word.createLiteral('99'))
51 | stack.put(0, Word.createLiteral('ff'))
52 | const top0 = stack.pop()
53 | const top1 = stack.pop()
54 | const top2 = stack.pop()
55 | expect(top0).toEqual(Word.createLiteral('ff'))
56 | expect(top1).toEqual(Word.createLiteral('02'))
57 | expect(top2).toEqual(Word.createLiteral('99'))
58 | })
59 | })
60 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/EVMStack.ts:
--------------------------------------------------------------------------------
1 | import { Word } from './Word'
2 |
3 | export class EVMStack {
4 | stack: Word[] = []
5 |
6 | push(word: Word) {
7 | this.stack.push(word)
8 | }
9 |
10 | pop(): Word {
11 | return this.stack.pop()
12 | }
13 |
14 | peek(): Word {
15 | return this.stack[this.stack.length - 1]
16 | }
17 |
18 | get(index: number): Word {
19 | return this.stack[this.stack.length - 1 - index]
20 | }
21 |
22 | put(index: number, word: Word) {
23 | this.stack[this.stack.length - 1 - index] = word
24 | }
25 |
26 | length(): number {
27 | return this.stack.length
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/EVMStorage.ts:
--------------------------------------------------------------------------------
1 | import { Word } from './Word'
2 |
3 | export class EVMStorage {
4 | storage = {}
5 | length
6 |
7 | store(slot: Word, value: Word) {
8 | if (!slot || !value) {
9 | return
10 | }
11 | if (slot.isSymbolic) {
12 | this.storage[slot.symbol] = value
13 | } else {
14 | this.storage[slot.value] = value
15 | }
16 | }
17 |
18 | load(slot: Word): Word {
19 | if (!slot) {
20 | return
21 | }
22 | if (slot.isSymbolic) {
23 | return this.storage[slot.symbol]
24 | } else {
25 | return this.storage[slot.value]
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/Symbols.ts:
--------------------------------------------------------------------------------
1 | export enum Symbols {
2 | // temporal placeholder until full symexec is implemented
3 | UNKNOWN = 'UNKNOWN',
4 | EMPTY = 'EMPTY',
5 |
6 | CALL = 'CALL',
7 | STATICCALL = 'STATICCALL',
8 | CALLCODE = 'CALLCODE',
9 | DELEGATECALL = 'DELEGATECALL',
10 | RETURNDATASIZE = 'RETURNDATASIZE',
11 | RETURNDATACOPY = 'RETURNDATACOPY',
12 |
13 | ADDRESS = 'ADDRESS',
14 | ORIGIN = 'ORIGIN',
15 | CALLER = 'CALLER',
16 | BALANCE = 'BALANCE',
17 | CALLVALUE = 'CALLVALUE',
18 | CALLDATASIZE = 'CALLDATASIZE',
19 | CALLDATALOAD = 'CALLDATALOAD',
20 | CODESIZE = 'CODESIZE',
21 | GAS = 'GAS',
22 | BLOCKHASH = 'BLOCKHASH',
23 | COINBASE = 'COINBASE',
24 | TIMESTAMP = 'TIMESTAMP',
25 | NUMBER = 'NUMBER',
26 | DIFFICULTY = 'DIFFICULTY',
27 | GASLIMIT = 'GASLIMIT',
28 | GASPRICE = 'GASPRICE',
29 | EXTCODESIZE = 'EXTCODESIZE',
30 | CREATE = 'CREATE'
31 | }
32 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/UintUtils.ts:
--------------------------------------------------------------------------------
1 | let BN = require('bn.js')
2 |
3 | export class UintUtils {
4 | static TWO_POW_256 = new BN('10000000000000000000000000000000000000000000000000000000000000000', 16)
5 | static ZERO = new BN('00', 16)
6 | static ONE = new BN('01', 16)
7 | static MAX_INTEGER = new BN('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)
8 | }
9 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/Word.ts:
--------------------------------------------------------------------------------
1 | import { Symbols } from './Symbols'
2 | let BN = require('bn.js')
3 |
4 | export class Word {
5 | static WORD_LENGTH_IN_BYTES = 32
6 |
7 | isSymbolic: boolean
8 | value?: any
9 | symbol?: Symbols
10 |
11 | static createLiteral(valueHex: string): Word {
12 | return { isSymbolic: false, value: new BN(valueHex, 16) } as Word
13 | }
14 |
15 | static createSymbolic(symbol: Symbols): Word {
16 | return { isSymbolic: true, symbol: symbol } as Word
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Add.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 | import { UintUtils } from '../UintUtils'
7 |
8 | export class Add implements Executor {
9 | execute(op: Operation, evm: EVM) {
10 | const operand1 = evm.stack.pop()
11 | const operand2 = evm.stack.pop()
12 | if (!operand1 || !operand2) {
13 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
14 | return
15 | }
16 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
17 | const op1Value = operand1.value
18 | const op2Value = operand2.value
19 | let result = op1Value.add(op2Value).mod(UintUtils.TWO_POW_256)
20 | evm.stack.push(Word.createLiteral(result.toString(16)))
21 | } else {
22 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Addmod.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 | import { UintUtils } from '../UintUtils'
7 |
8 | export class Addmod implements Executor {
9 | execute(op: Operation, evm: EVM) {
10 | const operand1 = evm.stack.pop()
11 | const operand2 = evm.stack.pop()
12 | const mod = evm.stack.pop()
13 | if (!operand1 || !operand2 || !mod) {
14 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
15 | return
16 | }
17 | if (!operand1.isSymbolic && !operand2.isSymbolic && !mod.isSymbolic) {
18 | if (mod.value.eq(UintUtils.ZERO)) {
19 | evm.stack.push(Word.createLiteral('00'))
20 | } else {
21 | const result = operand1.value.add(operand2.value).mod(mod.value)
22 | evm.stack.push(Word.createLiteral(result.toString(16)))
23 | }
24 | } else {
25 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Address.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Address', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test address', () => {
21 | const bytecode = '604030'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.ADDRESS))
25 | expect(executor.evm.stack.length()).toEqual(2)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Address.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Address implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.push(Word.createSymbolic(Symbols.ADDRESS))
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/And.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class And implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | const operand1 = evm.stack.pop()
10 | const operand2 = evm.stack.pop()
11 | if (!operand1 || !operand2) {
12 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
13 | return
14 | }
15 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
16 | const op1Value = operand1.value
17 | const op2Value = operand2.value
18 | let result = op1Value.and(op2Value)
19 | evm.stack.push(Word.createLiteral(result.toString(16)))
20 | } else {
21 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Balance.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Balance', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test balance', () => {
21 | const bytecode = '604031'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.BALANCE))
25 | expect(executor.evm.stack.length()).toEqual(1)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Balance.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Balance implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.pop()
10 | evm.stack.push(Word.createSymbolic(Symbols.BALANCE))
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Blockhash.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Blockhash', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test Blockhash', () => {
21 | const bytecode = '604040'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.BLOCKHASH))
25 | expect(executor.evm.stack.length()).toEqual(1)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Blockhash.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Blockhash implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.pop()
10 | evm.stack.push(Word.createSymbolic(Symbols.BLOCKHASH))
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Byte.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 | let BN = require('bn.js')
7 |
8 | export class Byte implements Executor {
9 | execute(op: Operation, evm: EVM) {
10 | const operand1 = evm.stack.pop()
11 | const operand2 = evm.stack.pop()
12 | if (!operand1 || !operand2) {
13 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
14 | return
15 | }
16 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
17 | const pos = operand1.value
18 | const word = operand2.value
19 | let result = new BN(0)
20 | if (!pos.gten(32)) {
21 | result = new BN(word.shrn((31 - pos.toNumber()) * 8).andln(0xff))
22 | }
23 | evm.stack.push(Word.createLiteral(result.toString(16)))
24 | } else {
25 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Call.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Call', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test Call', () => {
21 | const bytecode = '6010602060306040605060606070f1'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.CALL))
25 | expect(executor.evm.stack.length()).toEqual(1)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Call.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Call implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.pop()
10 | evm.stack.pop()
11 | evm.stack.pop()
12 | evm.stack.pop()
13 | evm.stack.pop()
14 | evm.stack.pop()
15 | evm.stack.pop()
16 | evm.stack.push(Word.createSymbolic(Symbols.CALL))
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Callcode.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Callcode', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test Callcode', () => {
21 | const bytecode = '6010602060306040605060606070f2'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.CALLCODE))
25 | expect(executor.evm.stack.length()).toEqual(1)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Callcode.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Callcode implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.pop()
10 | evm.stack.pop()
11 | evm.stack.pop()
12 | evm.stack.pop()
13 | evm.stack.pop()
14 | evm.stack.pop()
15 | evm.stack.pop()
16 | evm.stack.push(Word.createSymbolic(Symbols.CALLCODE))
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Calldatacopy.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 |
8 | describe('Calldatacopy', () => {
9 | let cfgCreator: EthereumCFGCreator
10 | let disassembler: Disassembler
11 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
12 |
13 | beforeEach(() => {
14 | cfgCreator = new EthereumCFGCreator()
15 | disassembler = createEVMDisassembler()
16 | })
17 |
18 | it('Test calldatacopy', () => {
19 | const bytecode = '60406041604237'
20 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
21 | executor.run(0)
22 | expect(executor.evm.stack.length()).toEqual(0)
23 | })
24 | })
25 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Calldatacopy.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 |
5 | export class Calldatacopy implements Executor {
6 | execute(op: Operation, evm: EVM) {
7 | evm.stack.pop()
8 | evm.stack.pop()
9 | evm.stack.pop()
10 | // TODO write symbol in memory (memory doesn't support symbolic values yet)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Calldataload.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Calldataload', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test calldataload', () => {
21 | const bytecode = '604035'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.CALLDATALOAD))
25 | expect(executor.evm.stack.length()).toEqual(1)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Calldataload.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Calldataload implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.pop()
10 | evm.stack.push(Word.createSymbolic(Symbols.CALLDATALOAD))
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Calldatasize.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Calldatasize', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test calldatasize', () => {
21 | const bytecode = '604036'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.CALLDATASIZE))
25 | expect(executor.evm.stack.get(1)).toEqual(Word.createLiteral('40'))
26 | expect(executor.evm.stack.length()).toEqual(2)
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Calldatasize.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Calldatasize implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.push(Word.createSymbolic(Symbols.CALLDATASIZE))
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Caller.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Caller', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test caller', () => {
21 | const bytecode = '604033'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.CALLER))
25 | expect(executor.evm.stack.length()).toEqual(2)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Caller.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Caller implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.push(Word.createSymbolic(Symbols.CALLER))
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Callvalue.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Callvalue', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test callvalue', () => {
21 | const bytecode = '604034'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.CALLVALUE))
25 | expect(executor.evm.stack.get(1)).toEqual(Word.createLiteral('40'))
26 | expect(executor.evm.stack.length()).toEqual(2)
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Callvalue.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Callvalue implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.push(Word.createSymbolic(Symbols.CALLVALUE))
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Codecopy.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Codecopy', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test codecopy', () => {
21 | const bytecode = '60406041604239'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.length()).toEqual(0)
25 | })
26 | })
27 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Codecopy.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 |
5 | export class Codecopy implements Executor {
6 | execute(op: Operation, evm: EVM) {
7 | evm.stack.pop()
8 | evm.stack.pop()
9 | evm.stack.pop()
10 | // TODO Push symbol when EVMMemory supports symbols
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Codesize.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Codesize', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test codesize', () => {
21 | const bytecode = '604038'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.CODESIZE))
25 | expect(executor.evm.stack.length()).toEqual(2)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Codesize.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Codesize implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.push(Word.createSymbolic(Symbols.CODESIZE))
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Coinbase.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Coinbase', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test Coinbase', () => {
21 | const bytecode = '604041'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.COINBASE))
25 | expect(executor.evm.stack.length()).toEqual(2)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Coinbase.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Coinbase implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.push(Word.createSymbolic(Symbols.COINBASE))
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Create.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Create', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test Create', () => {
21 | const bytecode = '604060416042f0'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.CREATE))
25 | expect(executor.evm.stack.length()).toEqual(1)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Create.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Create implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.pop()
10 | evm.stack.pop()
11 | evm.stack.pop()
12 | evm.stack.push(Word.createSymbolic(Symbols.CREATE))
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Delegatecall.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Delegatecall', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test Delegatecall', () => {
21 | const bytecode = '601060206030604060506060f4'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.DELEGATECALL))
25 | expect(executor.evm.stack.length()).toEqual(1)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Delegatecall.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Delegatecall implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.pop()
10 | evm.stack.pop()
11 | evm.stack.pop()
12 | evm.stack.pop()
13 | evm.stack.pop()
14 | evm.stack.pop()
15 | evm.stack.push(Word.createSymbolic(Symbols.DELEGATECALL))
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Difficulty.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Difficulty', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test Difficulty', () => {
21 | const bytecode = '604044'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.DIFFICULTY))
25 | expect(executor.evm.stack.length()).toEqual(2)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Difficulty.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Difficulty implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.push(Word.createSymbolic(Symbols.DIFFICULTY))
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Div.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 | import { UintUtils } from '../UintUtils'
7 |
8 | export class Div implements Executor {
9 | execute(op: Operation, evm: EVM) {
10 | const operand1 = evm.stack.pop()
11 | const operand2 = evm.stack.pop()
12 | if (!operand1 || !operand2) {
13 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
14 | return
15 | }
16 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
17 | const op1Value = operand1.value
18 | const op2Value = operand2.value
19 | let result = UintUtils.ZERO
20 | if (!op2Value.eq(UintUtils.ZERO)) {
21 | result = op1Value.div(op2Value)
22 | }
23 | evm.stack.push(Word.createLiteral(result.toString(16)))
24 | } else {
25 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Dup.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 |
5 | export class Dup implements Executor {
6 | execute(op: Operation, evm: EVM) {
7 | const index = parseInt(op.opcode.name.slice(3))
8 | const wordToDuplicate = evm.stack.get(index - 1)
9 | evm.stack.push(wordToDuplicate)
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Eq.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('EQ', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test EQ false', () => {
21 | const bytecode = '6002600114'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createLiteral('00'))
25 | expect(executor.evm.stack.length()).toEqual(1)
26 | })
27 |
28 | it('Test EQ true', () => {
29 | const bytecode = '6001600114'
30 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
31 | executor.run(0)
32 | expect(executor.evm.stack.get(0)).toEqual(Word.createLiteral('01'))
33 | expect(executor.evm.stack.length()).toEqual(1)
34 | })
35 |
36 | it('Test EQ Symbolic', () => {
37 | const bytecode = '60203414'
38 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
39 | executor.run(0)
40 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.UNKNOWN))
41 | expect(executor.evm.stack.length()).toEqual(1)
42 | })
43 | })
44 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Eq.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Eq implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | const operand1 = evm.stack.pop()
10 | const operand2 = evm.stack.pop()
11 | if (!operand1 || !operand2) {
12 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
13 | return
14 | }
15 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
16 | if (operand1.value.eq(operand2.value)) {
17 | evm.stack.push(Word.createLiteral('01'))
18 | } else {
19 | evm.stack.push(Word.createLiteral('00'))
20 | }
21 | } else {
22 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Executor.ts:
--------------------------------------------------------------------------------
1 | import { EVM } from '../EVM'
2 | import { Operation } from '../../../bytecode/Operation'
3 |
4 | export interface Executor {
5 | execute(op: Operation, evm: EVM)
6 | }
7 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Exp.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 | import { UintUtils } from '../UintUtils'
7 | let BN = require('bn.js')
8 |
9 | export class Exp implements Executor {
10 | execute(op: Operation, evm: EVM) {
11 | const base = evm.stack.pop()
12 | const exp = evm.stack.pop()
13 | if (!base || !exp) {
14 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
15 | return
16 | }
17 | if (!base.isSymbolic && !exp.isSymbolic) {
18 | const baseValue = base.value
19 | const expValue = exp.value
20 |
21 | let result = UintUtils.ONE
22 | if (!expValue.eq(UintUtils.ZERO)) {
23 | const mod = BN.red(UintUtils.TWO_POW_256)
24 | const b = baseValue.toRed(mod)
25 | result = b.redPow(expValue)
26 | }
27 | evm.stack.push(Word.createLiteral(result.toString(16)))
28 | } else {
29 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Extcodecopy.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Extcodecopy', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test extcodecopy', () => {
21 | const bytecode = '60406041604260433c'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.length()).toEqual(0)
25 | })
26 | })
27 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Extcodecopy.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 |
5 | export class Extcodecopy implements Executor {
6 | execute(op: Operation, evm: EVM) {
7 | evm.stack.pop()
8 | evm.stack.pop()
9 | evm.stack.pop()
10 | evm.stack.pop()
11 | // TODO push symbol to memory when it is supported
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Extcodesize.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Extcodesize', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test extcodesize', () => {
21 | const bytecode = '60403b'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.EXTCODESIZE))
25 | expect(executor.evm.stack.length()).toEqual(1)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Extcodesize.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Extcodesize implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.pop()
10 | evm.stack.push(Word.createSymbolic(Symbols.EXTCODESIZE))
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Gas.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Gas', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test Gas', () => {
21 | const bytecode = '60405a'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.GAS))
25 | expect(executor.evm.stack.length()).toEqual(2)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Gas.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Gas implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.push(Word.createSymbolic(Symbols.GAS))
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Gaslimit.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Gaslimit', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test Gaslimit', () => {
21 | const bytecode = '604045'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.GASLIMIT))
25 | expect(executor.evm.stack.length()).toEqual(2)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Gaslimit.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Gaslimit implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.push(Word.createSymbolic(Symbols.GASLIMIT))
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Gasprice.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Gasprice', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test gasprice', () => {
21 | const bytecode = '60403a'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.GASPRICE))
25 | expect(executor.evm.stack.get(1)).toEqual(Word.createLiteral('40'))
26 | expect(executor.evm.stack.length()).toEqual(2)
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Gasprice.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Gasprice implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.push(Word.createSymbolic(Symbols.GASPRICE))
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Gt.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Gt implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | const operand1 = evm.stack.pop()
10 | const operand2 = evm.stack.pop()
11 | if (!operand1 || !operand2) {
12 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
13 | return
14 | }
15 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
16 | if (operand1.value.gt(operand2.value)) {
17 | evm.stack.push(Word.createLiteral('01'))
18 | } else {
19 | evm.stack.push(Word.createLiteral('00'))
20 | }
21 | } else {
22 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/IsZero.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 |
9 | describe('IsZero', () => {
10 | let cfgCreator: EthereumCFGCreator
11 | let disassembler: Disassembler
12 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
13 |
14 | beforeEach(() => {
15 | cfgCreator = new EthereumCFGCreator()
16 | disassembler = createEVMDisassembler()
17 | })
18 |
19 | it('Test IsZero false', () => {
20 | const bytecode = '604015'
21 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
22 | executor.run(0)
23 | expect(executor.evm.stack.get(0)).toEqual(Word.createLiteral('00'))
24 | expect(executor.evm.stack.length()).toEqual(1)
25 | })
26 |
27 | it('Test IsZero true', () => {
28 | const bytecode = '600015'
29 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
30 | executor.run(0)
31 | expect(executor.evm.stack.get(0)).toEqual(Word.createLiteral('01'))
32 | expect(executor.evm.stack.length()).toEqual(1)
33 | })
34 | })
35 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/IsZero.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class IsZero implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | const value = evm.stack.pop()
10 | if (!value) {
11 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
12 | return
13 | }
14 | if (!value.isSymbolic) {
15 | if (value.value.isZero()) {
16 | evm.stack.push(Word.createLiteral('01'))
17 | } else {
18 | evm.stack.push(Word.createLiteral('00'))
19 | }
20 | } else {
21 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Jump.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 |
9 | describe('Jump', () => {
10 | let cfgCreator: EthereumCFGCreator
11 | let disassembler: Disassembler
12 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
13 |
14 | beforeEach(() => {
15 | cfgCreator = new EthereumCFGCreator()
16 | disassembler = createEVMDisassembler()
17 | })
18 |
19 | it('Test Jump', () => {
20 | const bytecode = '6001604056'
21 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
22 | executor.run(0)
23 | expect(executor.evm.stack.length()).toEqual(1)
24 | })
25 | })
26 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Jump.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 |
5 | export class Jump implements Executor {
6 | execute(op: Operation, evm: EVM) {
7 | const jumpLocation = evm.stack.pop()
8 | evm.nextJumpLocation = jumpLocation
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Jumpi.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 |
8 | describe('Jumpi', () => {
9 | let cfgCreator: EthereumCFGCreator
10 | let disassembler: Disassembler
11 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
12 |
13 | beforeEach(() => {
14 | cfgCreator = new EthereumCFGCreator()
15 | disassembler = createEVMDisassembler()
16 | })
17 |
18 | it('Test Jumpi', () => {
19 | const bytecode = '6001604057'
20 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
21 | executor.run(0)
22 | expect(executor.evm.stack.length()).toEqual(0)
23 | })
24 | })
25 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Jumpi.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 |
5 | export class Jumpi implements Executor {
6 | execute(op: Operation, evm: EVM) {
7 | const jumpLocation = evm.stack.pop()
8 | evm.stack.pop()
9 | evm.nextJumpLocation = jumpLocation
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Log.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 |
5 | export class Log implements Executor {
6 | execute(op: Operation, evm: EVM) {
7 | const index = parseInt(op.opcode.name.slice(3))
8 | const stackToRemove = index + 2
9 | let i = 1
10 | while (i <= stackToRemove) {
11 | evm.stack.pop()
12 | i++
13 | }
14 | // Don't need to store logs anywhere
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Lt.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Lt implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | const operand1 = evm.stack.pop()
10 | const operand2 = evm.stack.pop()
11 | if (!operand1 || !operand2) {
12 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
13 | return
14 | }
15 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
16 | if (operand1.value.lt(operand2.value)) {
17 | evm.stack.push(Word.createLiteral('01'))
18 | } else {
19 | evm.stack.push(Word.createLiteral('00'))
20 | }
21 | } else {
22 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/MLoad.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 |
9 | describe('MLoad', () => {
10 | let cfgCreator: EthereumCFGCreator
11 | let disassembler: Disassembler
12 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
13 |
14 | beforeEach(() => {
15 | cfgCreator = new EthereumCFGCreator()
16 | disassembler = createEVMDisassembler()
17 | })
18 |
19 | it('Test MLoad from 0', () => {
20 | const bytecode = '6080600052600051'
21 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
22 | executor.run(0)
23 | expect(executor.evm.stack.length()).toEqual(1)
24 | expect(executor.evm.stack.get(0)).toEqual(
25 | Word.createLiteral('0000000000000000000000000000000000000000000000000000000000000080')
26 | )
27 | })
28 |
29 | it('Test MLoad from arbitrary offset', () => {
30 | const bytecode = '6080602052602051'
31 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
32 | executor.run(0)
33 | expect(executor.evm.stack.length()).toEqual(1)
34 | expect(executor.evm.stack.get(0)).toEqual(
35 | Word.createLiteral('0000000000000000000000000000000000000000000000000000000000000080')
36 | )
37 | })
38 | })
39 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/MLoad.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Symbols } from '../Symbols'
5 | import { Word } from '../Word'
6 |
7 | export class MLoad implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | const location = evm.stack.pop()
10 | // TODO support symbolic memory
11 | if (!location) {
12 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
13 | return
14 | }
15 | if (!location.isSymbolic) {
16 | if (location.value.bitLength() > 53) {
17 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
18 | return
19 | }
20 | const memoryValue = evm.memory.loadWord(location.value.toNumber())
21 | evm.stack.push(memoryValue)
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/MStore.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 |
8 | describe('MStore', () => {
9 | let cfgCreator: EthereumCFGCreator
10 | let disassembler: Disassembler
11 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
12 |
13 | beforeEach(() => {
14 | cfgCreator = new EthereumCFGCreator()
15 | disassembler = createEVMDisassembler()
16 | })
17 |
18 | it('Test MStore', () => {
19 | const bytecode = '6080604052'
20 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
21 | executor.run(0)
22 | expect(executor.evm.stack.length()).toEqual(0)
23 | expect(executor.evm.memory.memory.toString('hex')).toEqual(
24 | '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000'
25 | )
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/MStore.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 |
5 | export class MStore implements Executor {
6 | execute(op: Operation, evm: EVM) {
7 | const location = evm.stack.pop()
8 | const value = evm.stack.pop()
9 | if (!location || !value) {
10 | return
11 | }
12 | if (!location.isSymbolic) {
13 | if (location.value.bitLength() > 53) {
14 | return
15 | }
16 | evm.memory.writeWord(location.value.toNumber(), value)
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/MStore8.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 |
8 | describe('Mstore8', () => {
9 | let cfgCreator: EthereumCFGCreator
10 | let disassembler: Disassembler
11 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
12 |
13 | beforeEach(() => {
14 | cfgCreator = new EthereumCFGCreator()
15 | disassembler = createEVMDisassembler()
16 | })
17 |
18 | it('Test Mstore', () => {
19 | const bytecode = '6099604053'
20 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
21 | executor.run(0)
22 | expect(executor.evm.stack.length()).toEqual(0)
23 | expect(executor.evm.memory.memory.toString('hex')).toEqual(
24 | '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000099000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
25 | )
26 | })
27 |
28 | it('Test Mstore masking whole word', () => {
29 | const bytecode = '619876604053'
30 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
31 | executor.run(0)
32 | expect(executor.evm.stack.length()).toEqual(0)
33 | expect(executor.evm.memory.memory.toString('hex')).toEqual(
34 | '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000076000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
35 | )
36 | })
37 | })
38 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Mod.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 | import { UintUtils } from '../UintUtils'
7 |
8 | export class Mod implements Executor {
9 | execute(op: Operation, evm: EVM) {
10 | const operand1 = evm.stack.pop()
11 | const operand2 = evm.stack.pop()
12 | if (!operand1 || !operand2) {
13 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
14 | return
15 | }
16 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
17 | if (operand2.value.eq(UintUtils.ZERO)) {
18 | evm.stack.push(Word.createLiteral('00'))
19 | } else {
20 | const result = operand1.value.mod(operand2.value)
21 | evm.stack.push(Word.createLiteral(result.toString(16)))
22 | }
23 | } else {
24 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Msize.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 |
9 | describe('Msize', () => {
10 | let cfgCreator: EthereumCFGCreator
11 | let disassembler: Disassembler
12 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
13 |
14 | beforeEach(() => {
15 | cfgCreator = new EthereumCFGCreator()
16 | disassembler = createEVMDisassembler()
17 | })
18 |
19 | it('Test Msize, empty', () => {
20 | const bytecode = '59'
21 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
22 | executor.run(0)
23 | expect(executor.evm.stack.get(0)).toEqual(Word.createLiteral('00'))
24 | expect(executor.evm.stack.length()).toEqual(1)
25 | })
26 |
27 | it('Test Msize', () => {
28 | const bytecode = '608060405259'
29 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
30 | executor.run(0)
31 | expect(executor.evm.stack.get(0)).toEqual(Word.createLiteral('60'))
32 | expect(executor.evm.stack.length()).toEqual(1)
33 | })
34 |
35 | it('Test Msize 2', () => {
36 | const bytecode = '608060405260ff60605359'
37 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
38 | executor.run(0)
39 | expect(executor.evm.stack.get(0)).toEqual(Word.createLiteral('80'))
40 | expect(executor.evm.stack.length()).toEqual(1)
41 | })
42 |
43 | it('Test Msize 3', () => {
44 | const bytecode = '608060405260ff60605360ee60ff5259'
45 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
46 | executor.run(0)
47 | expect(executor.evm.stack.get(0)).toEqual(Word.createLiteral('120'))
48 | expect(executor.evm.stack.length()).toEqual(1)
49 | })
50 | })
51 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Msize.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 |
6 | export class Msize implements Executor {
7 | execute(op: Operation, evm: EVM) {
8 | evm.stack.push(Word.createLiteral(evm.memory.wordCount().toString(16)))
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Mstore8.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 |
5 | export class MStore8 implements Executor {
6 | execute(op: Operation, evm: EVM) {
7 | const location = evm.stack.pop()
8 | const value = evm.stack.pop()
9 | if (!location || !value) {
10 | return
11 | }
12 | if (!location.isSymbolic && !value.isSymbolic) {
13 | evm.memory.writeByte(location.value.toNumber(), value)
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Mul.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 | import { UintUtils } from '../UintUtils'
7 |
8 | export class Mul implements Executor {
9 | execute(op: Operation, evm: EVM) {
10 | const operand1 = evm.stack.pop()
11 | const operand2 = evm.stack.pop()
12 | if (!operand1 || !operand2) {
13 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
14 | return
15 | }
16 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
17 | const op1Value = operand1.value
18 | const op2Value = operand2.value
19 | let result = op1Value.mul(op2Value).mod(UintUtils.TWO_POW_256)
20 | evm.stack.push(Word.createLiteral(result.toString(16)))
21 | } else {
22 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Mulmod.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Mulmod', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test Mulmod', () => {
21 | const bytecode = '60026003600309'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createLiteral('01'))
25 | expect(executor.evm.stack.length()).toEqual(1)
26 | })
27 |
28 | it('Test Mulmod 2', () => {
29 | const bytecode = '60006003600309'
30 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
31 | executor.run(0)
32 | expect(executor.evm.stack.get(0)).toEqual(Word.createLiteral('00'))
33 | expect(executor.evm.stack.length()).toEqual(1)
34 | })
35 |
36 | it('Test Mulmod Symbolic', () => {
37 | const bytecode = '60203409'
38 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
39 | executor.run(0)
40 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.UNKNOWN))
41 | expect(executor.evm.stack.length()).toEqual(1)
42 | })
43 | })
44 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Mulmod.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 | import { UintUtils } from '../UintUtils'
7 |
8 | export class Mulmod implements Executor {
9 | execute(op: Operation, evm: EVM) {
10 | const operand1 = evm.stack.pop()
11 | const operand2 = evm.stack.pop()
12 | const mod = evm.stack.pop()
13 | if (!operand1 || !operand2 || !mod) {
14 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
15 | return
16 | }
17 | if (!operand1.isSymbolic && !operand2.isSymbolic && !mod.isSymbolic) {
18 | const op1Value = operand1.value
19 | const op2Value = operand2.value
20 | const modValue = mod.value
21 | if (modValue.eq(UintUtils.ZERO)) {
22 | evm.stack.push(Word.createLiteral('00'))
23 | } else {
24 | let result = op1Value.mul(op2Value).mod(modValue)
25 | evm.stack.push(Word.createLiteral(result.toString(16)))
26 | }
27 | } else {
28 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Nop.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 |
5 | export class Nop implements Executor {
6 | execute(op: Operation, evm: EVM) {}
7 | }
8 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Not.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Not implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | const operand1 = evm.stack.pop()
10 | if (!operand1) {
11 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
12 | return
13 | }
14 | if (!operand1.isSymbolic) {
15 | const op1Value = operand1.value
16 | let result = op1Value.notn(256)
17 | evm.stack.push(Word.createLiteral(result.toString(16)))
18 | } else {
19 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Number.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Number', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test Number', () => {
21 | const bytecode = '604043'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.NUMBER))
25 | expect(executor.evm.stack.length()).toEqual(2)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Number.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Number implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.push(Word.createSymbolic(Symbols.NUMBER))
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Or.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Or implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | const operand1 = evm.stack.pop()
10 | const operand2 = evm.stack.pop()
11 | if (!operand1 || !operand2) {
12 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
13 | return
14 | }
15 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
16 | const op1Value = operand1.value
17 | const op2Value = operand2.value
18 | let result = op1Value.or(op2Value)
19 | evm.stack.push(Word.createLiteral(result.toString(16)))
20 | } else {
21 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Origin.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Origin', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test origin', () => {
21 | const bytecode = '604032'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.ORIGIN))
25 | expect(executor.evm.stack.length()).toEqual(2)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Origin.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Origin implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.push(Word.createSymbolic(Symbols.ORIGIN))
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Pc.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Pc', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test Pc', () => {
21 | const bytecode = '58'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createLiteral('00'))
25 | expect(executor.evm.stack.length()).toEqual(1)
26 | })
27 |
28 | it('Test Pc higher offset', () => {
29 | const bytecode = '604061112258'
30 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
31 | executor.run(0)
32 | expect(executor.evm.stack.get(0)).toEqual(Word.createLiteral('05'))
33 | expect(executor.evm.stack.length()).toEqual(3)
34 | })
35 | })
36 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Pc.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 |
6 | export class Pc implements Executor {
7 | execute(op: Operation, evm: EVM) {
8 | evm.stack.push(Word.createLiteral(op.offset.toString(16)))
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Pop.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 |
9 | describe('Pop', () => {
10 | let cfgCreator: EthereumCFGCreator
11 | let disassembler: Disassembler
12 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
13 |
14 | beforeEach(() => {
15 | cfgCreator = new EthereumCFGCreator()
16 | disassembler = createEVMDisassembler()
17 | })
18 |
19 | it('Test POP', () => {
20 | const bytecode = '604050'
21 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
22 | executor.run(0)
23 | expect(executor.evm.stack.length()).toEqual(0)
24 | })
25 |
26 | it('Test PUSH & POP', () => {
27 | const bytecode = '6040608050'
28 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
29 | executor.run(0)
30 | const expectedWord1: Word = Word.createLiteral('40')
31 | expect(executor.evm.stack.stack).toContainEqual(expectedWord1)
32 | expect(executor.evm.stack.length()).toEqual(1)
33 | })
34 | })
35 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Pop.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 |
5 | export class Pop implements Executor {
6 | execute(op: Operation, evm: EVM) {
7 | evm.stack.pop()
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Push.ts:
--------------------------------------------------------------------------------
1 | import 'reflect-metadata'
2 |
3 | import { Executor } from './Executor'
4 | import { EVM } from '../EVM'
5 | import { Word } from '../Word'
6 | import { Operation } from '../../../bytecode/Operation'
7 |
8 | export class Push implements Executor {
9 | execute(op: Operation, evm: EVM) {
10 | const word: Word = {
11 | isSymbolic: false,
12 | value: op.argument
13 | }
14 | evm.stack.push(word)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Return.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 |
5 | export class Return implements Executor {
6 | execute(op: Operation, evm: EVM) {
7 | evm.stack.pop()
8 | evm.stack.pop()
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Returndatacopy.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Returndatacopy', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test Returndatacopy', () => {
21 | const bytecode = '6010602060303e'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.RETURNDATACOPY))
25 | expect(executor.evm.stack.length()).toEqual(1)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Returndatacopy.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Returndatacopy implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.pop()
10 | evm.stack.pop()
11 | evm.stack.pop()
12 | evm.stack.push(Word.createSymbolic(Symbols.RETURNDATACOPY))
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Returndatasize.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Returndatasize', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test Returndatasize', () => {
21 | const bytecode = '60403d'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.RETURNDATASIZE))
25 | expect(executor.evm.stack.length()).toEqual(2)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Returndatasize.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Returndatasize implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.push(Word.createSymbolic(Symbols.RETURNDATASIZE))
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Sar.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 | import { UintUtils } from '../UintUtils';
7 |
8 | export class Sar implements Executor {
9 | execute(op: Operation, evm: EVM) {
10 | const operand1 = evm.stack.pop()
11 | const operand2 = evm.stack.pop()
12 | if (!operand1 || !operand2) {
13 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
14 | return
15 | }
16 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
17 | const op1Value = operand1.value
18 | const op2Value = operand2.value
19 |
20 | let result
21 | const isSigned = op2Value.testn(255)
22 | if(op1Value.gten(256)) {
23 | if (isSigned) {
24 | result = UintUtils.MAX_INTEGER
25 | } else {
26 | result = UintUtils.ZERO
27 | }
28 | evm.stack.push(Word.createLiteral(result.toString(16)))
29 | return
30 | }
31 |
32 | const temp = op2Value.shrn(op1Value.toNumber())
33 | if (isSigned) {
34 | const shifted = 255 - op1Value.toNumber()
35 | const mask = UintUtils.MAX_INTEGER.shrn(shifted).shln(shifted)
36 | result = temp.ior(mask)
37 | } else {
38 | result = temp
39 | }
40 |
41 | evm.stack.push(Word.createLiteral(result.toString(16)))
42 | } else {
43 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Sdiv.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 | import { UintUtils } from '../UintUtils'
7 |
8 | export class Sdiv implements Executor {
9 | execute(op: Operation, evm: EVM) {
10 | const operand1 = evm.stack.pop()
11 | const operand2 = evm.stack.pop()
12 | if (!operand1 || !operand2) {
13 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
14 | return
15 | }
16 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
17 | if (operand2.value.eq(UintUtils.ZERO)) {
18 | evm.stack.push(Word.createLiteral('00'))
19 | } else {
20 | const a = operand1.value.fromTwos(256)
21 | const b = operand2.value.fromTwos(256)
22 | const result = a.div(b).toTwos(256)
23 | evm.stack.push(Word.createLiteral(result.toString(16)))
24 | }
25 | } else {
26 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Selfdestruct.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Selfdestruct', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test Selfdestruct', () => {
21 | const bytecode = '60106020ff'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createLiteral('10'))
25 | expect(executor.evm.stack.length()).toEqual(1)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Selfdestruct.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 |
5 | export class Selfdestruct implements Executor {
6 | execute(op: Operation, evm: EVM) {
7 | evm.stack.pop()
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Sgt.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Sgt implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | const operand1 = evm.stack.pop()
10 | const operand2 = evm.stack.pop()
11 | if (!operand1 || !operand2) {
12 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
13 | return
14 | }
15 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
16 | if (operand1.value.fromTwos(256).gt(operand2.value.fromTwos(256))) {
17 | evm.stack.push(Word.createLiteral('01'))
18 | } else {
19 | evm.stack.push(Word.createLiteral('00'))
20 | }
21 | } else {
22 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Sha3.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 | let BN = require('bn.js')
7 | const utils = require('ethereumjs-util')
8 |
9 | export class Sha3 implements Executor {
10 | execute(op: Operation, evm: EVM) {
11 | const operand1 = evm.stack.pop()
12 | const operand2 = evm.stack.pop()
13 | if (!operand1 || !operand2) {
14 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
15 | return
16 | }
17 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
18 | const offset = operand1.value
19 | const length = operand2.value
20 | if (offset.bitLength() > 53 || length.bitLength() > 53) {
21 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
22 | return
23 | }
24 | const memoryContent = evm.memory.load(offset.toNumber(), length.toNumber())
25 | const result = new BN(utils.keccak256(memoryContent))
26 | evm.stack.push(Word.createLiteral(result.toString(16)))
27 | } else {
28 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Shl.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 | import { UintUtils } from '../UintUtils';
7 |
8 | export class Shl implements Executor {
9 | execute(op: Operation, evm: EVM) {
10 | const operand1 = evm.stack.pop()
11 | const operand2 = evm.stack.pop()
12 | if (!operand1 || !operand2) {
13 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
14 | return
15 | }
16 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
17 | const op1Value = operand1.value
18 | const op2Value = operand2.value
19 | if(op1Value.gten(256)) {
20 | evm.stack.push(Word.createLiteral('00'))
21 | return
22 | }
23 |
24 | let result = op2Value.shln(op1Value.toNumber()).iand(UintUtils.MAX_INTEGER)
25 | evm.stack.push(Word.createLiteral(result.toString(16)))
26 | } else {
27 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Shr.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Shr implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | const operand1 = evm.stack.pop()
10 | const operand2 = evm.stack.pop()
11 | if (!operand1 || !operand2) {
12 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
13 | return
14 | }
15 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
16 | const op1Value = operand1.value
17 | const op2Value = operand2.value
18 | if(op1Value.gten(256)) {
19 | evm.stack.push(Word.createLiteral('00'))
20 | return
21 | }
22 |
23 | let result = op2Value.shrn(op1Value.toNumber())
24 | evm.stack.push(Word.createLiteral(result.toString(16)))
25 | } else {
26 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Signextend.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 | let BN = require('bn.js')
7 |
8 | export class Signextend implements Executor {
9 | execute(op: Operation, evm: EVM) {
10 | const k = evm.stack.pop()
11 | const val = evm.stack.pop()
12 | if (!k || !val) {
13 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
14 | return
15 | }
16 | if (!k.isSymbolic && !val.isSymbolic) {
17 | const valArray = val.value.toArrayLike(Buffer, 'be', 32)
18 | let kValue = k.value
19 | let extend = false
20 |
21 | if (kValue.lten(31)) {
22 | kValue = kValue.toNumber()
23 | if (valArray[31 - kValue] & 0x80) {
24 | extend = true
25 | }
26 |
27 | for (let i = 30 - kValue; i >= 0; i--) {
28 | valArray[i] = extend ? 0xff : 0
29 | }
30 | }
31 | evm.stack.push(Word.createLiteral(new BN(valArray).toString(16)))
32 | } else {
33 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Sload.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Sload', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test Sload', () => {
21 | const bytecode = '6020600155600154'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.length()).toEqual(1)
25 | expect(executor.evm.stack.get(0)).toEqual(Word.createLiteral('20'))
26 | })
27 |
28 | it('Test Sload symbolic', () => {
29 | const bytecode = '34600155600154'
30 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
31 | executor.run(0)
32 | expect(executor.evm.stack.length()).toEqual(1)
33 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.CALLVALUE))
34 | })
35 | })
36 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Sload.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Sload implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | const slot = evm.stack.pop()
10 | if (!slot) {
11 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
12 | return
13 | }
14 | let value = evm.storage.load(slot)
15 | if (!value) {
16 | // This only has sense during CFG creation
17 | value = Word.createSymbolic(Symbols.UNKNOWN)
18 | }
19 | evm.stack.push(value)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Slt.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Slt implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | const operand1 = evm.stack.pop()
10 | const operand2 = evm.stack.pop()
11 | if (!operand1 || !operand2) {
12 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
13 | return
14 | }
15 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
16 | if (operand1.value.fromTwos(256).lt(operand2.value.fromTwos(256))) {
17 | evm.stack.push(Word.createLiteral('01'))
18 | } else {
19 | evm.stack.push(Word.createLiteral('00'))
20 | }
21 | } else {
22 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Smod.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 | import { UintUtils } from '../UintUtils'
7 |
8 | export class Smod implements Executor {
9 | execute(op: Operation, evm: EVM) {
10 | const operand1 = evm.stack.pop()
11 | const operand2 = evm.stack.pop()
12 | if (!operand1 || !operand2) {
13 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
14 | return
15 | }
16 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
17 | if (operand2.value.eq(UintUtils.ZERO)) {
18 | evm.stack.push(Word.createLiteral('00'))
19 | } else {
20 | const a = operand1.value.fromTwos(256)
21 | const b = operand2.value.fromTwos(256)
22 | let result = a.abs().mod(b.abs())
23 | if (a.isNeg()) {
24 | result = result.ineg()
25 | }
26 | evm.stack.push(Word.createLiteral(result.toTwos(256).toString(16)))
27 | }
28 | } else {
29 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Sstore.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 |
5 | export class Sstore implements Executor {
6 | execute(op: Operation, evm: EVM) {
7 | const slot = evm.stack.pop()
8 | const value = evm.stack.pop()
9 | evm.storage.store(slot, value)
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Staticcall.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 |
10 | describe('Staticcall', () => {
11 | let cfgCreator: EthereumCFGCreator
12 | let disassembler: Disassembler
13 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
14 |
15 | beforeEach(() => {
16 | cfgCreator = new EthereumCFGCreator()
17 | disassembler = createEVMDisassembler()
18 | })
19 |
20 | it('Test Staticcall', () => {
21 | const bytecode = '601060206030604060506060fa'
22 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
23 | executor.run(0)
24 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.STATICCALL))
25 | expect(executor.evm.stack.length()).toEqual(1)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Staticcall.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Staticcall implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.pop()
10 | evm.stack.pop()
11 | evm.stack.pop()
12 | evm.stack.pop()
13 | evm.stack.pop()
14 | evm.stack.pop()
15 | evm.stack.push(Word.createSymbolic(Symbols.STATICCALL))
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Sub.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Sub implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | const operand1 = evm.stack.pop()
10 | const operand2 = evm.stack.pop()
11 | if (!operand1 || !operand2) {
12 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
13 | return
14 | }
15 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
16 | const op1Value = operand1.value
17 | const op2Value = operand2.value
18 | let result = op1Value.sub(op2Value).toTwos(256)
19 | evm.stack.push(Word.createLiteral(result.toString(16)))
20 | } else {
21 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Swap.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 |
5 | export class Swap implements Executor {
6 | execute(op: Operation, evm: EVM) {
7 | const index = parseInt(op.opcode.name.slice(4))
8 | const stack0 = evm.stack.get(0)
9 | const stackIndex = evm.stack.get(index)
10 | evm.stack.put(0, stackIndex)
11 | evm.stack.put(index, stack0)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/TestUtils.ts:
--------------------------------------------------------------------------------
1 | import { Disassembler } from '../../../bytecode/Disassembler'
2 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
3 | import { OpcodeExecutor } from './OpcodeExecutor'
4 | import { Operation } from '../../../bytecode/Operation'
5 | import { CFGBlocks } from '../../../cfg/CFGBlocks'
6 | import { EVMExecutor } from '../EVMExecutor'
7 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler';
8 | import { ContractService } from '../../../service/service/ContractService';
9 | import { Solc } from '../../../service/service/Solc';
10 |
11 | export function createExecutor(
12 | disassembler: Disassembler,
13 | bytecode: string,
14 | cfgCreator: EthereumCFGCreator,
15 | opcodeExecutor: OpcodeExecutor
16 | ) {
17 | const ops: Operation[] = disassembler.disassembleBytecode(bytecode)
18 | const blocks: CFGBlocks = cfgCreator.divideBlocks(ops)
19 | return new EVMExecutor(blocks, opcodeExecutor)
20 | }
21 |
22 | export function createEVMDisassembler(): EVMDisassembler {
23 | return new EVMDisassembler(new ContractService(new Solc()), new Solc())
24 | }
25 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Timestamp.test.ts:
--------------------------------------------------------------------------------
1 | import { createExecutor, createEVMDisassembler } from './TestUtils'
2 | import { EVMExecutor } from '../EVMExecutor'
3 | import { EthereumCFGCreator } from '../../../cfg/EthereumCFGCreator'
4 | import { Disassembler } from '../../../bytecode/Disassembler'
5 | import { OpcodeExecutor } from './OpcodeExecutor'
6 | import { EVMDisassembler } from '../../../bytecode/EVMDisassembler'
7 | import { Word } from '../Word'
8 | import { Symbols } from '../Symbols'
9 | import { ContractService } from '../../../service/service/ContractService';
10 |
11 | describe('Timestamp', () => {
12 | let cfgCreator: EthereumCFGCreator
13 | let disassembler: Disassembler
14 | let opcodeExecutor: OpcodeExecutor = new OpcodeExecutor()
15 |
16 | beforeEach(() => {
17 | cfgCreator = new EthereumCFGCreator()
18 | disassembler = createEVMDisassembler()
19 | })
20 |
21 | it('Test Timestamp', () => {
22 | const bytecode = '604042'
23 | const executor: EVMExecutor = createExecutor(disassembler, bytecode, cfgCreator, opcodeExecutor)
24 | executor.run(0)
25 | expect(executor.evm.stack.get(0)).toEqual(Word.createSymbolic(Symbols.TIMESTAMP))
26 | expect(executor.evm.stack.length()).toEqual(2)
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Timestamp.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Timestamp implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | evm.stack.push(Word.createSymbolic(Symbols.TIMESTAMP))
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/symbolic/evm/exec/Xor.ts:
--------------------------------------------------------------------------------
1 | import { Executor } from './Executor'
2 | import { EVM } from '../EVM'
3 | import { Operation } from '../../../bytecode/Operation'
4 | import { Word } from '../Word'
5 | import { Symbols } from '../Symbols'
6 |
7 | export class Xor implements Executor {
8 | execute(op: Operation, evm: EVM) {
9 | const operand1 = evm.stack.pop()
10 | const operand2 = evm.stack.pop()
11 | if (!operand1 || !operand2) {
12 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
13 | return
14 | }
15 | if (!operand1.isSymbolic && !operand2.isSymbolic) {
16 | const op1Value = operand1.value
17 | const op2Value = operand2.value
18 | let result = op1Value.xor(op2Value)
19 | evm.stack.push(Word.createLiteral(result.toString(16)))
20 | } else {
21 | evm.stack.push(Word.createSymbolic(Symbols.UNKNOWN))
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/client/_redux/Constants.js:
--------------------------------------------------------------------------------
1 | export const SELECT_EDITOR_LINES = 'SELECT_EDITOR_LINES';
2 | export const SHOW_EVM_STATE = 'SHOW_EVM_STATE';
3 | export const HIDE_EVM_STATE = 'HIDE_EVM_STATE';
4 | export const SHOW_LOADING_MESSAGE = 'SHOW_LOADING_MESSAGE';
5 | export const HIDE_LOADING_MESSAGE = 'HIDE_LOADING_MESSAGE';
6 | export const SHOW_ERROR_MESSAGE = 'SHOW_ERROR_MESSAGE';
7 | export const HIDE_ERROR_MESSAGE = 'HIDE_ERROR_MESSAGE';
8 | export const GET_ERROR_MESSAGE = 'GET_ERROR_MESSAGE';
9 | export const GET_HOST = 'GET_HOST';
10 | export const GET_PROTOCOL = 'GET_PROTOCOL';
11 | export const GET_USERNAME = 'GET_USERNAME';
12 | export const GET_PASSWORD = 'GET_PASSWORD';
13 | export const GET_VERSION_NUM = 'GET_VERSION_NUM';
14 | export const ADD_VERSION = 'ADD_VERSION';
15 | export const VERSIONS_FETCHED = 'VERSIONS_FETCHED';
16 | export const TOGGLE_ERROR_MESSAGE = 'TOGGLE_ERROR_MESSAGE';
17 | export const TOGGLE_LOADING_MESSAGE = 'TOGGLE_LOADING_MESSAGE';
18 | export const TOGGLE_EVM_STATE = 'TOGGLE_EVM_STATE';
19 | export const GET_PARAMETER = 'GET_PARAMETER';
20 | export const FETCH_VERSIONS_SUCCESS = 'FETCH_VERSIONS_SUCCESS';
21 | export const FETCH_CONTRACTS_SUCCESS = 'FETCH_CONTRACTS_SUCCESS';
22 | export const FETCH_CONTRACTS = 'FETCH_CONTRACTS';
23 | export const FETCH_SOLC_VERSIONS = 'FETCH_SOLC_VERSIONS';
24 | export const POST_VERSION = 'POST_VERSION';
25 | export const FETCH_TRANSACTION_DEBUGGER = 'FETCH_TRANSACTION_DEBUGGER';
26 | export const FETCH_STORAGE = 'FETCH_STORAGE';
27 | export const FETCH_GRAPH = 'FETCH_GRAPH';
28 | export const FETCH_DISASSEMBLER = 'FETCH_DISASSEMBLER';
29 | export const DEBUGGER_FETCH_SUCCESS = 'DEBUGGER_FETCH_SUCCESS';
30 | export const STORAGE_FETCH_SUCCESS = 'STORAGE_FETCH_SUCCESS';
31 | export const GRAPH_FETCH_SUCCESS = 'GRAPH_FETCH_SUCCESS';
32 | export const DISASSEMBLER_FETCH_SUCCESS = 'DISASSEMBLER_FETCH_SUCCESS';
33 |
--------------------------------------------------------------------------------
/src/client/_redux/Reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 |
3 | import { selectLines, selectEVMState, loadingMessage, errorMessage, displayVersionNumber, versions, contracts, tools } from './reducers';
4 |
5 | export default combineReducers({
6 | selectLines,
7 | selectEVMState,
8 | loadingMessage,
9 | errorMessage,
10 | displayVersionNumber,
11 | versions,
12 | contracts,
13 | tools
14 | });
--------------------------------------------------------------------------------
/src/client/_redux/Store.js:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware } from 'redux';
2 | import createSagaMiddleware from 'redux-saga';
3 | import { composeWithDevTools } from 'redux-devtools-extension';
4 | import thunk from 'redux-thunk';
5 | import logger from 'redux-logger';
6 |
7 | import rootReducer from './reducers';
8 | import rootSaga from './sagas/sagas';
9 |
10 | const sagaMiddleware = createSagaMiddleware();
11 |
12 | const store = createStore(
13 | rootReducer,
14 | composeWithDevTools(applyMiddleware(sagaMiddleware, thunk)));
15 |
16 | sagaMiddleware.run(rootSaga);
17 |
18 | export default store;
19 |
20 |
--------------------------------------------------------------------------------
/src/client/_redux/sagas/contractsSaga.js:
--------------------------------------------------------------------------------
1 | import * as selectors from '../selectors';
2 |
3 | import { select, put, takeEvery, call } from 'redux-saga/effects';
4 | import { baseUrl, fetchData } from './utils';
5 |
6 | export function* contractsWatcher() {
7 | yield takeEvery('FETCH_CONTRACTS', fetchContracts)
8 | }
9 |
10 | export function* fetchContracts() {
11 | const parameter = yield select(selectors.getParameter);
12 | const endpoint = `${baseUrl}files/${encodeURIComponent(parameter) || ' '}?extension=sol`;
13 | try {
14 | yield put({ type: 'TOGGLE_LOADING_MESSAGE', payload: { isLoadingMessageOn: true, message: 'Loading...' } })
15 | const contracts = yield call(fetchData, endpoint);
16 | yield put({ type: 'FETCH_CONTRACTS_SUCCESS', payload: { contracts: contracts } });
17 | yield put({ type: 'TOGGLE_LOADING_MESSAGE', payload: { isLoadingMessageOn: false } })
18 | }
19 | catch(error) {
20 | yield put({ type: 'TOGGLE_ERROR_MESSAGE', payload: { isErrorMessageOn: true, message: error.message } });
21 | yield put({ type: 'TOGGLE_LOADING_MESSAGE', payload: { isLoadingMessageOn: false } });
22 | }
23 | }
--------------------------------------------------------------------------------
/src/client/_redux/sagas/sagas.js:
--------------------------------------------------------------------------------
1 | import { all } from 'redux-saga/effects';
2 |
3 | import { contractsWatcher } from './contractsSaga';
4 | import { versionsWatcher } from './versionsSaga';
5 | import { toolsWatcher } from './toolsSaga';
6 |
7 | export default function* rootSaga() {
8 | yield all([
9 | versionsWatcher(),
10 | contractsWatcher(),
11 | toolsWatcher()
12 | ])
13 | }
--------------------------------------------------------------------------------
/src/client/_redux/sagas/toolsSaga.test.js:
--------------------------------------------------------------------------------
1 | import { call, put } from 'redux-saga/effects';
2 | import { baseUrl, fetchData, postData } from './utils';
3 |
4 | import { fetchTransactionDebugger, fetchStorage, fetchGraph, fetchDisassembler } from './toolsSaga';
5 |
6 | describe.skip('should fetch data with the right parameters', () => {
7 | const debuggerGen = fetchTransactionDebugger();
8 | const storageGen = fetchStorage();
9 | const graphGen = fetchGraph();
10 | const disassemblerGen = fetchDisassembler();
11 |
12 | const headers = {
13 | method: 'POST',
14 | body: JSON.stringify({ request: body }),
15 | headers:{
16 | 'Content-Type': 'application/json'
17 | }
18 | }
19 |
20 | it('should fetch transaction debugger', () => {
21 | const response = call(postData, url, )
22 | });
23 |
24 | it('should fetch disassembler', () => {
25 |
26 | });
27 |
28 | it('should fetch control flowg raph', () => {
29 |
30 | });
31 |
32 | it('should fetch storagr', () => {
33 |
34 | });
35 | })
--------------------------------------------------------------------------------
/src/client/_redux/sagas/utils.js:
--------------------------------------------------------------------------------
1 | export const baseUrl = 'http://localhost:9090/';
2 |
3 | export const fetchData = (endpoint) => fetch(endpoint).then(res => res.json())
4 |
5 | export const postData = (endpoint, headers) => fetch(endpoint, headers).then(response => {
6 | if (response.ok) {
7 | return response;
8 | } else {
9 | var error = new Error('Error ' + response.status + ': ' + response.statusText);
10 |
11 | error.response = response;
12 | throw error;
13 | }
14 | },
15 | error => {
16 | var errmess = new Error(error.message);
17 | throw errmess;
18 | })
19 | .then(response => response.json())
--------------------------------------------------------------------------------
/src/client/_redux/sagas/versionsSaga.js:
--------------------------------------------------------------------------------
1 | import { put, takeEvery, takeLatest, call } from 'redux-saga/effects';
2 | import { baseUrl, fetchData, postData } from './utils';
3 |
4 | export function* versionsWatcher() {
5 | yield takeEvery('FETCH_SOLC_VERSIONS', fetchSolcVersions);
6 | yield takeLatest('POST_VERSION', postVersion);
7 | }
8 |
9 | export function* fetchSolcVersions() {
10 | const endpoint = `${baseUrl}solc/list`;
11 | try {
12 | yield put({ type: 'TOGGLE_LOADING_MESSAGE', payload: { isLoadingMessageOn: true, message: 'Loading...' } })
13 | const versions = yield call(fetchData, endpoint);
14 | yield put({ type: 'FETCH_VERSIONS_SUCCESS', payload: { versions: versions } });
15 | yield put({ type: 'TOGGLE_LOADING_MESSAGE', payload: { isLoadingMessageOn: false } })
16 | }
17 | catch(error) {
18 | yield put({ type: 'TOGGLE_ERROR_MESSAGE', payload: { isErrorMessageOn: true, message: error.message } });
19 | yield put({ type: 'TOGGLE_LOADING_MESSAGE', payload: { isLoadingMessageOn: false } });
20 | }
21 | }
22 |
23 | export function* postVersion(action) {
24 | const endpoint = `${baseUrl}solc`;
25 |
26 | try {
27 | yield put({ type: 'TOGGLE_LOADING_MESSAGE', payload: { isLoadingMessageOn: true, message: 'Loading... This might take a while' } })
28 | const headers = {
29 | method: 'POST',
30 | body: JSON.stringify(action.payload.version),
31 | headers: {
32 | 'Content-Type': 'application/json'
33 | },
34 | credentials: 'same-origin'
35 | }
36 |
37 | const version = yield call(postData, endpoint, headers);
38 | yield put({ type: 'ADD_VERSION', payload: { version: version } });
39 | yield put({ type: 'TOGGLE_LOADING_MESSAGE', payload: { isLoadingMessageOn: false } })
40 | } catch(error) {
41 | yield put({ type: 'TOGGLE_ERROR_MESSAGE', payload: { isErrorMessageOn: true, message: error.message } });
42 | yield put({ type: 'TOGGLE_LOADING_MESSAGE', payload: { isLoadingMessageOn: false } });
43 | }
44 | }
--------------------------------------------------------------------------------
/src/client/_redux/selectors.js:
--------------------------------------------------------------------------------
1 | export const getParameter = state => {
2 | return state.contracts.parameter;
3 | }
4 |
5 | export const getVersions = state => {
6 | return state.versions.versionsList;
7 | }
8 |
9 | export const getPostedVersions = state => {
10 | return state.versions.postedVersions
11 | }
12 |
13 | export const getContracts = state => {
14 | return state.contracts.contracts
15 | }
16 |
17 | export const getTransactionDebugger = state => {
18 | return state.tools.transactionDebugger;
19 | }
20 |
21 | export const getDisassembler = state => {
22 | return state.tools.disassembler;
23 | }
24 |
25 | export const getGraph = state => {
26 | return state.tools.graph;
27 | }
28 |
29 | export const getStorage = state => {
30 | return state.tools.storage;
31 | }
32 |
33 | export const getTabs = state => {
34 | return state.tools.tabs
35 | }
36 |
37 | export const getHasToolFetched = state => {
38 | return state.tools.hasFetched
39 | }
40 |
41 | export const getToolIsLoading = state => {
42 | return state.tools.isLoading
43 | }
--------------------------------------------------------------------------------
/src/client/components/Accordion/Accordion.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import styles from './Accordion.scss';
4 |
5 | const Accordion = ({ children }) => (
6 |
7 | {children}
8 |
9 | )
10 |
11 | Accordion.displayName = 'Accordion';
12 |
13 | export default Accordion;
--------------------------------------------------------------------------------
/src/client/components/Accordion/Accordion.scss:
--------------------------------------------------------------------------------
1 | .accordion {
2 | min-height: 100%;
3 | padding: 30px;
4 | text-align: center;
5 | }
--------------------------------------------------------------------------------
/src/client/components/Accordion/AccordionSection/AccordionSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import classnames from 'classnames/bind';
4 |
5 | import styles from './AccordionSection.scss';
6 |
7 | const cx = classnames.bind(styles);
8 |
9 | class AccordionSection extends React.Component {
10 | constructor(props) {
11 | super(props);
12 |
13 | this.state = {
14 | expanded: false,
15 | }
16 | }
17 |
18 | handleClick() {
19 | this.setState(prevState => ({
20 | expanded: !prevState.expanded,
21 | }))
22 | }
23 |
24 | render() {
25 |
26 | const { expanded } = this.state;
27 | const { title, content, children } = this.props;
28 |
29 | const titleClasses = cx({
30 | 'accordion-section__title': true,
31 | 'accordion-section__title--expanded': !!expanded,
32 | });
33 |
34 | const contentClasses = cx({
35 | 'accordion-section__content': true,
36 | 'accordion-section__content--expanded': !!expanded,
37 | })
38 |
39 | return (
40 |
41 |
this.handleClick()}>
42 | {title}
43 |
44 |
45 |
46 | {children}
47 |
48 |
49 |
50 | );
51 | }
52 | }
53 |
54 | AccordionSection.displayName = 'AccordionSection';
55 |
56 | export default AccordionSection;
--------------------------------------------------------------------------------
/src/client/components/Accordion/AccordionSection/AccordionSection.scss:
--------------------------------------------------------------------------------
1 | $parent: '.accordion-section__content';
2 |
3 | .accordion-section {
4 | margin: 0 auto;
5 | width: 100%;
6 |
7 | &__title {
8 | padding: 30px 30px;
9 | cursor: pointer;
10 | transform: translate3d(0, 0, 0);
11 | color: $color-green;
12 | position: relative;
13 | font-size: 20px;
14 | background: $color-grey;
15 | margin-bottom: -1px;
16 | border-bottom: 1px solid $color-green;
17 | text-align: left;
18 | text-transform: uppercase;
19 | transition: color 0.3s, background 0.3s;
20 |
21 | &::after {
22 | content: "+";
23 | font-size: 18px;
24 | color: $color-green;
25 | transition: transform .5s ease-in-out, color 0.5s;
26 | position: absolute;
27 | right: 30px;
28 | font-family: monospace;
29 | }
30 |
31 | &--expanded {
32 | transition: background .5s;
33 | background: $color-green;
34 | color: $color-grey;
35 |
36 | &::after {
37 | content: "-";
38 | transform: rotate(-360deg);
39 | color: $color-grey;
40 | }
41 | }
42 | }
43 |
44 | &__content {
45 | overflow: hidden;
46 | max-height: 0;
47 | transition: max-height .5s;
48 | margin: 0;
49 | padding: 0 30px;
50 | border: solid 1px $color-grey;
51 | border-top: 0;
52 | background: $color-grey;
53 |
54 | &__item {
55 | padding: 30px 0;
56 | margin: 0;
57 | opacity: 0;
58 | transition: opacity .5s;
59 | }
60 |
61 | &--expanded {
62 | max-height: 500px;
63 | overflow: auto;
64 |
65 | #{$parent}__item {
66 | opacity: 1;
67 | }
68 | }
69 | }
70 |
71 | &:after {
72 | width: 100%;
73 | height: 10px;
74 | display: block;
75 | background: $color-green;
76 | content: '';
77 | }
78 | }
79 |
80 |
--------------------------------------------------------------------------------
/src/client/components/ControlFlowGraph/ControlFlowGraph.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Graph from '../Graph/Graph';
4 |
5 | import styles from './ControlFlowGraph.scss';
6 |
7 | const ControlFlowGraphRuntime = ({ contractName, contractPath, graphResponse, type }) => {
8 | return (
9 |
10 |
17 |
18 | );
19 | }
20 |
21 | ControlFlowGraphRuntime.displayName = 'ControlFlowGraphRuntime';
22 |
23 | export default ControlFlowGraphRuntime;
24 |
--------------------------------------------------------------------------------
/src/client/components/ControlFlowGraph/ControlFlowGraph.scss:
--------------------------------------------------------------------------------
1 | .control-flow-graph {
2 | position: relative;
3 |
4 | &__body {
5 | width: 100%;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/client/components/Disassembler/Bytecode/Bytecode.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import styles from './Bytecode.scss';
4 |
5 | const Bytecode = ({ bytecode }) => (
6 |
9 | )
10 |
11 | Bytecode.displayName = 'ByteCode';
12 |
13 | export default Bytecode;
--------------------------------------------------------------------------------
/src/client/components/Disassembler/Bytecode/Bytecode.scss:
--------------------------------------------------------------------------------
1 | .bytecode {
2 |
3 | p {
4 | word-break: break-all;
5 | }
6 | }
--------------------------------------------------------------------------------
/src/client/components/Disassembler/Disassembler.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Accordion from '../Accordion/Accordion';
4 | import AccordionSection from '../Accordion/AccordionSection/AccordionSection';
5 | import Operations from './Operations/Operations';
6 | import Bytecode from './Bytecode/Bytecode';
7 |
8 | import styles from './Disassembler.scss';
9 |
10 | const Disassembler = ({ disassemblerResponse }) => {
11 |
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | );
27 |
28 | }
29 |
30 | Disassembler.displayName = 'Disassembler';
31 |
32 | export default Disassembler;
33 |
--------------------------------------------------------------------------------
/src/client/components/Disassembler/Disassembler.scss:
--------------------------------------------------------------------------------
1 | .disassembler {
2 | position: relative;
3 | color: #fff;
4 |
5 | &__body {
6 | width: 100%;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/client/components/Disassembler/Operations/Operations.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import styles from './Operations.scss'
4 |
5 | const Operations = ({ items }) => {
6 | return (
7 |
8 |
9 |
10 | [Offset]
11 |
12 |
13 | [Opcode hex]
14 |
15 |
16 | [Opcode]
17 |
18 |
19 | [Argument]
20 |
21 |
22 | {items.map((item, i) => {
23 | return (
24 |
25 |
26 | {`0x`}{item.offset.toString(16)}
27 |
28 |
29 | {`0x`}{item.opcode.opcode.toString(16)}
30 |
31 |
32 | {item.opcode.name}
33 |
34 | { item.opcode.parameters > 0 &&
35 |
36 | {`0x`}{item.argument}
37 |
38 | }
39 |
40 | )
41 | })}
42 |
43 | )
44 | }
45 |
46 | Operations.displayName = 'Operations';
47 |
48 | export default Operations;
--------------------------------------------------------------------------------
/src/client/components/Disassembler/Operations/Operations.scss:
--------------------------------------------------------------------------------
1 | .operations {
2 | display: flex;
3 | justify-content: flex-start;
4 |
5 | &__item {
6 | flex: 0 0 170px;
7 | text-align: left;
8 |
9 | span {
10 | word-break: break-all;
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/src/client/components/Dropdown/Dropdown.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames/bind';
3 |
4 | import styles from './Dropdown.scss';
5 |
6 | const cx = classnames.bind(styles);
7 |
8 | const Dropdown = ({ active, children, versions, settings, onClick }) => {
9 |
10 | const dropdownClasses = cx({
11 | 'dropdown': true,
12 | 'dropdown--active': !!active,
13 | 'dropdown--versions': !!versions,
14 | 'dropdown--settings': !!settings
15 | });
16 |
17 | return (
18 |
19 | { children }
20 |
21 | )
22 | }
23 |
24 | export default Dropdown;
--------------------------------------------------------------------------------
/src/client/components/Dropdown/Dropdown.scss:
--------------------------------------------------------------------------------
1 | .dropdown {
2 | width: 100%;
3 | position: absolute;
4 | right: 0;
5 | top: -262px;
6 | background: $color-dark-grey;
7 | z-index: -3;
8 | opacity: 0;
9 | padding: 10px 10px 20px 10px;
10 | transition: top 0.3s, opacity 0.4s;
11 |
12 | &--settings {
13 | width: 330px;
14 | }
15 |
16 | &--active {
17 | opacity: 1;
18 | top: 100%;
19 | }
20 | }
--------------------------------------------------------------------------------
/src/client/components/EVMState/EVMState.scss:
--------------------------------------------------------------------------------
1 | $parent: '.evm-state__item';
2 |
3 | .evm-state {
4 | padding: 10px;
5 |
6 | &__item {
7 | padding: 10px 0;
8 |
9 | &:first-of-type {
10 | display: flex;
11 |
12 | #{$parent}__content {
13 | margin: 0 0 0 5px;
14 | }
15 | }
16 |
17 | &__title {
18 |
19 | h4 {
20 | color: $color-light-grey;
21 | }
22 | }
23 |
24 | &__content {
25 | margin: 5px 0 0 0;
26 |
27 | span {
28 | color: $color-green;
29 | }
30 |
31 | &__row {
32 | padding: 2px;
33 | margin: 3px 0;
34 | border-bottom: 0.5px solid $color-light-grey;
35 |
36 | span {
37 | font-size: 11px;
38 | word-break: break-all;
39 | }
40 |
41 | &__key {
42 | position: relative;
43 | padding: 0 0 2px 0;
44 | border-bottom: 0.5px dotted $color-green;
45 | }
46 |
47 | &__value {
48 | padding: 5px 0 0 0;
49 | }
50 |
51 | &__key, &__value {
52 |
53 | .label {
54 | position: relative;
55 | width: 17px;
56 | height: 17px;
57 | border-radius: 50%;
58 | color: $color-light-grey;
59 | border: 1px solid $color-light-grey;
60 | margin: 0 5px 0 0;
61 |
62 | span {
63 | position: absolute;
64 | top: 50%;
65 | left: 50%;
66 | transform: translate(-50%, -50%);
67 | }
68 | }
69 | }
70 | }
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/src/client/components/Editor/Editor.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import CodeEditor from './AceEditor/AceEditor';
4 |
5 |
6 | const Editor = ({ code, path, name, index, changeCode }) => {
7 | return (
8 |
20 |
21 | );
22 | }
23 |
24 | let timeout = null
25 |
26 | const onChange = (code, path, name, event) => {
27 |
28 | clearTimeout(timeout)
29 |
30 | timeout = setTimeout(() => {
31 | fetch(`http://localhost:9090/files`,{
32 | body: JSON.stringify({
33 | path: path,
34 | name: name,
35 | content: code
36 | }),
37 | method: 'POST',
38 | headers: {
39 | 'Content-Type': 'application/json'
40 | }
41 | })
42 | }, 1000)
43 | }
44 |
45 | export default Editor;
46 |
--------------------------------------------------------------------------------
/src/client/components/Form/Form.scss:
--------------------------------------------------------------------------------
1 | .form {
2 | display: flex;
3 | justify-content: space-between;
4 | align-items: center;
5 |
6 | &__inputs {
7 | flex: 1 1 auto;
8 |
9 | &__item {
10 | padding: 5px 10px;
11 |
12 | input {
13 | width: 100%;
14 | padding: 10px 0;
15 | font-size: 14px;
16 | background: transparent;
17 | color: $color-light-grey;
18 | border-bottom: 1px dotted $color-light-grey;
19 | transition: border-color 0.2s;
20 |
21 | &:-webkit-autofill,
22 | &:-webkit-autofill:hover,
23 | &:-webkit-autofill:focus {
24 | border-bottom: 1px dotted $color-green;
25 | -webkit-text-fill-color: $color-light-grey;
26 | box-shadow: 0 0 0px 1000px $color-dark-grey inset;
27 | transition: background-color 5000s ease-in-out 0s;
28 | }
29 |
30 | &:focus {
31 | border-color: $color-green;
32 | outline: 0 none;
33 | }
34 | }
35 | }
36 | }
37 |
38 | button {
39 | padding: 10px;
40 | border-radius: 5px;
41 | background: transparent;
42 | border: 1px solid $color-light-grey;
43 | cursor: pointer;
44 | transition: border-color 0.2s;
45 |
46 | &:last-of-type {
47 | margin-left: 10px;
48 | }
49 |
50 | &:focus {
51 | border-color: $color-green;
52 | outline: 0 none;
53 |
54 | span {
55 | color: $color-green;
56 | }
57 | }
58 |
59 | &:hover {
60 | border-color: $color-green;
61 |
62 | span {
63 | color: $color-green;
64 | }
65 | }
66 |
67 | span {
68 | color: $color-light-grey;
69 | font-size: 14px;
70 | transition: color 0.2s;
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/src/client/components/Graph/Graph.scss:
--------------------------------------------------------------------------------
1 | .graph-container {
2 | max-height: 1000px;
3 | overflow: hidden;
4 | }
5 |
6 | .graph-container a:hover {
7 | cursor: pointer;
8 | }
9 |
--------------------------------------------------------------------------------
/src/client/components/Hamburger/Hamburger.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import styles from './Hamburger.scss';
4 |
5 | import classnames from 'classnames/bind';
6 |
7 | const cx = classnames.bind(styles);
8 |
9 | const Hamburger = ({ clicked, onIconClick }) => {
10 |
11 | const topLayerClasses = cx({
12 | 'hamburger__top-layer': true,
13 | 'hamburger__top-layer--active': !!clicked,
14 | });
15 |
16 | const middleLayerClasses = cx({
17 | 'hamburger__middle-layer': true,
18 | 'hamburger__middle-layer--active': !!clicked,
19 | });
20 |
21 | const bottomLayerClasses = cx({
22 | 'hamburger__bottom-layer': true,
23 | 'hamburger__bottom-layer--active': !!clicked,
24 | });
25 |
26 | return (
27 |
32 | )
33 | }
34 |
35 | Hamburger.displayName = 'Hamburger';
36 |
37 | export default Hamburger;
--------------------------------------------------------------------------------
/src/client/components/Hamburger/Hamburger.scss:
--------------------------------------------------------------------------------
1 | .hamburger {
2 | cursor: pointer;
3 |
4 |
5 | &__top-layer, &__middle-layer, &__bottom-layer {
6 | margin: 4px 0;
7 | width: 27px;
8 | height: 3px;
9 | background: $color-green;
10 | border-radius: 2px;
11 | opacity: 1;
12 | transform: translate(0, 0);
13 | transition: transform 0.3s;
14 | }
15 |
16 | &:hover & {
17 |
18 | &__top-layer {
19 | transform: translate(0, -3px);
20 | }
21 |
22 | &__bottom-layer {
23 | transform: translate(0, 3px);
24 | }
25 | }
26 | }
27 |
28 | //State
29 | .hamburger {
30 |
31 | &__top-layer--active {
32 | transform: translate(0, -3px) rotate(45deg);
33 | transform-origin: bottom left;
34 | }
35 |
36 | &__middle-layer--active {
37 | opacity: 0;
38 | }
39 |
40 | &__bottom-layer--active {
41 | transform: translate(0, 3px) rotate(-45deg);
42 | transform-origin: top left;
43 | }
44 |
45 | &:hover & {
46 |
47 | &__top-layer--active {
48 | transform: translate(0, -3px) rotate(45deg);
49 | transform-origin: bottom left;
50 | }
51 |
52 | &__middle-layer--active {
53 | opacity: 0;
54 | }
55 |
56 | &__bottom-layer--active {
57 | transform: translate(0, 3px) rotate(-45deg);
58 | transform-origin: top left;
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/src/client/components/Icon/Icon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import SVGInline from 'react-svg-inline';
4 |
5 | import CircleLeft from './SVG/circle-left.svg';
6 | import CircleRight from './SVG/circle-right.svg';
7 | import Cross from './SVG/cross.svg';
8 | import Menu from './SVG/menu.svg';
9 | import Spinner from './SVG/spinner.svg';
10 | import Cogs from './SVG/cogs.svg';
11 |
12 | import styles from './Icon.scss';
13 |
14 | const Icon = ({ iconName, onClick }) => {
15 |
16 | const icons = { CircleLeft, CircleRight, Menu, Cross, Spinner, Cogs };
17 |
18 | return (
19 |
20 |
21 |
22 | );
23 | }
24 |
25 | Icon.displayName = 'Icon';
26 |
27 | export default Icon;
--------------------------------------------------------------------------------
/src/client/components/Icon/Icon.scss:
--------------------------------------------------------------------------------
1 | .icon {
2 |
3 | svg {
4 | display: block;
5 | width: 1.5em;
6 | height: 1.5em;
7 | stroke-width: 0;
8 | stroke: $color-green;
9 | fill: $color-green;
10 | pointer-events: none;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/client/components/Icon/SVG/cancel-circle.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/client/components/Icon/SVG/circle-left.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/client/components/Icon/SVG/circle-right.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/client/components/Icon/SVG/cogs.svg:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/src/client/components/Icon/SVG/cross.svg:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/src/client/components/Icon/SVG/menu.svg:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/src/client/components/Icon/SVG/spinner.svg:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/src/client/components/Main/Main.scss:
--------------------------------------------------------------------------------
1 | .main-comp {
2 | display: flex;
3 | width: 100%;
4 | padding: 34px 0 20px 0;
5 | background: $color-black;
6 |
7 | &__left {
8 | width: 40%;
9 | position: relative;
10 | padding-top: 30px;
11 | padding-left: 10px;
12 |
13 | &__control {
14 | position: absolute;
15 | top: -14px;
16 | left: 10px;
17 | z-index: 4;
18 |
19 | button {
20 | background: transparent;
21 | outline: transparent;
22 | cursor: pointer;
23 | }
24 | }
25 |
26 | &__side-bar {
27 | position: absolute;
28 | top: 30px;
29 | left: -380px;
30 | transition: left 0.2s;
31 | pointer-events: none;
32 | }
33 | }
34 |
35 | &__right {
36 | flex: 1 1 auto;
37 | width: 100%;
38 | height: 100%;
39 | padding: 0 20px;
40 | overflow-x: auto;
41 | }
42 | }
43 |
44 | //State
45 | .main-comp {
46 | &__left {
47 |
48 | &__side-bar {
49 |
50 | &--open {
51 | left: 0;
52 | z-index: 6;
53 | pointer-events: auto;
54 | }
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/src/client/components/MessageComp/MessageComp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 |
4 | import * as actions from '../../_redux/actions.js';
5 |
6 | import Icon from '../Icon/Icon';
7 |
8 | import styles from './MessageComp.scss';
9 |
10 | const mapDispatchToProps = {
11 | toggleErrorMessage: actions.toggleErrorMessage
12 | }
13 |
14 | const mapStateToProps = state => ({
15 | errorMessage: state.errorMessage.message
16 | });
17 |
18 | class MessageComp extends React.Component {
19 | constructor(props) {
20 | super(props);
21 |
22 | this.handleKeyUp = this.handleKeyUp.bind(this);
23 | }
24 |
25 | componentDidMount() {
26 | document.addEventListener('keydown', this.handleKeyUp);
27 | }
28 |
29 | UNSAFE_componentWillMount() {
30 | document.removeEventListener('keydown', this.handleKeyUp);
31 | }
32 |
33 | handleKeyUp(event) {
34 | if(event.keyCode !== 27) {
35 | return;
36 | }
37 | this.props.toggleErrorMessage(false);
38 | }
39 |
40 | render() {
41 | const { message, toggleErrorMessage, errorMessage } = this.props;
42 |
43 | return (
44 |
45 |
46 |
47 |
{`${message}`}
48 |
49 |
50 | {
51 | !errorMessage
52 | ?
53 | :
54 |
55 | {`/ ESC`}
56 |
57 | }
58 |
59 |
60 |
61 | )
62 | }
63 | }
64 |
65 | MessageComp.displayName = 'MessageComp';
66 |
67 | export default connect(mapStateToProps, mapDispatchToProps)(MessageComp);
--------------------------------------------------------------------------------
/src/client/components/MessageComp/MessageComp.scss:
--------------------------------------------------------------------------------
1 | .message-comp {
2 | position: fixed;
3 | top: 0;
4 | left: 0;
5 | width:100%;
6 | height: 100%;
7 | background: rgba(0, 0, 0, 0.8);
8 | z-index: 9999;
9 |
10 | &__main {
11 | position: absolute;
12 | top: 50%;
13 | left: 50%;
14 | transform: translate(-50%, -50%);
15 |
16 | &__text {
17 | text-align: center;
18 | color: $color-green;
19 | }
20 |
21 | &__button {
22 | display: table;
23 | margin: 30px auto;
24 |
25 | svg {
26 | width: 40px;
27 | height: 40px;
28 | fill: $color-green;
29 | stroke: $color-green;
30 | animation: rotate 5s infinite;
31 | }
32 |
33 | &__item {
34 |
35 | button {
36 | padding: 10px;
37 | font-size: 14px;
38 | border: 1px solid $color-green;
39 | border-radius: 5px;
40 | background: transparent;
41 | outline: transparent;
42 | cursor: pointer;
43 |
44 | &:hover {
45 | opacity: 0.6;
46 | }
47 | }
48 |
49 | span {
50 | color: $color-green;
51 | font-size: 16px;
52 | }
53 |
54 | .escape {
55 | margin-left: 7px;
56 | font-size: 22px;
57 | }
58 | }
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/src/client/components/Modal/Modal.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Icon from '../Icon/Icon';
4 |
5 | import styles from './Modal.scss';
6 |
7 | const Modal = ({ onIconClick, children }) => {
8 |
9 | return (
10 |
11 |
12 |
13 |
16 |
17 |
18 | {children}
19 |
20 |
21 |
22 | )
23 | }
24 |
25 | Modal.displayName = 'Modal';
26 |
27 | export default Modal;
28 |
--------------------------------------------------------------------------------
/src/client/components/Modal/Modal.scss:
--------------------------------------------------------------------------------
1 | .modal {
2 | position: fixed;
3 | top: 0;
4 | left: 0;
5 | width:100%;
6 | height: 100%;
7 | background: rgba(0, 0, 0, 0.8);
8 | z-index: 9999;
9 |
10 |
11 | &__main {
12 | position: fixed;
13 | width: 80%;
14 | height: auto;
15 | top:50%;
16 | left:50%;
17 | padding: 50px;
18 | background: $color-dark-grey;
19 | box-shadow: 0.3px 0.4px 12px 0px $color-light-green;
20 | border-radius: 12px;
21 | transform: translate(-50%,-50%);
22 |
23 | &__button {
24 | position: absolute;
25 | top: 5px;
26 | right: 10px;
27 |
28 | button {
29 | background: transparent;
30 | outline: transparent;
31 | cursor: pointer;
32 | }
33 |
34 | svg {
35 | width: 10px;
36 | height: 10px;
37 | stroke: $color-light-grey;
38 | fill: $color-light-grey;
39 | }
40 | }
41 |
42 | &__body {
43 | width: 100%;
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/src/client/components/Panel/Panel.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import TransactionDebugger from '../TransactionDebugger/TransactionDebugger';
4 | import Disassembler from '../Disassembler/Disassembler';
5 | import ControlFlowGraph from '../ControlFlowGraph/ControlFlowGraph';
6 | import StorageViewer from '../StorageViewer/StorageViewer';
7 |
8 | import styles from './Panel.scss';
9 |
10 | const Panel = ({ type, contractName, contractCode, contractPath, debuggerResponse, graphResponse, disassemblerResponse, storageResponse }) => {
11 | console.log(disassemblerResponse)
12 | return (
13 |
14 | {type === 'Transaction Debugger' &&
15 |
20 | }
21 | {type === 'Disassembler' &&
22 |
25 | }
26 | {type === 'Control Flow Graph Runtime' &&
27 |
34 | }
35 | {type === 'Control Flow Graph Constructor' &&
36 |
43 | }
44 | {type === 'Storage Viewer' &&
45 |
46 | }
47 |
48 | );
49 | }
50 |
51 | Panel.displayName = 'Panel';
52 |
53 | export default Panel;
54 |
--------------------------------------------------------------------------------
/src/client/components/Panel/Panel.scss:
--------------------------------------------------------------------------------
1 | .panel {
2 | background: $color-dark-grey;
3 | color: $color-green;
4 | }
--------------------------------------------------------------------------------
/src/client/components/SettingsBar/SettingsBar.scss:
--------------------------------------------------------------------------------
1 | .settings-bar {
2 | width: 100%;
3 | background: $color-dark-grey;
4 | padding: 0 5px 10px 5px;
5 |
6 | &__buttons {
7 | padding: 5px 10px;
8 | display: flex;
9 | justify-content: space-between;
10 |
11 | button {
12 | padding: 10px;
13 | border-radius: 5px;
14 | background: transparent;
15 | border: 1px solid $color-light-grey;
16 | cursor: pointer;
17 | transition: border-color 0.2s;
18 |
19 | &:last-of-type {
20 | margin-left: 10px;
21 | }
22 |
23 | &:focus {
24 | border-color: $color-green;
25 | outline: 0 none;
26 |
27 | span {
28 | color: $color-green;
29 | }
30 | }
31 |
32 | &:hover {
33 | border-color: $color-green;
34 |
35 | span {
36 | color: $color-green;
37 | }
38 | }
39 |
40 | span {
41 | color: $color-light-grey;
42 | font-size: 14px;
43 | transition: color 0.2s;
44 | }
45 | }
46 | }
47 |
48 | &__message {
49 | display: table;
50 | margin: 20px auto 0 auto;
51 |
52 | p {
53 | color: $color-green;
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/src/client/components/SideBar/SideBar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import styles from './SideBar.scss';
4 |
5 | class SideBar extends React.Component {
6 |
7 | handleClick(type) {
8 | this.props.onClick(type);
9 | }
10 |
11 | render() {
12 |
13 | const { onTransactionDebuggerClick, onControlFlowGraphRuntimeClick, onControlFlowGraphConstructorClick, onDisassemblerClick, onViewStorageClick } = this.props;
14 |
15 | return (
16 |
17 |
18 | Debug Transaction
19 |
20 |
21 | Disassembler
22 |
23 |
24 | Control Flow Graph Constructor
25 |
26 |
27 | Control Flow Graph Runtime
28 |
29 |
30 | View Storage
31 |
32 |
33 | )
34 | }
35 | }
36 |
37 | SideBar.displayName = 'SideBar';
38 |
39 | export default SideBar;
40 |
--------------------------------------------------------------------------------
/src/client/components/SideBar/SideBar.scss:
--------------------------------------------------------------------------------
1 | .side-bar {
2 | width: 100%;
3 | padding: 10px 0;
4 | background: $color-grey;
5 |
6 | &__item {
7 | width: 100%;
8 | padding: 20px;
9 | //background: $color-dark-grey;
10 | color: $color-green;
11 | text-transform: uppercase;
12 | border-bottom: 1px solid $color-green;
13 | border-top: 1px solid $color-green;
14 | transition: background 0.2s, color 0.2s;
15 | cursor: pointer;
16 |
17 | &:hover {
18 | background: $color-green;
19 | color: $color-dark-grey;
20 | }
21 | }
22 | }
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/client/components/StorageViewer/StorageViewer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import styles from './StorageViewer.scss';
4 |
5 | const StorageViewer = ({ storageResponse }) => {
6 |
7 | return (
8 |
9 |
10 |
11 |
12 | Slot
13 |
14 |
15 |
16 |
17 | Value
18 |
19 |
20 |
21 |
22 | Set in block
23 |
24 |
25 |
26 |
27 | Set in transaction
28 |
29 |
30 |
31 |
32 | {
33 | Object.entries(storageResponse.storage).map(([key, val]) => {
34 | return (
35 |
36 |
37 | {`0x${key}`}
38 |
39 |
40 | {`0x${val.value}`}
41 |
42 |
43 | {`${val.block}`}
44 |
45 |
46 | {`${val.transactionHash}`}
47 |
48 |
49 | )
50 | })
51 | }
52 |
53 |
54 |
55 | )
56 | }
57 |
58 | export default StorageViewer;
--------------------------------------------------------------------------------
/src/client/components/StorageViewer/StorageViewer.scss:
--------------------------------------------------------------------------------
1 | .storage {
2 | padding: 15px;
3 |
4 | &__header {
5 | display: flex;
6 | justify-content: space-around;
7 | border-bottom: 1px dotted $color-green;
8 |
9 | &__item {
10 | flex: 0 1 50%;
11 | padding: 20px;
12 | text-align: center;
13 |
14 | &:first-of-type {
15 | border-right: 1px dotted $color-green;
16 | }
17 |
18 | span {
19 | text-transform: uppercase;
20 | color: $color-white;
21 | }
22 | }
23 | }
24 |
25 | &__body {
26 |
27 | &__item {
28 | display: flex;
29 | padding: 0 10px;
30 | border-bottom: 1px dotted $color-green;
31 |
32 | &__col {
33 | flex: 0 1 50%;
34 | padding: 20px 10px;
35 | word-break: break-all;
36 |
37 | span {
38 | color: $color-white;
39 | }
40 |
41 | &:first-of-type {
42 | border-right: 1px dotted $color-green;
43 | }
44 | }
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/src/client/components/Tab/Tab.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import TabMenuItem from './TabMenuItem/TabMenuItem';
4 |
5 | import styles from './Tab.scss';
6 |
7 | class Tab extends React.Component {
8 | constructor(props) {
9 | super(props);
10 |
11 | this.state = {
12 | currentTabIndex: 0,
13 | }
14 | }
15 |
16 | setActiveTab(index) {
17 | this.setState({
18 | currentTabIndex: index,
19 | });
20 | }
21 |
22 | handleIconClick(event, index) {
23 | event.stopPropagation();
24 |
25 | const { children } = this.props;
26 |
27 | this.setState({
28 | currentTabIndex:
29 | index === children.length - 1 && index === this.state.currentTabIndex ? 0
30 | : index === this.state.currentTabIndex ? index
31 | : this.state.currentTabIndex,
32 | });
33 |
34 | this.props.onMenuItemIconClick(index);
35 | }
36 |
37 | render() {
38 | const { currentTabIndex } = this.state;
39 |
40 | const children = React.Children.map(this.props.children, (child, index) => {
41 | if(!!child) {
42 | return React.cloneElement(child, {
43 | index,
44 | active: index === currentTabIndex,
45 | });
46 | }
47 | });
48 |
49 | return (
50 |
51 |
52 | {React.Children.map(children, (child, i) => {
53 | return (
54 | this.setActiveTab(i)}
59 | onIconClick={(e) => this.handleIconClick(e, i)}
60 | />
61 | )
62 | })}
63 |
64 |
65 | { children }
66 |
67 |
68 | );
69 | }
70 | }
71 |
72 | export default Tab;
73 |
74 | Tab.displayName = 'Tab';
75 |
--------------------------------------------------------------------------------
/src/client/components/Tab/Tab.scss:
--------------------------------------------------------------------------------
1 | .tab {
2 | width: 100%;
3 | overflow: hidden;
4 |
5 | &__navigation {
6 | width: 100%;
7 | display: flex;
8 | text-transform: uppercase;
9 | overflow-x: auto;
10 | overflow-y: hidden;
11 | }
12 |
13 | &__panels {
14 | position: relative;
15 | }
16 | }
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/client/components/Tab/TabMenuItem/TabMenuItem.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Icon from '../../Icon/Icon';
4 |
5 | import classnames from 'classnames/bind';
6 |
7 | import styles from './TabMenuItem.scss';
8 |
9 | const cx = classnames.bind(styles);
10 |
11 | const TabMenuItem = ({ name, onMenuItemClick, active, onIconClick, evm }) => {
12 |
13 | const classes = cx({
14 | 'tab-menu-item': true,
15 | 'tab-menu-item--active': !!active,
16 | });
17 |
18 | return (
19 |
20 | {
21 | !evm &&
22 |
23 |
24 |
25 | }
26 |
27 | {name}
28 |
29 |
30 | );
31 | }
32 |
33 |
34 | TabMenuItem.displayName = 'TabMenuItem';
35 |
36 | export default TabMenuItem;
37 |
--------------------------------------------------------------------------------
/src/client/components/Tab/TabMenuItem/TabMenuItem.scss:
--------------------------------------------------------------------------------
1 | .tab-menu-item {
2 | position: relative;
3 | height: 60px;
4 | flex: 1 1 auto;
5 | padding: 15px 20px 20px 20px;
6 | text-align: center;
7 | background: $color-grey;
8 | color: $color-green;
9 | z-index: 0;
10 | box-shadow: inset 2px 1px 5px (#000 + 30);
11 | overflow: hidden;
12 | text-overflow: ellipsis;
13 | transform: translate(0, 20px);
14 | transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out, color 0.2s ease-in-out, background 0.2s ease-in-out;
15 | cursor: pointer;
16 |
17 | &:first-of-type {
18 | border-top-left-radius: 8px;
19 | }
20 |
21 | &:last-of-type {
22 | border-top-right-radius: 8px;
23 | }
24 |
25 | &:hover {
26 | transform: translate(0, 15px);
27 | }
28 |
29 | &__icon {
30 | position: absolute;
31 | top: 5px;
32 | right: 5px;
33 |
34 | svg {
35 | width: 10px;
36 | height: 10px;
37 | fill: $color-green;
38 | stroke: $color-green;
39 | pointer-events: none;
40 | transition: fill 0.2s ease-in-out, stroke 0.2s ease-in-out;
41 | }
42 | }
43 | }
44 |
45 | //State
46 | .tab-menu-item {
47 |
48 | &--active {
49 | transform: translate(0, 10px);
50 | box-shadow: 2px 5px 6px 2px ($color-grey - 30);
51 | color: $color-grey;
52 | background: $color-green;
53 |
54 | &:hover {
55 | transform: translate(0, 10px);
56 | }
57 | }
58 |
59 | &--active & {
60 |
61 | &__icon {
62 |
63 | svg {
64 | fill: $color-grey;
65 | stroke: $color-grey;
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/client/components/Tab/TabPanel/TabPanel.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import styles from './TabPanel.scss';
4 |
5 | import classnames from 'classnames/bind';
6 |
7 | const cx = classnames.bind(styles);
8 |
9 | const TabPanel = ({ children, active }) => {
10 |
11 | const tabPanelClasses = cx({
12 | 'tab-panel': true,
13 | 'tab-panel--active': !!active,
14 | });
15 | return (
16 |
17 | {children}
18 |
19 | )
20 | }
21 |
22 | TabPanel.displayName = 'TabPanel';
23 |
24 | export default TabPanel;
25 |
--------------------------------------------------------------------------------
/src/client/components/Tab/TabPanel/TabPanel.scss:
--------------------------------------------------------------------------------
1 | .tab-panel {
2 | display: none;
3 | // width: 100%;
4 | // padding: 34px 0 20px 0;
5 | // background: $color-black;
6 | border-bottom-left-radius: 8px;
7 | border-bottom-right-radius: 8px;
8 | }
9 | // &__left {
10 | // width: 40%;
11 | // position: relative;
12 | // padding-top: 30px;
13 | // padding-left: 10px;
14 |
15 | // &__control {
16 | // position: absolute;
17 | // top: -14px;
18 | // left: 10px;
19 | // z-index: 4;
20 |
21 | // button {
22 | // background: transparent;
23 | // outline: transparent;
24 | // cursor: pointer;
25 | // }
26 | // }
27 |
28 | // &__side-bar {
29 | // position: absolute;
30 | // top: 30px;
31 | // left: -262px;
32 | // transition: left 0.2s;
33 | // pointer-events: none;
34 | // }
35 | // }
36 |
37 | // &__right {
38 | // flex: 1 1 auto;
39 | // width: 100%;
40 | // height: 100%;
41 | // padding: 0 20px;
42 | // overflow-x: auto;
43 | // }
44 | // }
45 |
46 | //State
47 | .tab-panel {
48 |
49 | &--active {
50 | display: flex;
51 | }
52 |
53 | // &__left {
54 |
55 | // &__side-bar {
56 |
57 | // &--open {
58 | // left: 0;
59 | // z-index: 6;
60 | // pointer-events: auto;
61 | // }
62 | // }
63 | // }
64 | }
65 |
--------------------------------------------------------------------------------
/src/client/components/TopNavBar/TopNavBar.scss:
--------------------------------------------------------------------------------
1 | .top-navbar {
2 | display: flex;
3 | align-items: center;
4 | width: 100%;
5 | position: fixed;
6 | top: 0;
7 | left: 0;
8 | right: 0;
9 | background: $color-dark-grey;
10 | z-index: 5;
11 |
12 | &__form {
13 | padding: 20px;
14 | background: $color-dark-grey;
15 | flex: 1 1 auto;
16 | }
17 |
18 | &__settings-dropdown {
19 | display: flex;
20 | justify-content: flex-end;
21 | flex: 0 1 auto;
22 | position: relative;
23 | padding: 30px 20px;
24 | height: 88px;
25 | cursor: pointer;
26 | background: $color-dark-grey;
27 | }
28 |
29 | &__versions-dropdown {
30 | flex: 0 0 250px;
31 | position: relative;
32 | padding-left: 10px;
33 | padding: 24.5px 20px;
34 | height: 88px;
35 | background: $color-dark-grey;
36 |
37 | &__text {
38 | position: absolute;
39 | top: 50%;
40 | left: 20px;
41 | transform: translate(0, -50%);
42 |
43 | span {
44 | color: $color-green;
45 | }
46 | }
47 |
48 | &__toggler {
49 | position: absolute;
50 | top: 50%;
51 | right: 0;
52 | transform: translate(0, -50%);
53 | padding: 10px;
54 | border-radius: 5px;
55 | background: transparent;
56 | border: 1px solid $color-light-grey;
57 | cursor: pointer;
58 | z-index: 3;
59 | transition: opacity 0.7, border-color 0.2s;
60 |
61 | span {
62 | color: $color-light-grey;
63 | transition: color 0.1s ease-in;
64 | font-size: 14px;
65 | }
66 |
67 | &:focus {
68 | border-color: $color-green;
69 | outline: 0 none;
70 |
71 | span {
72 | color: $color-green;
73 | }
74 | }
75 |
76 | &:hover {
77 | border-color: $color-green;
78 |
79 | span {
80 | color: $color-green;
81 | }
82 | }
83 | }
84 | }
85 | }
86 |
87 |
88 |
--------------------------------------------------------------------------------
/src/client/components/TransactionDebugger/TransactionDebugger.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Graph from '../Graph/Graph';
4 |
5 | import styles from './TransactionDebugger.scss';
6 |
7 | const TransactionDebugger = ({ contractName, contractPath, debuggerResponse }) => {
8 |
9 | return (
10 |
11 |
19 |
20 | );
21 | }
22 |
23 | TransactionDebugger.displayName = 'TransactionDebugger';
24 |
25 | export default TransactionDebugger;
26 |
--------------------------------------------------------------------------------
/src/client/components/TransactionDebugger/TransactionDebugger.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fergarrui/ethereum-graph-debugger/d7310f960c726ee04c54163b2803c3a5dda97b36/src/client/components/TransactionDebugger/TransactionDebugger.scss
--------------------------------------------------------------------------------
/src/client/components/Version/Version.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 |
4 | import * as actions from '../../_redux/actions';
5 |
6 | import styles from './Version.scss';
7 |
8 | const mapDispatchToProps = {
9 | getVersionNumber: actions.getVersionNumber,
10 | postVersion: actions.postVersion
11 | };
12 |
13 | const Version = ({ data, getVersionNumber, onVersionItemClick, postVersion }) => {
14 |
15 | const handleSelect = (item) => {
16 | postVersion({ version: item.commit });
17 | onVersionItemClick();
18 | getVersionNumber(item.version);
19 | }
20 |
21 | return (
22 |
23 | {
24 | data.map(item => {
25 | return (
26 |
handleSelect(item)}
30 | >
31 | {item.version}
32 |
33 | )})
34 | }
35 |
36 | )
37 | }
38 |
39 | export default connect(null, mapDispatchToProps)(Version);
--------------------------------------------------------------------------------
/src/client/components/Version/Version.scss:
--------------------------------------------------------------------------------
1 | .version {
2 | max-height: 300px;
3 | overflow: auto;
4 | padding: 20px 10px;
5 |
6 | &__item {
7 | width: 100%;
8 | padding: 10px 20px;
9 | border-bottom: 1px dotted $color-light-grey;
10 | transition: border-bottom-color 0.3s;
11 | cursor: pointer;
12 |
13 | &:hover {
14 | border-bottom-color: $color-green;
15 |
16 | span {
17 | color: $color-green;
18 | }
19 | }
20 |
21 | span {
22 | color: $color-light-grey;
23 | transition: color 0.2s;
24 | pointer-events: none;
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/client/styles/App.scss:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Montserrat');
2 |
3 | .app {
4 | width: 100%;
5 | position: relative;
6 | font-family: 'Montserrat', sans-serif;
7 |
8 | &__tabs {
9 | margin-top: 50px;
10 | padding: 50px 10px;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/client/styles/animate.scss:
--------------------------------------------------------------------------------
1 | @keyframes rotate {
2 | 0% {
3 | transform: rotate(0);
4 | }
5 |
6 | 100% {
7 | transform: rotate(360deg);
8 | }
9 | }
--------------------------------------------------------------------------------
/src/client/styles/reset.scss:
--------------------------------------------------------------------------------
1 | * {
2 | border: 0;
3 | padding: 0;
4 | margin: 0;
5 | box-sizing: border-box;
6 | }
7 |
8 | body {
9 | background: $color-light-grey;
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/src/client/styles/transitions/fade.scss:
--------------------------------------------------------------------------------
1 | //fade
2 | .enter {
3 | opacity: 0.01;
4 |
5 | &.enterActive {
6 | transition: opacity 0.3s ease-in;
7 | opacity: 1;
8 | }
9 | }
10 |
11 | .leave {
12 | opacity: 1;
13 |
14 | &.leaveActive {
15 | transition: opacity 0.3s ease-in;
16 | opacity: 0.01;
17 | }
18 | }
19 |
20 | .appear {
21 | opacity: 0.01;
22 |
23 | &.appearActive {
24 | transition: opacity 0.3s ease-in;
25 | opacity: 1;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/client/styles/transitions/scale.scss:
--------------------------------------------------------------------------------
1 | //scale
2 | .enter {
3 | opacity: 0.01;
4 | transform: scale(0);
5 |
6 | &.enterActive {
7 | transition: opacity 0.4s ease-in, transform 0.3s ease-in-out;
8 | opacity: 1;
9 | transform: scale(1);
10 | }
11 | }
12 |
13 | .leave {
14 | opacity: 1;
15 | transform: scale(1);
16 |
17 | &.leaveActive {
18 | transition: opacity 0.4s ease-in, transform 0.3s ease-in-out;
19 | opacity: 0.01;
20 | transform: scale(0);
21 | }
22 | }
23 |
24 | .appear {
25 | opacity: 0.01;
26 | transform: scale(0);
27 |
28 |
29 | &.appearActive {
30 | transition: opacity 0.4s ease-in, transform 0.3s ease-in-out;
31 | opacity: 1;
32 | transform: scale(1);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/client/styles/transitions/slide.scss:
--------------------------------------------------------------------------------
1 | //slide
2 | .enter {
3 | opacity: 0.01;
4 | top: -100%;
5 |
6 | &.enterActive {
7 | transition: opacity 0.3s ease-in, top 0.3s ease-in;
8 | opacity: 1;
9 | top: 0;
10 | }
11 | }
12 |
13 | .leave {
14 | opacity: 1;
15 | top: 0;
16 |
17 | &.leaveActive {
18 | transition: opacity 0.3s ease-in, top 0.3s ease-in;
19 | opacity: 0.01;
20 | top: -100%;
21 | }
22 | }
23 |
24 | .appear {
25 | opacity: 0.01;
26 | top: -100%;
27 |
28 | &.appearActive {
29 | transition: opacity 0.3s ease-in, top 0.3s ease-in;
30 | opacity: 1;
31 | top: 0;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/client/styles/utils.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 |
3 | const resources = [
4 | "variables.scss",
5 | "animate.scss",
6 | ];
7 |
8 | module.exports = resources.map(file => path.resolve(__dirname, file));
--------------------------------------------------------------------------------
/src/client/styles/variables.scss:
--------------------------------------------------------------------------------
1 | //Colors
2 | $color-green: #88F87B;
3 | $color-light-green: #B4FAAC;
4 | $color-black: #1D1D1B;
5 | $color-light-grey: #B7B7B7;
6 | $color-grey: #393E41;
7 | $color-dark-grey: #232323;
8 | $color-white: #fff;
--------------------------------------------------------------------------------
/src/client/utils/baseUrl.js:
--------------------------------------------------------------------------------
1 | export const baseUrl = `http://localhost:9090/`;
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { Provider } from 'react-redux';
4 | import "regenerator-runtime/runtime";
5 |
6 | import store from './client/_redux/store.js';
7 |
8 | import App from './client/App';
9 |
10 | import styles from './client/styles/reset.scss';
11 |
12 | ReactDOM.render(, document.getElementById('app'));
13 |
--------------------------------------------------------------------------------
/src/inversify/types.ts:
--------------------------------------------------------------------------------
1 | const TYPES = {
2 | Web3Instance: Symbol.for('Web3Instance'),
3 | FileService: Symbol.for('FileService'),
4 | TransactionService: Symbol.for('TransactionService'),
5 | Disassembler: Symbol.for('EVMDisassembler'),
6 | CFGCreator: Symbol.for('CFGCreator'),
7 | GraphVizService: Symbol.for('GraphVizService'),
8 | BlockService: Symbol.for('BlockService'),
9 | CFGService: Symbol.for('CFGService'),
10 | StorageRecover: Symbol.for('StorageRecover'),
11 | OpcodeExecutor: Symbol.for('OpcodeExecutor'),
12 | ContractService: Symbol.for('ContractService'),
13 | Solc: Symbol.for('Solc')
14 | }
15 |
16 | export { TYPES }
17 |
--------------------------------------------------------------------------------
/src/run-server.ts:
--------------------------------------------------------------------------------
1 | import { Server } from './Server'
2 | import { RegisterRoutes } from './routes'
3 |
4 | import './api/service/controller/DebuggerController'
5 | import './api/service/controller/TransactionController'
6 | import './api/service/controller/FileController'
7 | import './api/service/controller/DisassembleController'
8 | import './api/service/controller/ControlFlowGraphController'
9 | import './api/service/controller/StorageRecoverController'
10 | import './api/service/controller/ContractController'
11 | import './api/service/controller/SolcController'
12 |
13 | const server = new Server()
14 | // make it configurable
15 | const port = 9090
16 | RegisterRoutes(server.express)
17 |
18 | server.express.use((err: any, _req, res, next) => {
19 | const status = err.status || 500
20 | const body: any = {
21 | message: err.message || 'Sorry, there has been an error',
22 | name: err.name,
23 | status,
24 | error: true
25 | }
26 | res.status(status).json(body)
27 | next()
28 | })
29 |
30 | const runServer = () => {
31 | server.setLogConfig('info' as any, false).startOn(port)
32 | }
33 |
34 | server.express.get('/', function(request, response) {
35 | response.sendFile(__dirname + '/index.html')
36 | })
37 |
38 | server.express.get('/bundle.js', function(request, response) {
39 | response.sendFile(__dirname + '/bundle.js')
40 | })
41 |
42 | runServer()
43 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "outDir": "./dist",
5 | "rootDir": "./src",
6 | "sourceMap": true,
7 | "module": "commonjs",
8 | "target": "es6",
9 | "experimentalDecorators": true,
10 | "lib": ["es6", "es2015", "es2017", "dom"],
11 | "types": ["reflect-metadata", "jest", "node"],
12 | "moduleResolution": "node",
13 | "emitDecoratorMetadata": true,
14 | "allowSyntheticDefaultImports": true
15 | },
16 | "include": ["src/**/*"],
17 | "exclude": ["node_modules"],
18 | "compileOnSave": false
19 | }
20 |
--------------------------------------------------------------------------------
/tsoa.json:
--------------------------------------------------------------------------------
1 | {
2 | "routes": {
3 | "entryFile": "./src/run-server.ts",
4 | "routesDir": "./src",
5 | "iocModule" : "./src/inversify/ioc"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------