Skip to content

Update for Hardhat 3 #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 62 commits into
base: solidstate
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
1bac604
update hardhat dependencies, configure package as module
ItsNickBarry Apr 18, 2025
ad3932c
fix imports, export HardhatPlugin object
ItsNickBarry Apr 18, 2025
0249c0c
Merge branch 'master' into hh3
ItsNickBarry Apr 19, 2025
9a8b352
export HardhatPlugin object
ItsNickBarry Apr 19, 2025
fe91182
update tasks to Hardhat 3 API, register tasks in HardhatPlugin
ItsNickBarry Apr 19, 2025
3cc2e77
move task action functions to actions/ directory
ItsNickBarry Apr 19, 2025
770406b
load plugin into test config
ItsNickBarry Apr 19, 2025
2ba8158
fix lib file
ItsNickBarry Apr 19, 2025
a5a2145
fix build script
ItsNickBarry Apr 19, 2025
d6bdaf6
run clean script before build script
ItsNickBarry Apr 20, 2025
a4a0edd
use patch-package to patch hardhat output selection in development
ItsNickBarry Apr 20, 2025
9619276
replace extendConfig call with config hook
ItsNickBarry Apr 20, 2025
f3f710a
exclude artifacts from tsc
ItsNickBarry Apr 20, 2025
51cc205
add missing action export
ItsNickBarry Apr 20, 2025
73f5305
compile before all tasks
ItsNickBarry Apr 20, 2025
3989b3d
support non-fully-qualifed contract names
ItsNickBarry Apr 20, 2025
7902932
remove getCollatedStorageLayout function
ItsNickBarry Apr 20, 2025
f470b85
add git ref option to inspect task
ItsNickBarry Apr 20, 2025
15053cf
update test contract for git testing
ItsNickBarry Apr 20, 2025
a51bcf4
add callAtGitRef helper and getRawStorageLayoutFromArtifact callback
ItsNickBarry Apr 20, 2025
eb2fcc8
rename getRawStorageLayout to loadRawStorageLayout
ItsNickBarry Apr 20, 2025
a4d4ce2
read storage layout from file if path to .json is passed
ItsNickBarry Apr 20, 2025
707aca5
remove obsolete storage-layout-check task
ItsNickBarry Apr 20, 2025
fce55ff
update readme
ItsNickBarry Apr 20, 2025
1150c95
do not initialize git repository, wrap git checkout errors in Hardhat…
ItsNickBarry Apr 20, 2025
2c084c6
invert if condition to reduce nesting
ItsNickBarry Apr 20, 2025
0b061cb
remove obsolete ejs and mocha utilities
ItsNickBarry Apr 21, 2025
a5a1417
Merge branch 'solidstate' into hh3
ItsNickBarry Apr 21, 2025
2594b6b
avoid git checkout for file inputs
ItsNickBarry Apr 21, 2025
d407541
fix structure of loadRawStorageLayout
ItsNickBarry Apr 21, 2025
fc45bed
allow passing hre into bound function
ItsNickBarry Apr 21, 2025
f3b8a8b
add todo note
ItsNickBarry Apr 21, 2025
6231cb4
run patch-package on postinstall
ItsNickBarry Apr 21, 2025
76c0510
add getTmpHreAtGitRef helper, avoid double recompilation after git ch…
ItsNickBarry Apr 21, 2025
4f43935
remove callback pattern
ItsNickBarry Apr 21, 2025
c8019b0
remove unused intermediate variable
ItsNickBarry Apr 21, 2025
a5f44bf
update hardhat output selection patch
ItsNickBarry May 1, 2025
3b58f32
update hardhat output selection patch
ItsNickBarry May 1, 2025
e17a5e3
upgrade dependencies
ItsNickBarry May 5, 2025
e933705
handle git and npm errors
ItsNickBarry May 5, 2025
eb8684d
load remote createHardhatRuntimeEnvironment function
ItsNickBarry May 5, 2025
d1daa28
load remote findClosestHardhatConfig function
ItsNickBarry May 5, 2025
d3bff18
add todo notes
ItsNickBarry May 5, 2025
e633dbc
use indicator file to detect failed temporary git clone setup
ItsNickBarry May 5, 2025
1164293
replace pendingSetupIndicatorFile with successfulSetupIndicatorFile
ItsNickBarry May 5, 2025
5d09e93
upgrade dependencies
ItsNickBarry May 7, 2025
7129ea1
use prettier-plugin-packagejson to sort package.json
ItsNickBarry May 7, 2025
cc1e3a0
move types to types.ts
ItsNickBarry May 7, 2025
39923be
move print functions to separate file
ItsNickBarry May 7, 2025
de8ba31
do not export visualizeSlot function
ItsNickBarry May 7, 2025
0ebdc23
upgrade dependencies, remove patch-package and hardhat patch
ItsNickBarry May 7, 2025
0fd775a
rename load functions
ItsNickBarry May 7, 2025
6b4708c
support passing HookContext to getTmpHreAtGitRef, do not return HRE w…
ItsNickBarry May 8, 2025
c256f5e
use undefined default value for ref task options
ItsNickBarry May 8, 2025
f84ba04
use undefined ref options in task actions
ItsNickBarry May 8, 2025
78ec191
export compile task name
ItsNickBarry May 8, 2025
e762638
process git refs in tasks
ItsNickBarry May 8, 2025
20967ff
add --no-compile flag to all tasks
ItsNickBarry May 8, 2025
92df2f1
use hardhat-git plugin
ItsNickBarry May 10, 2025
29f3201
upgrade dependencies
ItsNickBarry May 11, 2025
9007357
update git hre factory calls, delegate npmInstall configuration to ha…
ItsNickBarry May 11, 2025
54e4695
import NewTaskActionFunction as type
ItsNickBarry May 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .lintstagedrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"*.{js,ts,ejs,sol,json,md}": ["prettier --write"]
"*.{js,ts,sol,json,md}": ["prettier --write"]
}
2 changes: 1 addition & 1 deletion .prettierrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"trailingComma": "all",
"bracketSpacing": true,
"plugins": [
"prettier-plugin-ejs",
"prettier-plugin-packagejson",
"prettier-plugin-solidity",
"@trivago/prettier-plugin-sort-imports"
]
Expand Down
31 changes: 22 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,16 @@ yarn add --dev @solidstate/hardhat-storage-layout-diff
Load plugin in Hardhat config:

