@@ -66,13 +66,6 @@ contract GWAssetTracker is AssetTrackerBase, IGWAssetTracker {
6666 /// empty messageRoot calculated for specific chain.
6767 mapping (uint256 chainId = > bytes32 emptyMessageRoot ) internal emptyMessageRoot;
6868
69- /// @notice We save the chainBalance which equals the chains totalSupply before the first GW->L1 migration so that it can be replayed.
70- /// @dev Note, that the balance is only saved for even migration numbers, i.e. when the chain did not settle on top of Gateway.
71- /// This is needed so that in the future after e.g. a chain migrated with number N (odd number), we would remember how much funds did it
72- /// have right before the migration (when N - 1 was the migration number).
73- mapping (uint256 chainId = > mapping (uint256 migrationNumber = > mapping (bytes32 assetId = > SavedTotalSupply savedChainBalance )))
74- internal savedChainBalance;
75-
7669 modifier onlyUpgrader () {
7770 if (msg .sender != L2_COMPLEX_UPGRADER_ADDR) {
7871 revert Unauthorized (msg .sender );
@@ -170,8 +163,6 @@ contract GWAssetTracker is AssetTrackerBase, IGWAssetTracker {
170163 bytes32 _canonicalTxHash ,
171164 BalanceChange calldata _balanceChange
172165 ) external onlyL2InteropCenter {
173- uint256 chainMigrationNumber = _getChainMigrationNumber (_chainId);
174-
175166 if (_tokenCanSkipMigrationOnSettlementLayer (_chainId, _balanceChange.assetId)) {
176167 _forceSetAssetMigrationNumber (_chainId, _balanceChange.assetId);
177168 }
@@ -180,12 +171,11 @@ contract GWAssetTracker is AssetTrackerBase, IGWAssetTracker {
180171 }
181172
182173 /// Note we don't decrease L1ChainBalance here, since we don't track L1 chainBalance on Gateway.
183- _increaseAndSaveChainBalance (_chainId, _balanceChange.assetId, _balanceChange.amount, chainMigrationNumber );
174+ _increaseAndSaveChainBalance (_chainId, _balanceChange.assetId, _balanceChange.amount);
184175 _increaseAndSaveChainBalance (
185176 _chainId,
186177 _balanceChange.baseTokenAssetId,
187- _balanceChange.baseTokenAmount,
188- chainMigrationNumber
178+ _balanceChange.baseTokenAmount
189179 );
190180
191181 _registerToken (_balanceChange.assetId, _balanceChange.originToken, _balanceChange.tokenOriginChainId);
@@ -379,8 +369,7 @@ contract GWAssetTracker is AssetTrackerBase, IGWAssetTracker {
379369 _increaseAndSaveChainBalance (
380370 interopBundle.destinationChainId,
381371 destinationChainBaseTokenAssetId,
382- totalBaseTokenAmount,
383- _getChainMigrationNumber (interopBundle.destinationChainId)
372+ totalBaseTokenAmount
384373 );
385374 }
386375
@@ -453,8 +442,7 @@ contract GWAssetTracker is AssetTrackerBase, IGWAssetTracker {
453442 _decreaseChainBalance (_sourceChainId, _assetId, _amount);
454443 }
455444 if (_destinationChainId != L1_CHAIN_ID) {
456- uint256 chainMigrationNumber = _getChainMigrationNumber (_destinationChainId);
457- _increaseAndSaveChainBalance (_destinationChainId, _assetId, _amount, chainMigrationNumber);
445+ _increaseAndSaveChainBalance (_destinationChainId, _assetId, _amount);
458446 }
459447 }
460448 }
@@ -521,18 +509,19 @@ contract GWAssetTracker is AssetTrackerBase, IGWAssetTracker {
521509 }
522510
523511 /// @notice Migrates the token balance from Gateway to L1.
524- /// @dev This function can be called multiple times on the Gateway as it saves the chainBalance on the first call.
525- /// @dev This function is permissionless .
512+ /// @dev This function is intended to be permissionless so that a chain that has moved out
513+ /// of Gateway has an easy way to migrate its balance out of the system .
526514 function initiateGatewayToL1MigrationOnGateway (uint256 _chainId , bytes32 _assetId ) external {
527515 address zkChain = L2_BRIDGEHUB.getZKChain (_chainId);
528516 require (zkChain != address (0 ), ChainIdNotRegistered (_chainId));
529517
530518 // If the chain already migrated back to GW, then we need the previous migration number.
531519 uint256 chainMigrationNumber = _calculatePreviousChainMigrationNumber (_chainId);
532520 require (assetMigrationNumber[_chainId][_assetId] < chainMigrationNumber, InvalidAssetMigrationNumber ());
533- // We don't save chainBalance here since it might not be the final chainBalance for this value of the chainMigrationNumber.
534- uint256 amount = _getOrSaveChainBalance (_chainId, _assetId, chainMigrationNumber);
535521
522+ require (chainMigrationNumber == 2 , "Chain must have migrated back to L1 before withdraing balance " );
523+
524+ uint256 amount = chainBalance[_chainId][_assetId];
536525 GatewayToL1TokenBalanceMigrationData memory tokenBalanceMigrationData = GatewayToL1TokenBalanceMigrationData ({
537526 version: TOKEN_BALANCE_MIGRATION_DATA_VERSION,
538527 originToken: originToken[_assetId],
@@ -545,6 +534,10 @@ contract GWAssetTracker is AssetTrackerBase, IGWAssetTracker {
545534 });
546535 _sendGatewayToL1MigrationDataToL1 (tokenBalanceMigrationData);
547536
537+ // We assign chain balance to the 0 and bump asset migration number for replay protection
538+ chainBalance[_chainId][_assetId] = 0 ;
539+ assetMigrationNumber[_chainId][_assetId] = chainMigrationNumber;
540+
548541 emit GatewayToL1MigrationInitiated (_assetId, _chainId, amount);
549542 }
550543
@@ -558,61 +551,22 @@ contract GWAssetTracker is AssetTrackerBase, IGWAssetTracker {
558551 return chainMigrationNumber;
559552 }
560553
561- /// @notice Gets the chain balance for migration, saving it if this is the first time it's accessed.
562- /// @dev This function implements a "snapshot and clear" pattern for chain balances during migration.
563- /// @dev On first access, it saves the current chainBalance and sets it to 0 to prevent double-spending.
564- /// @dev Subsequent accesses return the saved value without modifying the current chainBalance.
565- /// @param _chainId The chain ID whose balance is being queried.
566- /// @param _assetId The asset ID of the token.
567- /// @param _migrationNumber The migration number for this operation.
568- /// @return The saved chain balance for this migration.
569- function _getOrSaveChainBalance (
570- uint256 _chainId ,
571- bytes32 _assetId ,
572- uint256 _migrationNumber
573- ) internal returns (uint256 ) {
574- // Check if we've already saved the balance for this migration
575- SavedTotalSupply memory tokenSavedTotalSupply = savedChainBalance[_chainId][_migrationNumber][_assetId];
576- if (! tokenSavedTotalSupply.isSaved) {
577- // First time accessing this balance for this migration number
578- tokenSavedTotalSupply.amount = chainBalance[_chainId][_assetId];
579- // Persist the saved balance for this specific migration
580- savedChainBalance[_chainId][_migrationNumber][_assetId] = SavedTotalSupply ({
581- isSaved: true ,
582- amount: tokenSavedTotalSupply.amount
583- });
584- }
585-
586- // Return the balance that was available at the time of this migration
587- return tokenSavedTotalSupply.amount;
588- }
589-
590554 /// @notice Confirms a migration operation has been completed and updates the asset migration number.
591555 /// @param _data The migration confirmation data containing chain ID, asset ID, and migration number.
592556 function confirmMigrationOnGateway (MigrationConfirmationData calldata _data ) external onlyServiceTransactionSender {
593- _confirmMigrationOnGateway (_data);
594- }
595-
596- function _confirmMigrationOnGateway (MigrationConfirmationData memory _data ) internal {
597- assetMigrationNumber[_data.chainId][_data.assetId] = _data.assetMigrationNumber;
598- // Register the token if it wasn't already
599- _registerToken (_data.assetId, _data.originToken, _data.tokenOriginChainId);
600557 if (_data.isL1ToGateway) {
558+ assetMigrationNumber[_data.chainId][_data.assetId] = _data.assetMigrationNumber;
559+ // Register the token if it wasn't already
560+ _registerToken (_data.assetId, _data.originToken, _data.tokenOriginChainId);
561+
601562 /// In this case the balance might never have been migrated back to L1.
602563 chainBalance[_data.chainId][_data.assetId] += _data.amount;
603- } else {
604- _decreaseChainBalance (_data.chainId, _data.assetId, _data.amount);
605-
606- uint256 chainMigrationNumber = _calculatePreviousChainMigrationNumber (_data.chainId);
607- SavedTotalSupply memory savedBalance = savedChainBalance[_data.chainId][chainMigrationNumber][
608- _data.assetId
609- ];
610- if (savedBalance.isSaved) {
611- savedChainBalance[_data.chainId][chainMigrationNumber][_data.assetId].amount =
612- savedBalance.amount -
613- _data.amount;
614- }
615564 }
565+
566+ // For migrations from GW, the chainBalance and assetMigrationNumber are updated at the initiation of the migration.
567+ // Additionally, all the tokens are expected to be registered the first time they are deposited via the GWAssetTracker, i.e.
568+ // the amount migrated can not be more than 0 if the token was not registered.
569+
616570 }
617571
618572 /*//////////////////////////////////////////////////////////////
@@ -622,14 +576,8 @@ contract GWAssetTracker is AssetTrackerBase, IGWAssetTracker {
622576 function _increaseAndSaveChainBalance (
623577 uint256 _chainId ,
624578 bytes32 _assetId ,
625- uint256 _amount ,
626- uint256 _chainMigrationNumber
579+ uint256 _amount
627580 ) internal {
628- // We save the chainBalance for the previous migration number so that the chain balance can be migrated back to GW in case it was not migrated.
629- // Note, that for this logic to be correct, we need to ensure that `_chainMigrationNumber` is odd, i.e. the chain actually
630- // actively settles on top of Gateway.
631- _getOrSaveChainBalance (_chainId, _assetId, _chainMigrationNumber - 1 );
632- // we increase the chain balance of the token.
633581 if (_amount > 0 ) {
634582 chainBalance[_chainId][_assetId] += _amount;
635583 }
0 commit comments