evm
Version:
An ethereum virtual machine (EVM) bytecode decompiler
138 lines (127 loc) • 4.74 kB
text/typescript
import * as BigNumber from '../../node_modules/big-integer';
import * as functionHashes from '../../data/functionHashes.json';
const parseSingle = (data: any, type: any) => {
if (type === 'string') {
return '"' + Buffer.from(data, 'hex').toString('utf8') + '"';
} else if (type === 'address') {
return '0x' + data.substring(24);
} else if (type === 'uint256' || type === 'uint8') {
return BigNumber(data, 16).toString();
} else if (type === 'bool') {
return (!BigNumber(data, 16).isZero()).toString();
} else {
return data;
}
};
export default class Transaction {
blockHash?: string;
blockNumber?: number;
from?: string;
gas?: number;
gasPrice?: number;
input?: string;
to?: string;
value?: number;
constructor(transactionObject?: any) {
if (transactionObject) {
if ('blockHash' in transactionObject) {
this.blockHash = transactionObject.blockHash;
}
if ('blockNumber' in transactionObject) {
this.blockNumber = transactionObject.blockNumber;
}
if ('from' in transactionObject) {
this.from = transactionObject.from;
}
if ('gas' in transactionObject) {
this.gas = transactionObject.gas;
}
if ('gasPrice' in transactionObject) {
this.gasPrice = transactionObject.gasPrice;
}
if ('input' in transactionObject) {
this.input = transactionObject.input.replace('0x', '');
}
if ('to' in transactionObject) {
this.to = transactionObject.to;
}
if ('value' in transactionObject) {
this.value = transactionObject.value;
}
}
}
setInput(input: string): void {
this.input = input.replace('0x', '');
}
getFunctionHash(): string | false {
if (this.input && this.input.length >= 8) {
return this.input.substr(0, 8);
} else {
return false;
}
}
getFunction(): string | false {
const functionHash = this.getFunctionHash();
if (functionHash && functionHash in functionHashes) {
return (functionHashes as any)[functionHash];
} else {
return false;
}
}
getFunctionName(): string | false {
const rawFunction = this.getFunction();
if (rawFunction) {
return rawFunction.split('(')[0];
} else {
return false;
}
}
getRawArguments(): string[] {
if (this.input && this.input.length >= 70) {
return this.input.substr(8).match(/.{1,64}/g)!;
} else {
return [];
}
}
getArguments(descriptive: boolean = true): string[] {
const functionName = this.getFunction();
const functionArguments = this.getRawArguments();
if (functionName && this.input) {
const rawFunctionArguments = functionName
.split('(')[1]
.slice(0, -1)
.split(',');
if (
rawFunctionArguments.length === 1 &&
rawFunctionArguments[0] === '' &&
functionArguments.length === 0
) {
return [];
} else {
const result: string[] = [];
for (let i = 0; i < rawFunctionArguments.length; i++) {
const functionArgumentType = rawFunctionArguments[i] || 'unknown';
const functionArgument = functionArguments[i];
if (functionArgumentType === 'string') {
const location = BigNumber(functionArgument, 16)
.divide(32)
.toJSNumber();
const length = BigNumber(functionArguments[location], 16)
.multiply(2)
.toJSNumber();
const data = this.input.substring(8).substr((location + 1) * 64, length);
result.push(parseSingle(data, functionArgumentType));
} else {
result.push(parseSingle(functionArgument, functionArgumentType));
}
}
return result;
}
} else {
return functionArguments;
}
}
isContractCreation(): boolean {
return this.to === null;
}
}