From bd82ae6c73852a3355faced700320a6be2090b95 Mon Sep 17 00:00:00 2001 From: "A.L." Date: Thu, 23 Jan 2025 16:27:52 +0700 Subject: [PATCH] fix: use try catch when calling afterLiquidityEvent --- package-lock.json | 30 ++++++++++++++-------------- package.json | 2 +- script/optimized-deployer-meta | 4 ++-- src/ReservoirDeployer.sol | 4 ++-- src/ReservoirPair.sol | 6 ++++-- test/integration/Euler.t.sol | 36 ++++++++++++++++++++++++++++++++++ 6 files changed, 60 insertions(+), 22 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9c65e528..6f646057 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@proxima-oss/eslint-config": "6.0.1", "markdownlint-cli": "0.31.1", "prettier": "2.6.2", - "solhint": "5.0.3", + "solhint": "5.0.5", "ts-node": "10.8.1" } }, @@ -310,9 +310,9 @@ } }, "node_modules/@solidity-parser/parser": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.18.0.tgz", - "integrity": "sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.19.0.tgz", + "integrity": "sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA==", "dev": true }, "node_modules/@szmarczak/http-timer": { @@ -3074,12 +3074,12 @@ } }, "node_modules/solhint": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.0.3.tgz", - "integrity": "sha512-OLCH6qm/mZTCpplTXzXTJGId1zrtNuDYP5c2e6snIv/hdRVxPfBBz/bAlL91bY/Accavkayp2Zp2BaDSrLVXTQ==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.0.5.tgz", + "integrity": "sha512-WrnG6T+/UduuzSWsSOAbfq1ywLUDwNea3Gd5hg6PS+pLUm8lz2ECNr0beX609clBxmDeZ3676AiA9nPDljmbJQ==", "dev": true, "dependencies": { - "@solidity-parser/parser": "^0.18.0", + "@solidity-parser/parser": "^0.19.0", "ajv": "^6.12.6", "antlr4": "^4.13.1-patch-1", "ast-parents": "^0.0.1", @@ -3937,9 +3937,9 @@ "dev": true }, "@solidity-parser/parser": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.18.0.tgz", - "integrity": "sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.19.0.tgz", + "integrity": "sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA==", "dev": true }, "@szmarczak/http-timer": { @@ -5932,12 +5932,12 @@ } }, "solhint": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.0.3.tgz", - "integrity": "sha512-OLCH6qm/mZTCpplTXzXTJGId1zrtNuDYP5c2e6snIv/hdRVxPfBBz/bAlL91bY/Accavkayp2Zp2BaDSrLVXTQ==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.0.5.tgz", + "integrity": "sha512-WrnG6T+/UduuzSWsSOAbfq1ywLUDwNea3Gd5hg6PS+pLUm8lz2ECNr0beX609clBxmDeZ3676AiA9nPDljmbJQ==", "dev": true, "requires": { - "@solidity-parser/parser": "^0.18.0", + "@solidity-parser/parser": "^0.19.0", "ajv": "^6.12.6", "antlr4": "^4.13.1-patch-1", "ast-parents": "^0.0.1", diff --git a/package.json b/package.json index 5c715fc7..ce51028d 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "@proxima-oss/eslint-config": "6.0.1", "markdownlint-cli": "0.31.1", "prettier": "2.6.2", - "solhint": "5.0.3", + "solhint": "5.0.5", "ts-node": "10.8.1" } } diff --git a/script/optimized-deployer-meta b/script/optimized-deployer-meta index a522818b..203efd44 100644 --- a/script/optimized-deployer-meta +++ b/script/optimized-deployer-meta @@ -1,5 +1,5 @@ { - "constant_product_hash": "0x10d229cba772589e1df33e1086576f195abcfdb890068f1e9008331694833feb", + "constant_product_hash": "0x3655a1654f428733171b79b5aa0eb876a0b26771aa4c113fe4b447fc164f6f3c", "factory_hash": "0x87b0f73fafcf4bb41e013c8423dc679f6885527007d6c3f1e1834a670cbaadc5", - "stable_hash": "0x77bb394a2dea26c639518f7a39df2397ee6ae4ac52894e1c90d91d0b69e7acdf" + "stable_hash": "0x3a9c9a0643670e1711efa1d1647c9ad9d483706f2f83adb59a928f522d464ee1" } \ No newline at end of file diff --git a/src/ReservoirDeployer.sol b/src/ReservoirDeployer.sol index 1d5c9f3d..cb041d6f 100644 --- a/src/ReservoirDeployer.sol +++ b/src/ReservoirDeployer.sol @@ -27,8 +27,8 @@ contract ReservoirDeployer { // Bytecode hashes. bytes32 public constant FACTORY_HASH = bytes32(0x87b0f73fafcf4bb41e013c8423dc679f6885527007d6c3f1e1834a670cbaadc5); bytes32 public constant CONSTANT_PRODUCT_HASH = - bytes32(0x10d229cba772589e1df33e1086576f195abcfdb890068f1e9008331694833feb); - bytes32 public constant STABLE_HASH = bytes32(0x77bb394a2dea26c639518f7a39df2397ee6ae4ac52894e1c90d91d0b69e7acdf); + bytes32(0x3655a1654f428733171b79b5aa0eb876a0b26771aa4c113fe4b447fc164f6f3c); + bytes32 public constant STABLE_HASH = bytes32(0x3a9c9a0643670e1711efa1d1647c9ad9d483706f2f83adb59a928f522d464ee1); // Deployment addresses. GenericFactory public factory; diff --git a/src/ReservoirPair.sol b/src/ReservoirPair.sol index 0854e1b9..c112353c 100644 --- a/src/ReservoirPair.sol +++ b/src/ReservoirPair.sol @@ -416,8 +416,10 @@ abstract contract ReservoirPair is IAssetManagedPair, ReservoirERC20, RGT { if (address(assetManager) == address(0)) { return; } - - assetManager.afterLiquidityEvent(); + // Sometimes rebalancing can fail to due to reasons such as exceeding the supply cap, or if there's insufficient cash + // in the vault to fulfil the redemption. So it's necessary to catch the error to prevent an otherwise successful mint/burn from reverting. + // solhint-disable-next-line no-empty-blocks + try assetManager.afterLiquidityEvent() { } catch { } } function adjustManagement(int256 aToken0Change, int256 aToken1Change) external { diff --git a/test/integration/Euler.t.sol b/test/integration/Euler.t.sol index 604e21c3..26bdb315 100644 --- a/test/integration/Euler.t.sol +++ b/test/integration/Euler.t.sol @@ -593,6 +593,42 @@ contract EulerIntegrationTest is BaseTest { assertEq(_manager.getBalance(_pair, USDC), 0); } + function testAfterLiquidityEvent_ExceedMaxDeposit() external allNetworks allPairs { + // arrange + IERC4626 lVault = _manager.assetVault(USDC); + uint256 lMaxDeposit = lVault.maxDeposit(address(_manager)); + uint256 lAmtToMint = lMaxDeposit * 4; + + // act + _deal(address(USDC), address(this), lAmtToMint); + USDC.transfer(address(_pair), lAmtToMint); + _tokenA.mint(address(_pair), lAmtToMint); + + // assert - mint should succeed even if it exceeds the max deposit + _pair.mint(address(this)); + assertGt(_pair.balanceOf(address(this)), 0); + assertEq(_pair.token0Managed(), 0); + assertEq(_pair.token1Managed(), 0); + } + + function testAfterLiquidityEvent_ExceedMaxWithdraw() external allNetworks allPairs { + // arrange + _increaseManagementOneToken(int256(4 * MINT_AMOUNT / 5)); // above the threshold + IERC4626 lVault = _manager.assetVault(USDC); + uint256 lLpTokenBal = _pair.balanceOf(_alice); + uint256 lAmtToBurn = lLpTokenBal / 100; // burn 1% + vm.prank(_alice); + _pair.transfer(address(_pair), lAmtToBurn); + + // act - simulate a failure in withdrawing during `afterLiquidityEvent` + vm.mockCallRevert(address(lVault), bytes4(IERC4626.withdraw.selector), ""); + _pair.burn(address(this)); + + // assert - tokens are still redeemed from the pair + assertGt(USDC.balanceOf(address(this)), 0); + assertGt(_tokenA.balanceOf(address(this)), 0); + } + function testSwap_ReturnAsset() public allNetworks allPairs { // arrange (uint256 lReserve0, uint256 lReserve1,,) = _pair.getReserves();