From 16d20afd68be3f65fba257be1fbda41ad324c214 Mon Sep 17 00:00:00 2001 From: kyriediculous Date: Wed, 3 Jul 2024 13:05:29 +0200 Subject: [PATCH] fix: solidity 0.8.25; transient storage; nonreentrant using transient storage; prevent flash loan attack on liquidity using transient storage; --- .solhint.json | 17 +++++++--- foundry.toml | 2 +- script/add_liq.s.sol | 2 +- script/check.s.sol | 2 +- script/deploy.local.s.sol | 2 +- src/Registry.sol | 2 +- src/adapters/Adapter.sol | 13 +++++--- src/adapters/ETHx/ETHxAdapter.sol | 2 +- src/adapters/eETH/EETHAdapter.sol | 2 +- src/adapters/lsETH/LsETHAdapter.sol | 2 +- src/adapters/mETH/METHAdapter.sol | 2 +- src/adapters/stETH/StETHAdapter.sol | 2 +- src/adapters/swETH/SwETHAdapter.sol | 2 +- src/lpETH/LPToken.sol | 2 +- src/lpETH/LpETH.sol | 48 ++++++++++++++++++++++++----- src/lpETH/UnsETHQueue.sol | 2 +- src/lpETH/WithdrawQueue.sol | 2 +- src/periphery/SwapRouter.sol | 29 +++++++++++++++++ src/unsETH/Base64.sol | 2 +- src/unsETH/Renderer.sol | 2 +- src/unsETH/UnsETH.sol | 2 +- src/utils/ERC721Receiver.sol | 2 +- src/utils/SelfPermit.sol | 2 +- test/Registry.t.sol | 2 +- test/UnsETH.t.sol | 2 +- test/adapters/EETHAdapter.t.sol | 2 +- test/adapters/ETHxAdapter.t.sol | 2 +- test/adapters/METHAdapter.t.sol | 2 +- test/adapters/StETHAdapter.t.sol | 2 +- test/adapters/SwETHAdapter.t.sol | 2 +- test/helpers/MockERC20.sol | 2 +- test/lpETH/FeeGauge.t.sol | 2 +- test/lpETH/LPToken.t.sol | 2 +- test/lpETH/LpETH.t.sol | 6 +++- test/lpETH/UnsETHQueue.t.sol | 2 +- test/lpETH/WithdrawQueue.t.sol | 2 +- 36 files changed, 126 insertions(+), 49 deletions(-) create mode 100644 src/periphery/SwapRouter.sol diff --git a/.solhint.json b/.solhint.json index d434614..2011841 100644 --- a/.solhint.json +++ b/.solhint.json @@ -1,8 +1,14 @@ { "extends": "solhint:recommended", "rules": { - "code-complexity": ["error", 8], - "compiler-version": ["error", ">=0.8.20"], + "code-complexity": [ + "error", + 8 + ], + "compiler-version": [ + "error", + ">=0.8.25" + ], "func-name-mixedcase": "off", "func-visibility": [ "error", @@ -10,10 +16,13 @@ "ignoreConstructors": true } ], - "max-line-length": ["error", 120], + "max-line-length": [ + "error", + 120 + ], "named-parameters-mapping": "warn", "no-console": "off", "not-rely-on-time": "off", "one-contract-per-file": "off" } -} +} \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index 136026f..3c2f6ad 100644 --- a/foundry.toml +++ b/foundry.toml @@ -4,7 +4,7 @@ auto_detect_solc = false block_timestamp = 1_680_220_800 # March 31, 2023 at 00:00 GMT bytecode_hash = "none" -evm_version = "paris" # See https://www.evmdiff.com/features?name=PUSH0&kind=opcode +evm_version = "cancun" # See https://www.evmdiff.com/features?name=PUSH0&kind=opcode fuzz = { runs = 1_000 } gas_reports = ["*"] optimizer = true diff --git a/script/add_liq.s.sol b/script/add_liq.s.sol index f52f125..71fa834 100644 --- a/script/add_liq.s.sol +++ b/script/add_liq.s.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Script, console2 } from "forge-std/Script.sol"; import { Registry } from "@/Registry.sol"; diff --git a/script/check.s.sol b/script/check.s.sol index 8d75494..7d6a744 100644 --- a/script/check.s.sol +++ b/script/check.s.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Script, console2 } from "forge-std/Script.sol"; import { UnsETH } from "@/unsETH/UnsETH.sol"; diff --git a/script/deploy.local.s.sol b/script/deploy.local.s.sol index 0de3400..165cf65 100644 --- a/script/deploy.local.s.sol +++ b/script/deploy.local.s.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Script, console2 } from "forge-std/Script.sol"; import { Registry } from "@/Registry.sol"; diff --git a/src/Registry.sol b/src/Registry.sol index 2de322a..6fd43f7 100644 --- a/src/Registry.sol +++ b/src/Registry.sol @@ -9,7 +9,7 @@ // // Copyright (c) Tenderize Labs Ltd -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { OwnableUpgradeable } from "@openzeppelin/upgradeable/access/OwnableUpgradeable.sol"; import { Initializable } from "@openzeppelin/upgradeable/proxy/utils/Initializable.sol"; diff --git a/src/adapters/Adapter.sol b/src/adapters/Adapter.sol index ae71798..385abda 100644 --- a/src/adapters/Adapter.sol +++ b/src/adapters/Adapter.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; library AdapterDelegateCall { error AdapterDelegateCallFailed(string msg); @@ -8,12 +8,15 @@ library AdapterDelegateCall { (bool success, bytes memory returnData) = address(adapter).delegatecall(data); if (!success) { - // Next 5 lines from https://ethereum.stackexchange.com/a/83577 - if (returnData.length < 68) revert AdapterDelegateCallFailed(""); + if (returnData.length < 4) { + revert AdapterDelegateCallFailed("Unknown error occurred"); + } + + // Bubble up the full return data assembly { - returnData := add(returnData, 0x04) + let returndata_size := mload(returnData) + revert(add(returnData, 0x20), returndata_size) } - revert AdapterDelegateCallFailed(abi.decode(returnData, (string))); } return returnData; diff --git a/src/adapters/ETHx/ETHxAdapter.sol b/src/adapters/ETHx/ETHxAdapter.sol index 412011b..976af46 100644 --- a/src/adapters/ETHx/ETHxAdapter.sol +++ b/src/adapters/ETHx/ETHxAdapter.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Adapter } from "@/adapters/Adapter.sol"; import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; diff --git a/src/adapters/eETH/EETHAdapter.sol b/src/adapters/eETH/EETHAdapter.sol index 0e677c7..c400de8 100644 --- a/src/adapters/eETH/EETHAdapter.sol +++ b/src/adapters/eETH/EETHAdapter.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Adapter } from "@/adapters/Adapter.sol"; import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; diff --git a/src/adapters/lsETH/LsETHAdapter.sol b/src/adapters/lsETH/LsETHAdapter.sol index cbfcfd4..075455e 100644 --- a/src/adapters/lsETH/LsETHAdapter.sol +++ b/src/adapters/lsETH/LsETHAdapter.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Adapter } from "@/adapters/Adapter.sol"; import { IRiver, IRedeemManager } from "@/adapters/lsETH/ILiquidCollective.sol"; diff --git a/src/adapters/mETH/METHAdapter.sol b/src/adapters/mETH/METHAdapter.sol index 256751b..76c4f28 100644 --- a/src/adapters/mETH/METHAdapter.sol +++ b/src/adapters/mETH/METHAdapter.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Adapter } from "@/adapters/Adapter.sol"; import { IStaking } from "@/adapters/mETH/IMantle.sol"; diff --git a/src/adapters/stETH/StETHAdapter.sol b/src/adapters/stETH/StETHAdapter.sol index 211ce9d..90c5604 100644 --- a/src/adapters/stETH/StETHAdapter.sol +++ b/src/adapters/stETH/StETHAdapter.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Adapter } from "@/Registry.sol"; import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; diff --git a/src/adapters/swETH/SwETHAdapter.sol b/src/adapters/swETH/SwETHAdapter.sol index 203f4a1..455e315 100644 --- a/src/adapters/swETH/SwETHAdapter.sol +++ b/src/adapters/swETH/SwETHAdapter.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Adapter } from "@/adapters/Adapter.sol"; import { IswETH, IswEXIT } from "@/adapters/swETH/ISwell.sol"; diff --git a/src/lpETH/LPToken.sol b/src/lpETH/LPToken.sol index b3ad55d..bc41ae4 100644 --- a/src/lpETH/LPToken.sol +++ b/src/lpETH/LPToken.sol @@ -9,7 +9,7 @@ // // Copyright (c) Tenderize Labs Ltd -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { ERC20 } from "@solady/tokens/ERC20.sol"; import { Ownable } from "solady/auth/Ownable.sol"; diff --git a/src/lpETH/LpETH.sol b/src/lpETH/LpETH.sol index 006ad8d..cb57d9f 100644 --- a/src/lpETH/LpETH.sol +++ b/src/lpETH/LpETH.sol @@ -9,7 +9,7 @@ // // Copyright (c) Tenderize Labs Ltd -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Registry } from "@/Registry.sol"; import { LPToken } from "@/lpETH/LPToken.sol"; @@ -69,6 +69,7 @@ abstract contract LpETHEvents { error ErrorRecoveryMode(); error GaugeZero(); error ErrorInsufficientAmount(); + error DepositedInCurrentTx(); event Deposit(address indexed from, uint256 amount, uint256 lpSharesMinted); event Withdraw(address indexed to, uint256 amount, uint256 lpSharesBurnt, uint256 requestId); @@ -135,6 +136,9 @@ contract LpETH is using UnsETHQueue for UnsETHQueue.Data; using WithdrawQueue for WithdrawQueue.Data; + // uint256(keccak256("DEPOSITED_IN_CURRENT_TX")) + uint256 private constant NONREENTRANT_TSTORE = 0x20; + uint256 private constant DEPOSITED_IN_CURRENT_TX_TSTORE = 0x40; // tstore slot LPToken private immutable LPTOKEN = LPToken(address(0)); Registry private immutable REGISTRY = Registry(address(0)); UnsETH private immutable UNSETH = UnsETH(payable(0xA2FE2b9298c03AF9C5d885e62Bc04F77a7Ff91BF)); @@ -147,6 +151,19 @@ contract LpETH is receive() external payable { } + modifier nonreentrant() { + assembly { + if tload(NONREENTRANT_TSTORE) { revert(0, 0) } + tstore(NONREENTRANT_TSTORE, 1) + } + _; + // Unlocks the guard, making the pattern composable. + // After the function exits, it can be called again, even in the same transaction. + assembly { + tstore(NONREENTRANT_TSTORE, 0) + } + } + /// @custom:oz-upgrades-unsafe-allow constructor constructor(ConstructorConfig memory config) { REGISTRY = config.registry; @@ -178,13 +195,28 @@ contract LpETH is if (lpShares < minLpShares) revert ErrorSlippage(lpShares, minLpShares); if (lpShares == 0) revert ErrorDepositSharesZero(); - LPTOKEN.mint(msg.sender, lpShares); $.liabilities += msg.value; + LPTOKEN.mint(msg.sender, lpShares); + + assembly { + tstore(DEPOSITED_IN_CURRENT_TX_TSTORE, 1) + } emit Deposit(msg.sender, msg.value, lpShares); } - function withdraw(uint256 amount, uint256 maxLpSharesBurnt) external returns (uint256 requestId) { + function withdraw(uint256 amount, uint256 maxLpSharesBurnt) external nonreentrant returns (uint256 requestId) { + bytes4 selector = LpETHEvents.DepositedInCurrentTx.selector; + assembly { + // Get the free memory pointer + let freeMemPtr := mload(0x40) + if eq(tload(DEPOSITED_IN_CURRENT_TX_TSTORE), 1) { + // Store the selector at the free memory pointer + mstore(freeMemPtr, selector) + // Revert with the selector stored in memory + revert(freeMemPtr, 0x04) + } + } Data storage $ = _loadStorageSlot(); uint256 available = ud(amount).mul(UNIT_60x18.sub(ud($.unlocking).div(ud($.liabilities)))).unwrap(); @@ -219,7 +251,7 @@ contract LpETH is out = _quote(asset, amount, p); } - function swap(address asset, uint256 amount, uint256 minOut) external returns (uint256 out) { + function swap(address asset, uint256 amount, uint256 minOut) external nonreentrant returns (uint256 out) { Data storage $ = _loadStorageSlot(); Adapter adapter = REGISTRY.adapters(asset); if (address(adapter) == address(0)) revert ErrorInvalidAsset(asset); @@ -261,7 +293,7 @@ contract LpETH is emit Swap(msg.sender, asset, amount, fee, tokenId); } - function redeemUnlock() external { + function redeemUnlock() external nonreentrant { Data storage $ = _loadStorageSlot(); // get oldest item from unlock queue @@ -295,7 +327,7 @@ contract LpETH is emit UnlockRedeemed(msg.sender, unlock.tokenId, amountReceived, relayerReward, lpReward); } - function batchRedeemUnlocks(uint256 n) external { + function batchRedeemUnlocks(uint256 n) external nonreentrant { Data storage $ = _loadStorageSlot(); uint256 totalReceived; uint256 totalExpected; @@ -362,7 +394,7 @@ contract LpETH is $.liabilities += lpReward; } - function buyUnlock(uint256 expectedTokenId) external payable returns (uint256 tokenId) { + function buyUnlock(uint256 expectedTokenId) external payable nonreentrant returns (uint256 tokenId) { Data storage $ = _loadStorageSlot(); // Can not purchase unlocks in recovery mode @@ -413,7 +445,7 @@ contract LpETH is emit UnlockBought(msg.sender, tokenId, request.amount, reward, lpCut); } - function batchBuyUnlock(uint256 n, uint256 expectedStartId) external payable { + function batchBuyUnlock(uint256 n, uint256 expectedStartId) external payable nonreentrant { Data storage $ = _loadStorageSlot(); // Can not purchase unlocks in recovery mode diff --git a/src/lpETH/UnsETHQueue.sol b/src/lpETH/UnsETHQueue.sol index fbf60a0..6369a91 100644 --- a/src/lpETH/UnsETHQueue.sol +++ b/src/lpETH/UnsETHQueue.sol @@ -9,7 +9,7 @@ // // Copyright (c) Tenderize Labs Ltd -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; /** * @notice This file implements the necessary functionality for a double-ended queue or deque. diff --git a/src/lpETH/WithdrawQueue.sol b/src/lpETH/WithdrawQueue.sol index c1ea277..a43d225 100644 --- a/src/lpETH/WithdrawQueue.sol +++ b/src/lpETH/WithdrawQueue.sol @@ -9,7 +9,7 @@ // // Copyright (c) Tenderize Labs Ltd -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { SafeTransferLib } from "@solady/utils/SafeTransferLib.sol"; diff --git a/src/periphery/SwapRouter.sol b/src/periphery/SwapRouter.sol new file mode 100644 index 0000000..5a67129 --- /dev/null +++ b/src/periphery/SwapRouter.sol @@ -0,0 +1,29 @@ +pragma solidity ^0.8.25; + +import { LpETH } from "@/lpETH/LpETH.sol"; +import { ERC20 } from "@solady/tokens/ERC20.sol"; +import { SafeTransferLib } from "@solady/utils/SafeTransferLib.sol"; + +address constant WRAPPED_STETH = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; +address constant WRAPPED_EETH = 0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee; + +LpETH constant LPETH = LpETH(payable(address(2))); + +interface Unwrap { + function unwrap(uint256 amount) external returns (uint256); +} + +contract SwapRouter { + using SafeTransferLib for address; + + receive() external payable { } + + function swap(address tokenIn, uint256 amount, uint256 minOut) external returns (uint256 out) { + tokenIn.safeTransferFrom(msg.sender, address(this), amount); + if (tokenIn == WRAPPED_STETH || tokenIn == WRAPPED_EETH) { + amount = Unwrap(tokenIn).unwrap(amount); + } + out = LPETH.swap(tokenIn, amount, minOut); + payable(msg.sender).transfer(out); + } +} diff --git a/src/unsETH/Base64.sol b/src/unsETH/Base64.sol index 5575aaf..da695b9 100644 --- a/src/unsETH/Base64.sol +++ b/src/unsETH/Base64.sol @@ -9,7 +9,7 @@ // // Copyright (c) Tenderize Labs Ltd -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; /** * Based on Brecht Devos (Brechtpd) implementation - MIT licence diff --git a/src/unsETH/Renderer.sol b/src/unsETH/Renderer.sol index a50ac7b..10b45b0 100644 --- a/src/unsETH/Renderer.sol +++ b/src/unsETH/Renderer.sol @@ -9,7 +9,7 @@ // // Copyright (c) Tenderize Labs Ltd -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Initializable } from "@openzeppelin/upgradeable/proxy/utils/Initializable.sol"; import { UUPSUpgradeable } from "@openzeppelin/upgradeable/proxy/utils/UUPSUpgradeable.sol"; diff --git a/src/unsETH/UnsETH.sol b/src/unsETH/UnsETH.sol index 507e94a..269fed9 100644 --- a/src/unsETH/UnsETH.sol +++ b/src/unsETH/UnsETH.sol @@ -23,7 +23,7 @@ import { Registry } from "@/Registry.sol"; import { ERC721Receiver } from "@/utils/ERC721Receiver.sol"; import { Adapter, AdapterDelegateCall } from "@/adapters/Adapter.sol"; -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; // solhint-disable quotes diff --git a/src/utils/ERC721Receiver.sol b/src/utils/ERC721Receiver.sol index 5ea5646..16e9b1b 100644 --- a/src/utils/ERC721Receiver.sol +++ b/src/utils/ERC721Receiver.sol @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MIT -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; abstract contract ERC721Receiver { function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) { diff --git a/src/utils/SelfPermit.sol b/src/utils/SelfPermit.sol index c4a2af8..92c476d 100644 --- a/src/utils/SelfPermit.sol +++ b/src/utils/SelfPermit.sol @@ -4,7 +4,7 @@ import { ERC20 } from "solady/tokens/ERC20.sol"; -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; /// @title Self Permit /// @notice Functionality to call permit on any EIP-2612-compliant token for use in the route diff --git a/test/Registry.t.sol b/test/Registry.t.sol index a4939f0..119b1f1 100644 --- a/test/Registry.t.sol +++ b/test/Registry.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; +pragma solidity ^0.8.25; import "forge-std/Test.sol"; import "@/adapters/Adapter.sol"; diff --git a/test/UnsETH.t.sol b/test/UnsETH.t.sol index dc983c9..6462475 100644 --- a/test/UnsETH.t.sol +++ b/test/UnsETH.t.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Test, console } from "forge-std/Test.sol"; import { VmSafe } from "forge-std/Vm.sol"; diff --git a/test/adapters/EETHAdapter.t.sol b/test/adapters/EETHAdapter.t.sol index 62a1acf..9496721 100644 --- a/test/adapters/EETHAdapter.t.sol +++ b/test/adapters/EETHAdapter.t.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Test, console } from "forge-std/Test.sol"; import { VmSafe } from "forge-std/Vm.sol"; diff --git a/test/adapters/ETHxAdapter.t.sol b/test/adapters/ETHxAdapter.t.sol index 859664a..2260b33 100644 --- a/test/adapters/ETHxAdapter.t.sol +++ b/test/adapters/ETHxAdapter.t.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Test, console } from "forge-std/Test.sol"; import { VmSafe } from "forge-std/Vm.sol"; diff --git a/test/adapters/METHAdapter.t.sol b/test/adapters/METHAdapter.t.sol index 1b6fa28..923b1d0 100644 --- a/test/adapters/METHAdapter.t.sol +++ b/test/adapters/METHAdapter.t.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Test, console } from "forge-std/Test.sol"; import { VmSafe } from "forge-std/Vm.sol"; diff --git a/test/adapters/StETHAdapter.t.sol b/test/adapters/StETHAdapter.t.sol index 968ccb9..b58d4e9 100644 --- a/test/adapters/StETHAdapter.t.sol +++ b/test/adapters/StETHAdapter.t.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Test, console } from "forge-std/Test.sol"; import { VmSafe } from "forge-std/Vm.sol"; diff --git a/test/adapters/SwETHAdapter.t.sol b/test/adapters/SwETHAdapter.t.sol index 1a947da..ac55286 100644 --- a/test/adapters/SwETHAdapter.t.sol +++ b/test/adapters/SwETHAdapter.t.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Test, console } from "forge-std/Test.sol"; import { VmSafe } from "forge-std/Vm.sol"; diff --git a/test/helpers/MockERC20.sol b/test/helpers/MockERC20.sol index 86eef39..9143e0d 100644 --- a/test/helpers/MockERC20.sol +++ b/test/helpers/MockERC20.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { ERC20 } from "solady/tokens/ERC20.sol"; diff --git a/test/lpETH/FeeGauge.t.sol b/test/lpETH/FeeGauge.t.sol index 8febab1..a8349d5 100644 --- a/test/lpETH/FeeGauge.t.sol +++ b/test/lpETH/FeeGauge.t.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Test, console } from "forge-std/Test.sol"; import { VmSafe } from "forge-std/Vm.sol"; diff --git a/test/lpETH/LPToken.t.sol b/test/lpETH/LPToken.t.sol index a5582a4..5c29582 100644 --- a/test/lpETH/LPToken.t.sol +++ b/test/lpETH/LPToken.t.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Test, console } from "forge-std/Test.sol"; import { VmSafe } from "forge-std/Vm.sol"; diff --git a/test/lpETH/LpETH.t.sol b/test/lpETH/LpETH.t.sol index 988e893..12408ab 100644 --- a/test/lpETH/LpETH.t.sol +++ b/test/lpETH/LpETH.t.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { Test, console } from "forge-std/Test.sol"; import { VmSafe } from "forge-std/Vm.sol"; @@ -18,6 +18,10 @@ import { ERC721Receiver } from "@/utils/ERC721Receiver.sol"; // This is an integration test. // Only `Adapter` calls are mocked. +// NOTE: Since this contract uses transient storage, use the "--isolate" flag to run the tests. +// This will execute top level calls as a context independent transaction. +// see: https://github.com/foundry-rs/foundry/issues/6908#issuecomment-2205157619 + contract LpETH_Harness is LpETH { constructor(ConstructorConfig memory config) LpETH(config) { } } diff --git a/test/lpETH/UnsETHQueue.t.sol b/test/lpETH/UnsETHQueue.t.sol index bf3cf28..eab43b3 100644 --- a/test/lpETH/UnsETHQueue.t.sol +++ b/test/lpETH/UnsETHQueue.t.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; // see https://github.com/Tenderize/tenderswap/blob/main/test/UnlockQueue.t.sol // the only difference is the type of data stored in the queue, // which isn't highly relevant to its logical implementation diff --git a/test/lpETH/WithdrawQueue.t.sol b/test/lpETH/WithdrawQueue.t.sol index 470fbef..8dd5577 100644 --- a/test/lpETH/WithdrawQueue.t.sol +++ b/test/lpETH/WithdrawQueue.t.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.8.20; +pragma solidity >=0.8.25; import { WithdrawQueue } from "@/lpETH/WithdrawQueue.sol";