0xweb
Version:
Contract package manager and other web3 tools
191 lines (182 loc) • 6.58 kB
text/typescript
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));
}
};