UNPKG

0xweb

Version:

Contract package manager and other web3 tools

260 lines (251 loc) 9.29 kB
import { $is } from '@dequanto/utils/$is'; import { EvmBytecode } from '../EvmBytecode'; import Opcode from '../interfaces/IOpcode'; import stringify from '../utils/stringify'; import { Variable } from './jumpi'; const parseMapping = (...items: any[]) => { const mappings: any = []; items.forEach((item2: any) => { if (item2.name === 'SHA3' && item2.items) { mappings.push(...parseMapping(...item2.items)); } else { mappings.push(item2); } }); return mappings; }; export class MappingStore { readonly name: string; readonly type?: string; readonly wrapped: boolean; readonly location: any; readonly count: any; readonly items: any; readonly data: any; readonly structlocation?: any; readonly mappings: any; constructor( mappings: any, location: any, items: any, data: any, count: any, structlocation?: any ) { this.name = 'MappingStore'; this.wrapped = false; this.location = location; this.items = items; this.data = data; this.count = count; this.structlocation = structlocation; this.mappings = mappings; } toString() { let mappingName = 'mapping' + (this.count + 1); if (this.location in this.mappings() && this.mappings()[this.location].name) { mappingName = this.mappings()[this.location].name; } if ( this.data.name === 'ADD' && this.data.right.name === 'MappingLoad' && stringify(this.data.right.location) === stringify(this.location) ) { return ( mappingName + this.items.map((item: any) => '[' + stringify(item) + ']').join('') + ' += ' + stringify(this.data.left) + ';' ); } else if ( this.data.name === 'SUB' && this.data.left.name === 'MappingLoad' && stringify(this.data.left.location) === stringify(this.location) ) { return ( mappingName + this.items.map((item: any) => '[' + stringify(item) + ']').join('') + ' -= ' + stringify(this.data.right) + ';' ); } else { return ( mappingName + this.items.map((item: any) => '[' + stringify(item) + ']').join('') + ' = ' + stringify(this.data) + ';' ); } } } export class SSTORE { readonly name: string; readonly type?: string; readonly wrapped: boolean; readonly location: any; readonly data: any; readonly variables: any; constructor(location: any, data: any, variables: any) { this.name = 'SSTORE'; this.wrapped = true; this.location = location; this.data = data; this.variables = variables; if ($is.BigInt(this.location) && this.location.toString() in this.variables()) { this.variables()[this.location.toString()].types.push(() => this.data.type); } else if ( $is.BigInt(this.location) && !(this.location.toString() in this.variables()) ) { this.variables()[this.location.toString()] = new Variable(false, [ () => this.data.type ]); } } toString() { let variableName = 'storage[' + stringify(this.location) + ']'; if ($is.BigInt(this.location) && this.location.toString() in this.variables()) { if (this.variables()[this.location.toString()].label) { variableName = this.variables()[this.location.toString()].label; } else { variableName = 'var' + (Object.keys(this.variables()).indexOf(this.location.toString()) + 1); } } if ( this.data.name === 'ADD' && this.data.right.name === 'SLOAD' && stringify(this.data.right.location) === stringify(this.location) ) { return variableName + ' += ' + stringify(this.data.left) + ';'; } else if ( this.data.name === 'SUB' && this.data.left.name === 'SLOAD' && stringify(this.data.left.location) === stringify(this.location) ) { return variableName + ' -= ' + stringify(this.data.right) + ';'; } else { return variableName + ' = ' + stringify(this.data) + ';'; } } } export default (opcode: Opcode, state: EvmBytecode): void => { const storeLocation = state.stack.pop(); const storeData = state.stack.pop(); if (storeLocation.name === 'SHA3') { const mappingItems = parseMapping(...storeLocation.items); const mappingLocation = mappingItems.find((mappingItem: any) => $is.BigInt(mappingItem) ); const mappingParts = mappingItems.filter( (mappingItem: any) => !$is.BigInt(mappingItem) ); if (mappingLocation && mappingParts.length > 0) { if (!(mappingLocation in state.mappings)) { state.mappings[mappingLocation] = { name: false, structs: [], keys: [], values: [] }; } state.mappings[mappingLocation].keys.push(mappingParts); state.mappings[mappingLocation].values.push(storeData); state.instructions.push( new MappingStore( () => state.mappings, mappingLocation, mappingParts, storeData, Object.keys(state.mappings).indexOf(mappingLocation.toString()) ) ); } else { state.instructions.push(new SSTORE(storeLocation, storeData, () => state.variables)); } } else if ( storeLocation.name === 'ADD' && storeLocation.left.name === 'SHA3' && $is.BigInt(storeLocation.right) ) { const mappingItems = parseMapping(...storeLocation.left.items); const mappingLocation = mappingItems.find((mappingItem: any) => $is.BigInt(mappingItem) ); const mappingParts = mappingItems.filter( (mappingItem: any) => !$is.BigInt(mappingItem) ); if (mappingLocation && mappingParts.length > 0) { if (!(mappingLocation in state.mappings)) { state.mappings[mappingLocation] = { name: false, structs: [], keys: [], values: [] }; } state.mappings[mappingLocation].keys.push(mappingParts); state.instructions.push( new MappingStore( () => state.mappings, mappingLocation, mappingParts, storeData, Object.keys(state.mappings).indexOf(mappingLocation.toString()), storeLocation.right ) ); } else { state.instructions.push(new SSTORE(storeLocation, storeData, () => state.variables)); } } else if ( storeLocation.name === 'ADD' && $is.BigInt(storeLocation.left) && storeLocation.right.name === 'SHA3' ) { const mappingItems = parseMapping(...storeLocation.right.items); const mappingLocation = mappingItems.find((mappingItem: any) => $is.BigInt(mappingItem) ); const mappingParts = mappingItems.filter( (mappingItem: any) => !$is.BigInt(mappingItem) ); if (mappingLocation && mappingParts.length > 0) { if (!(mappingLocation in state.mappings)) { state.mappings[mappingLocation] = { name: false, structs: [], keys: [], values: [] }; } state.mappings[mappingLocation].keys.push(mappingParts); state.instructions.push( new MappingStore( () => state.mappings, mappingLocation, mappingParts, storeData, Object.keys(state.mappings).indexOf(mappingLocation.toString()), storeLocation.left ) ); } else { state.instructions.push(new SSTORE(storeLocation, storeData, () => state.variables)); } } else if ( false && $is.BigInt(storeLocation) && storeLocation.toString() in state.variables && storeData.type && !state.variables[storeLocation.toString()].types.includes(storeData.type) ) { state.instructions.push(new SSTORE(storeLocation, storeData, () => state.variables)); state.variables[storeLocation.toString()].types.push(storeData.type); } else { state.instructions.push(new SSTORE(storeLocation, storeData, () => state.variables)); } };