Skip to content

fix: use L2_ADMIN (ZkSync Safe) instead of NODL_ADMIN for L2 contract ownership#109

Merged
aliXsed merged 6 commits intomainfrom
aliX/fix-l2-owner
Apr 10, 2026
Merged

fix: use L2_ADMIN (ZkSync Safe) instead of NODL_ADMIN for L2 contract ownership#109
aliXsed merged 6 commits intomainfrom
aliX/fix-l2-owner

Conversation

@aliXsed
Copy link
Copy Markdown
Collaborator

@aliXsed aliXsed commented Apr 10, 2026

Problem

All L2 swarm contracts (ServiceProvider, FleetIdentity, SwarmRegistry, BondTreasuryPaymaster) were deployed with NODL_ADMIN (0x55f5...AD8) as owner — which is the L1 Ethereum Safe multisig. This address has no code on ZkSync L2 (it's an EOA there), and since nobody holds its private key, ownership functions (upgrade, configure) are effectively locked.

Verified on-chain

  • 0x55f5E48A1d30d67ac13751b523Ca1b3cB5838AD8 — Safe multisig on L1 only, EOA on ZkSync
  • 0x5e097AC1BCF81E7Ff2657045F72cAa6cF06486C9 — Safe multisig on ZkSync L2 only, confirmed as NODL token default admin
  • Cross-chain Safe replay is not possible (ZkSync uses a different CREATE2 formula, producing a different address)

Fix

Introduce L2_ADMIN environment variable — the ZkSync Safe multisig address — and use it as the owner for all L2 contract deployments instead of NODL_ADMIN.

Changes

File Change
script/DeploySwarmUpgradeableZkSync.s.sol NODL_ADMINL2_ADMIN (now required, not optional)
ops/deploy_swarm_contracts_zksync.sh NODL_ADMINL2_ADMIN with validation
hardhat-deploy/DeploySwarmUpgradeable.ts OWNERL2_ADMIN with validation

Not changed (intentionally)

  • NODL_ADMIN in .env-prod — still needed for L1 contracts (bridge, L1 NODL token)
  • script/DeployL1Nodl.s.sol, script/DeployL1Ens.s.sol — L1 deployments correctly use L1 Safe

Redeployment required

The existing mainnet contracts need to be redeployed with the correct owner. The current deployments (2026-04-07) are locked and cannot be upgraded.

aliXsed added 2 commits April 10, 2026 14:08
- Add virtual version() returning '1.0.0' to FleetIdentityUpgradeable
- Update V2 mock to override with '2.0.0'
- Add test_FleetIdentity_Version and test_FleetIdentity_VersionChangesAfterUpgrade
- Fix override specifier in TestUpgradeOnAnvil V2 mock
… ownership

NODL_ADMIN (0x55f5...AD8) is the L1 Ethereum Safe multisig and has no
code on ZkSync L2, making contracts owned by it effectively locked.

Replace with L2_ADMIN which must be set to the ZkSync Safe multisig
(0x5e09...6C9) — verified as the NODL token default admin on L2.

Affected deployment scripts:
- script/DeploySwarmUpgradeableZkSync.s.sol: L2_ADMIN now required (was optional NODL_ADMIN)
- ops/deploy_swarm_contracts_zksync.sh: L2_ADMIN required with validation
- hardhat-deploy/DeploySwarmUpgradeable.ts: L2_ADMIN required with validation

Contracts affected: ServiceProvider, FleetIdentity, SwarmRegistry,
BondTreasuryPaymaster (all on ZkSync Era).
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 10, 2026

LCOV of commit 9aae07f during checks #651

Summary coverage rate:
  lines......: 31.9% (771 of 2414 lines)
  functions..: 27.9% (105 of 377 functions)
  branches...: 37.6% (140 of 372 branches)

Files changed coverage rate:
                                                  |Lines       |Functions  |Branches    
  Filename                                        |Rate     Num|Rate    Num|Rate     Num
  ======================================================================================
  script/DeploySwarmUpgradeableZkSync.s.sol       | 0.0%     64| 0.0%     1|    -      0
  test/upgradeable/UpgradeableContracts.t.sol     | 0.0%     20| 0.0%     9| 0.0%      2

aliXsed added 4 commits April 10, 2026 15:36
- Add ops/verify_zksync_contracts.py: standalone script that generates
  standard JSON via forge, rewrites OpenZeppelin's "../" relative imports
  to resolved project paths, and submits directly to ZkSync verification API.
  Supports single-contract and batch (--broadcast) modes.

- Add bytecode_hash = "none" to foundry.toml (both profiles): omits CBOR
  metadata hash from bytecode so future deployments achieve full (not partial)
  verification on ZkSync explorer.

- Rewrite verify_source_code() in deploy_swarm_contracts_zksync.sh to call
  the Python script instead of the broken flatten approach.

- Document the verification problem and solution in copilot-instructions.md
  so AI assistants know the correct approach immediately.
…instructions.md, remove Cursor-specific .agent/rules/
@aliXsed aliXsed merged commit 40d3af8 into main Apr 10, 2026
3 checks passed
@aliXsed aliXsed deleted the aliX/fix-l2-owner branch April 10, 2026 04:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant