Skip to content

Make chain balance migration use totalWithdrawn/totalSuccessfulDeposits instead of totalSupply()#2041

Merged
StanislavBreadless merged 64 commits intodraft-v31from
sb/light-chain-balance-migration
Feb 25, 2026
Merged

Make chain balance migration use totalWithdrawn/totalSuccessfulDeposits instead of totalSupply()#2041
StanislavBreadless merged 64 commits intodraft-v31from
sb/light-chain-balance-migration

Conversation

@StanislavBreadless
Copy link
Collaborator

What ❔

Why ❔

Checklist

  • PR title corresponds to the body of PR (we generate changelog entries from PRs).
  • Tests for the changes have been added / updated.
  • Documentation comments have been added / updated.

function receiveMigrationOnL1(FinalizeL1DepositParams calldata _finalizeWithdrawalParams) external {
/// @notice Finalizes a token migration from L1 to Gateway.
/// @param _finalizeWithdrawalParams Message inclusion proof parameters.
function receiveL1ToGatewayMigrationOnL1(FinalizeL1DepositParams calldata _finalizeWithdrawalParams) external {
Copy link
Contributor

Choose a reason for hiding this comment

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

I would do this via a bool, it would remove quite a bit of code duplication.

Copy link
Collaborator Author

@StanislavBreadless StanislavBreadless Feb 19, 2026

Choose a reason for hiding this comment

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

I dont like bool because the fields for the structs are different, but at least some of the duplication can be moved to the inner functions I think

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I look at the code and it seems that the amount of common logic is not that large (asset id check, etc).

but the rest of the operations while they call the same functions, they call them with parameters with different means and so on, so IMO keeping those separate introduces less mental load for the auditor, though indeed a bit more code is needed

@StanislavBreadless StanislavBreadless force-pushed the sb/light-chain-balance-migration branch from acf08fd to 4044f76 Compare February 21, 2026 16:36
@StanislavBreadless StanislavBreadless force-pushed the sb/light-chain-balance-migration branch from 4044f76 to b1fe69e Compare February 21, 2026 16:36
/// before v31 it is equal to `2^256-1 - <sum of other chainBalances, including l1>`. For new tokens it is exactly `2^256-1`.
/// @param totalDepositedFromL1 Total amount deposited from L1 to the chain since v31 accounting started. Note, that it is not
/// just about any L1->L2 deposit, but only those that debited the chainBalance on L1 directly and it is assumed that every such
/// deposit will be processed while the chain is still settling on L1. It is the responsibility of the chain admin to ensure that.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

need to double check whether it is the responsibility of chain admin or the chain, i.e. does our impl enforce it in any way

function receiveMigrationOnL1(FinalizeL1DepositParams calldata _finalizeWithdrawalParams) external {
/// @notice Finalizes a token migration from L1 to Gateway.
/// @param _finalizeWithdrawalParams Message inclusion proof parameters.
function receiveL1ToGatewayMigrationOnL1(FinalizeL1DepositParams calldata _finalizeWithdrawalParams) external {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I look at the code and it seems that the amount of common logic is not that large (asset id check, etc).

but the rest of the operations while they call the same functions, they call them with parameters with different means and so on, so IMO keeping those separate introduces less mental load for the auditor, though indeed a bit more code is needed

@StanislavBreadless StanislavBreadless marked this pull request as ready for review February 21, 2026 18:05
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8e929e2cf0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +530 to +531
chainBalance[_chainId][_assetId] = 0;
assetMigrationNumber[_chainId][_assetId] = chainMigrationNumber;

Choose a reason for hiding this comment

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

P1 Badge Defer GW state mutation until L1 migration is confirmed

This eagerly zeroes chainBalance and advances assetMigrationNumber before L1 has accepted the Gateway->L1 migration message. If L1AssetTracker.receiveGatewayToL1MigrationOnL1 later reverts (for example on its settlement-layer whitelist or migration-number checks), the same migration cannot be retried because initiateGatewayToL1MigrationOnGateway requires assetMigrationNumber < chainMigrationNumber, so the balance is effectively stranded on Gateway.

Useful? React with 👍 / 👎.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

it is assumed it wont happen

Copy link
Contributor

@kelemeno kelemeno left a comment

Choose a reason for hiding this comment

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

ok, I reviewed the main processes now, looks good

@github-actions
Copy link
Contributor

Coverage after merging sb/light-chain-balance-migration into draft-v31 will be

90.88%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
contracts/bridge
   BridgeHelper.sol100%100%100%100%
   BridgedStandardERC20.sol96.25%100%92.31%97.01%231–232
   L1ERC20Bridge.sol97.78%100%100%97.30%261
   L1Nullifier.sol96.12%100%100%95.40%432–433, 436, 462, 715, 718, 720, 736
   UpgradeableBeaconDeployer.sol100%100%100%100%
contracts/bridge/asset-router
   AssetRouterBase.sol98.53%100%100%98.21%128
   L1AssetRouter.sol91.62%100%86.67%92.70%104, 319, 330, 412–413, 432, 590, 601, 615, 620
contracts/bridge/asset-tracker
   AssetTrackerBase.sol93.33%100%88.89%95.24%88
   GWAssetTracker.sol92.42%100%92.50%92.41%102, 152–154, 156–158, 163–164, 292–294, 310, 445, 635, 79–81
   L1AssetTracker.sol91.75%100%100%90.61%107–108, 121, 126, 138, 302, 304–305, 308, 542, 549, 555, 561, 567, 595, 60, 89
   LegacySharedBridgeAddresses.sol83.33%100%100%81.82%39, 41
contracts/bridge/interfaces
   AssetHandlerModifiers.sol75%100%100%66.67%13
contracts/bridge/ntv
   L1NativeTokenVault.sol98.17%100%100%97.70%184, 186
   NativeTokenVaultBase.sol98.94%100%100%98.73%149, 155
contracts/common
   MessageVerification.sol88.24%100%87.50%88.46%34, 41–42
   ReentrancyGuard.sol100%100%100%100%
contracts/common/l2-helpers
   L2ContractHelper.sol98.11%100%100%97.78%102
   SystemContractsCaller.sol52.50%100%60%51.43%42–43, 45, 47, 49, 51, 64, 67, 70, 73, 76, 81, 87, 89, 91, 94, 96
contracts/common/libraries
   DataEncoding.sol95.90%100%95.83%95.92%185, 275, 293, 299
   DynamicIncrementalMerkle.sol100%100%100%100%
   DynamicIncrementalMerkleMemory.sol98.96%100%100%98.84%196
   FullMerkle.sol98.28%100%100%98.11%109
   FullMerkleMemory.sol93.81%100%100%93.33%114, 131, 149, 163, 194, 90
   Merkle.sol100%100%100%100%
   MessageHashing.sol98.67%100%100%98.46%154
   SemVer.sol100%100%100%100%
   UncheckedMath.sol100%100%100%100%
   UnsafeBytes.sol100%100%100%100%
   ZKSyncOSBytecodeInfo.sol100%100%100%100%
contracts/common/libraries/TransientPrimitives
   TransientPrimitives.sol100%100%100%100%
contracts/core/bridgehub
   BridgehubBase.sol96.86%100%100%96.23%136, 285, 301, 561, 565, 568
   L1Bridgehub.sol92.78%100%100%91.86%202, 277, 281–282, 285, 295, 85
   L2Bridgehub.sol66.67%100%60%68.57%103–104, 112, 114–115, 124, 129–130, 132–133, 76
contracts/core/chain-asset-handler
   ChainAssetHandlerBase.sol85.86%100%92.31%84.88%104–105, 123–125, 174, 177, 186–187, 323, 327, 349, 97
   L1ChainAssetHandler.sol88.07%100%82.35%89.13%170, 259, 261–263, 302, 75–76, 80–81
   L2ChainAssetHandler.sol84.21%100%80%85.71%120, 124, 69, 93
contracts/core/chain-registration
   ChainRegistrationSender.sol90.91%100%100%88.89%41, 88, 92, 98
contracts/core/ctm-deployment
   CTMDeploymentTracker.sol100%100%100%100%
contracts/core/message-root
   L1MessageRoot.sol95.24%100%91.67%96.08%161–162
   L2MessageRoot.sol62.22%100%45.45%67.65%105, 112, 116–117, 38–39, 48–49, 53, 60, 76
   MessageRootBase.sol92.78%100%100%91.36%119, 123, 200, 271, 290, 334, 99
contracts/governance
   AccessControlRestriction.sol100%100%100%100%
   ChainAdmin.sol97.87%100%100%97.30%39
   ChainAdminOwnable.sol100%100%100%100%
   Governance.sol100%100%100%100%
   L2ProxyAdminDeployer.sol100%100%100%100%
   PermanentRestriction.sol100%100%100%100%
   ServerNotifier.sol100%100%100%100%
   TransitionaryOwner.sol100%100%100%100%
contracts/governance/restriction
   Restriction.sol100%100%100%100%
   RestrictionValidator.sol100%100%100%100%
contracts/interop
   AttributesDecoder.sol100%100%100%100%
   InteropCenter.sol95.56%100%88.46%96.48%103, 147–148, 546, 630, 91–92
   InteropDataEncoding.sol100%100%100%100%
   InteropHandler.sol96.64%100%100%96.26%34, 377, 399, 404
   L2InteropRootStorage.sol0%100%0%0%20–22, 41, 46, 52–53, 58, 60–62, 71, 73–74, 76–77, 81–82, 86, 88
   L2MessageVerification.sol100%100%100%100%
contracts/l2-system/zksync-os
   L1MessageGasLib.sol100%100%100%100%
   L1Messenger.sol94.12%100%100%92.86%29
   SystemContext.sol100%100%100%100%
   ZKOSContractDeployer.sol0%100%0%0%12–14, 20, 26, 30–31
contracts/l2-upgrades
   L2ComplexUpgrader.sol0%100%0%0%23–25, 39, 44, 46, 56, 62–63, 70, 79–81, 84, 86–87
   L2GenesisForceDeploymentsHelper.sol93.71%100%100%93.15%125, 171, 173, 177, 179–180, 210, 216, 435, 92
   L2GenesisUpgrade.sol0%100%0%0%30, 37, 39–40, 43, 47–50, 53, 55, 63
   L2V30TestnetSystemProxiesUpgrade.sol0%100%0%0%22, 27–28, 30, 41, 47, 52, 56, 61, 66, 71, 76, 81, 86, 93, 99
   L2V31Upgrade.sol0%100%0%0%14–15
   SystemContractProxy.sol88%100%66.67%90.91%16–17
   SystemContractProxyAdmin.sol60%100%66.67%57.14%12, 18–19
   V31AcrossRecovery.sol0%100%0%0%43–45, 64–65, 67–68, 72, 77–78, 93
contracts/state-transition
   AccessControlEnumerablePerChainAddressUpgradeable.sol98.25%100%100%97.83%179
   ChainTypeManagerBase.sol96.19%100%100%95.29%195, 198, 372, 462, 467, 609, 672, 710, 786
   EraChainTypeManager.sol94.12%100%100%92.86%34
   ZKsyncOSChainTypeManager.sol80%100%66.67%83.33%22–23
contracts/state-transition/chain-deps
   DiamondInit.sol94.23%100%100%94%58, 62, 66
   DiamondProxy.sol100%100%100%100%
   StoredBatchHashing.sol100%100%100%100%
contracts/state-transition/chain-deps/facets
   Admin.sol91.71%100%93.75%91.35%160, 164, 168, 238, 263–264, 348, 387, 57–59, 61–62, 73–75
   Committer.sol90.80%100%100%90%146, 171, 178, 224, 227–228, 232–233, 342,

@StanislavBreadless StanislavBreadless merged commit 22423f0 into draft-v31 Feb 25, 2026
27 checks passed
@StanislavBreadless StanislavBreadless deleted the sb/light-chain-balance-migration branch February 25, 2026 11:39
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.

4 participants