-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathtracer.js
More file actions
97 lines (84 loc) · 4.61 KB
/
tracer.js
File metadata and controls
97 lines (84 loc) · 4.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
const ethers = require('ethers');
exports.parseTrace = async (from, trace, provider) => {
if (!trace || !trace.structLogs)
return [];
const opCodes = ['CALL', 'CALLCODE', 'DELEGATECALL', 'STATICCALL', 'CREATE', 'CREATE2'];
const filteredData = trace.structLogs.filter(log => opCodes.indexOf(log.op) > -1 || log.pc == 1507);
const parsedOps = [];
for (const log of filteredData) {
try {
switch(log.op) {
case 'CALL':
case 'CALLCODE':
const inputStart = parseInt(log.stack[log.stack.length - 4], 16) * 2;
const inputSize = parseInt(log.stack[log.stack.length - 5], 16) * 2;
const input = `0x${log.memory.join('').slice(inputStart, inputStart + inputSize)}`;
const deeperLogs = trace.structLogs.filter(returnLog => returnLog.pc == log.pc + 1);
const outLog = trace.structLogs[trace.structLogs.indexOf(deeperLogs[0]) - 1];
const outLogMemory = Buffer.from(outLog.memory.join(''));
const outStart = parseInt(outLog.stack[outLog.stack.length - 1], 16) * 2;
const outSize = parseInt(outLog.stack[outLog.stack.length - 2], 16) * 2;
const out = `0x${outLogMemory.slice(outStart, outStart + outSize)}`;
const address = `0x${log.stack[log.stack.length - 2].slice(-40)}`.toLowerCase();
const bytecode = await provider.getCode(address);
parsedOps.push({
op: log.op,
address: address,
input: input,
returnData: out != '0x' ? out : '',
depth: log.depth,
contractHashedBytecode: ethers.utils.keccak256(bytecode)
})
break;
case 'DELEGATECALL':
case 'STATICCALL': {
const inputStart = parseInt(log.stack[log.stack.length - 3], 16) * 2;
const inputSize = parseInt(log.stack[log.stack.length - 4], 16) * 2;
const input = `0x${log.memory.join('').slice(inputStart, inputStart + inputSize)}`;
const deeperLogs = trace.structLogs.filter(returnLog => returnLog.pc == log.pc + 1);
const outLog = trace.structLogs[trace.structLogs.indexOf(deeperLogs[0]) - 1];
const outLogMemory = Buffer.from(outLog.memory.join(''));
const outStart = parseInt(outLog.stack[outLog.stack.length - 1], 16) * 2;
const outSize = parseInt(outLog.stack[outLog.stack.length - 2], 16) * 2;
const out = `0x${outLogMemory.slice(outStart, outStart + outSize)}`;
const address = `0x${log.stack[log.stack.length - 2].slice(-40)}`.toLowerCase();
const bytecode = await provider.getCode(address);
parsedOps.push({
op: log.op,
address: address,
input: input,
returnData: out != '0x' ? out : '',
depth: log.depth,
contractHashedBytecode: ethers.utils.keccak256(bytecode)
})
break;
}
case 'CREATE':
case 'CREATE2': {
const stackCopy = [...log.stack];
stackCopy.pop();
const p = parseInt(stackCopy.pop().valueOf(), 16) * 2;
const n = parseInt(stackCopy.pop().valueOf(), 16) * 2;
const s = `0x${stackCopy.pop()}`;
const creationBytecode = `0x${log.memory.join('').slice(p, p + n)}`;
const hashedCreationBytecode = ethers.utils.keccak256(creationBytecode);
const address = ethers.utils.getCreate2Address(from, s, hashedCreationBytecode);
const runtimeBytecode = await provider.getCode(address);
const contractHashedBytecode = ethers.utils.keccak256(runtimeBytecode);
parsedOps.push({
op: log.op,
address: address,
depth: log.depth,
contractHashedBytecode: contractHashedBytecode
});
break;
}
default:
}
} catch(error) {
console.log(error);
return [];
}
}
return parsedOps
};