Commit 96b9e701 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

contracts-bedrock: migrate to just (#11276)

* contracts-bedrock: migrate to just

Move away from `pnpm` for contracts scripts
and towards `just`. `just` was made for this,
since we are moving away from JS it makes no
sense to keep `pnpm` around which is native
to the JS ecosystem.

* ci: install just

* ops: cleanup, docs

* ci: install just

* justfile: update

* ci: fix install

* snapshots: update

* contracts-bedrock: remove pnpm/node, cleanup dockerfile

* slither ci: no longer need for workaround (TM)

* ts-linting: remove

* kontrol: regenerate snapshots

* safecall: update test

* test: update
Co-authored-by: default avatarMatt Solomon <matt@mattsolomon.dev>

* docs: update
Co-authored-by: default avatarMatt Solomon <matt@mattsolomon.dev>

* readme: update
Co-authored-by: default avatarMatt Solomon <matt@mattsolomon.dev>

* docs: update
Co-authored-by: default avatarMatt Solomon <matt@mattsolomon.dev>

* docs: update
Co-authored-by: default avatarMatt Solomon <matt@mattsolomon.dev>

* docs: update
Co-authored-by: default avatarMaurelian <john@oplabs.co>

* versions: use latest

* ci: fix

* CONTRIBUTING: update

* ci: fix

* lint: fix

---------
Co-authored-by: default avatarprotolambda <proto@protolambda.com>
Co-authored-by: default avatarMatt Solomon <matt@mattsolomon.dev>
Co-authored-by: default avatarMaurelian <john@oplabs.co>
parent 2491a373
...@@ -528,7 +528,7 @@ jobs: ...@@ -528,7 +528,7 @@ jobs:
# We do not use the pre-built contracts becuase forge coverage uses different optimizer settings # We do not use the pre-built contracts becuase forge coverage uses different optimizer settings
- run: - run:
name: test and generate coverage name: test and generate coverage
command: pnpm coverage:lcov command: just coverage-lcov
no_output_timeout: 18m no_output_timeout: 18m
environment: environment:
FOUNDRY_PROFILE: ci FOUNDRY_PROFILE: ci
...@@ -556,7 +556,7 @@ jobs: ...@@ -556,7 +556,7 @@ jobs:
working_directory: packages/contracts-bedrock working_directory: packages/contracts-bedrock
- run: - run:
name: run tests name: run tests
command: pnpm test command: just test
environment: environment:
FOUNDRY_PROFILE: ci FOUNDRY_PROFILE: ci
working_directory: packages/contracts-bedrock working_directory: packages/contracts-bedrock
...@@ -602,22 +602,22 @@ jobs: ...@@ -602,22 +602,22 @@ jobs:
# Semver lock must come second because one of the later steps may modify the cache & force a contracts rebuild. # Semver lock must come second because one of the later steps may modify the cache & force a contracts rebuild.
name: semver lock name: semver lock
command: | command: |
pnpm semver-lock just semver-lock
git diff --exit-code semver-lock.json || echo "export SEMVER_LOCK_STATUS=1" >> "$BASH_ENV" git diff --exit-code semver-lock.json || echo "export SEMVER_LOCK_STATUS=1" >> "$BASH_ENV"
working_directory: packages/contracts-bedrock working_directory: packages/contracts-bedrock
- run: - run:
name: check deploy configs name: check deploy configs
command: pnpm validate-deploy-configs || echo "export DEPLOY_CONFIGS_STATUS=1" >> "$BASH_ENV" command: just validate-deploy-configs || echo "export DEPLOY_CONFIGS_STATUS=1" >> "$BASH_ENV"
working_directory: packages/contracts-bedrock working_directory: packages/contracts-bedrock
- run: - run:
name: lint name: lint
command: | command: |
pnpm lint:check || echo "export LINT_STATUS=1" >> "$BASH_ENV" just lint-check || echo "export LINT_STATUS=1" >> "$BASH_ENV"
working_directory: packages/contracts-bedrock working_directory: packages/contracts-bedrock
- run: - run:
name: gas snapshot name: gas snapshot
command: | command: |
pnpm gas-snapshot --check || echo "export GAS_SNAPSHOT_STATUS=1" >> "$BASH_ENV" just gas-snapshot-check || echo "export GAS_SNAPSHOT_STATUS=1" >> "$BASH_ENV"
environment: environment:
FOUNDRY_PROFILE: ci FOUNDRY_PROFILE: ci
working_directory: packages/contracts-bedrock working_directory: packages/contracts-bedrock
...@@ -625,13 +625,13 @@ jobs: ...@@ -625,13 +625,13 @@ jobs:
- run: - run:
name: invariant docs name: invariant docs
command: | command: |
pnpm autogen:invariant-docs just autogen-invariant-docs
git diff --exit-code ./invariant-docs/*.md || echo "export INVARIANT_DOCS_STATUS=1" >> "$BASH_ENV" git diff --exit-code ./invariant-docs/*.md || echo "export INVARIANT_DOCS_STATUS=1" >> "$BASH_ENV"
working_directory: packages/contracts-bedrock working_directory: packages/contracts-bedrock
- run: - run:
name: snapshots name: snapshots
command: | command: |
pnpm snapshots:check || echo "export SNAPSHOTS_STATUS=1" >> "$BASH_ENV" just snapshots-check || echo "export SNAPSHOTS_STATUS=1" >> "$BASH_ENV"
working_directory: packages/contracts-bedrock working_directory: packages/contracts-bedrock
- run: - run:
name: size check name: size check
...@@ -697,7 +697,7 @@ jobs: ...@@ -697,7 +697,7 @@ jobs:
patterns: contracts-bedrock patterns: contracts-bedrock
- run: - run:
name: validate spacers name: validate spacers
command: pnpm validate-spacers command: just validate-spacers
working_directory: packages/contracts-bedrock working_directory: packages/contracts-bedrock
todo-issues: todo-issues:
...@@ -1162,6 +1162,11 @@ jobs: ...@@ -1162,6 +1162,11 @@ jobs:
command: | command: |
nvm install nvm install
nvm use && node --version && npm --version nvm use && node --version && npm --version
- run:
name: Install Just
command: |
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to $HOME/bin
echo 'export PATH="${PATH}:$HOME/bin"' >> $BASH_ENV
- run: - run:
name: Install pnpm name: Install pnpm
command: | command: |
...@@ -1491,7 +1496,7 @@ jobs: ...@@ -1491,7 +1496,7 @@ jobs:
docker_layer_caching: true docker_layer_caching: true
- run: - run:
name: Run Kontrol Tests name: Run Kontrol Tests
command: pnpm test:kontrol command: just test-kontrol
working_directory: ./packages/contracts-bedrock working_directory: ./packages/contracts-bedrock
- store_artifacts: - store_artifacts:
path: ./packages/contracts-bedrock/test/kontrol/logs/kontrol-results_latest.tar.gz path: ./packages/contracts-bedrock/test/kontrol/logs/kontrol-results_latest.tar.gz
......
...@@ -15,13 +15,6 @@ jobs: ...@@ -15,13 +15,6 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
# Workaround to prevent slither-action from trying to install JS deps.
# Without this step, it detects the `package.json`, and since there is no
# lockfile it defaults `npm install` which fails due to the preinstall
# script to enforce pnpm. https://github.com/crytic/slither-action/issues/44#issuecomment-1338183656
- name: Remove package.json
run: rm packages/contracts-bedrock/package.json
- name: Run Slither - name: Run Slither
uses: crytic/slither-action@v0.4.0 uses: crytic/slither-action@v0.4.0
id: slither id: slither
......
# This Dockerfile builds all the dependencies needed by the monorepo, and should # This Dockerfile builds all the dependencies needed by the smart-contracts, excluding Go and Python.
# be used to build any of the follow-on services
#
# Stage 0 (named `manifests`) collects
# dependency manifest files (`package.json` and `pnpm-lock.yaml`) which are then
# used by stage 1 to install these dependencies
# development. The only reason we need a separate stage just for collecting the
# dependency manifests is that Docker's `COPY` command still does not allow
# copying based on a glob pattern (see this GitHub issue for more details
# https://github.com/moby/moby/issues/15858). Being able to copy only manifests
# into stage 1 (the `COPY --from=manifests` statement) is important to maximize
# Docker build cache hit rate. `alpine` is chosen as the base image for the
# first stage because it's the smallest image that have access to the `cp
# --parents -t` command (by installing the `coreutils` package).
FROM alpine:3.16 as manifests
RUN apk add coreutils
WORKDIR /tmp
COPY pnpm-lock.yaml pnpm-workspace.yaml .nvmrc package.json ./src/
COPY packages src/packages/
RUN mkdir manifests && \
cd src && \
# copy package.json recursively
find . -name 'package.json' | xargs cp --parents -t ../manifests/ && \
# pnpm-lock.yaml
cp pnpm-lock.yaml ../manifests/ && \
# pnpm-workspace.yaml
cp pnpm-workspace.yaml ../manifests/ && \
# .nvmrc
cp .nvmrc ../manifests/
FROM us-docker.pkg.dev/oplabs-tools-artifacts/images/ci-builder:latest as foundry FROM us-docker.pkg.dev/oplabs-tools-artifacts/images/ci-builder:latest as foundry
# bullseye-slim is debian based
# we use it rather than alpine because it's not much # Historically the contracts-bedrock was on the node image based on Debian 11 (bullseye),
# bigger and alpine is often missing packages for node applications # for Node / PNPM compatibility reasons.
# alpine is not officially supported by node.js # We no longer use Node JS, but continue to use the same Debian version for compatibility.
FROM node:20.8.1-bullseye-slim as base FROM debian:bullseye-slim as base
# Base: install deps # Base: install deps
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
curl \ curl \
jq \ jq \
python3 \
ca-certificates \ ca-certificates \
git \ git \
g++ \
make \ make \
gcc \
musl-dev \
bash \ bash \
# the following 4 deps are needed for node-hid
# which is a deep sub dependency of ethers to install
# correctly
pkg-config \
libusb-1.0-0-dev \
libudev-dev \
--no-install-recommends --no-install-recommends
COPY /ops/docker/oplabs.crt /usr/local/share/ca-certificates/oplabs.crt COPY /ops/docker/oplabs.crt /usr/local/share/ca-certificates/oplabs.crt
RUN chmod 644 /usr/local/share/ca-certificates/oplabs.crt \ RUN chmod 644 /usr/local/share/ca-certificates/oplabs.crt \
&& update-ca-certificates && update-ca-certificates
RUN npm install pnpm --global # Note: "just" is only available on Debian 13. Instead, pull it from the foundry image.
COPY --from=foundry /usr/local/bin/just /usr/local/bin/just
COPY --from=foundry /usr/local/bin/forge /usr/local/bin/forge COPY --from=foundry /usr/local/bin/forge /usr/local/bin/forge
COPY --from=foundry /usr/local/bin/cast /usr/local/bin/cast COPY --from=foundry /usr/local/bin/cast /usr/local/bin/cast
WORKDIR /opt/optimism WORKDIR /opt/optimism
# Copy manifest files into the image in COPY ./versions.json ./versions.json
# preparation for `pnpm install`.
COPY --from=manifests /tmp/manifests ./
COPY *.json ./
RUN pnpm install --frozen-lockfile
COPY ./packages ./packages COPY ./packages ./packages
COPY .git/ ./.git COPY .git/ ./.git
COPY .gitmodules ./.gitmodules COPY .gitmodules ./.gitmodules
RUN git submodule update --init --recursive RUN git submodule update --init --recursive
# Not to be confused with OP, this is a OnePassword CLI tool.
COPY --from=1password/op:2 /usr/local/bin/op /usr/local/bin/op COPY --from=1password/op:2 /usr/local/bin/op /usr/local/bin/op
RUN pnpm build # prebuild the smart-contracts for the convenience of the user
RUN cd packages/contracts-bedrock && just build
ENTRYPOINT ["pnpm", "run"]
FROM base as contracts-bedrock FROM base as contracts-bedrock
WORKDIR /opt/optimism/packages/contracts-bedrock WORKDIR /opt/optimism/packages/contracts-bedrock
# Set "just" as entrypoint, so the default args (the Dockerfile CMD)
# are passed in to it. This was previously "pnpm run" + "deploy".
ENTRYPOINT ["just"]
CMD ["deploy"] CMD ["deploy"]
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"clean": "rm -rf node_modules packages/**/node_modules", "clean": "rm -rf node_modules packages/**/node_modules",
"build": "cd packages/contracts-bedrock && pnpm build", "build": "cd packages/contracts-bedrock && just build",
"test": "cd packages/contracts-bedrock && pnpm test", "test": "cd packages/contracts-bedrock && just test",
"issues": "./ops/scripts/todo-checker.sh", "issues": "./ops/scripts/todo-checker.sh",
"lint:shellcheck": "find . -type f -name '*.sh' -not -path '*/node_modules/*' -not -path './packages/contracts-bedrock/lib/*' -not -path './packages/contracts-bedrock/kout*/*' -exec sh -c 'echo \"Checking $1\"; shellcheck \"$1\"' _ {} \\;", "lint:shellcheck": "find . -type f -name '*.sh' -not -path '*/node_modules/*' -not -path './packages/contracts-bedrock/lib/*' -not -path './packages/contracts-bedrock/kout*/*' -exec sh -c 'echo \"Checking $1\"; shellcheck \"$1\"' _ {} \\;",
"install:foundry": "curl -L https://foundry.paradigm.xyz | bash && pnpm update:foundry", "install:foundry": "curl -L https://foundry.paradigm.xyz | bash && pnpm update:foundry",
......
# Deps and test files
lib
# build output
artifacts
forge-artifacts
cache
coverage*
deployments
module.exports = {
root: true,
env: {
browser: true,
es6: true,
},
ignorePatterns: ['dist', 'coverage'],
extends: ['plugin:prettier/recommended'],
parser: '@babel/eslint-parser',
parserOptions: {
es6: true,
ecmaVersion: 6,
sourceType: 'module',
requireConfigFile: false,
},
plugins: [
'eslint-plugin-import',
'eslint-plugin-jsdoc',
'eslint-plugin-prefer-arrow',
'@typescript-eslint',
],
overrides: [
{
files: ['**/*.ts'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: './packages/**/tsconfig.json',
sourceType: 'module',
allowAutomaticSingleRunInference: true,
},
rules: {
'@typescript-eslint/adjacent-overload-signatures': 'error',
'@typescript-eslint/array-type': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/consistent-type-assertions': 'error',
'@typescript-eslint/dot-notation': 'off',
'@typescript-eslint/indent': 'off',
'@typescript-eslint/member-delimiter-style': [
'off',
{
multiline: {
delimiter: 'none',
requireLast: true,
},
singleline: {
delimiter: 'semi',
requireLast: false,
},
},
],
'@typescript-eslint/member-ordering': 'off',
'@typescript-eslint/naming-convention': 'off',
'@typescript-eslint/no-empty-function': 'error',
'@typescript-eslint/no-empty-interface': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-misused-new': 'error',
'@typescript-eslint/no-namespace': 'error',
'@typescript-eslint/no-parameter-properties': 'off',
'@typescript-eslint/no-shadow': [
'error',
{
hoist: 'all',
},
],
'@typescript-eslint/no-this-alias': 'error',
'@typescript-eslint/no-unused-expressions': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/no-var-requires': 'error',
'@typescript-eslint/prefer-for-of': 'error',
'@typescript-eslint/prefer-function-type': 'error',
'@typescript-eslint/prefer-namespace-keyword': 'error',
'@typescript-eslint/quotes': 'off',
'@typescript-eslint/semi': ['off', null],
'@typescript-eslint/triple-slash-reference': [
'error',
{
path: 'always',
types: 'prefer-import',
lib: 'always',
},
],
'@typescript-eslint/type-annotation-spacing': 'off',
'@typescript-eslint/unified-signatures': 'error',
'@typescript-eslint/no-unused-vars': 'error',
},
},
],
rules: {
'prettier/prettier': 'warn',
'arrow-parens': ['off', 'always'],
'brace-style': ['off', 'off'],
'comma-dangle': 'off',
complexity: 'off',
'constructor-super': 'error',
curly: 'error',
'dot-notation': 'off',
'eol-last': 'off',
eqeqeq: ['error', 'smart'],
'guard-for-in': 'error',
'id-blacklist': 'off',
'id-match': 'off',
'import/no-extraneous-dependencies': ['error'],
'import/no-internal-modules': 'off',
'import/order': [
'error',
{
groups: ['builtin', 'external', 'internal'],
'newlines-between': 'always',
},
],
indent: 'off',
'jsdoc/check-alignment': 'error',
'jsdoc/check-indentation': 'error',
'linebreak-style': 'off',
'max-classes-per-file': 'off',
'max-len': 'off',
'new-parens': 'off',
'newline-per-chained-call': 'off',
'no-bitwise': 'off',
'no-caller': 'error',
'no-cond-assign': 'error',
'no-console': 'off',
'no-debugger': 'error',
'no-duplicate-case': 'error',
'no-duplicate-imports': 'error',
'no-empty': 'error',
'no-eval': 'error',
'no-extra-bind': 'error',
'no-extra-semi': 'off',
'no-fallthrough': 'off',
'no-invalid-this': 'off',
'no-irregular-whitespace': 'off',
'no-multiple-empty-lines': 'off',
'no-new-func': 'error',
'no-new-wrappers': 'error',
'no-redeclare': 'error',
'no-return-await': 'error',
'no-sequences': 'error',
'no-sparse-arrays': 'error',
'no-template-curly-in-string': 'error',
'no-throw-literal': 'error',
'no-trailing-spaces': 'off',
'no-undef-init': 'error',
'no-underscore-dangle': 'off',
'no-unsafe-finally': 'error',
'no-unused-expressions': 'off',
'no-unused-labels': 'error',
'no-use-before-define': 'off',
'no-var': 'error',
'object-shorthand': 'error',
'one-var': ['error', 'never'],
'padded-blocks': [
'off',
{
blocks: 'never',
},
{
allowSingleLineBlocks: true,
},
],
'prefer-arrow/prefer-arrow-functions': 'error',
'prefer-const': 'error',
'prefer-object-spread': 'error',
'quote-props': 'off',
quotes: 'off',
radix: 'error',
'react/jsx-curly-spacing': 'off',
'react/jsx-equals-spacing': 'off',
'react/jsx-tag-spacing': [
'off',
{
afterOpening: 'allow',
closingSlash: 'allow',
},
],
'react/jsx-wrap-multilines': 'off',
semi: 'off',
'space-before-blocks': 'error',
'space-before-function-paren': 'off',
'space-in-parens': ['off', 'never'],
'unicorn/prefer-ternary': 'off',
'use-isnan': 'error',
'valid-typeof': 'off',
},
}
module.exports = {
$schema: 'http://json.schemastore.org/prettierrc',
plugins: [],
trailingComma: 'es5',
tabWidth: 2,
semi: false,
singleQuote: true,
arrowParens: 'always',
overrides: [],
}
...@@ -52,7 +52,8 @@ The best place to begin contributing is by looking through the issues with the ` ...@@ -52,7 +52,8 @@ The best place to begin contributing is by looking through the issues with the `
Optimism's smart contracts are written in Solidity and we use [foundry](https://github.com/foundry-rs/foundry) as our development framework. To get started, you'll need to install several dependencies: Optimism's smart contracts are written in Solidity and we use [foundry](https://github.com/foundry-rs/foundry) as our development framework. To get started, you'll need to install several dependencies:
1. [pnpm](https://pnpm.io) 1. [pnpm](https://pnpm.io)
1. Make sure to `pnpm install` 1. [just](https://github.com/casey/just)
1. Make sure to `just install`
1. [foundry](https://getfoundry.sh) 1. [foundry](https://getfoundry.sh)
1. Foundry is built with [rust](https://www.rust-lang.org/tools/install), and this project uses a pinned version of foundry. Install the rust toolchain with `rustup`. 1. Foundry is built with [rust](https://www.rust-lang.org/tools/install), and this project uses a pinned version of foundry. Install the rust toolchain with `rustup`.
1. Make sure to install the version of foundry used by `ci-builder`, defined in the `versions.json` file in the root of this repo under the `foundry` key. Once you have `foundryup` installed, there is a helper to do this: `pnpm install:foundry` 1. Make sure to install the version of foundry used by `ci-builder`, defined in the `versions.json` file in the root of this repo under the `foundry` key. Once you have `foundryup` installed, there is a helper to do this: `pnpm install:foundry`
...@@ -61,20 +62,20 @@ Optimism's smart contracts are written in Solidity and we use [foundry](https:// ...@@ -61,20 +62,20 @@ Optimism's smart contracts are written in Solidity and we use [foundry](https://
Our [Style Guide](STYLE_GUIDE.md) contains information about the project structure, syntax preferences, naming conventions, and more. Please take a look at it before submitting a PR, and let us know if you spot inconsistencies! Our [Style Guide](STYLE_GUIDE.md) contains information about the project structure, syntax preferences, naming conventions, and more. Please take a look at it before submitting a PR, and let us know if you spot inconsistencies!
Once you've read the styleguide and are ready to work on your PR, there are a plethora of useful `pnpm` scripts to know about that will help you with development: Once you've read the style guide and are ready to work on your PR, there are a plethora of useful `just` scripts to know about that will help you with development.
1. `pnpm build` Builds the smart contracts. You can run `just -l` to list them all, some of the key ones are:
1. `pnpm test` Runs the full `forge` test suite. 1. `just build` Builds the smart contracts.
1 `pnpm gas-snapshot` Generates the gas snapshot for the smart contracts. 1. `just test` Runs the full `forge` test suite.
1. `pnpm semver-lock` Generates the semver lockfile. 1 `just gas-snapshot` Generates the gas snapshot for the smart contracts.
1. `pnpm storage-snapshot` Generates the storage lockfile. 1. `just semver-lock` Generates the semver lockfile.
1. `pnpm autogen:invariant-docs` Generates the invariant test documentation. 1. `just snapshots` Generates the storage and ABI snapshots.
1. `pnpm clean` Removes all build artifacts for `forge` and `go` compilations. 1. `just autogen-invariant-docs` Generates the invariant test documentation.
1. `pnpm validate-spacers` Validates the positions of the storage slot spacers. 1. `just clean` Removes all build artifacts for `forge` and `go` compilations.
1. `pnpm validate-deploy-configs` Validates the deployment configurations in `deploy-config` 1. `just validate-spacers` Validates the positions of the storage slot spacers.
1. `pnpm slither` Runs the slither static analysis tool on the smart contracts. 1. `just validate-deploy-configs` Validates the deployment configurations in `deploy-config`
1. `pnpm lint` Runs the linter on the smart contracts and scripts. 1. `just lint` Runs the linter on the smart contracts and scripts.
1. `pnpm pre-pr` Runs most checks, generators, and linters prior to a PR. For most PRs, this is sufficient to pass CI if everything is in order. 1. `just pre-pr` Runs most checks, generators, and linters prior to a PR. For most PRs, this is sufficient to pass CI if everything is in order.
1. `pnpm pre-pr:full` Runs all checks, generators, and linters prior to a PR. 1. `just pre-pr-full` Runs all checks, generators, and linters prior to a PR.
### Improving The Documentation ### Improving The Documentation
...@@ -90,11 +91,11 @@ To deploy the smart contracts on a local devnet, run `make devnet-up` in the mon ...@@ -90,11 +91,11 @@ To deploy the smart contracts on a local devnet, run `make devnet-up` in the mon
In order to make sure that we don't accidentally overwrite storage slots, contract storage layouts are checked to make sure spacing is correct. In order to make sure that we don't accidentally overwrite storage slots, contract storage layouts are checked to make sure spacing is correct.
This uses the `.storage-layout` file to check contract spacing. Run `pnpm validate-spacers` to check the spacing of all contracts. This uses the `snapshots/storageLayout` directory to check contract spacing. Run `just validate-spacers` to check the spacing of all contracts.
#### Gas Snapshots #### Gas Snapshots
We use forge's `gas-snapshot` subcommand to produce a gas snapshot for most tests within our suite. CI will check that the gas snapshot has been updated properly when it runs, so make sure to run `pnpm gas-snapshot`! We use forge's `gas-snapshot` subcommand to produce a gas snapshot for tests in `Benchmark.t.sol`. CI will check that the gas snapshot has been updated properly when it runs, so make sure to run `just gas-snapshot`!
#### Semver Locking #### Semver Locking
...@@ -102,4 +103,4 @@ Many of our smart contracts are semantically versioned. To make sure that change ...@@ -102,4 +103,4 @@ Many of our smart contracts are semantically versioned. To make sure that change
#### Storage Snapshots #### Storage Snapshots
Due to the many proxied contracts in Optimism's protocol, we automate tracking the diff to storage layouts of the contracts in the project. This is to ensure that we don't break a proxy by upgrading its implementation to a contract with a different storage layout. To generate the storage lockfile, run `pnpm storage-snapshot`. Due to the many proxied contracts in Optimism's protocol, we automate tracking the diff to storage layouts of the contracts in the project. This is to ensure that we don't break a proxy by upgrading its implementation to a contract with a different storage layout. To generate the storage lockfile, run `just snapshots`.
...@@ -361,7 +361,7 @@ to reduce the overhead of maintaining multiple ways to set up the state as well ...@@ -361,7 +361,7 @@ to reduce the overhead of maintaining multiple ways to set up the state as well
The L1 contract addresses are held in `deployments/hardhat/.deploy` and the L2 test state is held in a `.testdata` directory. The L1 addresses are used to create the L2 state The L1 contract addresses are held in `deployments/hardhat/.deploy` and the L2 test state is held in a `.testdata` directory. The L1 addresses are used to create the L2 state
and it is possible for stale addresses to be pulled into the L2 state, causing tests to fail. Stale addresses may happen if the order of the L1 deployments happen differently and it is possible for stale addresses to be pulled into the L2 state, causing tests to fail. Stale addresses may happen if the order of the L1 deployments happen differently
since some contracts are deployed using `CREATE`. Run `pnpm clean` and rerun the tests if they are failing for an unknown reason. since some contracts are deployed using `CREATE`. Run `just clean` and rerun the tests if they are failing for an unknown reason.
### Static Analysis ### Static Analysis
......
prebuild:
./scripts/checks/check-foundry-install.sh
build: prebuild
forge build
build-go-ffi:
cd scripts/go-ffi && go build
autogen-invariant-docs:
go run ./scripts/autogen/generate-invariant-docs .
test: build-go-ffi
forge test
test-kontrol:
./test/kontrol/scripts/run-kontrol.sh script
genesis:
forge script scripts/L2Genesis.s.sol:L2Genesis --sig 'runWithStateDump()'
coverage: build-go-ffi
forge coverage || (bash -c "forge coverage 2>&1 | grep -q 'Stack too deep' && echo -e '\\033[1;33mWARNING\\033[0m: Coverage failed with stack too deep, so overriding and exiting successfully' && exit 0 || exit 1")
coverage-lcov: build-go-ffi
forge coverage --report lcov || (bash -c "forge coverage --report lcov 2>&1 | grep -q 'Stack too deep' && echo -e '\\033[1;33mWARNING\\033[0m: Coverage failed with stack too deep, so overriding and exiting successfully' && exit 0 || exit 1")
deploy:
./scripts/deploy/deploy.sh
gas-snapshot-no-build:
forge snapshot --match-contract GasBenchMark
statediff:
./scripts/statediff.sh && git diff --exit-code
gas-snapshot: build-go-ffi gas-snapshot-no-build
gas-snapshot-check: build-go-ffi
forge snapshot --match-contract GasBenchMark --check
kontrol-summary:
./test/kontrol/scripts/make-summary-deployment.sh
kontrol-summary-fp:
KONTROL_FP_DEPLOYMENT=true ./test/kontrol/scripts/make-summary-deployment.sh
snapshots-abi-storage:
go run ./scripts/autogen/generate-snapshots .
snapshots: build snapshots-no-build
snapshots-no-build: snapshots-abi-storage kontrol-summary-fp kontrol-summary
snapshots-check:
./scripts/checks/check-snapshots.sh
semver-lock:
forge script scripts/SemverLock.s.sol
validate-deploy-configs:
./scripts/checks/check-deploy-configs.sh
validate-spacers-no-build:
go run ./scripts/checks/spacers
validate-spacers: build validate-spacers-no-build
clean:
rm -rf ./artifacts ./forge-artifacts ./cache ./scripts/go-ffi/go-ffi ./.testdata ./deployments/hardhat/*
pre-pr-no-build: gas-snapshot-no-build snapshots-no-build semver-lock autogen-invariant-docs lint
pre-pr: clean build-go-ffi build pre-pr-no-build
pre-pr-full: test validate-deploy-configs validate-spacers pre-pr
lint-forge-tests-check:
go run ./scripts/checks/names
lint-contracts-check:
forge fmt --check
lint-check: lint-contracts-check
lint-contracts-fix:
forge fmt
lint-fix: lint-contracts-fix
lint: lint-fix lint-check
{
"name": "@eth-optimism/contracts-bedrock",
"version": "0.17.3",
"description": "Contracts for Optimism Specs",
"license": "MIT",
"engines": {
"node": ">=16",
"pnpm": ">=9"
},
"files": [
"forge-artifacts/**/*.json",
"!forge-artifacts/**/*.t.sol/*.json",
"deployments/**/*.json",
"src/**/*.sol"
],
"scripts": {
"prebuild": "./scripts/checks/check-foundry-install.sh",
"build": "forge build",
"build:go-ffi": "(cd scripts/go-ffi && go build)",
"autogen:invariant-docs": "go run ./scripts/autogen/generate-invariant-docs .",
"test": "pnpm build:go-ffi && forge test",
"test:kontrol": "./test/kontrol/scripts/run-kontrol.sh script",
"genesis": "forge script scripts/L2Genesis.s.sol:L2Genesis --sig 'runWithStateDump()'",
"coverage": "pnpm build:go-ffi && (forge coverage || (bash -c \"forge coverage 2>&1 | grep -q 'Stack too deep' && echo -e '\\033[1;33mWARNING\\033[0m: Coverage failed with stack too deep, so overriding and exiting successfully' && exit 0 || exit 1\"))",
"coverage:lcov": "pnpm build:go-ffi && (forge coverage --report lcov || (bash -c \"forge coverage --report lcov 2>&1 | grep -q 'Stack too deep' && echo -e '\\033[1;33mWARNING\\033[0m: Coverage failed with stack too deep, so overriding and exiting successfully' && exit 0 || exit 1\"))",
"deploy": "./scripts/deploy/deploy.sh",
"gas-snapshot:no-build": "forge snapshot --match-contract GasBenchMark",
"statediff": "./scripts/statediff.sh && git diff --exit-code",
"gas-snapshot": "pnpm build:go-ffi && pnpm gas-snapshot:no-build",
"kontrol-summary": "./test/kontrol/scripts/make-summary-deployment.sh",
"kontrol-summary-fp": "KONTROL_FP_DEPLOYMENT=true pnpm kontrol-summary",
"snapshots": "forge build && go run ./scripts/autogen/generate-snapshots . && pnpm kontrol-summary-fp && pnpm kontrol-summary",
"snapshots:check": "./scripts/checks/check-snapshots.sh",
"semver-lock": "forge script scripts/SemverLock.s.sol",
"validate-deploy-configs": "./scripts/checks/check-deploy-configs.sh",
"validate-spacers:no-build": "go run ./scripts/checks/spacers",
"validate-spacers": "pnpm build && pnpm validate-spacers:no-build",
"clean": "rm -rf ./artifacts ./forge-artifacts ./cache ./tsconfig.tsbuildinfo ./tsconfig.build.tsbuildinfo ./scripts/go-ffi/go-ffi ./.testdata ./deployments/hardhat/*",
"pre-pr:no-build": "pnpm gas-snapshot:no-build && pnpm snapshots && pnpm semver-lock && pnpm autogen:invariant-docs && pnpm lint",
"pre-pr": "pnpm clean && pnpm build:go-ffi && pnpm build && pnpm pre-pr:no-build",
"pre-pr:full": "pnpm test && pnpm validate-deploy-configs && pnpm validate-spacers && pnpm pre-pr",
"lint:ts:check": "eslint . --max-warnings=0",
"lint:forge-tests:check": "go run ./scripts/checks/names",
"lint:contracts:check": "pnpm lint:fix && git diff --exit-code",
"lint:check": "pnpm lint:contracts:check && pnpm lint:ts:check",
"lint:ts:fix": "eslint --fix .",
"lint:contracts:fix": "forge fmt",
"lint:fix": "pnpm lint:contracts:fix && pnpm lint:ts:fix",
"lint": "pnpm lint:fix && pnpm lint:check"
},
"devDependencies": {
"@babel/eslint-parser": "^7.23.10",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"@types/node": "^20.14.12",
"doctoc": "^2.2.0",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsdoc": "^48.8.3",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^4.0.0",
"prettier": "^2.8.0",
"tsx": "^4.16.2",
"typescript": "^5.5.4"
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
set -euo pipefail set -euo pipefail
# Generate the snapshots # Generate the snapshots
pnpm snapshots just snapshots
# Check if the generated `snapshots` or `test/kontrol` files are different from the committed versions # Check if the generated `snapshots` or `test/kontrol` files are different from the committed versions
if git diff --exit-code snapshots test/kontrol > /dev/null; then if git diff --exit-code snapshots test/kontrol > /dev/null; then
......
...@@ -37,6 +37,7 @@ ver_foundry=$(versionFoundry "$(forge --version)") ...@@ -37,6 +37,7 @@ ver_foundry=$(versionFoundry "$(forge --version)")
ver_make=$(version "$(make --version)") ver_make=$(version "$(make --version)")
ver_jq=$(version "$(jq --version)") ver_jq=$(version "$(jq --version)")
ver_direnv=$(version "$(direnv --version)") ver_direnv=$(version "$(direnv --version)")
ver_just=$(version "$(just --version)")
# Print versions # Print versions
echo "Dependency | Minimum | Actual" echo "Dependency | Minimum | Actual"
...@@ -48,3 +49,4 @@ echo "foundry 0.2.0 (a5efe4f) $ver_foundry" ...@@ -48,3 +49,4 @@ echo "foundry 0.2.0 (a5efe4f) $ver_foundry"
echo "make 3 $ver_make" echo "make 3 $ver_make"
echo "jq 1.6 $ver_jq" echo "jq 1.6 $ver_jq"
echo "direnv 2 $ver_direnv" echo "direnv 2 $ver_direnv"
echo "just 1.34.0 $ver_just"
...@@ -13,6 +13,8 @@ contract SafeCall_Test is Test { ...@@ -13,6 +13,8 @@ contract SafeCall_Test is Test {
function assumeNot(address _addr) internal { function assumeNot(address _addr) internal {
vm.assume(_addr.balance == 0); vm.assume(_addr.balance == 0);
vm.assume(_addr != address(this)); vm.assume(_addr != address(this));
vm.assume(uint256(uint160(_addr)) > uint256(256)); // TODO temp fix until new forge-std release with modern
// precompiles: https://github.com/foundry-rs/forge-std/pull/594
assumeAddressIsNot(_addr, StdCheatsSafe.AddressType.ForgeAddress, StdCheatsSafe.AddressType.Precompile); assumeAddressIsNot(_addr, StdCheatsSafe.AddressType.ForgeAddress, StdCheatsSafe.AddressType.Precompile);
} }
......
{
"compilerOptions": {
"outDir": "./dist",
"skipLibCheck": true,
"module": "commonjs",
"target": "es2017",
"sourceMap": true,
"esModuleInterop": true,
"composite": true,
"resolveJsonModule": true,
"declaration": true,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"typeRoots": [
"node_modules/@types"
]
},
"exclude": [
"node_modules",
"dist"
],
"include": [
"deploy-config/**/*",
"deploy-config/**/*.json",
"scripts/**/*"
]
}
...@@ -5,5 +5,6 @@ ...@@ -5,5 +5,6 @@
"eth2_testnet_genesis": "v0.10.0", "eth2_testnet_genesis": "v0.10.0",
"nvm": "v20.9.0", "nvm": "v20.9.0",
"slither": "0.10.2", "slither": "0.10.2",
"kontrol": "0.1.316" "kontrol": "0.1.316",
"just": "1.34.0"
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment