From ec985203f001a2751acc2a44b0ef20ce261dc613 Mon Sep 17 00:00:00 2001 From: web3rover Date: Thu, 13 Nov 2025 20:18:10 +0530 Subject: [PATCH 1/3] fix: remove market from emode group when unlisting --- .../Diamond/facets/MarketFacet.sol | 59 ++++++++++++------- .../Comptroller/Diamond/assetListTest.ts | 5 ++ 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/contracts/Comptroller/Diamond/facets/MarketFacet.sol b/contracts/Comptroller/Diamond/facets/MarketFacet.sol index 2ef2d729b..1930ae7ca 100644 --- a/contracts/Comptroller/Diamond/facets/MarketFacet.sol +++ b/contracts/Comptroller/Diamond/facets/MarketFacet.sol @@ -217,6 +217,18 @@ contract MarketFacet is IMarketFacet, FacetBase { require(_market.collateralFactorMantissa == 0, "collateral factor is not 0"); _market.isListed = false; + + for (uint96 i = lastPoolId; i > corePoolId; i--) { + address[] memory markets = getPoolVTokens(uint96(i)); + + for (uint256 j = 0; j < markets.length; j++) { + if (markets[j] == market) { + _removePoolMarket(i, market); + break; + } + } + } + emit MarketUnlisted(market); return uint256(Error.NO_ERROR); @@ -409,27 +421,7 @@ contract MarketFacet is IMarketFacet, FacetBase { */ function removePoolMarket(uint96 poolId, address vToken) external { ensureAllowed("removePoolMarket(uint96,address)"); - - if (poolId == corePoolId) revert InvalidOperationForCorePool(); - PoolMarketId index = getPoolMarketIndex(poolId, vToken); - if (!_poolMarkets[index].isListed) { - revert PoolMarketNotFound(poolId, vToken); - } - - address[] storage assets = pools[poolId].vTokens; - - uint256 length = assets.length; - for (uint256 i; i < length; i++) { - if (assets[i] == vToken) { - assets[i] = assets[length - 1]; - assets.pop(); - break; - } - } - - delete _poolMarkets[index]; - - emit PoolMarketRemoved(poolId, vToken); + _removePoolMarket(poolId, vToken); } /** @@ -507,7 +499,7 @@ contract MarketFacet is IMarketFacet, FacetBase { * @custom:error PoolDoesNotExist Reverts if the given pool ID do not exist. * @custom:error InvalidOperationForCorePool Reverts if called on the Core Pool. */ - function getPoolVTokens(uint96 poolId) external view returns (address[] memory) { + function getPoolVTokens(uint96 poolId) public view returns (address[] memory) { if (poolId > lastPoolId) revert PoolDoesNotExist(poolId); if (poolId == corePoolId) revert InvalidOperationForCorePool(); return pools[poolId].vTokens; @@ -697,6 +689,29 @@ contract MarketFacet is IMarketFacet, FacetBase { emit PoolMarketInitialized(poolId, vToken); } + function _removePoolMarket(uint96 poolId, address vToken) internal { + if (poolId == corePoolId) revert InvalidOperationForCorePool(); + PoolMarketId index = getPoolMarketIndex(poolId, vToken); + if (!_poolMarkets[index].isListed) { + revert PoolMarketNotFound(poolId, vToken); + } + + address[] storage assets = pools[poolId].vTokens; + + uint256 length = assets.length; + for (uint256 i; i < length; i++) { + if (assets[i] == vToken) { + assets[i] = assets[length - 1]; + assets.pop(); + break; + } + } + + delete _poolMarkets[index]; + + emit PoolMarketRemoved(poolId, vToken); + } + /** * @notice Returns only the core risk parameters (CF, LI, LT) for a vToken in a specific pool. * @dev If the pool is inactive, or if the vToken is not configured in the given pool and diff --git a/tests/hardhat/Comptroller/Diamond/assetListTest.ts b/tests/hardhat/Comptroller/Diamond/assetListTest.ts index a85104aca..d5daeb8a7 100644 --- a/tests/hardhat/Comptroller/Diamond/assetListTest.ts +++ b/tests/hardhat/Comptroller/Diamond/assetListTest.ts @@ -145,6 +145,7 @@ describe("Comptroller: assetListTest", () => { const receipt = await comptroller.connect(customer).unlistMarket(unlistToken.address); expect(receipt).to.emit(unitroller, "MarketUnlisted"); + expect(receipt).to.emit(unitroller, "PoolMarketRemoved"); const expectedError_ = expectedError || Error.NO_ERROR; expect(reply).to.equal(expectedError_); @@ -326,6 +327,10 @@ describe("Comptroller: assetListTest", () => { true, ); + const newLabel = "test-pool"; + await comptroller.createPool(newLabel); + await comptroller.addPoolMarkets([1], [OMG.address]); + await unlistAndCheckMarket(OMG, [BAT, ZRX], [OMG, BAT, ZRX]); }); From 84c3d39b23fade78950fa112690f020660ed07ed Mon Sep 17 00:00:00 2001 From: web3rover Date: Mon, 17 Nov 2025 00:03:06 +0530 Subject: [PATCH 2/3] fix: optimisations --- .../Comptroller/Diamond/facets/MarketFacet.sol | 14 +++++--------- tests/hardhat/Comptroller/Diamond/assetListTest.ts | 6 ++++++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/contracts/Comptroller/Diamond/facets/MarketFacet.sol b/contracts/Comptroller/Diamond/facets/MarketFacet.sol index 1930ae7ca..f740f4d7d 100644 --- a/contracts/Comptroller/Diamond/facets/MarketFacet.sol +++ b/contracts/Comptroller/Diamond/facets/MarketFacet.sol @@ -216,19 +216,15 @@ contract MarketFacet is IMarketFacet, FacetBase { require(_market.collateralFactorMantissa == 0, "collateral factor is not 0"); - _market.isListed = false; - for (uint96 i = lastPoolId; i > corePoolId; i--) { - address[] memory markets = getPoolVTokens(uint96(i)); - - for (uint256 j = 0; j < markets.length; j++) { - if (markets[j] == market) { - _removePoolMarket(i, market); - break; - } + PoolMarketId index = getPoolMarketIndex(i, market); + if (_poolMarkets[index].isListed) { + _removePoolMarket(i, market); } } + _market.isListed = false; + emit MarketUnlisted(market); return uint256(Error.NO_ERROR); diff --git a/tests/hardhat/Comptroller/Diamond/assetListTest.ts b/tests/hardhat/Comptroller/Diamond/assetListTest.ts index d5daeb8a7..3d497806f 100644 --- a/tests/hardhat/Comptroller/Diamond/assetListTest.ts +++ b/tests/hardhat/Comptroller/Diamond/assetListTest.ts @@ -143,10 +143,16 @@ describe("Comptroller: assetListTest", () => { ) { const reply = await comptroller.connect(customer).callStatic.unlistMarket(unlistToken.address); + let poolVTokens = await comptroller.getPoolVTokens(1); + expect(poolVTokens).to.include(unlistToken.address); + const receipt = await comptroller.connect(customer).unlistMarket(unlistToken.address); expect(receipt).to.emit(unitroller, "MarketUnlisted"); expect(receipt).to.emit(unitroller, "PoolMarketRemoved"); + poolVTokens = await comptroller.getPoolVTokens(1); + expect(poolVTokens).to.not.include(unlistToken.address); + const expectedError_ = expectedError || Error.NO_ERROR; expect(reply).to.equal(expectedError_); From 2e512eb84f754315587033c7ff83d1e33f8847df Mon Sep 17 00:00:00 2001 From: web3rover Date: Wed, 19 Nov 2025 13:01:45 +0530 Subject: [PATCH 3/3] fix: fixed tests --- tests/hardhat/Comptroller/Diamond/assetListTest.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/hardhat/Comptroller/Diamond/assetListTest.ts b/tests/hardhat/Comptroller/Diamond/assetListTest.ts index 3d497806f..53e0fa44d 100644 --- a/tests/hardhat/Comptroller/Diamond/assetListTest.ts +++ b/tests/hardhat/Comptroller/Diamond/assetListTest.ts @@ -142,16 +142,21 @@ describe("Comptroller: assetListTest", () => { expectedError: ComptrollerErrorReporter.Error | null = null, ) { const reply = await comptroller.connect(customer).callStatic.unlistMarket(unlistToken.address); + const lastPoolId = await comptroller.lastPoolId(); - let poolVTokens = await comptroller.getPoolVTokens(1); - expect(poolVTokens).to.include(unlistToken.address); + if (lastPoolId.toNumber() != 0) { + const poolVTokens = await comptroller.getPoolVTokens(lastPoolId); + expect(poolVTokens).to.include(unlistToken.address); + } const receipt = await comptroller.connect(customer).unlistMarket(unlistToken.address); expect(receipt).to.emit(unitroller, "MarketUnlisted"); expect(receipt).to.emit(unitroller, "PoolMarketRemoved"); - poolVTokens = await comptroller.getPoolVTokens(1); - expect(poolVTokens).to.not.include(unlistToken.address); + if (lastPoolId.toNumber() != 0) { + const poolVTokens = await comptroller.getPoolVTokens(lastPoolId); + expect(poolVTokens).to.not.include(unlistToken.address); + } const expectedError_ = expectedError || Error.NO_ERROR; expect(reply).to.equal(expectedError_);