From 540299e6621403cc475993983416ebd40ec4b2f5 Mon Sep 17 00:00:00 2001 From: krlosMata Date: Wed, 15 Apr 2026 15:48:11 +0200 Subject: [PATCH] Fix inconsistency: updating lastUpdatedDepositCount on backwardLET & forwardLET --- .../sovereignChains/AgglayerBridgeL2.sol | 6 +- .../BridgeL2SovereignChain.test.ts | 67 +++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/contracts/sovereignChains/AgglayerBridgeL2.sol b/contracts/sovereignChains/AgglayerBridgeL2.sol index cb6452344..216dbe8dd 100644 --- a/contracts/sovereignChains/AgglayerBridgeL2.sol +++ b/contracts/sovereignChains/AgglayerBridgeL2.sol @@ -774,8 +774,9 @@ contract AgglayerBridgeL2 is AgglayerBridge, IAgglayerBridgeL2 { depositCount = newDepositCount; - // Update LER + // Update LER & lastUpdatedDepositCount bytes32 newLER = getRoot(); + lastUpdatedDepositCount = uint32(newDepositCount); globalExitRootManager.updateExitRoot(newLER); // emit event @@ -837,7 +838,8 @@ contract AgglayerBridgeL2 is AgglayerBridge, IAgglayerBridgeL2 { revert InvalidExpectedLER(); } - // Update GER + // Update LER & lastUpdatedDepositCount + lastUpdatedDepositCount = uint32(depositCount); globalExitRootManager.updateExitRoot(computedRoot); // emit event with the new deposit count diff --git a/test/contractsv2/BridgeL2SovereignChain.test.ts b/test/contractsv2/BridgeL2SovereignChain.test.ts index 28a03bdfe..c7efa682b 100644 --- a/test/contractsv2/BridgeL2SovereignChain.test.ts +++ b/test/contractsv2/BridgeL2SovereignChain.test.ts @@ -3435,6 +3435,57 @@ describe('AgglayerBridgeL2 Contract', () => { // Verify the root changed (different from original) expect(await sovereignChainBridgeContract.getRoot()).to.not.equal(originalTree.getRoot()); }); + + it('should update lastUpdatedDepositCount after backwardLET', async () => { + await sovereignChainBridgeContract.connect(emergencyBridgePauser).activateEmergencyState(); + + const originalLeaves = generateTestLeaves(3); + const originalTree = buildMerkleTreeForTesting(originalLeaves); + await sovereignChainBridgeContract + .connect(globalExitRootRemover) + .forwardLET(originalLeaves, originalTree.getRoot()); + + expect(await sovereignChainBridgeContract.depositCount()).to.equal(3); + + // Deactivate emergency, sync lastUpdatedDepositCount via updateGlobalExitRoot, re-activate + await sovereignChainBridgeContract.connect(emergencyBridgePauser).deactivateEmergencyState(); + await sovereignChainBridgeContract.updateGlobalExitRoot(); + expect(await sovereignChainBridgeContract.lastUpdatedDepositCount()).to.equal(3); + await sovereignChainBridgeContract.connect(emergencyBridgePauser).activateEmergencyState(); + + // Rollback to 1 leaf + const newDepositCount = 1; + + const newFrontier = Array(32).fill(ethers.ZeroHash); + newFrontier[0] = getLeafValue( + originalLeaves[0].leafType, + originalLeaves[0].originNetwork, + originalLeaves[0].originAddress, + originalLeaves[0].destinationNetwork, + originalLeaves[0].destinationAddress, + originalLeaves[0].amount, + ethers.keccak256(originalLeaves[0].metadata), + ); + + const nextLeaf = originalLeaves[newDepositCount]; + const nextLeafValue = getLeafValue( + nextLeaf.leafType, + nextLeaf.originNetwork, + nextLeaf.originAddress, + nextLeaf.destinationNetwork, + nextLeaf.destinationAddress, + nextLeaf.amount, + ethers.keccak256(nextLeaf.metadata), + ); + const proof = originalTree.getProofTreeByIndex(newDepositCount); + + await sovereignChainBridgeContract + .connect(globalExitRootRemover) + .backwardLET(newDepositCount, newFrontier as [string, ...string[]], nextLeafValue, proof); + + expect(await sovereignChainBridgeContract.depositCount()).to.equal(1); + expect(await sovereignChainBridgeContract.lastUpdatedDepositCount()).to.equal(1); + }); }); describe('forwardLET', () => { @@ -3745,6 +3796,22 @@ describe('AgglayerBridgeL2 Contract', () => { // Verify no leaves were added (transaction reverted) expect(await sovereignChainBridgeContract.depositCount()).to.equal(0); }); + + it('should update lastUpdatedDepositCount after forwardLET', async () => { + await sovereignChainBridgeContract.connect(emergencyBridgePauser).activateEmergencyState(); + + expect(await sovereignChainBridgeContract.lastUpdatedDepositCount()).to.equal(0); + expect(await sovereignChainBridgeContract.depositCount()).to.equal(0); + + const newLeaves = generateTestLeaves(3); + const expectedTree = buildMerkleTreeForTesting(newLeaves); + await sovereignChainBridgeContract + .connect(globalExitRootRemover) + .forwardLET(newLeaves, expectedTree.getRoot()); + + expect(await sovereignChainBridgeContract.depositCount()).to.equal(3); + expect(await sovereignChainBridgeContract.lastUpdatedDepositCount()).to.equal(3); + }); }); describe('Combined LET Operations', () => {