diff --git a/script/add_liq.s.sol b/script/add_liq.s.sol index 1e9e019..5b06d86 100644 --- a/script/add_liq.s.sol +++ b/script/add_liq.s.sol @@ -4,7 +4,7 @@ import { Script, console2 } from "forge-std/Script.sol"; import { Registry } from "@/Registry.sol"; import { UnsETH } from "@/unsETH/UnsETH.sol"; import { Renderer } from "@/unsETH/Renderer.sol"; -import { LPETH } from "@/LPETH.sol"; +import { LPETH } from "@/lpETH/LPETH.sol"; import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import { ERC20 } from "solady/tokens/ERC20.sol"; diff --git a/script/check.s.sol b/script/check.s.sol index 3a558a0..aa70d20 100644 --- a/script/check.s.sol +++ b/script/check.s.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.20; import { Script, console2 } from "forge-std/Script.sol"; import { UnsETH } from "@/unsETH/UnsETH.sol"; import { Renderer } from "@/unsETH/Renderer.sol"; -import { LPETH } from "@/LPETH.sol"; +import { LPETH } from "@/lpETH/LPETH.sol"; import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import { ERC20 } from "solady/tokens/ERC20.sol"; diff --git a/script/deploy.local.s.sol b/script/deploy.local.s.sol index dea6141..3d0f127 100644 --- a/script/deploy.local.s.sol +++ b/script/deploy.local.s.sol @@ -1,83 +1,82 @@ -// pragma solidity >=0.8.20; +pragma solidity >=0.8.20; -// import { Script, console2 } from "forge-std/Script.sol"; -// import { Registry } from "@/Registry.sol"; -// import { UnsETH } from "@/unsETH/UnsETH.sol"; -// import { Renderer } from "@/unsETH/Renderer.sol"; -// import { LPETH, ConstructorConfig } from "@/LPETH.sol"; -// import { LPToken } from "@/LPToken.sol"; -// import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; -// import { ERC20 } from "solady/tokens/ERC20.sol"; +import { Script, console2 } from "forge-std/Script.sol"; +import { Registry } from "@/Registry.sol"; +import { UnsETH } from "@/unsETH/UnsETH.sol"; +import { Renderer } from "@/unsETH/Renderer.sol"; +import { LPETH, ConstructorConfig } from "@/lpETH/LPETH.sol"; +import { LPToken } from "@/lpETH/LPToken.sol"; +import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import { ERC20 } from "solady/tokens/ERC20.sol"; -// // Adapters -// import { Adapter } from "@/adapters/Adapter.sol"; -// import { EETHAdapter, EETH_TOKEN } from "@/adapters/eETH/EETHAdapter.sol"; -// import { ETHxAdapter, ETHx_TOKEN } from "@/adapters/ETHx/ETHxAdapter.sol"; -// import { METHAdapter, METH_TOKEN } from "@/adapters/mETH/METHAdapter.sol"; -// import { StETHAdapter, STETH_TOKEN } from "@/adapters/stETH/StETHAdapter.sol"; -// import { SwETHAdapter, SWETH_TOKEN } from "@/adapters/swETH/SwETHAdapter.sol"; +// Adapters +import { Adapter } from "@/adapters/Adapter.sol"; +import { EETHAdapter, EETH_TOKEN } from "@/adapters/eETH/EETHAdapter.sol"; +import { ETHxAdapter, ETHx_TOKEN } from "@/adapters/ETHx/ETHxAdapter.sol"; +import { METHAdapter, METH_TOKEN } from "@/adapters/mETH/METHAdapter.sol"; +import { StETHAdapter, STETH_TOKEN } from "@/adapters/stETH/StETHAdapter.sol"; +import { SwETHAdapter, SWETH_TOKEN } from "@/adapters/swETH/SwETHAdapter.sol"; -// // Token holders, to get some funds -// import { EETH_HOLDER } from "@test/adapters/EETHAdapter.t.sol"; -// import { ETHx_HOLDER } from "@test/adapters/ETHxAdapter.t.sol"; -// import { METH_HOLDER } from "@test/adapters/METHAdapter.t.sol"; -// import { STETH_HOLDER } from "@test/adapters/StETHAdapter.t.sol"; -// import { SWETH_HOLDER } from "@test/adapters/SwETHAdapter.t.sol"; +// Token holders, to get some funds +import { EETH_HOLDER } from "@test/adapters/EETHAdapter.t.sol"; +import { ETHx_HOLDER } from "@test/adapters/ETHxAdapter.t.sol"; +import { METH_HOLDER } from "@test/adapters/METHAdapter.t.sol"; +import { STETH_HOLDER } from "@test/adapters/StETHAdapter.t.sol"; +import { SWETH_HOLDER } from "@test/adapters/SwETHAdapter.t.sol"; -// contract DeployLocal is Script { -// bytes32 salt = bytes32(uint256(1)); +contract DeployLocal is Script { + bytes32 salt = bytes32(uint256(1)); -// function run() public { -// uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); -// vm.startBroadcast(deployerPrivateKey); + function run() public { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + vm.startBroadcast(deployerPrivateKey); -// LPToken lpToken = new LPToken(); + LPToken lpToken = new LPToken(); -// address registry_impl = address(new Registry{ salt: salt }()); -// Registry registryProxy = Registry(address(new ERC1967Proxy{ salt: salt }(address(registry_impl), ""))); -// registryProxy.initialize(); -// console2.log("Registry Implementation: %s", registry_impl); -// console2.log("Registry Proxy: %s", address(registryProxy)); + address registry_impl = address(new Registry{ salt: salt }()); + Registry registryProxy = Registry(address(new ERC1967Proxy{ salt: salt }(address(registry_impl), ""))); + registryProxy.initialize(); + console2.log("Registry Implementation: %s", registry_impl); + console2.log("Registry Proxy: %s", address(registryProxy)); -// address renderer = address(new Renderer()); -// address unsETH_impl = address(new UnsETH{ salt: salt }(address(registryProxy), renderer)); -// UnsETH unsETHProxy = UnsETH(payable(address(new ERC1967Proxy{ salt: salt }(unsETH_impl, "")))); -// unsETHProxy.initialize(); -// console2.log("UnsETH Implementation: %s", unsETH_impl); -// console2.log("UnsETH Proxy: %s", address(unsETHProxy)); + address renderer = address(new Renderer()); + address unsETH_impl = address(new UnsETH{ salt: salt }(address(registryProxy), renderer)); + UnsETH unsETHProxy = UnsETH(payable(address(new ERC1967Proxy{ salt: salt }(unsETH_impl, "")))); + unsETHProxy.initialize(); + console2.log("UnsETH Implementation: %s", unsETH_impl); + console2.log("UnsETH Proxy: %s", address(unsETHProxy)); -// ConstructorConfig memory config = ConstructorConfig({ -// registry: registryProxy, -// lpToken: lpToken, -// treasury: address(0), -// unsETH: address(unsETHProxy), -// withdrawQueue: address(0) -// }); + ConstructorConfig memory config = ConstructorConfig({ + registry: registryProxy, + lpToken: lpToken, + unsETH: address(unsETHProxy), + treasury: address(0) + }); -// address lpETH_impl = address(new LPETH{ salt: salt }()); -// LPETH lpETHProxy = LPETH(payable(address(new ERC1967Proxy{ salt: salt }(lpETH_impl, "")))); -// lpETHProxy.initialize(); -// console2.log("LPETH Implementation: %s", lpETH_impl); -// console2.log("LPETH Proxy: %s", address(lpETHProxy)); -// console2.log("LP Token: %s", address(lpETHProxy.lpToken())); + address lpETH_impl = address(new LPETH{ salt: salt }(config)); + LPETH lpETHProxy = LPETH(payable(address(new ERC1967Proxy{ salt: salt }(lpETH_impl, "")))); + lpETHProxy.initialize(); + console2.log("LPETH Implementation: %s", lpETH_impl); + console2.log("LPETH Proxy: %s", address(lpETHProxy)); + console2.log("LP Token: %s", address(lpETHProxy.lpToken())); -// // Register and deploy adapters, send some funds -// Adapter eETHAdapter = new EETHAdapter(); -// registryProxy.setAdapter(EETH_TOKEN, eETHAdapter); -// console2.log("EETH Adapter: %s", address(eETHAdapter)); + // Register and deploy adapters, send some funds + Adapter eETHAdapter = new EETHAdapter(); + registryProxy.setAdapter(EETH_TOKEN, eETHAdapter); + console2.log("EETH Adapter: %s", address(eETHAdapter)); -// Adapter ethxAdapter = new ETHxAdapter(); -// registryProxy.setAdapter(ETHx_TOKEN, ethxAdapter); -// console2.log("ETHx Adapter: %s", address(ethxAdapter)); + Adapter ethxAdapter = new ETHxAdapter(); + registryProxy.setAdapter(ETHx_TOKEN, ethxAdapter); + console2.log("ETHx Adapter: %s", address(ethxAdapter)); -// Adapter methAdapter = new METHAdapter(); -// registryProxy.setAdapter(METH_TOKEN, methAdapter); -// console2.log("METH Adapter: %s", address(methAdapter)); + Adapter methAdapter = new METHAdapter(); + registryProxy.setAdapter(METH_TOKEN, methAdapter); + console2.log("METH Adapter: %s", address(methAdapter)); -// Adapter stETHAdapter = new StETHAdapter(); -// registryProxy.setAdapter(STETH_TOKEN, stETHAdapter); -// console2.log("StETH Adapter: %s", address(stETHAdapter)); + Adapter stETHAdapter = new StETHAdapter(); + registryProxy.setAdapter(STETH_TOKEN, stETHAdapter); + console2.log("StETH Adapter: %s", address(stETHAdapter)); -// vm.stopBroadcast(); -// } -// } + vm.stopBroadcast(); + } +} diff --git a/src/WithdrawQueue.sol b/src/WithdrawQueue.sol deleted file mode 100644 index 0e2edc9..0000000 --- a/src/WithdrawQueue.sol +++ /dev/null @@ -1,96 +0,0 @@ -pragma solidity >=0.8.20; - -address constant LPETH = address(0); - -error NotFinalized(uint256 id); -error InsufficientMsgvalue(); -error Unauthorized(); - -struct WithdrawRequest { - uint128 amount; // original request amount - uint128 claimed; // amount claimed - uint256 cumulative; // cumulative lifetime requested - address payable account; -} - -contract WithdrawQueue { - uint256 private head; - uint256 private tail; - uint256 private lifetimeFinalized; - uint128 private partiallyFinalizedAmount; - - mapping(uint256 id => WithdrawRequest) private queue; - - receive() external payable { } - - function createRequest(uint128 amount, address payable account) external returns (uint256 id) { - if (msg.sender != LPETH) revert Unauthorized(); - // start head at 1 - id = ++tail; - queue[id] = WithdrawRequest(amount, 0, queue[id - 1].cumulative + amount, account); - if (head == 0) head = 1; - } - - function claimRequest(uint256 id) external { - WithdrawRequest storage req = queue[id]; - if (msg.sender != req.account) revert Unauthorized(); - if (id < head) { - uint256 amount = req.amount - req.claimed; - delete queue[id]; - req.account.transfer(amount); - } else if (id == head) { - req.claimed = partiallyFinalizedAmount; - req.account.transfer(partiallyFinalizedAmount); - } else { - revert NotFinalized(id); - } - } - - function finalizeRequests() external payable { - uint256 amount = msg.value; - if (msg.sender != LPETH) revert Unauthorized(); - uint256 index = _findFinalizableIndex(head, tail, amount); - head = index + 1; - partiallyFinalizedAmount = uint128(amount - (queue[index].cumulative - lifetimeFinalized)); - lifetimeFinalized += amount; - } - - function getClaimableForRequest(uint256 id) external view returns (uint256) { - if (id < head) { - WithdrawRequest memory req = queue[id]; - return req.amount - req.claimed; - } else if (id == head) { - WithdrawRequest memory req = queue[id]; - return partiallyFinalizedAmount - req.claimed; - } else { - return 0; - } - } - - function length() external view returns (uint256) { - return tail - head; - } - - function amountUnfinalized() external view returns (uint256) { - return queue[tail].cumulative - lifetimeFinalized; - } - - function _findFinalizableIndex(uint256 start, uint256 end, uint256 amount) internal view returns (uint256) { - uint256 _ltf = lifetimeFinalized; - - while (start < end) { - uint256 mid = (start + end) / 2; - uint256 midCumulative = queue[mid].cumulative; - - if (midCumulative - _ltf == amount) { - return mid; - } else if (midCumulative - _ltf <= amount) { - start = mid + 1; - } else { - end = mid; - } - } - - return start; - } -} diff --git a/src/LPETH.sol b/src/lpETH/LPETH.sol similarity index 96% rename from src/LPETH.sol rename to src/lpETH/LPETH.sol index 1e3858b..39bd3f2 100644 --- a/src/LPETH.sol +++ b/src/lpETH/LPETH.sol @@ -12,11 +12,11 @@ pragma solidity >=0.8.20; import { Registry } from "@/Registry.sol"; -import { LPToken } from "@/LPToken.sol"; +import { LPToken } from "@/lpETH/LPToken.sol"; import { UnsETH, Metadata } from "@/unsETH/UnsETH.sol"; -import { UnsETHQueue } from "@/UnsETHQueue.sol"; +import { UnsETHQueue } from "@/lpETH/UnsETHQueue.sol"; import { Adapter } from "@/adapters/Adapter.sol"; -import { WithdrawQueue } from "@/WithdrawQueue.sol"; +import { WithdrawQueue } from "@/lpETH/WithdrawQueue.sol"; import { ERC721Receiver } from "@/utils/ERC721Receiver.sol"; import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; @@ -47,9 +47,8 @@ UD60x18 constant MIN_LP_CUT = UD60x18.wrap(0.2e18); struct ConstructorConfig { Registry registry; LPToken lpToken; - address treasury; address unsETH; - address withdrawQueue; + address treasury; } struct SwapParams { @@ -71,7 +70,8 @@ abstract contract LpETHEvents { error GaugeZero(); event Deposit(address indexed from, uint256 amount, uint256 lpSharesMinted); - event Withdraw(address indexed to, uint256 amount, uint256 lpSharesBurnt); + event Withdraw(address indexed to, uint256 amount, uint256 lpSharesBurnt, uint256 requestId); + event ClaimWithdrawRequest(uint256 indexed requestId, address indexed to, uint256 amount); event Swap(address indexed caller, address indexed asset, uint256 amountIn, uint256 fee, uint256 unlockId); event UnlockBought(address indexed caller, uint256 tokenId, uint256 amount, uint256 reward, uint256 lpFees); event UnlockRedeemed(address indexed relayer, uint256 tokenId, uint256 amount, uint256 reward, uint256 lpFees); @@ -99,6 +99,8 @@ abstract contract LpETHStorage { uint256 treasuryRewards; // Unlock queue to hold unlocks UnsETHQueue.Data unsETHQueue; + // Withdraw request queue + WithdrawQueue.Data withdrawQueue; // amount unlocking per asset mapping(address asset => uint256 unlocking) unlockingForAsset; // last supply of a tenderizer when seen, tracked because they are rebasing tokens @@ -130,12 +132,12 @@ contract LPETH is ERC721Receiver { using UnsETHQueue for UnsETHQueue.Data; + using WithdrawQueue for WithdrawQueue.Data; LPToken private immutable LPTOKEN = LPToken(address(0)); Registry private immutable REGISTRY = Registry(address(0)); - address payable private immutable TREASURY = payable(0x5542b58080FEE48dBE6f38ec0135cE9011519d96); address payable private immutable UNSETH = payable(0xA2FE2b9298c03AF9C5d885e62Bc04F77a7Ff91BF); - address payable private immutable WITHDRAW_QUEUE = payable(address(0)); + address payable private immutable TREASURY = payable(0x5542b58080FEE48dBE6f38ec0135cE9011519d96); function initialize() public initializer { __Ownable_init(msg.sender); @@ -150,7 +152,6 @@ contract LPETH is LPTOKEN = config.lpToken; TREASURY = payable(config.treasury); UNSETH = payable(config.unsETH); - WITHDRAW_QUEUE = payable(config.withdrawQueue); _disableInitializers(); } @@ -187,7 +188,7 @@ contract LPETH is uint256 available = ud(amount).mul(ud($.unlocking).div(ud($.liabilities))).unwrap(); - requestId = WithdrawQueue(WITHDRAW_QUEUE).createRequest(uint128(amount - available), payable(msg.sender)); + requestId = $.withdrawQueue.createRequest(uint128(amount - available), payable(msg.sender)); // Calculate LP tokens to burn uint256 lpShares = @@ -204,7 +205,7 @@ contract LPETH is // Transfer available tokens to caller payable(msg.sender).transfer(available); - emit Withdraw(msg.sender, amount, lpShares); + emit Withdraw(msg.sender, amount, lpShares, requestId); } function quote(address asset, uint256 amount) external view returns (uint256 out) { @@ -299,7 +300,7 @@ contract LPETH is // Finalize requests { uint256 amountToFinalize = amountReceived - unlock.fee; - WithdrawQueue(WITHDRAW_QUEUE).finalizeRequests{ value: amountToFinalize }(); + $.withdrawQueue.finalizeRequests(amountToFinalize); } emit UnlockRedeemed(msg.sender, unlock.tokenId, amountReceived, relayerReward, lpReward); @@ -356,7 +357,7 @@ contract LPETH is // Finalize requests { uint256 amountToFinalize = totalReceived - totalFee; - WithdrawQueue(WITHDRAW_QUEUE).finalizeRequests{ value: amountToFinalize }(); + $.withdrawQueue.finalizeRequests(amountToFinalize); } emit BatchUnlockRedeemed(msg.sender, totalReceived, relayerReward, lpReward, tokenIds); @@ -417,7 +418,7 @@ contract LPETH is // Finalize requests { uint256 amountToFinalize = amountExpected - unlock.fee; - WithdrawQueue(WITHDRAW_QUEUE).finalizeRequests{ value: amountToFinalize }(); + $.withdrawQueue.finalizeRequests(amountToFinalize); } // transfer unlock amount minus reward from caller to pool @@ -497,7 +498,7 @@ contract LPETH is // Finalize requests { uint256 amountToFinalize = totalAmountExpected - totalRewards - totalLpCut - totalTreasuryCut; - WithdrawQueue(WITHDRAW_QUEUE).finalizeRequests{ value: amountToFinalize }(); + $.withdrawQueue.finalizeRequests(amountToFinalize); } emit BatchUnlockBought(msg.sender, totalAmountExpected, totalRewards, totalLpCut, tokenIds); @@ -529,6 +530,11 @@ contract LPETH is payable(TREASURY).transfer(treasuryReward); } + function claimWithdrawRequest(uint256 id) external returns (uint256 amount) { + amount = _loadStorageSlot().withdrawQueue.claimRequest(id); + emit ClaimWithdrawRequest(id, msg.sender, amount); + } + function lpToken() external view returns (address) { return address(LPTOKEN); } diff --git a/src/LPToken.sol b/src/lpETH/LPToken.sol similarity index 100% rename from src/LPToken.sol rename to src/lpETH/LPToken.sol diff --git a/src/UnsETHQueue.sol b/src/lpETH/UnsETHQueue.sol similarity index 99% rename from src/UnsETHQueue.sol rename to src/lpETH/UnsETHQueue.sol index 0676f76..e6e76a0 100644 --- a/src/UnsETHQueue.sol +++ b/src/lpETH/UnsETHQueue.sol @@ -15,7 +15,7 @@ * It is used to store a list of unlocks for a given TenderSwap pool. * @dev modified from https://github.com/Tenderize/tenderswap/blob/main/src/UnlockQueue.sol */ -pragma solidity >=0.8.19; +pragma solidity >=0.8.20; library UnsETHQueue { error QueueEmpty(); diff --git a/src/lpETH/WithdrawQueue.sol b/src/lpETH/WithdrawQueue.sol new file mode 100644 index 0000000..16154ca --- /dev/null +++ b/src/lpETH/WithdrawQueue.sol @@ -0,0 +1,100 @@ +pragma solidity >=0.8.20; + +library WithdrawQueue { + error NotFinalized(uint256 id); + error InsufficientMsgvalue(); + error Unauthorized(); + + struct WithdrawRequest { + uint128 amount; // original request amount + uint128 claimed; // amount claimed + uint256 cumulative; // cumulative lifetime requested + address payable account; + } + + struct Data { + uint256 head; + uint256 tail; + uint256 lifetimeFinalized; + uint128 partiallyFinalizedAmount; + mapping(uint256 id => WithdrawRequest) queue; + } + + function createRequest(Data storage $, uint128 amount, address payable account) external returns (uint256 id) { + // start head at 1 + id = ++$.tail; + $.queue[id] = WithdrawRequest(amount, 0, $.queue[id - 1].cumulative + amount, account); + if ($.head == 0) $.head = 1; + } + + function claimRequest(Data storage $, uint256 id) external returns (uint256 amount) { + WithdrawRequest storage req = $.queue[id]; + if (msg.sender != req.account) revert Unauthorized(); + if (id < $.head) { + amount = req.amount - req.claimed; + delete $.queue[id]; + req.account.transfer(amount); + } else if (id == $.head) { + amount = $.partiallyFinalizedAmount; + req.claimed = uint128(amount); // TODO: safecast + req.account.transfer(amount); + } else { + revert NotFinalized(id); + } + } + + function finalizeRequests(Data storage $, uint256 amount) external { + uint256 index = _findFinalizableIndex($, $.head, $.tail, amount); + $.head = index + 1; + $.partiallyFinalizedAmount = uint128(amount - ($.queue[index].cumulative - $.lifetimeFinalized)); + $.lifetimeFinalized += amount; + } + + function getClaimableForRequest(Data storage $, uint256 id) external view returns (uint256) { + if (id < $.head) { + WithdrawRequest memory req = $.queue[id]; + return req.amount - req.claimed; + } else if (id == $.head) { + WithdrawRequest memory req = $.queue[id]; + return $.partiallyFinalizedAmount - req.claimed; + } else { + return 0; + } + } + + function length(Data storage $) external view returns (uint256) { + return $.tail - $.head; + } + + function amountUnfinalized(Data storage $) external view returns (uint256) { + return $.queue[$.tail].cumulative - $.lifetimeFinalized; + } + + function _findFinalizableIndex( + Data storage $, + uint256 start, + uint256 end, + uint256 amount + ) + internal + view + returns (uint256) + { + uint256 _ltf = $.lifetimeFinalized; + + while (start < end) { + uint256 mid = (start + end) / 2; + uint256 midCumulative = $.queue[mid].cumulative; + + if (midCumulative - _ltf == amount) { + return mid; + } else if (midCumulative - _ltf <= amount) { + start = mid + 1; + } else { + end = mid; + } + } + + return start; + } +} diff --git a/test/lpETH/FeeGauge.t.sol b/test/lpETH/FeeGauge.t.sol index 6ddacad..1f2c60d 100644 --- a/test/lpETH/FeeGauge.t.sol +++ b/test/lpETH/FeeGauge.t.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.20; import { Test, console } from "forge-std/Test.sol"; import { VmSafe } from "forge-std/Vm.sol"; -import { LPETH, LpETHEvents, ConstructorConfig } from "@/LPETH.sol"; -import { LPToken } from "@/LPToken.sol"; +import { LPETH, LpETHEvents, ConstructorConfig } from "@/lpETH/LPETH.sol"; +import { LPToken } from "@/lpETH/LPToken.sol"; import { Registry } from "@/Registry.sol"; import { UD60x18, UNIT, ud } from "@prb/math/UD60x18.sol"; @@ -18,9 +18,8 @@ contract LPETH_FeeGauge_Test is Test { ConstructorConfig memory config = ConstructorConfig({ registry: Registry(address(8)), lpToken: LPToken(address(9)), - treasury: address(10), unsETH: address(11), - withdrawQueue: address(12) + treasury: address(10) }); LPETH lpETH_impl = new LPETH(config); lpETH = LPETH(payable(address(new ERC1967Proxy(address(lpETH_impl), "")))); diff --git a/test/LPToken.t.sol b/test/lpETH/LPToken.t.sol similarity index 96% rename from test/LPToken.t.sol rename to test/lpETH/LPToken.t.sol index b5f8239..ba7ef27 100644 --- a/test/LPToken.t.sol +++ b/test/lpETH/LPToken.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.20; import { Test, console } from "forge-std/Test.sol"; import { VmSafe } from "forge-std/Vm.sol"; -import { LPToken } from "@/LPToken.sol"; +import { LPToken } from "@/lpETH/LPToken.sol"; contract LPTokenTest is Test { LPToken lpToken;