From 50232999180e6fbf9a4c198c57f3c9d01e0c374e Mon Sep 17 00:00:00 2001 From: Veliko Minkov <2662912+vminkov@users.noreply.github.com> Date: Mon, 18 Mar 2024 13:20:56 +0200 Subject: [PATCH 1/6] pool borrowers pagination --- .../compound/ComptrollerFirstExtension.sol | 31 ++++++++++- contracts/compound/ComptrollerInterface.sol | 10 ++-- contracts/test/DevTesting.t.sol | 52 +++++++++++++++++++ 3 files changed, 88 insertions(+), 5 deletions(-) diff --git a/contracts/compound/ComptrollerFirstExtension.sol b/contracts/compound/ComptrollerFirstExtension.sol index f61dc58d..c70b82c5 100644 --- a/contracts/compound/ComptrollerFirstExtension.sol +++ b/contracts/compound/ComptrollerFirstExtension.sol @@ -38,7 +38,7 @@ contract ComptrollerFirstExtension is event MarketUnlisted(ICErc20 cToken); function _getExtensionFunctions() external pure virtual override returns (bytes4[] memory) { - uint8 fnsCount = 31; + uint8 fnsCount = 32; bytes4[] memory functionSelectors = new bytes4[](fnsCount); functionSelectors[--fnsCount] = this.addNonAccruingFlywheel.selector; functionSelectors[--fnsCount] = this._setMarketSupplyCaps.selector; @@ -56,6 +56,7 @@ contract ComptrollerFirstExtension is functionSelectors[--fnsCount] = this._unsupportMarket.selector; functionSelectors[--fnsCount] = this.getAllMarkets.selector; functionSelectors[--fnsCount] = this.getAllBorrowers.selector; + functionSelectors[--fnsCount] = this.getPaginatedBorrowers.selector; functionSelectors[--fnsCount] = this.getWhitelist.selector; functionSelectors[--fnsCount] = this.getRewardsDistributors.selector; functionSelectors[--fnsCount] = this.isUserOfPool.selector; @@ -431,6 +432,34 @@ contract ComptrollerFirstExtension is return allBorrowers; } + function getPaginatedBorrowers(uint256 page, uint256 pageSize) + public + view + returns (uint256 _totalPages, address[] memory _pageOfBorrowers) { + if (pageSize == 0) pageSize = 300; + uint256 currentPageSize = pageSize; + uint256 allBorrowersCount = allBorrowers.length; + + if (allBorrowersCount == 0) { + return (0, new address[](0)); + } + + _totalPages = allBorrowersCount / pageSize; + if (allBorrowersCount % pageSize > 0) _totalPages++; + + if (page + 1 == _totalPages) { + currentPageSize = allBorrowersCount % pageSize; + } else if (page + 1 > _totalPages) { + return (_totalPages, new address[](0)); + } + + _pageOfBorrowers = new address[](pageSize); + for (uint256 i = 0; i < currentPageSize; i++) { + uint256 offset = page * pageSize; + _pageOfBorrowers[i] = allBorrowers[i + offset]; + } + } + /** * @notice Return all of the whitelist * @dev The automatic getter may be used to access an individual whitelist status. diff --git a/contracts/compound/ComptrollerInterface.sol b/contracts/compound/ComptrollerInterface.sol index 393a85cc..49550a9d 100644 --- a/contracts/compound/ComptrollerInterface.sol +++ b/contracts/compound/ComptrollerInterface.sol @@ -134,10 +134,10 @@ interface ComptrollerInterface { external view returns ( - uint256, - uint256, - uint256, - uint256 + uint256 error, + uint256 collateralValue, + uint256 liquidity, + uint256 shortfall ); function liquidateCalculateSeizeTokens( @@ -214,6 +214,8 @@ interface ComptrollerExtensionInterface { function getAllBorrowers() external view returns (address[] memory); + function getPaginatedBorrowers(uint256 page, uint256 pageSize) external view returns (uint256 _totalPages, address[] memory _pageOfBorrowers); + function getRewardsDistributors() external view returns (address[] memory); function getAccruingFlywheels() external view returns (address[] memory); diff --git a/contracts/test/DevTesting.t.sol b/contracts/test/DevTesting.t.sol index 2ebc3dc4..42719335 100644 --- a/contracts/test/DevTesting.t.sol +++ b/contracts/test/DevTesting.t.sol @@ -6,6 +6,9 @@ import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/trans import "./config/BaseTest.t.sol"; import { IonicComptroller } from "../compound/ComptrollerInterface.sol"; +import { ComptrollerFirstExtension } from "../compound/ComptrollerFirstExtension.sol"; +import { Unitroller } from "../compound/Unitroller.sol"; +import { DiamondExtension } from "../ionic/DiamondExtension.sol"; import { ICErc20 } from "../compound/CTokenInterfaces.sol"; import { ISwapRouter } from "../external/uniswap/ISwapRouter.sol"; import { MasterPriceOracle } from "../oracles/MasterPriceOracle.sol"; @@ -166,6 +169,55 @@ contract DevTesting is BaseTest { } } + function upgradePool() internal { + ComptrollerFirstExtension newComptrollerExtension = new ComptrollerFirstExtension(); + + Unitroller asUnitroller = Unitroller(payable(address(pool))); + + // upgrade to the new comptroller extension + vm.startPrank(asUnitroller.admin()); + asUnitroller._registerExtension( + newComptrollerExtension, + DiamondExtension(asUnitroller._listExtensions()[1]) + ); + + //asUnitroller._upgrade(); + vm.stopPrank(); + } + + function testModeFetchBorrowers() public fork(MODE_MAINNET) { + // address[] memory borrowers = pool.getAllBorrowers(); + // emit log_named_uint("borrowers.len", borrowers.length); + + upgradePool(); + + (uint256 totalPages, address[] memory borrowersPage) = pool.getPaginatedBorrowers(1, 0); + + emit log_named_uint("total pages with 300 size (default)", totalPages); + + (totalPages, borrowersPage) = pool.getPaginatedBorrowers(totalPages - 1, 50); + emit log_named_array("last page of 300 borrowers", borrowersPage); + + (totalPages, borrowersPage) = pool.getPaginatedBorrowers(1, 50); + emit log_named_uint("total pages with 50 size", totalPages); + emit log_named_array("page of 50 borrowers", borrowersPage); + + // for (uint256 i = 0; i < borrowers.length; i++) { +// ( +// uint256 error, +// uint256 collateralValue, +// uint256 liquidity, +// uint256 shortfall +// ) = pool.getAccountLiquidity(borrowers[i]); +// +// emit log(""); +// emit log_named_address("user", borrowers[i]); +// emit log_named_uint("collateralValue", collateralValue); +// if (liquidity > 0) emit log_named_uint("liquidity", liquidity); +// if (shortfall > 0) emit log_named_uint("SHORTFALL", shortfall); +// } + } + function testModeUsdcBorrow() public debuggingOnly fork(MODE_MAINNET) { vm.prank(deployer); require(usdcMarket.borrow(5e6) == 0, "can't borrow"); From 7b201b992d5e8b9dc8d34e517420910c418a57b7 Mon Sep 17 00:00:00 2001 From: Veliko Minkov <2662912+vminkov@users.noreply.github.com> Date: Mon, 18 Mar 2024 13:29:23 +0200 Subject: [PATCH 2/6] prettier --- .../compound/ComptrollerFirstExtension.sol | 3 +- contracts/compound/ComptrollerInterface.sol | 5 ++- contracts/test/DevTesting.t.sol | 31 +++++++++---------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/contracts/compound/ComptrollerFirstExtension.sol b/contracts/compound/ComptrollerFirstExtension.sol index c70b82c5..55aede11 100644 --- a/contracts/compound/ComptrollerFirstExtension.sol +++ b/contracts/compound/ComptrollerFirstExtension.sol @@ -435,7 +435,8 @@ contract ComptrollerFirstExtension is function getPaginatedBorrowers(uint256 page, uint256 pageSize) public view - returns (uint256 _totalPages, address[] memory _pageOfBorrowers) { + returns (uint256 _totalPages, address[] memory _pageOfBorrowers) + { if (pageSize == 0) pageSize = 300; uint256 currentPageSize = pageSize; uint256 allBorrowersCount = allBorrowers.length; diff --git a/contracts/compound/ComptrollerInterface.sol b/contracts/compound/ComptrollerInterface.sol index 49550a9d..52c3e288 100644 --- a/contracts/compound/ComptrollerInterface.sol +++ b/contracts/compound/ComptrollerInterface.sol @@ -214,7 +214,10 @@ interface ComptrollerExtensionInterface { function getAllBorrowers() external view returns (address[] memory); - function getPaginatedBorrowers(uint256 page, uint256 pageSize) external view returns (uint256 _totalPages, address[] memory _pageOfBorrowers); + function getPaginatedBorrowers(uint256 page, uint256 pageSize) + external + view + returns (uint256 _totalPages, address[] memory _pageOfBorrowers); function getRewardsDistributors() external view returns (address[] memory); diff --git a/contracts/test/DevTesting.t.sol b/contracts/test/DevTesting.t.sol index 42719335..365de9de 100644 --- a/contracts/test/DevTesting.t.sol +++ b/contracts/test/DevTesting.t.sol @@ -176,10 +176,7 @@ contract DevTesting is BaseTest { // upgrade to the new comptroller extension vm.startPrank(asUnitroller.admin()); - asUnitroller._registerExtension( - newComptrollerExtension, - DiamondExtension(asUnitroller._listExtensions()[1]) - ); + asUnitroller._registerExtension(newComptrollerExtension, DiamondExtension(asUnitroller._listExtensions()[1])); //asUnitroller._upgrade(); vm.stopPrank(); @@ -203,19 +200,19 @@ contract DevTesting is BaseTest { emit log_named_array("page of 50 borrowers", borrowersPage); // for (uint256 i = 0; i < borrowers.length; i++) { -// ( -// uint256 error, -// uint256 collateralValue, -// uint256 liquidity, -// uint256 shortfall -// ) = pool.getAccountLiquidity(borrowers[i]); -// -// emit log(""); -// emit log_named_address("user", borrowers[i]); -// emit log_named_uint("collateralValue", collateralValue); -// if (liquidity > 0) emit log_named_uint("liquidity", liquidity); -// if (shortfall > 0) emit log_named_uint("SHORTFALL", shortfall); -// } + // ( + // uint256 error, + // uint256 collateralValue, + // uint256 liquidity, + // uint256 shortfall + // ) = pool.getAccountLiquidity(borrowers[i]); + // + // emit log(""); + // emit log_named_address("user", borrowers[i]); + // emit log_named_uint("collateralValue", collateralValue); + // if (liquidity > 0) emit log_named_uint("liquidity", liquidity); + // if (shortfall > 0) emit log_named_uint("SHORTFALL", shortfall); + // } } function testModeUsdcBorrow() public debuggingOnly fork(MODE_MAINNET) { From daf3c18655d5236f797e067c15c35de7289973f4 Mon Sep 17 00:00:00 2001 From: Veliko Minkov <2662912+vminkov@users.noreply.github.com> Date: Mon, 18 Mar 2024 13:35:26 +0200 Subject: [PATCH 3/6] clearer logic --- contracts/compound/ComptrollerFirstExtension.sol | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/contracts/compound/ComptrollerFirstExtension.sol b/contracts/compound/ComptrollerFirstExtension.sol index 55aede11..1e5b37a1 100644 --- a/contracts/compound/ComptrollerFirstExtension.sol +++ b/contracts/compound/ComptrollerFirstExtension.sol @@ -446,11 +446,15 @@ contract ComptrollerFirstExtension is } _totalPages = allBorrowersCount / pageSize; - if (allBorrowersCount % pageSize > 0) _totalPages++; + uint256 sizeOfPageFromRemainder = allBorrowersCount % pageSize; + if (sizeOfPageFromRemainder > 0) { + _totalPages++; + if (page + 1 == _totalPages) { + currentPageSize = sizeOfPageFromRemainder; + } + } - if (page + 1 == _totalPages) { - currentPageSize = allBorrowersCount % pageSize; - } else if (page + 1 > _totalPages) { + if (page + 1 > _totalPages) { return (_totalPages, new address[](0)); } From ba28ba3435e19bbfd188863eeab14140c2f466d6 Mon Sep 17 00:00:00 2001 From: Veliko Minkov <2662912+vminkov@users.noreply.github.com> Date: Mon, 18 Mar 2024 13:36:45 +0200 Subject: [PATCH 4/6] last page size fix --- contracts/compound/ComptrollerFirstExtension.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/compound/ComptrollerFirstExtension.sol b/contracts/compound/ComptrollerFirstExtension.sol index 1e5b37a1..308317f0 100644 --- a/contracts/compound/ComptrollerFirstExtension.sol +++ b/contracts/compound/ComptrollerFirstExtension.sol @@ -458,7 +458,7 @@ contract ComptrollerFirstExtension is return (_totalPages, new address[](0)); } - _pageOfBorrowers = new address[](pageSize); + _pageOfBorrowers = new address[](currentPageSize); for (uint256 i = 0; i < currentPageSize; i++) { uint256 offset = page * pageSize; _pageOfBorrowers[i] = allBorrowers[i + offset]; From 9eea8ad7030737ee7ee2b6546d1235e5fd49b6bd Mon Sep 17 00:00:00 2001 From: Veliko Minkov <2662912+vminkov@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:04:42 +0200 Subject: [PATCH 5/6] all borrowers count getter --- contracts/compound/ComptrollerFirstExtension.sol | 7 ++++++- contracts/compound/ComptrollerInterface.sol | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/contracts/compound/ComptrollerFirstExtension.sol b/contracts/compound/ComptrollerFirstExtension.sol index 308317f0..467c04af 100644 --- a/contracts/compound/ComptrollerFirstExtension.sol +++ b/contracts/compound/ComptrollerFirstExtension.sol @@ -38,7 +38,7 @@ contract ComptrollerFirstExtension is event MarketUnlisted(ICErc20 cToken); function _getExtensionFunctions() external pure virtual override returns (bytes4[] memory) { - uint8 fnsCount = 32; + uint8 fnsCount = 33; bytes4[] memory functionSelectors = new bytes4[](fnsCount); functionSelectors[--fnsCount] = this.addNonAccruingFlywheel.selector; functionSelectors[--fnsCount] = this._setMarketSupplyCaps.selector; @@ -56,6 +56,7 @@ contract ComptrollerFirstExtension is functionSelectors[--fnsCount] = this._unsupportMarket.selector; functionSelectors[--fnsCount] = this.getAllMarkets.selector; functionSelectors[--fnsCount] = this.getAllBorrowers.selector; + functionSelectors[--fnsCount] = this.getAllBorrowersCount.selector; functionSelectors[--fnsCount] = this.getPaginatedBorrowers.selector; functionSelectors[--fnsCount] = this.getWhitelist.selector; functionSelectors[--fnsCount] = this.getRewardsDistributors.selector; @@ -432,6 +433,10 @@ contract ComptrollerFirstExtension is return allBorrowers; } + function getAllBorrowersCount() public view returns (uint256) { + return allBorrowers.length; + } + function getPaginatedBorrowers(uint256 page, uint256 pageSize) public view diff --git a/contracts/compound/ComptrollerInterface.sol b/contracts/compound/ComptrollerInterface.sol index 52c3e288..6d02bf9d 100644 --- a/contracts/compound/ComptrollerInterface.sol +++ b/contracts/compound/ComptrollerInterface.sol @@ -214,6 +214,8 @@ interface ComptrollerExtensionInterface { function getAllBorrowers() external view returns (address[] memory); + function getAllBorrowersCount() external view returns (uint256); + function getPaginatedBorrowers(uint256 page, uint256 pageSize) external view From 169f954a17e48ec41d2554674d215d591d9ef14c Mon Sep 17 00:00:00 2001 From: Veliko Minkov <2662912+vminkov@users.noreply.github.com> Date: Tue, 19 Mar 2024 10:06:11 +0200 Subject: [PATCH 6/6] minor fixes --- contracts/compound/ComptrollerFirstExtension.sol | 10 +++++----- contracts/test/liquidators/IonicLiquidatorTest.sol | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/compound/ComptrollerFirstExtension.sol b/contracts/compound/ComptrollerFirstExtension.sol index 467c04af..f23d4010 100644 --- a/contracts/compound/ComptrollerFirstExtension.sol +++ b/contracts/compound/ComptrollerFirstExtension.sol @@ -442,16 +442,16 @@ contract ComptrollerFirstExtension is view returns (uint256 _totalPages, address[] memory _pageOfBorrowers) { - if (pageSize == 0) pageSize = 300; - uint256 currentPageSize = pageSize; uint256 allBorrowersCount = allBorrowers.length; - if (allBorrowersCount == 0) { return (0, new address[](0)); } - _totalPages = allBorrowersCount / pageSize; + if (pageSize == 0) pageSize = 300; + uint256 currentPageSize = pageSize; uint256 sizeOfPageFromRemainder = allBorrowersCount % pageSize; + + _totalPages = allBorrowersCount / pageSize; if (sizeOfPageFromRemainder > 0) { _totalPages++; if (page + 1 == _totalPages) { @@ -463,9 +463,9 @@ contract ComptrollerFirstExtension is return (_totalPages, new address[](0)); } + uint256 offset = page * pageSize; _pageOfBorrowers = new address[](currentPageSize); for (uint256 i = 0; i < currentPageSize; i++) { - uint256 offset = page * pageSize; _pageOfBorrowers[i] = allBorrowers[i + offset]; } } diff --git a/contracts/test/liquidators/IonicLiquidatorTest.sol b/contracts/test/liquidators/IonicLiquidatorTest.sol index 903bdb39..baf48b98 100644 --- a/contracts/test/liquidators/IonicLiquidatorTest.sol +++ b/contracts/test/liquidators/IonicLiquidatorTest.sol @@ -75,7 +75,7 @@ contract IonicLiquidatorTest is UpgradesBaseTest { swapRouter = 0x5D61c537393cf21893BE619E36fC94cd73C77DD3; // kim router //quoter = IUniswapV3Quoter(0x7Fd569b2021850fbA53887dd07736010aCBFc787); // other sup quoter? quoter = IUniswapV3Quoter(0x5E6AEbab1AD525f5336Bd12E6847b851531F72ba); // sup quoter - usdcWhale = 0xB4fb31E7B1471A8e52dD1e962A281a732EaD59c1; + usdcWhale = 0x34b83A3759ba4c9F99c339604181bf6bBdED4C79; // vault wethWhale = 0xF4C85269240C1D447309fA602A90ac23F1CB0Dc0; poolAddress = 0xFB3323E24743Caf4ADD0fDCCFB268565c0685556; //uniV3PooForFlash = 0x293f2B2c17f8cEa4db346D87Ef5712C9dd0491EF; // kim weth-usdc pool