UNPKG

0xweb

Version:

Contract package manager and other web3 tools

191 lines (182 loc) 6.58 kB
import { $is } from '@dequanto/utils/$is'; import { EvmBytecode } from '../EvmBytecode'; import Opcode from '../interfaces/IOpcode'; import stringify from '../utils/stringify'; 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 MappingLoad { readonly name: string; readonly type?: string; readonly wrapped: boolean; readonly location: any; readonly count: any; readonly items: any; readonly structlocation?: any; readonly mappings: any; constructor(mappings: any, location: any, items: any, count: any, structlocation?: any) { this.name = 'MappingLoad'; this.wrapped = false; this.location = location; this.count = count; this.items = items; 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.structlocation) { return ( mappingName + this.items.map((item: any) => '[' + stringify(item) + ']').join('') + '[' + this.structlocation.toString() + ']' ); } else { return ( mappingName + this.items.map((item: any) => '[' + stringify(item) + ']').join('') ); } } } export class SLOAD { readonly name: string; readonly type?: string; readonly wrapped: boolean; readonly location: any; readonly variables: any; constructor(location: any, variables: any) { this.name = 'SLOAD'; this.wrapped = false; this.location = location; this.variables = variables; } toString() { if ($is.BigInt(this.location) && this.location.toString() in this.variables()) { if (this.variables()[this.location.toString()].label) { return this.variables()[this.location.toString()].label; } else { return ( 'var' + (Object.keys(this.variables()).indexOf(this.location.toString()) + 1) ); } } else { return 'storage[' + stringify(this.location) + ']'; } } } export default (opcode: Opcode, state: EvmBytecode): void => { const storeLocation = 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.stack.push( new MappingLoad( () => state.mappings, mappingLocation, mappingParts, Object.keys(state.mappings).indexOf(mappingLocation.toString()) ) ); } else { state.stack.push(new SLOAD(storeLocation, () => 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.stack.push( new MappingLoad( () => state.mappings, mappingLocation, mappingParts, Object.keys(state.mappings).indexOf(mappingLocation.toString()), storeLocation.right ) ); } else { state.stack.push(new SLOAD(storeLocation, () => 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.stack.push( new MappingLoad( () => state.mappings, mappingLocation, mappingParts, Object.keys(state.mappings).indexOf(mappingLocation.toString()), storeLocation.left ) ); } else { state.stack.push(new SLOAD(storeLocation, () => state.variables)); } } else { state.stack.push(new SLOAD(storeLocation, () => state.variables)); } };