UNPKG

sol2uml

Version:

Solidity contract visualisation tool.

130 lines 5.64 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.convertStorages2Dot = void 0; exports.convertStorage2Dot = convertStorage2Dot; const converterClasses2Storage_1 = require("./converterClasses2Storage"); const umlClass_1 = require("./umlClass"); const formatters_1 = require("./utils/formatters"); const debug = require('debug')('sol2uml'); const convertStorages2Dot = (storageSections, options) => { let dotString = ` digraph StorageDiagram { rankdir=LR arrowhead=open bgcolor="${options.backColor}" edge [color="${options.shapeColor}"] node [shape=record, style=filled, color="${options.shapeColor}", fillcolor="${options.fillColor}", fontcolor="${options.textColor}", fontname="Courier New"]`; // process contract and the struct storages storageSections.forEach((storage) => { dotString = convertStorage2Dot(storage, dotString, options); }); // link contract and structs to structs storageSections.forEach((slot) => { slot.variables.forEach((storage) => { if (storage.referenceSectionId) { dotString += `\n ${slot.id}:${storage.id} -> ${storage.referenceSectionId}`; } }); }); // Need to close off the last digraph dotString += '\n}'; debug(dotString); return dotString; }; exports.convertStorages2Dot = convertStorages2Dot; function convertStorage2Dot(storageSection, dotString, options) { // write storage header with name and optional address dotString += `\n${storageSection.id} [label="${storageSection.name} \\<\\<${storageSection.type}\\>\\>\\n${storageSection.address || storageSection.offset || ''}`; dotString += ' | {'; const startingVariables = storageSection.variables.filter((s) => s.byteOffset === 0); // for each slot displayed, does is have any variables with parsed data? const displayData = startingVariables.map((startVar) => storageSection.variables.some((variable) => variable.fromSlot === startVar.fromSlot && variable.parsedValue)); const linePad = '\\n\\ '; // write slot numbers const dataLine = options.data ? linePad : ''; dotString += storageSection.offset || storageSection.mapping ? `{ offset${dataLine}` : `{ slot${dataLine}`; startingVariables.forEach((variable, i) => { const dataLine = options.data && displayData[i] ? linePad : ''; if (variable.offset) { dotString += ` | ${(0, formatters_1.shortBytes32)(variable.offset)}${dataLine}`; } else if (variable.fromSlot === variable.toSlot) { dotString += ` | ${variable.fromSlot}${dataLine}`; } else { dotString += ` | ${variable.fromSlot}-${variable.toSlot}${dataLine}`; } }); // write slot values if available if (options.data && !options.hideValues) { dotString += `} | {value${dataLine}`; startingVariables.forEach((variable, i) => { if (displayData[i]) { dotString += ` | ${variable.slotValue || ''}${linePad}`; } else { dotString += ` | `; } }); } const contractVariablePrefix = storageSection.type === converterClasses2Storage_1.StorageSectionType.Contract ? '\\<inherited contract\\>.' : ''; const dataLine2 = options.data ? `\\ndecoded data` : ''; dotString += `} | { type: ${contractVariablePrefix}variable (bytes)${dataLine2}`; // For each slot startingVariables.forEach((variable) => { // Get all the storage variables in this slot const slotVariables = storageSection.variables.filter((s) => (!s.offset && s.fromSlot === variable.fromSlot) || (s.offset && s.offset === variable.offset)); const usedBytes = slotVariables.reduce((acc, s) => acc + s.byteSize, 0); if (usedBytes < 32) { // Create an unallocated variable for display purposes slotVariables.push({ id: 0, fromSlot: variable.fromSlot, toSlot: variable.fromSlot, byteSize: 32 - usedBytes, byteOffset: usedBytes, type: 'unallocated', attributeType: umlClass_1.AttributeType.UserDefined, dynamic: false, displayValue: false, getValue: false, contractName: variable.contractName, name: '', }); } const slotVariablesReversed = slotVariables.reverse(); // For each variable in the slot slotVariablesReversed.forEach((variable, i) => { if (i === 0) { dotString += ` | { ${dotVariable(variable, storageSection.name)} `; } else { dotString += ` | ${dotVariable(variable, storageSection.name)} `; } }); dotString += '}'; }); // Need to close off the last label dotString += '}}"]\n'; return dotString; } const dotVariable = (variable, contractName) => { const port = variable.referenceSectionId !== undefined ? `<${variable.id}>` : ''; const contractNamePrefix = variable.contractName !== contractName ? `${variable.contractName}.` : ''; const variableValue = variable.parsedValue ? `\\n\\ ${variable.parsedValue}` : ''; const variableName = variable.name ? `: ${contractNamePrefix}${variable.name}` : ''; return `${port} ${variable.type}${variableName} (${variable.byteSize})${variableValue}`; }; //# sourceMappingURL=converterStorage2Dot.js.map