```javascript
require('@solidstate/hardhat-storage-layout-diff');
import HardhatStorageLayoutDiff from '@solidstate/hardhat-storage-layout-diff';

const config: HardhatUserConfig = {
plugins: [
HardhatStorageLayoutDiff,
],
storageLayoutDiff: {
... // see table for configuration options
},
};
```

Add configuration under the `storageLayoutDiff` key:
Expand All @@ -31,6 +40,8 @@ Add configuration under the `storageLayoutDiff` key:
| `except` | `Array` of `String` matchers used to exclude contracts | `[]` |
| `spacing` | number of spaces per indentation level of formatted output | `2` |

Additional configuration options are provided by [`@solidstate/hardhat-git`](https://www.npmjs.com/package/@solidstate/hardhat-git), which is included as a dependency.

Export storage layouts:

```bash
Expand All @@ -39,24 +50,26 @@ npx hardhat export-storage-layout
yarn run hardhat export-storage-layout
```

Compare two contracts:
Inspect a contract's storage layout:

```bash
npx hardhat diff-storage-layout [CONTRACT_A_FULLY_QUALIFIED_NAME] [CONTRACT_B_FULLY_QUALIFIED_NAME]
npx hardhat inspect-storage-layout [CONTRACT_IDENTIFIER]
# or
yarn run hardhat diff-storage-layout [CONTRACT_A_FULLY_QUALIFIED_NAME] [CONTRACT_B_FULLY_QUALIFIED_NAME]
yarn run hardhat inspect-storage-layout [CONTRACT_IDENTIFIER]
```

Include the optional `--a-ref` and/or `--b-ref` arguments to specify the git reference where contracts `a` and `b` are defined, respectively.

Compare a contract to an exported JSON layout:
Compare two contracts:

```bash
npx hardhat storage-layout-check --source [PATH_TO_LAYOUT_JSON] --b [CONTRACT_B_FULLY_QUALIFIED_NAME]
npx hardhat diff-storage-layout [CONTRACT_A_IDENTIFIER] [CONTRACT_B_IDENTIFIER]
# or
yarn run hardhat storage-layout-check --source [PATH_TO_LAYOUT_JSON] --b [CONTRACT_B_FULLY_QUALIFIED_NAME]
yarn run hardhat diff-storage-layout [CONTRACT_A_IDENTIFIER] [CONTRACT_B_IDENTIFIER]
```

A contract identifier may be a name, a fully qualified name, or a path to a JSON file containing a storage layout.

Include the optional git ref options to look up a contract identifier at a particular git reference.

## Development

Install dependencies via Yarn:
Expand Down
2 changes: 1 addition & 1 deletion contracts/Test.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ contract Test {
struct Struct {
address a;
E e;
address b;
address b_changed;
E f;
}

Expand Down
3 changes: 2 additions & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import './src/index';
import HardhatStorageLayoutDiff from './src/index.js';
import { HardhatUserConfig } from 'hardhat/config';

const config: HardhatUserConfig = {
solidity: '0.8.28',
plugins: [HardhatStorageLayoutDiff],
};

export default config;
39 changes: 20 additions & 19 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"name": "@solidstate/hardhat-storage-layout-diff",
"version": "1.0.0",
"license": "MIT",
"description": "Compare storage layouts between two contracts",
"keywords": [
"hardhat",
Expand All @@ -15,39 +14,41 @@
"wow"
],
"repository": "github:solidstate-network/hardhat-storage-layout-diff",
"license": "MIT",
"author": "Nick Barry",
"type": "module",
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
"scripts": {
"build": "tsc --build --clean",
"prepare": "husky",
"prettier": "prettier --write ."
},
"files": [
"dist/src",
"src"
],
"peerDependencies": {
"hardhat": "^2.0.0"
"scripts": {
"build": "yarn clean && tsc --build",
"clean": "tsc --build --clean",
"prepare": "husky",
"prettier": "prettier --write ."
},
"dependencies": {
"@solidstate/hardhat-git": "^1.0.0-next.2",
"chalk": "^5.4.1",
"cli-table3": "^0.6.5",
"simple-git": "^3.27.0"
},
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"@types/ejs": "^3.1.5",
"@types/mocha": "^10.0.10",
"@types/node": "^22.14.1",
"hardhat": "^2.23.0",
"@types/node": "^22.15.17",
"hardhat": "^3.0.0-next.7",
"husky": "^9.1.7",
"lint-staged": "^15.5.1",
"lint-staged": "^16.0.0",
"prettier": "^3.5.3",
"prettier-plugin-ejs": "^1.0.3",
"prettier-plugin-solidity": "^1.4.2",
"prettier-plugin-packagejson": "^2.5.12",
"prettier-plugin-solidity": "^2.0.0",
"ts-node": "^10.9.2",
"typescript": "^5.8.3"
},
"dependencies": {
"chalk": "^5.4.1",
"cli-table3": "^0.6.5",
"simple-git": "^3.27.0"
"peerDependencies": {
"hardhat": "^3.0.0-next.6"
},
"publishConfig": {
"access": "public"
Expand Down
51 changes: 51 additions & 0 deletions src/actions/diff_storage_layout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { printMergedCollatedSlots } from '../lib/print.js';
import {
collateStorageLayout,
loadStorageLayout,
mergeCollatedSlots,
} from '../lib/storage_layout_diff.js';
import { TASK_COMPILE } from '../task_names.js';
import { createHardhatRuntimeEnvironmentAtGitRef } from '@solidstate/hardhat-git';
import type { NewTaskActionFunction } from 'hardhat/types/tasks';

interface DiffStorageLayoutTaskActionArguments {
a: string;
b: string;
aRef?: string;
bRef?: string;
noCompile: boolean;
}

const action: NewTaskActionFunction<
DiffStorageLayoutTaskActionArguments
> = async (args, hre) => {
const { aRef, bRef } = args;

const hreRefA = aRef
? await createHardhatRuntimeEnvironmentAtGitRef(hre.config, aRef)
: hre;

const hreRefB =
bRef === aRef
? hreRefA
: bRef
? await createHardhatRuntimeEnvironmentAtGitRef(hre.config, bRef)
: hre;

if (!args.noCompile) {
await hreRefA.tasks.getTask(TASK_COMPILE).run();

if (aRef !== bRef) {
await hreRefB.tasks.getTask(TASK_COMPILE).run();
}
}

const slotsA = collateStorageLayout(await loadStorageLayout(hreRefA, args.a));
const slotsB = collateStorageLayout(await loadStorageLayout(hreRefB, args.b));

const mergedSlots = mergeCollatedSlots(slotsA, slotsB);

printMergedCollatedSlots(mergedSlots);
};

export default action;
72 changes: 72 additions & 0 deletions src/actions/export_storage_layout.ts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import pkg from '../../package.json';
import { loadStorageLayout } from '../lib/storage_layout_diff.js';
import { TASK_COMPILE } from '../task_names.js';
import { HardhatPluginError } from 'hardhat/plugins';
import type { NewTaskActionFunction } from 'hardhat/types/tasks';
import fs from 'node:fs';
import path from 'node:path';

interface TaskActionArguments {
noCompile: boolean;
}

const action: NewTaskActionFunction<TaskActionArguments> = async (
args,
hre,
) => {
if (!args.noCompile) {
await hre.tasks.getTask(TASK_COMPILE).run();
}

const config = hre.config.storageLayoutDiff;

const outputDirectory = path.resolve(hre.config.paths.root, config.path);

if (!outputDirectory.startsWith(hre.config.paths.root)) {
throw new HardhatPluginError(
pkg.name,
'resolved path must be inside of project directory',
);
}

if (outputDirectory === hre.config.paths.root) {
throw new HardhatPluginError(
pkg.name,
'resolved path must not be root directory',
);
}

if (config.clear && fs.existsSync(outputDirectory)) {
fs.rmdirSync(outputDirectory, { recursive: true });
}

if (!fs.existsSync(outputDirectory)) {
fs.mkdirSync(outputDirectory, { recursive: true });
}

for (let fullName of await hre.artifacts.getAllFullyQualifiedNames()) {
if (config.only.length && !config.only.some((m) => fullName.match(m)))
continue;
if (config.except.length && config.except.some((m) => fullName.match(m)))
continue;

const storageLayout = await loadStorageLayout(hre, fullName);
const { storage, types } = storageLayout;

if (!storage.length) continue;

const destination =
path.resolve(outputDirectory, config.flat ? '' : '', fullName) + '.json';

if (!fs.existsSync(path.dirname(destination))) {
fs.mkdirSync(path.dirname(destination), { recursive: true });
}

fs.writeFileSync(
destination,
`${JSON.stringify({ storage, types }, null, config.spacing)}\n`,
);
}
};

export default action;
35 changes: 35 additions & 0 deletions src/actions/inspect_storage_layout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { printCollatedSlots } from '../lib/print.js';
import {
collateStorageLayout,
loadStorageLayout,
} from '../lib/storage_layout_diff.js';
import { TASK_COMPILE } from '../task_names.js';
import { createHardhatRuntimeEnvironmentAtGitRef } from '@solidstate/hardhat-git';
import type { NewTaskActionFunction } from 'hardhat/types/tasks';

interface InspectStorageLayoutTaskActionArguments {
contract: string;
ref?: string;
noCompile: boolean;
}

const action: NewTaskActionFunction<
InspectStorageLayoutTaskActionArguments
> = async (args, hre) => {
if (args.ref) {
// TODO: initialize hre with plugin or user config containing storageLayout output selection
hre = await createHardhatRuntimeEnvironmentAtGitRef(hre.config, args.ref);
}

if (!args.noCompile) {
await hre.tasks.getTask(TASK_COMPILE).run();
}

const slots = collateStorageLayout(
await loadStorageLayout(hre, args.contract),
);

printCollatedSlots(slots);
};

export default action;
40 changes: 40 additions & 0 deletions src/hooks/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { StorageLayoutDiffConfig } from '../types.js';
import type { ConfigHooks } from 'hardhat/types/hooks';

const DEFAULT_CONFIG: StorageLayoutDiffConfig = {
path: './storage_layout',
clear: false,
flat: false,
only: [],
except: [],
spacing: 2,
};

export default async (): Promise<Partial<ConfigHooks>> => ({
resolveUserConfig: async (userConfig, resolveConfigurationVariable, next) => {
const result = {
...(await next(userConfig, resolveConfigurationVariable)),
storageLayoutDiff: {
...DEFAULT_CONFIG,
...userConfig.storageLayoutDiff,
},
};

for (const key in result.solidity.profiles) {
const profile = result.solidity.profiles[key];

for (const compiler of profile.compilers) {
const settings = compiler.settings;
settings.outputSelection ??= {};
settings.outputSelection['*'] ??= {};
settings.outputSelection['*']['*'] ??= [];

if (!settings.outputSelection['*']['*'].includes('storageLayout')) {
settings.outputSelection['*']['*'].push('storageLayout');
}
}
}

return result;
},
});
Loading