Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

sol2uml

Package Overview
Dependencies
Maintainers
1
Versions
84
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sol2uml - npm Package Compare versions

Comparing version 2.0.5 to 2.1.0

4

lib/converterAST2Classes.js

@@ -101,3 +101,5 @@ "use strict";

// this has come from Etherscan
const importPath = path.join(codeFolder, childNode.path);
const importPath = childNode.path[0] === '@'
? childNode.path
: path.join(codeFolder, childNode.path);
imports.push({

@@ -104,0 +106,0 @@ absolutePath: importPath,

@@ -6,3 +6,3 @@ import { Attribute, UmlClass } from './umlClass';

}
export interface Storage {
export interface Variable {
id: number;

@@ -16,7 +16,7 @@ fromSlot: number;

contractName?: string;
value?: string;
structObjectId?: number;
values: string[];
structStorageId?: number;
enumId?: number;
}
export interface StorageObject {
export interface Storage {
id: number;

@@ -26,7 +26,14 @@ name: string;

type: StorageType;
storages: Storage[];
variables: Variable[];
}
export declare const convertClasses2StorageObjects: (contractName: string, umlClasses: UmlClass[]) => StorageObject[];
export declare const parseStructStorageObject: (attribute: Attribute, otherClasses: UmlClass[], storageObjects: StorageObject[]) => StorageObject | undefined;
/**
*
* @param url
* @param contractAddress Contract address to get the storage slot values from
* @param storage is mutated with the storage values
*/
export declare const addStorageValues: (url: string, contractAddress: string, storage: Storage, blockTag: string) => Promise<void>;
export declare const convertClasses2Storages: (contractName: string, umlClasses: UmlClass[]) => Storage[];
export declare const parseStructStorage: (attribute: Attribute, otherClasses: UmlClass[], storages: Storage[]) => Storage | undefined;
export declare const calcStorageByteSize: (attribute: Attribute, umlClass: UmlClass, otherClasses: UmlClass[]) => number;
export declare const isElementary: (type: string) => boolean;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isElementary = exports.calcStorageByteSize = exports.parseStructStorageObject = exports.convertClasses2StorageObjects = exports.StorageType = void 0;
exports.isElementary = exports.calcStorageByteSize = exports.parseStructStorage = exports.convertClasses2Storages = exports.addStorageValues = exports.StorageType = void 0;
const umlClass_1 = require("./umlClass");
const associations_1 = require("./associations");
const slotValues_1 = require("./slotValues");
var StorageType;

@@ -11,5 +12,19 @@ (function (StorageType) {

})(StorageType = exports.StorageType || (exports.StorageType = {}));
let storageObjectId = 1;
let storageId = 1;
const convertClasses2StorageObjects = (contractName, umlClasses) => {
let variableId = 1;
/**
*
* @param url
* @param contractAddress Contract address to get the storage slot values from
* @param storage is mutated with the storage values
*/
const addStorageValues = async (url, contractAddress, storage, blockTag) => {
const slots = storage.variables.map((s) => s.fromSlot);
const values = await (0, slotValues_1.getStorageValues)(url, contractAddress, slots, blockTag);
storage.variables.forEach((storage, i) => {
storage.values = [values[i]];
});
};
exports.addStorageValues = addStorageValues;
const convertClasses2Storages = (contractName, umlClasses) => {
// Find the base UML Class from the base contract name

@@ -22,21 +37,21 @@ const umlClass = umlClasses.find(({ name }) => {

}
const storageObjects = [];
const storages = parseStorage(umlClass, umlClasses, [], storageObjects, []);
storageObjects.unshift({
id: storageObjectId++,
const storages = [];
const variables = parseVariables(umlClass, umlClasses, [], storages, []);
storages.unshift({
id: storageId++,
name: contractName,
type: StorageType.Contract,
storages,
variables: variables,
});
return storageObjects;
return storages;
};
exports.convertClasses2StorageObjects = convertClasses2StorageObjects;
exports.convertClasses2Storages = convertClasses2Storages;
/**
* Recursively parses the storage for a given contract.
* Recursively parses the storage variables for a given contract.
* @param umlClass contract or file level struct
* @param umlClasses other contracts, structs and enums that may be a type of a storage variable.
* @param storages mutable array of storage slots that is appended to
* @param storageObjects mutable array of StorageObjects that is appended with structs
* @param variables mutable array of storage slots that is appended to
* @param storages mutable array of storages that is appended with structs
*/
const parseStorage = (umlClass, umlClasses, storages, storageObjects, inheritedContracts) => {
const parseVariables = (umlClass, umlClasses, variables, storages, inheritedContracts) => {
// Add storage slots from inherited contracts first.

@@ -55,3 +70,3 @@ // Get immediate parent contracts that the class inherits from

// recursively parse inherited contract
parseStorage(parentClass, umlClasses, storages, storageObjects, inheritedContracts);
parseVariables(parentClass, umlClasses, variables, storages, inheritedContracts);
});

@@ -65,9 +80,9 @@ // Parse storage for each attribute

// find any dependent structs
const linkedStruct = (0, exports.parseStructStorageObject)(attribute, umlClasses, storageObjects);
const structObjectId = linkedStruct?.id;
const linkedStruct = (0, exports.parseStructStorage)(attribute, umlClasses, storages);
const structStorageId = linkedStruct?.id;
// Get the toSlot of the last storage item
let lastToSlot = 0;
let nextOffset = 0;
if (storages.length > 0) {
const lastStorage = storages[storages.length - 1];
if (variables.length > 0) {
const lastStorage = variables[variables.length - 1];
lastToSlot = lastStorage.toSlot;

@@ -77,5 +92,5 @@ nextOffset = lastStorage.byteOffset + lastStorage.byteSize;

if (nextOffset + byteSize > 32) {
const nextFromSlot = storages.length > 0 ? lastToSlot + 1 : 0;
storages.push({
id: storageId++,
const nextFromSlot = variables.length > 0 ? lastToSlot + 1 : 0;
variables.push({
id: variableId++,
fromSlot: nextFromSlot,

@@ -88,8 +103,9 @@ toSlot: nextFromSlot + Math.floor((byteSize - 1) / 32),

contractName: umlClass.name,
structObjectId,
structStorageId,
values: [],
});
}
else {
storages.push({
id: storageId++,
variables.push({
id: variableId++,
fromSlot: lastToSlot,

@@ -102,14 +118,15 @@ toSlot: lastToSlot,

contractName: umlClass.name,
structObjectId,
structStorageId,
values: [],
});
}
});
return storages;
return variables;
};
const parseStructStorageObject = (attribute, otherClasses, storageObjects) => {
const parseStructStorage = (attribute, otherClasses, storages) => {
if (attribute.attributeType === umlClass_1.AttributeType.UserDefined) {
// Have we already created the storageObject?
const existingStorageObject = storageObjects.find((dep) => dep.name === attribute.type);
if (existingStorageObject) {
return existingStorageObject;
// Have we already created the storage?
const existingStorage = storages.find((dep) => dep.name === attribute.type);
if (existingStorage) {
return existingStorage;
}

@@ -124,11 +141,11 @@ // Is the user defined type linked to another Contract, Struct or Enum?

if (dependentClass.stereotype === umlClass_1.ClassStereotype.Struct) {
const storages = parseStorage(dependentClass, otherClasses, [], storageObjects, []);
const newStorageObject = {
id: storageObjectId++,
const variables = parseVariables(dependentClass, otherClasses, [], storages, []);
const newStorage = {
id: storageId++,
name: attribute.type,
type: StorageType.Struct,
storages,
variables,
};
storageObjects.push(newStorageObject);
return newStorageObject;
storages.push(newStorage);
return newStorage;
}

@@ -146,6 +163,6 @@ return undefined;

if (result !== null && result[1] && !(0, exports.isElementary)(result[1])) {
// Have we already created the storageObject?
const existingStorageObject = storageObjects.find(({ name }) => name === result[1] || name === result[1].split('.')[1]);
if (existingStorageObject) {
return existingStorageObject;
// Have we already created the storage?
const existingStorage = storages.find(({ name }) => name === result[1] || name === result[1].split('.')[1]);
if (existingStorage) {
return existingStorage;
}

@@ -158,11 +175,11 @@ // Find UserDefined type

if (typeClass.stereotype === umlClass_1.ClassStereotype.Struct) {
const storages = parseStorage(typeClass, otherClasses, [], storageObjects, []);
const newStorageObject = {
id: storageObjectId++,
const variables = parseVariables(typeClass, otherClasses, [], storages, []);
const newStorage = {
id: storageId++,
name: typeClass.name,
type: StorageType.Struct,
storages,
variables,
};
storageObjects.push(newStorageObject);
return newStorageObject;
storages.push(newStorage);
return newStorage;
}

@@ -174,3 +191,3 @@ }

};
exports.parseStructStorageObject = parseStructStorageObject;
exports.parseStructStorage = parseStructStorage;
// Calculates the storage size of an attribute in bytes

@@ -177,0 +194,0 @@ const calcStorageByteSize = (attribute, umlClass, otherClasses) => {

@@ -1,3 +0,3 @@

import { StorageObject } from './converterClasses2Storage';
export declare const convertStorage2Dot: (storageObjects: StorageObject[]) => string;
export declare function convertStorageObject2Dot(storageObject: StorageObject, dotString: string): string;
import { Storage } from './converterClasses2Storage';
export declare const convertStorages2Dot: (storages: Storage[]) => string;
export declare function convertStorage2Dot(storage: Storage, dotString: string): string;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.convertStorageObject2Dot = exports.convertStorage2Dot = void 0;
exports.convertStorage2Dot = exports.convertStorages2Dot = void 0;
const converterClasses2Storage_1 = require("./converterClasses2Storage");
const debug = require('debug')('sol2uml');
const convertStorage2Dot = (storageObjects) => {
const convertStorages2Dot = (storages) => {
let dotString = `

@@ -13,11 +13,11 @@ digraph StorageDiagram {

node [shape=record, style=filled, fillcolor=gray95]`;
// process contract and the struct objects
storageObjects.forEach((storageObject) => {
dotString = convertStorageObject2Dot(storageObject, dotString);
// process contract and the struct storages
storages.forEach((storage) => {
dotString = convertStorage2Dot(storage, dotString);
});
// link contract and structs to structs
storageObjects.forEach((slot) => {
slot.storages.forEach((storage) => {
if (storage.structObjectId) {
dotString += `\n ${slot.id}:${storage.id} -> ${storage.structObjectId}`;
storages.forEach((slot) => {
slot.variables.forEach((storage) => {
if (storage.structStorageId) {
dotString += `\n ${slot.id}:${storage.id} -> ${storage.structStorageId}`;
}

@@ -31,51 +31,57 @@ });

};
exports.convertStorage2Dot = convertStorage2Dot;
function convertStorageObject2Dot(storageObject, dotString) {
const steorotype = storageObject.type === converterClasses2Storage_1.StorageType.Struct ? 'Struct' : 'Contract';
// write object header with name and optional address
dotString += `\n${storageObject.id} [label="{\\<\\<${steorotype}\\>\\>\\n${storageObject.name}\\n${storageObject.address || ''} | `;
exports.convertStorages2Dot = convertStorages2Dot;
function convertStorage2Dot(storage, dotString) {
const steorotype = storage.type === converterClasses2Storage_1.StorageType.Struct ? 'Struct' : 'Contract';
// write storage header with name and optional address
dotString += `\n${storage.id} [label="${storage.name} \\<\\<${steorotype}\\>\\>\\n${storage.address || ''} | {`;
const startingVariables = storage.variables.filter((s) => s.byteOffset === 0);
// write slot numbers
storageObject.storages.forEach((storage, i) => {
if (i === 0) {
dotString += `{slot | 0`;
dotString += '{ slot';
startingVariables.forEach((variable, i) => {
if (variable.fromSlot === variable.toSlot) {
dotString += `| ${variable.fromSlot} `;
}
else if (storage.byteOffset === 0) {
if (storage.fromSlot === storage.toSlot) {
dotString += `| ${storage.fromSlot}`;
else {
dotString += `| ${variable.fromSlot}-${variable.toSlot} `;
}
});
// write slot values if available
if (startingVariables[0]?.values[0]) {
dotString += '} | {value';
startingVariables.forEach((variable, i) => {
dotString += ` | ${variable.values[0]}`;
});
}
const contractVariablePrefix = storage.type === converterClasses2Storage_1.StorageType.Contract ? '\\<inherited contract\\>.' : '';
dotString += `} | { type: ${contractVariablePrefix}variable (bytes)`;
// For each slot
startingVariables.forEach((variable) => {
// Get all the storage variables in this slot
const slotVariables = storage.variables.filter((s) => s.fromSlot === variable.fromSlot);
const usedBytes = slotVariables.reduce((acc, s) => acc + s.byteSize, 0);
if (usedBytes < 32) {
slotVariables.push({
id: 0,
fromSlot: variable.fromSlot,
toSlot: variable.fromSlot,
byteSize: 32 - usedBytes,
byteOffset: usedBytes,
type: 'unallocated',
contractName: variable.contractName,
variable: '',
values: [],
});
}
const slotVariablesReversed = slotVariables.reverse();
// For each variable in the slot
slotVariablesReversed.forEach((variable, i) => {
if (i === 0) {
dotString += ` | { ${dotVariable(variable, storage.name)} `;
}
else {
dotString += `| ${storage.fromSlot}-${storage.toSlot}`;
dotString += ` | ${dotVariable(variable, storage.name)} `;
}
}
});
dotString += '}';
});
// write storage types
storageObject.storages.forEach((storage, i) => {
const lastStorage = i > 0 ? storageObject.storages[i - 1] : undefined;
const nextStorage = i + 1 < storageObject.storages.length
? storageObject.storages[i + 1]
: undefined;
if (i === 0) {
const contractVaraiblePrefix = storageObject.type === converterClasses2Storage_1.StorageType.Contract
? '\\<inherited contract\\>.'
: '';
dotString += `} | {type: ${contractVaraiblePrefix}variable (bytes) `;
}
// if next storage is in the same slot
// and storage is the first in the slot
if (nextStorage?.fromSlot === storage.fromSlot &&
storage.byteOffset === 0) {
dotString += `| { ${dotVariable(storage, storageObject.name)} `;
return;
}
// if last storage was on the same slot
// and the next storage is on a different slot
if (lastStorage?.fromSlot === storage.fromSlot &&
(nextStorage?.fromSlot > storage.fromSlot ||
nextStorage === undefined)) {
dotString += `| ${dotVariable(storage, storageObject.name)} } `;
return;
}
// If storage covers a whole slot or is not at the start or end of a slot
dotString += `| ${dotVariable(storage, storageObject.name)} `;
});
// Need to close off the last label

@@ -85,8 +91,11 @@ dotString += '}}"]\n';

}
exports.convertStorageObject2Dot = convertStorageObject2Dot;
exports.convertStorage2Dot = convertStorage2Dot;
const dotVariable = (storage, contractName) => {
const port = storage.structObjectId !== undefined ? `<${storage.id}>` : '';
const port = storage.structStorageId !== undefined ? `<${storage.id}>` : '';
const contractNamePrefix = storage.contractName !== contractName ? `${storage.contractName}.` : '';
return `${port} ${storage.type}: ${contractNamePrefix}${storage.variable} (${storage.byteSize})`;
const variable = storage.variable
? `: ${contractNamePrefix}${storage.variable}`
: '';
return `${port} ${storage.type}${variable} (${storage.byteSize})`;
};
//# sourceMappingURL=converterStorage2Dot.js.map

@@ -1,21 +0,51 @@

// import { providers } from 'ethers'
// import { BigNumberish } from '@ethersproject/bignumber'
// import { BlockTag } from '@ethersproject/abstract-provider'
//
// export const getStorageValue = async (
// contractAddress: string,
// slot: BigNumberish,
// blockTag: BlockTag = 'latest'
// ) => {
// const provider = new providers.JsonRpcProvider(
// 'https://eth-mainnet.alchemyapi.io/v2/iRsTnBFfuK96dHeFnEJ0wg56wdzioYPg',
// 'mainnet'
// )
// const slotValue = await provider.getStorageAt(
// contractAddress,
// slot,
// blockTag
// )
// console.log(`Slot ${slot}: ${slotValue}`)
// }
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getStorageValues = exports.getStorageValue = void 0;
const bignumber_1 = require("@ethersproject/bignumber");
const axios_1 = __importDefault(require("axios"));
const debug = require('debug')('sol2uml');
const getStorageValue = async (url, contractAddress, slot, blockTag = 'latest') => {
debug(`About to get storage slot ${slot} value for ${contractAddress}`);
const values = await (0, exports.getStorageValues)(url, contractAddress, [slot], blockTag);
debug(`Got slot ${slot} value: ${values[0]}`);
return values[0];
};
exports.getStorageValue = getStorageValue;
let jsonRpcId = 0;
const getStorageValues = async (url, contractAddress, slots, blockTag = 'latest') => {
try {
debug(`About to get ${slots.length} storage values for ${contractAddress} at block ${blockTag}`);
const block = blockTag === 'latest'
? blockTag
: bignumber_1.BigNumber.from(blockTag).toHexString();
const payload = slots.map((slot) => ({
id: (jsonRpcId++).toString(),
jsonrpc: '2.0',
method: 'eth_getStorageAt',
params: [
contractAddress,
bignumber_1.BigNumber.from(slot).toHexString(),
block,
],
}));
const response = await axios_1.default.post(url, payload);
console.log(response.data);
if (response.data?.error?.message) {
throw new Error(response.data.error.message);
}
if (response.data.length !== slots.length) {
throw new Error(`Requested ${slots.length} storage slot values but only got ${response.data.length}`);
}
const responseData = response.data;
const sortedResponses = responseData.sort((a, b) => bignumber_1.BigNumber.from(a.id).gt(b.id) ? 1 : -1);
return sortedResponses.map((data) => data.result);
}
catch (err) {
throw new Error(`Failed to get ${slots.length} storage values for ${contractAddress} from ${url}`, { cause: err });
}
};
exports.getStorageValues = getStorageValues;
//# sourceMappingURL=slotValues.js.map

@@ -78,3 +78,3 @@ #! /usr/bin/env node

};
const { umlClasses } = await (0, parserGeneral_1.parserUmlClasses)(fileFolderAddress, combinedOptions);
const { umlClasses, contractName } = await (0, parserGeneral_1.parserUmlClasses)(fileFolderAddress, combinedOptions);
let filteredUmlClasses = umlClasses;

@@ -86,3 +86,3 @@ if (options.baseContractNames) {

const dotString = (0, converterClasses2Dot_1.convertUmlClasses2Dot)(filteredUmlClasses, combinedOptions.clusterFolders, combinedOptions);
await (0, writerFiles_1.writeOutputFiles)(dotString, fileFolderAddress, combinedOptions.outputFormat, combinedOptions.outputFileName);
await (0, writerFiles_1.writeOutputFiles)(dotString, fileFolderAddress, contractName, combinedOptions.outputFormat, combinedOptions.outputFileName);
debug(`Finished generating UML`);

@@ -98,4 +98,9 @@ }

.argument('<fileFolderAddress>', 'file name, base folder or contract address')
.option('-c, --contractName <value>', 'Contract name in local Solidity files. Not needed when using an address as the first argument.')
// .option('-d, --data', 'gets the data in the storage slots')
.option('-c, --contract <name>', 'Contract name in local Solidity files. Not needed when using an address as the first argument as the contract name can be derived from Etherscan.')
.option('-d, --data', 'Gets the values in the storage slots from an Ethereum node.', false)
.option('-s, --storage <address>', 'The address of the contract with the storage values. This will be different from the contract with the code if a proxy contract is used. This is not needed if `fileFolderAddress` is an address and the contract is not proxied.')
.addOption(new commander_1.Option('-u, --url <url>', 'URL of the Ethereum node to get storage values if the `data` option is used.')
.env('NODE_URL')
.default('http://localhost:8545'))
.option('-bn, --block <number>', 'Block number to get the contract storage values from.', 'latest')
.action(async (fileFolderAddress, options, command) => {

@@ -108,10 +113,28 @@ try {

let { umlClasses, contractName } = await (0, parserGeneral_1.parserUmlClasses)(fileFolderAddress, combinedOptions);
contractName = combinedOptions.contractName || contractName;
const storageObjects = (0, converterClasses2Storage_1.convertClasses2StorageObjects)(contractName, umlClasses);
contractName = combinedOptions.contract || contractName;
const storages = (0, converterClasses2Storage_1.convertClasses2Storages)(contractName, umlClasses);
if ((0, regEx_1.isAddress)(fileFolderAddress)) {
// The first object is the contract
storageObjects[0].address = fileFolderAddress;
// The first storage is the contract
storages[0].address = fileFolderAddress;
}
debug(storageObjects);
const dotString = (0, converterStorage2Dot_1.convertStorage2Dot)(storageObjects);
debug(storages);
if (combinedOptions.data) {
let storageAddress = combinedOptions.storage;
if (storageAddress) {
if (!(0, regEx_1.isAddress)(storageAddress)) {
throw Error(`Invalid address to get storage data from "${storageAddress}"`);
}
}
else {
if (!(0, regEx_1.isAddress)(fileFolderAddress)) {
throw Error(`Can not get storage slot values if first param is not an address and the \`address\` option is not used.`);
}
storageAddress = fileFolderAddress;
}
const storage = storages.find((so) => so.name === contractName);
if (!storageAddress)
throw Error(`Could not find the "${contractName}" contract in list of parsed storages`);
await (0, converterClasses2Storage_1.addStorageValues)(combinedOptions.url, storageAddress, storage, combinedOptions.blockNumber);
}
const dotString = (0, converterStorage2Dot_1.convertStorages2Dot)(storages);
await (0, writerFiles_1.writeOutputFiles)(dotString, fileFolderAddress, contractName, combinedOptions.outputFormat, combinedOptions.outputFileName);

@@ -118,0 +141,0 @@ }

@@ -5,4 +5,4 @@ export declare type OutputFormats = 'svg' | 'png' | 'dot' | 'all';

export declare function writeSolidity(code: string, filename?: string): void;
export declare function writeDot(dot: string, filename?: string): void;
export declare function writeDot(dot: string, filename: string): void;
export declare function writeSVG(svg: any, svgFilename?: string, outputFormats?: OutputFormats): Promise<void>;
export declare function writePng(svg: any, filename: string): Promise<void>;

@@ -13,9 +13,2 @@ "use strict";

const writeOutputFiles = async (dot, fileFolderAddress, contractName, outputFormat = 'svg', outputFilename) => {
if (outputFormat === 'dot' || outputFormat === 'all') {
writeDot(dot, outputFilename);
// No need to continue if only generating a dot file
if (outputFormat === 'dot') {
return;
}
}
// If all output then extension is svg

@@ -40,2 +33,9 @@ const outputExt = outputFormat === 'all' ? 'svg' : outputFormat;

}
if (outputFormat === 'dot' || outputFormat === 'all') {
writeDot(dot, outputFilename);
// No need to continue if only generating a dot file
if (outputFormat === 'dot') {
return;
}
}
const svg = convertDot2Svg(dot);

@@ -78,9 +78,7 @@ if (outputFormat === 'svg' || outputFormat === 'all') {

exports.writeSolidity = writeSolidity;
function writeDot(dot, filename = 'classDiagram.dot') {
const extension = path_1.default.extname(filename);
const outputFile = extension === '.dot' ? filename : filename + '.dot';
debug(`About to write Dot file to ${outputFile}`);
(0, fs_1.writeFile)(outputFile, dot, (err) => {
function writeDot(dot, filename) {
debug(`About to write Dot file to ${filename}`);
(0, fs_1.writeFile)(filename, dot, (err) => {
if (err) {
throw new Error(`Failed to write Dot file to ${outputFile}`, {
throw new Error(`Failed to write Dot file to ${filename}`, {
cause: err,

@@ -90,3 +88,3 @@ });

else {
console.log(`Dot file written to ${outputFile}`);
console.log(`Dot file written to ${filename}`);
}

@@ -93,0 +91,0 @@ });

{
"name": "sol2uml",
"version": "2.0.5",
"version": "2.1.0",
"description": "Unified Modeling Language (UML) class diagram generator for Solidity contracts",

@@ -28,2 +28,3 @@ "main": "./lib/index.js",

"debug": "^4.3.4",
"ethers": "^5.6.9",
"js-graph-algorithms": "^1.0.18",

@@ -30,0 +31,0 @@ "klaw": "^4.0.1"

@@ -118,8 +118,12 @@ # Solidity 2 UML

Arguments:
fileFolderAddress file name, base folder or contract address
fileFolderAddress file name, base folder or contract address
Options:
-c, --contractName <value> Contract name in local Solidity files. Not needed when using an address as the first argument.
-h, --help display help for command
-c, --contract <name> Contract name in local Solidity files. Not needed when using an address as the first argument as the contract name can be derived from Etherscan.
-d, --data Gets the values in the storage slots from an Ethereum node. (default: false)
-s, --storage <address> The address of the contract with the storage values. This will be different from the contract with the code if a proxy contract is used. This is not needed if `fileFolderAddress` is an address and
the contract is not proxied.
-u, --url <url> URL of the Ethereum node to get storage values if the `data` option is used. (default: "http://localhost:8545", env: NODE_URL)
-bn, --block <number> Block number to get the contract storage values from. (default: "latest")
-h, --help display help for command
```

@@ -126,0 +130,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc