Skip to content

chore(deps): bump script SDKs (dotenv 18, chalk 6, bs58 6, merkletreejs 0.6) - #2630

Open
gvladika wants to merge 36 commits into
mainfrom
chore/exsc-1306-script-sdk-upgrades
Open

gvladika wants to merge 36 commits into
mainfrom
chore/exsc-1306-script-sdk-upgrades

Conversation

@gvladika

@gvladika gvladika commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Which Linear task belongs to this PR?

Fixes EXSC-1306

Why did I implement it this way?

Internal takeover of fork PR #2606 by @philippzentner. CI and secrets don't run on fork PRs. Their 6 signed commits are kept as they made them, merged in, with one fix commit on top. Thanks for the detailed write-up on #2606. The package notes below come from it.

Stacked on #2609, which is stacked on #2607. Merge after both. Until then, GitHub shows #2609's changes as the base of this diff.

Packages (from #2606)

package from → to change in scripts
dotenv 16.6.1 → 18.0.9 dotenv 17+ prints an "injected env" line on every config() call. Explicit calls now pass { quiet: true }, including the facet demo template, except in the five demo scripts listed below. import 'dotenv/config' is quiet by default in 18.
bs58 4.0.1 → 6.0.0 v6 ships types, so the @ts-expect-error is gone.
merkletreejs 0.3.11 → 0.6.0 No code change. #2606 checked that the output is byte-identical (demoGenerateMerkleTree.ts plus 72 synthetic trees).
chalk 5.6.2 → 6.0.1 No code change. v6 raises the Node floor to 22.

Not bumped, as in #2606:

  • @solana/web3.js 3: @solana/spl-token 0.4.x still peers on web3.js 1.
  • citty 0.2: it breaks 11 script/deploy/safe flag tests, so it needs its own reviewed PR.

Changes on top of #2606

  • @arbitrum/sdk removed instead of bumped, and demoArbitrumBridge.ts deleted. It was the only user. The demo targets the Goerli testnet, which is shut down, and it reads config['goerli'].l2GatewayRouter, a key that config/arbitrumBridge.json doesn't have. Nothing references it. config/arbitrumBridge.json stays: DeployArbitrumBridgeFacet.s.sol reads it.
  • @cowprotocol/cow-sdk removed instead of bumped to 9, and demoPatcher.ts plus utils/cowSwapHelpers.ts deleted. They were the only users. The demo's CowShed post-hook calls RelayFacet.startBridgeTokensViaRelay, and RelayFacet is no longer on the diamond, so the script fails against current deployments (its own header said so). docs/Patcher.md and demoPatcherDest.ts still show the Patcher pattern.
  • Five demo scripts left as on main: demoChainflip, demoGasZip, demoLidoWrapper, demoMayanSolana, demoSquid. Their only change was the dotenv quiet flag. Touching them makes validate-scripts type-check them, and they have 15 type errors that already exist on main. Running them now prints one dotenv line.
  • Exact pins for the bumped packages, matching chore: CI and tooling upgrades (actions, TypeScript 6, husky 9, solhint 6, forge-std) #2609.
  • protobufjs override removed. Nothing in the dependency tree installs protobufjs any more, so the override matched nothing.

Signing path

script/deploy/safe/ changes by one line in each of 7 files: config() → config({ quiet: true, override: false }). Nothing else under the Safe/timelock scripts changes.

override: false is there because dotenv 17+ merges DOTENV_OVERRIDE / DOTENV_CONFIG_OVERRIDE from the shell into every config() call (16 only read them for import 'dotenv/config'). Without the pin, a signer with that flag exported would have .env replace an exported PRIVATE_KEY or SC_MONGODB_URI. Options passed in code win over the shell, so the pin keeps the old precedence: an export beats the file. I checked this against dotenv 18.0.9 with DOTENV_OVERRIDE=true. propose-to-safe.ts still uses import 'dotenv/config', which reads these variables in both versions, so docs/SigningFallbackRunbook.md §3 now stops the ceremony when any DOTENV_* variable is exported, and its description of the config() call is updated.

Verification

  • bunx tsx ./script/utils/validateScripts.ts --base origin/chore/exsc-1281-ci-tooling-upgrades: passes (typecheck of changed scripts, bare imports, citty args)
  • bun test:ts: 7207 pass, 0 fail
  • bunx prettier --check on the touched script directories: clean. bunx oxlint --type-aware on the changed helpers: exit 0. The remaining warnings are older anys on lines this PR doesn't touch.
  • Node smoke run via tsx: bs58 round trip, chalk, quiet dotenv and a merkletreejs root all load and run.

Checklist before requesting a review

Checklist for reviewer (DO NOT DEPLOY and contracts BEFORE CHECKING THIS!!!)

  • I have checked that any arbitrary calls to external contracts are validated and or restricted
  • I have checked that any privileged calls (i.e. storage modifications) are validated and or restricted
  • I have ensured that any new contracts have had AT A MINIMUM 1 preliminary audit conducted on by <company/auditor>

🤖 Generated with Claude Code

philippzentner and others added 30 commits October 31, 2026 11:14
Node 22 reaches end-of-life on 2027-04-30. Pin CI and .nvmrc to Node 26,
raise engines.node to >=24 so developers on the 24 LTS line keep working,
and move @types/node to 24.19.2 to match the lowest supported runtime.
tj-actions/changed-files was compromised in March 2025. The Olympix job only
needs the added/copied/modified/renamed src/**/*.sol list and a boolean, which
dorny/paths-filter (already used elsewhere) provides with identical semantics.
The immutable-registry job used bun-version: latest; use bun-version-file:
package.json like every other setup-bun step.
Bump the overrides still needed to the latest safe version within their
current major (protobufjs 7.6.6, axios 1.21.0, smol-toml 1.9.1, lodash 4.18.1,
katex 0.18.11, ws 8.22.1, ip-address 10.7.5, fast-uri 3.1.9; markdown-it is
already at the latest 14.x) and move the direct axios and smol-toml pins with
them. Drop socks, validator and handlebars: without the override the tree
already resolves a non-vulnerable version. bun audit: 83 -> 60.
Node 24+ matches engines.node; .nvmrc now selects 26. Bun follows the packageManager pin, which CI also uses.
Unify actions/checkout on v7.0.1 (four different v4 SHAs were in use) and
move every other external action to its latest release, SHA-pinned with
a version comment.
Minor and patch bumps for bun.lock dependencies arrive as one grouped PR
per month, with at most 5 open Dependabot PRs. The github-actions entry
stays weekly and ungrouped.
Moves the submodule to the v1.17.0 tag commit (f3dae6e) and updates
foundry.lock. src artifacts compile to identical bytecode, and forge test
gives the same pass/fail set as before.
TypeScript 7 (the native Go port) only ships the tsc binary and an
unstable API under typescript/unstable/*; require('typescript') returns
just the version. The node-runtime and funnel fences, validate-scripts
and several placement tests use the classic compiler API, so 6.0.3 is the
newest release that works.
husky 9: prepare runs `husky` (no `husky install`), and hooks no longer
source husky.sh. husky 9's wrapper still runs hooks under `sh -e`, so
pre-commit and pre-push keep re-execing themselves under `bash -e`, now
behind their own guard variable instead of husky v8's husky_skip_init.

lint-staged 17: the pre-commit output filter also drops the new progress
lines so failures still show only the tool output.
solhint 6 adds use-natspec, function-max-lines and seven gas-* rules to
solhint:recommended, which would raise ~900 warnings on src/. They are
turned off to keep the v5 rule set; the other new recommended rules
(duplicated-imports, no-immutable-before-declaration, no-unchecked-calls)
report nothing on src/ and stay on.

no-unused-vars now also checks modifier parameters (solhint 6.0.1) and
flags the unused _polymerData parameter of PolymerCCTPFacet's
validatePolymerData modifier. Fixing it changes src bytecode, so the rule
drops to warn and lint:sol reports 0 errors, 1 warning. .solhint.json is
plain JSON and solhint rejects extra keys, so the reasons live here.
.oxfmtrc.json is generated by `oxfmt --migrate=prettier` from
.prettierrc.cjs (same options, .prettierignore entries as ignorePatterns).
Prettier stays on 2.8 + prettier-plugin-solidity 1.4 for *.sol only:
Prettier 3 + plugin 2 would reformat 113 .sol files (49 under src/), and
any src/*.sol change alters bytecode metadata. solhint-plugin-prettier
stays on 0.0.5 because 0.1.0 needs Prettier 3.

Updates the format scripts, lint-staged, the agent format hook, the
factory format check, the docs that name the formatter and the VS Code
settings template.
Mechanical output of `bun format:fix` after the switch to oxfmt. No
.sol file changes. Listed in .git-blame-ignore-revs.

Committed with --no-verify: lint-staged's typecheck-files step fails on
script/demoScripts/demoChainflip.ts with the same 4 type errors it has on
main. oxlint, both fences and typecheck of the other 89 files pass.
- node-gyp 10 -> 13
- plop 3 -> 4 (bun codegen --help and a non-interactive facet run work)
- @typechain/ethers-v5 10 -> 11: same 369 files; inputs lose the
  PromiseOrValue<T> wrapper and overloaded event keys use full tuple
  signatures. No script uses either; tsc reports the same errors.
- markdownlint-cli2 0.23.3 -> 0.24.0 (lint:md clean)
- @types/bun 1.2 -> 1.4
- patch-package removed together with its postinstall step: the repo has
  no patches/ directory, so it never applied anything.
Its header says only humans edit the factory rules, so the switch of its
format check to oxfmt is left to a maintainer.
The file has 4 type errors on main, including an undefined
lifiDiamondAddress, so they can't be fixed with type-only changes.
Reformatting it made validate-scripts type-check it and fail. It is
restored byte-for-byte to main and listed in the oxfmt ignorePatterns.
lint-staged's oxfmt entry gets --no-error-on-unmatched-pattern so
staging an ignored file doesn't fail the commit.

Committed with --no-verify: staging the file makes lint-staged's
typecheck-files step report its 4 pre-existing errors, which happens for
any commit that touches it on main too.
v11 drops PromiseOrValue<T> from common.ts and every input type and
renames overloaded event keys. types.yaml publishes this output to
lifinance/lifi-contract-types as a patch/minor release, so v11 would
break downstream TS consumers. It needs a coordinated major release of
lifi-contract-types plus a downstream migration. The typechain output is
identical to the #2604 baseline again.
v4 renamed L1ToL2MessageGasEstimator to ParentToChildMessageGasEstimator
and exports it from the package root. estimateAll keeps the same
arguments and the l2CallValue field, so the demo script only needs the
import and constructor rename.
bs58 6 ships its own types, so the @ts-expect-error on the default
import is no longer needed. decode() now returns a Uint8Array instead of
a Buffer; the only consumer passes it to viem's toHex, which accepts
both.
Output is unchanged: demoGenerateMerkleTree.ts writes a byte-identical
outputMerkleProofs.json under 0.3.11 and 0.6.0 (sha256 0ab8f479…), and a
comparison over 72 trees (both gasRebates networks plus synthetic trees
of 1-70 leaves, including odd counts and a duplicate leaf) gives the
same roots and proofs.
chalk 6 only raises the Node floor to 22 (the repo runs Node 26) and
changes numeric FORCE_COLOR / ansi256 downsampling, neither of which the
scripts use. Kept as an exact pin, like before.
dotenv 17+ logs an "injected env" line on every config() call (to
stderr since 18). Pass { quiet: true } at all 34 explicit config() call
sites, including the facet demo template, so script output stays the
same as on dotenv 16. The 'dotenv/config' side-effect import already
defaults to quiet since 18.0.4. No script uses the removed .env.vault
support or preloading.

Touches signing-path files under script/deploy/safe/ (one-line
config() -> config({ quiet: true }) each).
cow-sdk 7+ takes a provider adapter instead of an ethers signer. The
demo now passes a ViemAdapter (@cowprotocol/sdk-viem-adapter) built from
the same Arbitrum RPC and private key; the ethers v5 adapter was not used
because it peers on @typechain/ethers-v5 11. postSwapOrder now returns an
object, so the order id is read from .orderId.

The CowShed constants moved to @cowprotocol/sdk-cow-shed and are keyed by
version; the helper keeps the 1.0.0 factory and implementation, which
are the same addresses cow-sdk 5 exported.
- Restore the validator 13.15.26 override: tronweb pins 13.15.23,
  which still carries AIKIDO-2025-10980 (see #2257).
- Pin dorny/paths-filter to v3.0.4: list-files: shell is affected by
  GHSA-7hc6-8hq5-9q2m below 3.0.4.
- Raise the Node minimum to 26 (engines, @types/node 26.6.6, Setup.md)
  to match .nvmrc, CI and the factory doctor check.
- Correct the setup-bun version comment (the SHA is v2.1.2) and quote
  $GITHUB_ENV in the Olympix args step.
- Reword the node-runtime fence comment: the allowlist follows what a
  .ts entry gets under tsx, not a Node version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Pin the three remaining setup-bun@v2 steps to v2.1.2 with
  bun-version-file, and install with --frozen-lockfile in validate-scripts
- Add setup-node (node-version-file: .nvmrc) after every setup-bun step,
  so scripts run by `bunx tsx` use the Node that engines requires; the
  two existing setup-node steps also read .nvmrc
- Move every dorny/paths-filter call site to v3.0.4
- Olympix: read the changed-file list as JSON and fail on whitespace in
  a path instead of re-parsing shell output with xargs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	.github/workflows/olympixStaticAnalysis.yml
#	.github/workflows/validateScripts.yml
#	bun.lock
#	package.json
- factory.yml: check TS/JS format with oxfmt, which now owns it.
- Drop .git-blame-ignore-revs: it names a fork-branch SHA that a
  squash merge discards. Add the main-branch SHA after merge.
- dependabot: 7-day cooldown on bun updates, and ignore the majors
  this PR holds back (@typechain/ethers-v5, prettier,
  prettier-plugin-solidity, solhint-plugin-prettier >=0.1, typescript).
- solhint: keep no-unused-vars an error, with validateParameters off
  so the existing unused modifier parameter in PolymerCCTPFacet does
  not need a src change.
- Drop the ip-address override: its only consumer (socks) is gone.
- Pin the bumped dev dependencies to their resolved versions.
- .oxfmtrc.json: drop the copy of .prettierignore, which oxfmt reads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
oxfmt follows Prettier 3's output, so switching from Prettier 2.8.8
rewrites ~90 TS/JS files (ternary indentation, trailing commas in type
arguments, parentheses around ??) with no way to configure it back.
That churn conflicts with every open script branch and pushes this PR
past CodeRabbit's 100-file limit. Restore the formatter setup, the
reformatted files and the docs/hooks to their pre-switch state, and
leave a formatter change for its own PR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gvladika and others added 4 commits November 2, 2026 15:04
Brings in d1cde7d (setup-node after every setup-bun, paths-filter
unified, Olympix JSON file list). Conflicts keep this branch's newer
pins (paths-filter v4.0.3, setup-bun v2.2.0), and every setup-node,
including the ones d1cde7d adds, moves to v7.1.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
husky 9 runs hooks under sh -e, so sourcing ~/.huskyrc before the re-exec
ran it under dash on Linux and dropped its unexported variables at exec.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…k-upgrades

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- pin the bumped SDKs to exact versions
- drop the protobufjs override: the cow-sdk 9 tree no longer pulls it in
- delete demoArbitrumBridge.ts and @arbitrum/sdk: the demo targets the shut
  down Goerli testnet and reads a config key that does not exist
- leave five demo scripts as on main: their only change was dotenv's quiet
  flag, and touching them surfaces type errors that predate this PR

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

Note

CodeRabbit ASCII loading animation

Currently processing new changes in this PR. This may take a few minutes, please wait...

Review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6cb6172b-b363-413b-a55a-41a5db3ae414
Commits

Reviewing files that changed from the base of the PR and between dfdd1b1 and dfdd1b1.

Files ignored due to path filters: 2

  • bun.lock is excluded by !**/*.lock
  • foundry.lock is excluded by !**/*.lock
Files selected for processing: 50

  • .github/actions/setup-foundry/action.yml
  • .github/dependabot.yml
  • .github/workflows/assignRequiresTypesLabel.yml
  • .github/workflows/bunLockfileCheck.yml
  • .github/workflows/convertForkedPRsToInternal.yml
  • .github/workflows/cronLiveness.yml
  • .github/workflows/deploy-smoke-test.yml
  • .github/workflows/deploymentAddressConsistency.yml
  • .github/workflows/diamondEmergencyPause.yml
  • .github/workflows/enforceLibAssetRouting.yml
  • .github/workflows/enforceProposalFunnel.yml
  • .github/workflows/forge-unit-tests.yml
  • .github/workflows/healthCheckAllNetworks.yml
  • .github/workflows/healthCheckForNewNetworkDeployment.yml
  • .github/workflows/healthCheckInvariantsReminder.yml
  • .github/workflows/jsonChecker.yml
  • .github/workflows/markdownlint.yml
  • .github/workflows/mintBuildAttestations.yml
  • .github/workflows/networkRpcsChecker.yml
  • .github/workflows/notifyDataTeamOnDeployment.yml
  • .github/workflows/olympixStaticAnalysis.yml
  • .github/workflows/protectAuditLabels.yml
  • .github/workflows/protectSecurityRelevantCode.yml
  • .github/workflows/qa-review-trigger.yml
  • .github/workflows/reconcileParkedTasks.yml
  • .github/workflows/runPendingTimelockTXs.yml
  • .github/workflows/securityAlertsReview.yml
  • .github/workflows/solc-floor-build.yml
  • .github/workflows/spdxLicenseChecker.yml
  • .github/workflows/syncLedgerClearSigning.yml
  • .github/workflows/ticketLinkageMetric.yml
  • .github/workflows/timelockWatcher.yml
  • .github/workflows/ts-unit-tests.yml
  • .github/workflows/types.yaml
  • .github/workflows/updateLouperViem.yml
  • .github/workflows/updateScriptConfigReminder.yml
  • .github/workflows/validateScripts.yml
  • .github/workflows/verifyClearSigning.yml
  • .github/workflows/verifyCommitsSigned.yml
  • .github/workflows/verifyEmergencyPauseReadiness.yml
  • .github/workflows/versionControlAndAuditCheck.yml
  • .github/workflows/weeklyCoverageReport.yml
  • .husky/pre-commit
  • .husky/pre-push
  • .nvmrc
  • .solhint.json
  • docs/Setup.md
  • lib/forge-std
  • package.json
  • script/utils/node-runtime-fence.ts

No actionable comments were generated in the recent review.

Walkthrough

The PR updates package dependencies, removes three demo-related code components, and changes dotenv configuration across scripts and a template. It also updates the signing runbook’s environment checks and removes a TypeScript suppression on the bs58 import.

Changes

Script and dependency updates

Layer / File(s) Summary
Dependency changes and demo removals
package.json, script/demoScripts/demoArbitrumBridge.ts, script/demoScripts/demoPatcher.ts, script/demoScripts/utils/cowSwapHelpers.ts
Dependency versions and package entries changed. The Arbitrum bridge demo, Patcher demo, and CowSwap helper file were removed.
Quiet dotenv initialization
script/demoScripts/*, script/mongoDb/fetch-rpcs.ts, script/utils/*, templates/facetDemoScript.template.hbs
Dotenv calls now use quiet: true. The @ts-expect-error directive on the bs58 import was removed.
Safe-script environment loading and runbook checks
script/deploy/safe/*, docs/SigningFallbackRunbook.md
Safe scripts now use dotenv options quiet: true and override: false. The runbook documents dotenv configuration variables and flags exported DOTENV_* variables as environment conflicts.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Other

Possibly related PRs

Merge Risk: Low · up to dfdd1

The new override:false setting in the Safe scripts does not protect against earlier dotenv loads in shared helpers. A direct CLI run with DOTENV_CONFIG_OVERRIDE set could replace exported signing values. Apply override:false to those helper loads or accept the limited risk before merging.

Pre-merge checks: Passed 5

Check name Status Explanation
Title check Passed The title identifies the main dependency upgrades.
Description check Passed The description includes all template sections and explains the changes and verification. The tests and documentation checklist items remain unchecked.
Docstring Coverage Passed No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 28 files. (1 skipped: 1 unsupported.)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Recent review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d3ad28ae-51d0-418a-8151-0ce4bc5216ff
Commits

Reviewing files that changed from the base of the PR and between 34e6c07 and dfdd1b1.

Files selected for processing: 8

  • docs/SigningFallbackRunbook.md
  • script/deploy/safe/add-safe-owners-and-threshold.ts
  • script/deploy/safe/confirm-safe-tx.ts
  • script/deploy/safe/deploy-safe.ts
  • script/deploy/safe/enqueue-parked-task.ts
  • script/deploy/safe/list-parked-tasks.ts
  • script/deploy/safe/list-pending-proposals.ts
  • script/deploy/safe/safe-utils.ts

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 0 remain after this review.

@lifi-action-bot
lifi-action-bot marked this pull request as draft November 6, 2026 13:00
@github-actions github-actions Bot added the requires-types Trigger Types Bindings CI (ABI/type generation for lifi-contract-types) label Nov 6, 2026
@gvladika

gvladika commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor
Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@gvladika
gvladika marked this pull request as ready for review November 6, 2026 14:32
demoPatcher.ts was the only user of @cowprotocol/cow-sdk,
sdk-cow-shed and sdk-viem-adapter. Its post-hook calls RelayFacet,
which is no longer on the diamond.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gvladika gvladika changed the title chore(deps): bump script SDKs (cow-sdk 9, dotenv 18, chalk 6, bs58 6, merkletreejs 0.6) chore(deps): bump script SDKs (dotenv 18, chalk 6, bs58 6, merkletreejs 0.6) Nov 6, 2026
@gvladika

gvladika commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor
Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

dotenv 17+ merges DOTENV_OVERRIDE / DOTENV_CONFIG_OVERRIDE from the
shell into every config() call, so an exported flag could let .env
replace an exported PRIVATE_KEY or SC_MONGODB_URI. Passing
override: false keeps exports ahead of the file. The signing runbook
now also stops on any exported DOTENV_* setting, which still applies
to propose-to-safe's import 'dotenv/config'.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gvladika

gvladika commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor
Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@lifi-qa-agent

lifi-qa-agent Bot commented Nov 6, 2026

Copy link
Copy Markdown

🔍 QA Review — EXSC-1306 · PR #2630

🔗 Pull Request #2630 · EXSC-1306

Verdict: ✅ Approve · Head dfdd1b1bd7eb · 🆕 First review · 0 findings · Awaiting response: 0 · 5 refuted

Summary

Script dependency bump (dotenv 18, chalk 6, bs58 6, merkletreejs 0.6) that removes @arbitrum/sdk, the CoW SDKs and their demo scripts. 35 files, +76/−1370, no src/ change (no audit entry needed). The PR is stacked on #2609, so the files diff is only this PR's own work; it must merge after #2609 and #2607.

Ticket check

AC Result
Remove @arbitrum/sdk with demoArbitrumBridge.ts ✅
Remove @cowprotocol/cow-sdk with demoPatcher.ts, cowSwapHelpers.ts ✅
dotenv 16 → 18 with quiet: true ✅
chalk 5 → 6, bs58 4 → 6, merkletreejs 0.3 → 0.6 ✅
Skip @solana/web3.js 3 and citty 0.2 ✅

Findings

None.

Refuted candidates

  1. Removed deps still referenced: repo-wide grep (excluding bun.lock) finds no remaining reference to @arbitrum/sdk, @cowprotocol/*, cowSwapHelpers, demoPatcher.ts, demoArbitrumBridge, protobufjs.
  2. bs58 6 break: sole user demoScriptHelpers.ts uses decode/encode with Uint8Array, which viem's toHex accepts; dropping the @ts-expect-error is right since v6 ships types.
  3. Unpinned dotenv in the signing path: all 7 script/deploy/safe/* config() calls pass { quiet: true, override: false }; only the 5 demo scripts keep bare calls, as the PR states.
  4. chalk 6 / merkletreejs 0.6 API change: imports and the new MerkleTree(leafNodes, keccak256, { sortPairs: true }) call match the new APIs.
  5. Lockfile / protobufjs override: bun-lockfile-check passes and bun.lock has no protobufjs entry.

Notes (do not gate)

  • 🔵 No test pins override: false in the 7 signing files; a later refactor could drop it unnoticed.
  • 🔵 DOTENV_CONFIG_PATH could redirect which .env the signing scripts load under dotenv 17+; the new runbook ^DOTENV_ check covers the manual ceremony.
  • 🔵 bs58 and dotenv sit in devDependencies although demo scripts use them at runtime (pre-existing).

Downstream impact

Tooling only; no ABI, selector or storage change. CI is green (run-ts-tests, validate-scripts, bun-lockfile-check, check-secrets, enforce-proposal-funnel, verify-build-manifest); audit and Solidity jobs are skipped as expected. I did not run the scripts; CI is the evidence.

lifi-qa-agent[bot]
lifi-qa-agent Bot previously approved these changes Nov 6, 2026

@lifi-qa-agent lifi-qa-agent Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [Automated QA Review] Approved — PR #2630: script SDK bump verified; removed SDKs have no remaining references, signing path pins dotenv override: false, no src/ change

@lifi-qa-agent lifi-qa-agent Bot added the QA AI Approved Zeus QA review passed label Nov 6, 2026

@0xDEnYO 0xDEnYO left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bumps and removals check out. merkletreejs 0.6 gives byte-identical roots and proofs, bs58 6's Uint8Array decode is fine for the one toHex use, CI runs Node 26 for chalk 6, and nothing references the removed SDKs any more.

One thing to fix: the override: false pin in script/deploy/safe/ doesn't hold. Those files import viemScriptHelpers.ts, which imports utils.ts, and both load .env without a pin at module scope (import 'dotenv/config' in utils.ts:6, dotenv.config({ quiet: true }) in viemScriptHelpers.ts:39). ESM runs those before the safe file's own config() call, so by the time the pin runs, .env has already overwritten the export.

Repro: export a variable, put a different value in a file passed via DOTENV_PATH, set DOTENV_OVERRIDE=true, and import safe-utils.ts. The file value wins. Without DOTENV_OVERRIDE the export still wins, as before.

The new runbook guard on DOTENV_* still stops the ceremony, so this isn't a live hole there. But the PR description and runbook §3 promise more than the code does, and anyone running the safe scripts outside the runbook isn't covered. Part of this predates the PR (dotenv 16 already honoured DOTENV_CONFIG_OVERRIDE through utils.ts), but 18 applies it to every config() call.

Suggested fix: pin override: false in utils.ts and viemScriptHelpers.ts, ideally through one shared loader, then rerun the repro.

import { getRPCEnvVarName, getRPCFallbacksEnvVarName, OUT_ROOT } from './utils'

dotenv.config()
dotenv.config({ quiet: true })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every pinned call in script/deploy/safe/ runs after this one, because they import this file. With DOTENV_OVERRIDE=true exported, this call has already let .env overwrite the export. It needs override: false here too, and so does the import 'dotenv/config' in utils.ts:6, which this file imports.

So a stale value exported earlier in the session silently beats the file.
dotenv also takes its own options from `DOTENV_*` / `DOTENV_CONFIG_*`
variables: `DOTENV_PATH` loads a different file, and `DOTENV_OVERRIDE` flips
the precedence for `import 'dotenv/config'`. Check all of it, and never print

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DOTENV_OVERRIDE flips precedence for any unpinned config() in the import graph, not only import 'dotenv/config'. Also, utils.ts's dotenv/config loads before confirm-safe-tx's pinned call. The STOP outcome is right; the explanation just needs to match the code once the pin is fixed.

Base automatically changed from chore/exsc-1281-ci-tooling-upgrades to main November 9, 2026 11:57
@gvladika
gvladika dismissed lifi-qa-agent[bot]’s stale review November 9, 2026 11:57

The base branch was changed.

@gvladika
gvladika requested review from a team November 9, 2026 11:57

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

QA AI Approved Zeus QA review passed requires-types Trigger Types Bindings CI (ABI/type generation for lifi-contract-types)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants