diff --git a/docs/LidoARMHierarchy.svg b/docs/LidoARMHierarchy.svg
new file mode 100644
index 0000000..2fcc331
--- /dev/null
+++ b/docs/LidoARMHierarchy.svg
@@ -0,0 +1,80 @@
+
+
+
+
+
diff --git a/docs/LidoARMPublicSquashed.svg b/docs/LidoARMPublicSquashed.svg
new file mode 100644
index 0000000..9b0c980
--- /dev/null
+++ b/docs/LidoARMPublicSquashed.svg
@@ -0,0 +1,87 @@
+
+
+
+
+
diff --git a/docs/LidoARMSquashed.svg b/docs/LidoARMSquashed.svg
new file mode 100644
index 0000000..880ffda
--- /dev/null
+++ b/docs/LidoARMSquashed.svg
@@ -0,0 +1,117 @@
+
+
+
+
+
diff --git a/docs/generate.sh b/docs/generate.sh
index aa0c8b5..4589e56 100644
--- a/docs/generate.sh
+++ b/docs/generate.sh
@@ -13,10 +13,10 @@ sol2uml storage ../src/contracts -c OethARM -o OethARMStorage.svg \
-st address,address \
--hideExpand gap,_gap
-sol2uml ../src/contracts -v -hv -hf -he -hs -hl -hi -b LidoFixedPriceMultiLpARM -o LidoFixedPriceMultiLpARMHierarchy.svg
-sol2uml ../src/contracts -s -d 0 -b LidoFixedPriceMultiLpARM -o LidoFixedPriceMultiLpARMSquashed.svg
-sol2uml ../src/contracts -hp -s -d 0 -b LidoFixedPriceMultiLpARM -o LidoFixedPriceMultiLpARMPublicSquashed.svg
-sol2uml storage ../src/contracts,../lib -c LidoFixedPriceMultiLpARM -o LidoFixedPriceMultiLpARMStorage.svg \
+sol2uml ../src/contracts -v -hv -hf -he -hs -hl -hi -b LidoARM -o LidoARMHierarchy.svg
+sol2uml ../src/contracts -s -d 0 -b LidoARM -o LidoARMSquashed.svg
+sol2uml ../src/contracts -hp -s -d 0 -b LidoARM -o LidoARMPublicSquashed.svg
+sol2uml storage ../src/contracts,../lib -c LidoARM -o LidoARMStorage.svg \
-sn eip1967.proxy.implementation,eip1967.proxy.admin \
-st address,address \
--hideExpand gap,_gap
diff --git a/script/deploy/mainnet/003_UpgradeLidoARMScript.sol b/script/deploy/mainnet/003_UpgradeLidoARMScript.sol
index 62b3d51..9f8ae83 100644
--- a/script/deploy/mainnet/003_UpgradeLidoARMScript.sol
+++ b/script/deploy/mainnet/003_UpgradeLidoARMScript.sol
@@ -6,7 +6,7 @@ import "forge-std/console.sol";
import {Vm} from "forge-std/Vm.sol";
import {IERC20, IWETH, LegacyAMM} from "contracts/Interfaces.sol";
-import {LidoFixedPriceMultiLpARM} from "contracts/LidoFixedPriceMultiLpARM.sol";
+import {LidoARM} from "contracts/LidoARM.sol";
import {LiquidityProviderController} from "contracts/LiquidityProviderController.sol";
import {Proxy} from "contracts/Proxy.sol";
import {Mainnet} from "contracts/utils/Addresses.sol";
@@ -23,7 +23,7 @@ contract UpgradeLidoARMMainnetScript is AbstractDeployScript {
Proxy lidoARMProxy;
Proxy lpcProxy;
- LidoFixedPriceMultiLpARM lidoARMImpl;
+ LidoARM lidoARMImpl;
function _execute() internal override {
console.log("Deploy:", DEPLOY_NAME);
@@ -53,7 +53,7 @@ contract UpgradeLidoARMMainnetScript is AbstractDeployScript {
liquidityProviderController.setLiquidityProviderCaps(liquidityProviders, 10 ether);
// 6. Deploy Lido implementation
- lidoARMImpl = new LidoFixedPriceMultiLpARM(Mainnet.STETH, Mainnet.WETH, Mainnet.LIDO_WITHDRAWAL);
+ lidoARMImpl = new LidoARM(Mainnet.STETH, Mainnet.WETH, Mainnet.LIDO_WITHDRAWAL);
_recordDeploy("LIDO_ARM_IMPL", address(lidoARMImpl));
// 7. Transfer ownership of LiquidityProviderController to the mainnet 5/8 multisig
@@ -113,7 +113,7 @@ contract UpgradeLidoARMMainnetScript is AbstractDeployScript {
lidoARMProxy.upgradeToAndCall(address(lidoARMImpl), data);
// Set the buy price with a 8 basis point discount. The sell price is 1.0
- LidoFixedPriceMultiLpARM(payable(Mainnet.LIDO_ARM)).setPrices(9994e32, 1e36);
+ LidoARM(payable(Mainnet.LIDO_ARM)).setPrices(9994e32, 1e36);
// transfer ownership of the Lido ARM proxy to the mainnet 5/8 multisig
lidoARMProxy.setOwner(Mainnet.GOV_MULTISIG);
diff --git a/src/contracts/AbstractARM.sol b/src/contracts/AbstractARM.sol
index 8132261..74d8c85 100644
--- a/src/contracts/AbstractARM.sol
+++ b/src/contracts/AbstractARM.sol
@@ -1,10 +1,38 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
+import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
+import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
+
import {OwnableOperable} from "./OwnableOperable.sol";
-import {IERC20} from "./Interfaces.sol";
+import {IERC20, ILiquidityProviderController} from "./Interfaces.sol";
+
+abstract contract AbstractARM is OwnableOperable, ERC20Upgradeable {
+ ////////////////////////////////////////////////////
+ /// Constants
+ ////////////////////////////////////////////////////
+
+ /// @notice Maximum amount the Operator can set the price from 1 scaled to 36 decimals.
+ /// 1e33 is a 0.1% deviation, or 10 basis points.
+ uint256 public constant MAX_PRICE_DEVIATION = 1e33;
+ /// @notice Scale of the prices.
+ uint256 public constant PRICE_SCALE = 1e36;
+ /// @notice The delay before a withdrawal request can be claimed in seconds
+ uint256 public constant CLAIM_DELAY = 10 minutes;
+ /// @dev The amount of shares that are minted to a dead address on initalization
+ uint256 internal constant MIN_TOTAL_SUPPLY = 1e12;
+ /// @dev The address with no known private key that the initial shares are minted to
+ address internal constant DEAD_ACCOUNT = 0x000000000000000000000000000000000000dEaD;
+ /// @notice The scale of the performance fee
+ /// 10,000 = 100% performance fee
+ uint256 public constant FEE_SCALE = 10000;
-abstract contract AbstractARM is OwnableOperable {
+ ////////////////////////////////////////////////////
+ /// Immutable Variables
+ ////////////////////////////////////////////////////
+
+ /// @notice The address of the asset that is used to add and remove liquidity. eg WETH
+ address internal immutable liquidityAsset;
/// @notice The swap input token that is transferred to this contract.
/// From a User perspective, this is the token being sold.
/// token0 is also compatible with the Uniswap V2 Router interface.
@@ -14,9 +42,85 @@ abstract contract AbstractARM is OwnableOperable {
/// token1 is also compatible with the Uniswap V2 Router interface.
IERC20 public immutable token1;
- uint256[50] private _gap;
+ ////////////////////////////////////////////////////
+ /// Storage Variables
+ ////////////////////////////////////////////////////
+
+ /**
+ * @notice For one `token0` from a Trader, how many `token1` does the pool send.
+ * For example, if `token0` is WETH and `token1` is stETH then
+ * `traderate0` is the WETH/stETH price.
+ * From a Trader's perspective, this is the stETH/WETH buy price.
+ * Rate is to 36 decimals (1e36).
+ */
+ uint256 public traderate0;
+ /**
+ * @notice For one `token1` from a Trader, how many `token0` does the pool send.
+ * For example, if `token0` is WETH and `token1` is stETH then
+ * `traderate1` is the stETH/WETH price.
+ * From a Trader's perspective, this is the stETH/WETH sell price.
+ * Rate is to 36 decimals (1e36).
+ */
+ uint256 public traderate1;
+
+ /// @notice cumulative total of all withdrawal requests included the ones that have already been claimed
+ uint128 public withdrawsQueued;
+ /// @notice total of all the withdrawal requests that have been claimed
+ uint128 public withdrawsClaimed;
+ /// @notice cumulative total of all the withdrawal requests that can be claimed including the ones already claimed
+ uint128 public withdrawsClaimable;
+ /// @notice index of the next withdrawal request starting at 0
+ uint128 public nextWithdrawalIndex;
+
+ struct WithdrawalRequest {
+ address withdrawer;
+ bool claimed;
+ // When the withdrawal can be claimed
+ uint40 claimTimestamp;
+ // Amount of assets to withdraw
+ uint128 assets;
+ // cumulative total of all withdrawal requests including this one.
+ // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.
+ uint128 queued;
+ }
+
+ /// @notice Mapping of withdrawal request indices to the user withdrawal request data
+ mapping(uint256 requestId => WithdrawalRequest) public withdrawalRequests;
+
+ /// @notice The account that can collect the performance fee
+ address public feeCollector;
+ /// @notice Performance fee that is collected by the feeCollector measured in basis points (1/100th of a percent)
+ /// 10,000 = 100% performance fee
+ /// 2,000 = 20% performance fee
+ /// 500 = 5% performance fee
+ uint16 public fee;
+ /// @notice The performance fees accrued but not collected.
+ /// This is removed from the total assets.
+ uint112 public feesAccrued;
+ /// @notice The total assets at the last time performance fees were calculated.
+ /// This can only go up so is a high watermark.
+ uint128 public lastTotalAssets;
+
+ address public liquidityProviderController;
+
+ uint256[42] private _gap;
+
+ ////////////////////////////////////////////////////
+ /// Events
+ ////////////////////////////////////////////////////
+
+ event TraderateChanged(uint256 traderate0, uint256 traderate1);
+ event RedeemRequested(
+ address indexed withdrawer, uint256 indexed requestId, uint256 assets, uint256 queued, uint256 claimTimestamp
+ );
+ event RedeemClaimed(address indexed withdrawer, uint256 indexed requestId, uint256 assets);
+ event FeeCalculated(uint256 newFeesAccrued, uint256 assetIncrease);
+ event FeeCollected(address indexed feeCollector, uint256 fee);
+ event FeeUpdated(uint256 fee);
+ event FeeCollectorUpdated(address indexed newFeeCollector);
+ event LiquidityProviderControllerUpdated(address indexed liquidityProviderController);
- constructor(address _inputToken, address _outputToken1) {
+ constructor(address _inputToken, address _outputToken1, address _liquidityAsset) {
require(IERC20(_inputToken).decimals() == 18);
require(IERC20(_outputToken1).decimals() == 18);
@@ -24,8 +128,54 @@ abstract contract AbstractARM is OwnableOperable {
token1 = IERC20(_outputToken1);
_setOwner(address(0)); // Revoke owner for implementation contract at deployment
+
+ require(_liquidityAsset == address(token0) || _liquidityAsset == address(token1), "invalid liquidity asset");
+ liquidityAsset = _liquidityAsset;
}
+ /// @notice Initialize the contract.
+ /// The deployer that calls initialize has to approve the this ARM's proxy contract to transfer 1e12 WETH.
+ /// @param _operator The address of the account that can request and claim Lido withdrawals.
+ /// @param _name The name of the liquidity provider (LP) token.
+ /// @param _symbol The symbol of the liquidity provider (LP) token.
+ /// @param _fee The performance fee that is collected by the feeCollector measured in basis points (1/100th of a percent).
+ /// 10,000 = 100% performance fee
+ /// 500 = 5% performance fee
+ /// @param _feeCollector The account that can collect the performance fee
+ /// @param _liquidityProviderController The address of the Liquidity Provider Controller
+ function _initARM(
+ address _operator,
+ string calldata _name,
+ string calldata _symbol,
+ uint256 _fee,
+ address _feeCollector,
+ address _liquidityProviderController
+ ) internal {
+ _initOwnableOperable(_operator);
+
+ __ERC20_init(_name, _symbol);
+
+ // Transfer a small bit of liquidity from the intializer to this contract
+ IERC20(liquidityAsset).transferFrom(msg.sender, address(this), MIN_TOTAL_SUPPLY);
+
+ // mint a small amount of shares to a dead account so the total supply can never be zero
+ // This avoids donation attacks when there are no assets in the ARM contract
+ _mint(DEAD_ACCOUNT, MIN_TOTAL_SUPPLY);
+
+ // Initialize the last total assets to the current total assets
+ // This ensures no performance fee is accrued when the performance fee is calculated when the fee is set
+ lastTotalAssets = SafeCast.toUint128(_rawTotalAssets());
+ _setFee(_fee);
+ _setFeeCollector(_feeCollector);
+
+ liquidityProviderController = _liquidityProviderController;
+ emit LiquidityProviderControllerUpdated(_liquidityProviderController);
+ }
+
+ ////////////////////////////////////////////////////
+ /// Swap Functions
+ ////////////////////////////////////////////////////
+
/**
* @notice Swaps an exact amount of input tokens for as many output tokens as possible.
* msg.sender should have already given the ARM contract an allowance of
@@ -141,27 +291,396 @@ abstract contract AbstractARM is OwnableOperable {
amounts[1] = amountOut;
}
+ function _inDeadline(uint256 deadline) internal view {
+ require(deadline >= block.timestamp, "ARM: Deadline expired");
+ }
+
+ /// @dev Ensure any liquidity assets reserved for the withdrawal queue are not used
+ /// in swaps that send liquidity assets out of the ARM
+ function _transferAsset(address asset, address to, uint256 amount) internal virtual {
+ if (asset == liquidityAsset) {
+ require(amount <= _liquidityAvailable(), "ARM: Insufficient liquidity");
+ }
+
+ IERC20(asset).transfer(to, amount);
+ }
+
+ /// @dev Hook to transfer assets into the ARM contract
+ function _transferAssetFrom(address asset, address from, address to, uint256 amount) internal virtual {
+ IERC20(asset).transferFrom(from, to, amount);
+ }
+
function _swapExactTokensForTokens(IERC20 inToken, IERC20 outToken, uint256 amountIn, address to)
internal
virtual
- returns (uint256 amountOut);
+ returns (uint256 amountOut)
+ {
+ uint256 price;
+ if (inToken == token0) {
+ require(outToken == token1, "ARM: Invalid out token");
+ price = traderate0;
+ } else if (inToken == token1) {
+ require(outToken == token0, "ARM: Invalid out token");
+ price = traderate1;
+ } else {
+ revert("ARM: Invalid in token");
+ }
+ amountOut = amountIn * price / PRICE_SCALE;
+
+ // Transfer the input tokens from the caller to this ARM contract
+ _transferAssetFrom(address(inToken), msg.sender, address(this), amountIn);
+
+ // Transfer the output tokens to the recipient
+ _transferAsset(address(outToken), to, amountOut);
+ }
function _swapTokensForExactTokens(IERC20 inToken, IERC20 outToken, uint256 amountOut, address to)
internal
virtual
- returns (uint256 amountIn);
+ returns (uint256 amountIn)
+ {
+ uint256 price;
+ if (inToken == token0) {
+ require(outToken == token1, "ARM: Invalid out token");
+ price = traderate0;
+ } else if (inToken == token1) {
+ require(outToken == token0, "ARM: Invalid out token");
+ price = traderate1;
+ } else {
+ revert("ARM: Invalid in token");
+ }
+ amountIn = ((amountOut * PRICE_SCALE) / price) + 1; // +1 to always round in our favor
- function _inDeadline(uint256 deadline) internal view {
- require(deadline >= block.timestamp, "ARM: Deadline expired");
+ // Transfer the input tokens from the caller to this ARM contract
+ _transferAssetFrom(address(inToken), msg.sender, address(this), amountIn);
+
+ // Transfer the output tokens to the recipient
+ _transferAsset(address(outToken), to, amountOut);
}
- /// @dev Hook to transfer assets out of the ARM contract
- function _transferAsset(address asset, address to, uint256 amount) internal virtual {
- IERC20(asset).transfer(to, amount);
+ /**
+ * @notice Set exchange rates from an operator account from the ARM's perspective.
+ * If token 0 is WETH and token 1 is stETH, then both prices will be set using the stETH/WETH price.
+ * @param buyT1 The price the ARM buys Token 1 from the Trader, denominated in Token 0, scaled to 36 decimals.
+ * From the Trader's perspective, this is the sell price.
+ * @param sellT1 The price the ARM sells Token 1 to the Trader, denominated in Token 0, scaled to 36 decimals.
+ * From the Trader's perspective, this is the buy price.
+ */
+ function setPrices(uint256 buyT1, uint256 sellT1) external onlyOperatorOrOwner {
+ // Limit funds and loss when called by the Operator
+ if (msg.sender == operator) {
+ require(sellT1 >= PRICE_SCALE - MAX_PRICE_DEVIATION, "ARM: sell price too low");
+ require(buyT1 <= PRICE_SCALE + MAX_PRICE_DEVIATION, "ARM: buy price too high");
+ }
+ uint256 _traderate0 = 1e72 / sellT1; // base (t0) -> token (t1)
+ uint256 _traderate1 = buyT1; // token (t1) -> base (t0)
+ _setTraderates(_traderate0, _traderate1);
}
- /// @dev Hook to transfer assets into the ARM contract
- function _transferAssetFrom(address asset, address from, address to, uint256 amount) internal virtual {
- IERC20(asset).transferFrom(from, to, amount);
+ function _setTraderates(uint256 _traderate0, uint256 _traderate1) internal {
+ require((1e72 / (_traderate0)) > _traderate1, "ARM: Price cross");
+ traderate0 = _traderate0;
+ traderate1 = _traderate1;
+
+ emit TraderateChanged(_traderate0, _traderate1);
+ }
+
+ ////////////////////////////////////////////////////
+ /// Liquidity Provider Functions
+ ////////////////////////////////////////////////////
+
+ /// @notice Preview the amount of shares that would be minted for a given amount of assets
+ /// @param assets The amount of liquidity assets to deposit
+ /// @return shares The amount of shares that would be minted
+ function previewDeposit(uint256 assets) external view returns (uint256 shares) {
+ shares = convertToShares(assets);
+ }
+
+ /// @notice deposit liquidity assets in exchange for liquidity provider (LP) shares.
+ /// The caller needs to have approved the contract to transfer the assets.
+ /// @param assets The amount of liquidity assets to deposit
+ /// @return shares The amount of shares that were minted
+ function deposit(uint256 assets) external returns (uint256 shares) {
+ // Accrue any performance fees based on the increase in total assets before
+ // the liquidity asset from the deposit is transferred into the ARM
+ _accruePerformanceFee();
+
+ // Calculate the amount of shares to mint after the performance fees have been accrued
+ // which reduces the total assets and before new assets are deposited.
+ shares = convertToShares(assets);
+
+ // Transfer the liquidity asset from the sender to this contract
+ IERC20(liquidityAsset).transferFrom(msg.sender, address(this), assets);
+
+ // mint shares
+ _mint(msg.sender, shares);
+
+ // Save the new total assets after the performance fee accrued and new assets deposited
+ lastTotalAssets = SafeCast.toUint128(_rawTotalAssets());
+
+ // Check the liquidity provider caps after the new assets have been deposited
+ if (liquidityProviderController != address(0)) {
+ ILiquidityProviderController(liquidityProviderController).postDepositHook(msg.sender, assets);
+ }
+ }
+
+ /// @notice Preview the amount of assets that would be received for burning a given amount of shares
+ /// @param shares The amount of shares to burn
+ /// @return assets The amount of liquidity assets that would be received
+ function previewRedeem(uint256 shares) external view returns (uint256 assets) {
+ assets = convertToAssets(shares);
+ }
+
+ /// @notice Request to redeem liquidity provider shares for liquidity assets
+ /// @param shares The amount of shares the redeemer wants to burn for liquidity assets
+ /// @return requestId The index of the withdrawal request
+ /// @return assets The amount of liquidity assets that will be claimable by the redeemer
+ function requestRedeem(uint256 shares) external returns (uint256 requestId, uint256 assets) {
+ // Accrue any performance fees based on the increase in total assets before
+ // the liquidity asset from the redeem is reserved for the ARM withdrawal queue
+ _accruePerformanceFee();
+
+ // Calculate the amount of assets to transfer to the redeemer
+ assets = convertToAssets(shares);
+
+ requestId = nextWithdrawalIndex;
+ uint128 queued = SafeCast.toUint128(withdrawsQueued + assets);
+ uint40 claimTimestamp = uint40(block.timestamp + CLAIM_DELAY);
+
+ // Store the next withdrawal request
+ nextWithdrawalIndex = SafeCast.toUint128(requestId + 1);
+ // Store the updated queued amount which reserves WETH in the withdrawal queue
+ withdrawsQueued = queued;
+ // Store requests
+ withdrawalRequests[requestId] = WithdrawalRequest({
+ withdrawer: msg.sender,
+ claimed: false,
+ claimTimestamp: claimTimestamp,
+ assets: SafeCast.toUint128(assets),
+ queued: queued
+ });
+
+ // burn redeemer's shares
+ _burn(msg.sender, shares);
+
+ // Save the new total assets after performance fee accrued and withdrawal queue updated
+ lastTotalAssets = SafeCast.toUint128(_rawTotalAssets());
+
+ emit RedeemRequested(msg.sender, requestId, assets, queued, claimTimestamp);
+ }
+
+ /// @notice Claim liquidity assets from a previous withdrawal request after the claim delay has passed
+ /// @param requestId The index of the withdrawal request
+ /// @return assets The amount of liquidity assets that were transferred to the redeemer
+ function claimRedeem(uint256 requestId) external returns (uint256 assets) {
+ // Update the ARM's withdrawal queue's claimable amount
+ _updateWithdrawalQueueLiquidity();
+
+ // Load the structs from storage into memory
+ WithdrawalRequest memory request = withdrawalRequests[requestId];
+
+ require(request.claimTimestamp <= block.timestamp, "Claim delay not met");
+ // If there isn't enough reserved liquidity in the queue to claim
+ require(request.queued <= withdrawsClaimable, "Queue pending liquidity");
+ require(request.withdrawer == msg.sender, "Not requester");
+ require(request.claimed == false, "Already claimed");
+
+ // Store the request as claimed
+ withdrawalRequests[requestId].claimed = true;
+ // Store the updated claimed amount
+ withdrawsClaimed += request.assets;
+
+ assets = request.assets;
+
+ emit RedeemClaimed(msg.sender, requestId, assets);
+
+ // transfer the liquidity asset to the withdrawer
+ IERC20(liquidityAsset).transfer(msg.sender, assets);
+ }
+
+ /// @dev Updates the claimable amount in the ARM's withdrawal queue.
+ /// That's the amount that is used to check if a request can be claimed or not.
+ function _updateWithdrawalQueueLiquidity() internal {
+ // Load the claimable amount from storage into memory
+ uint256 withdrawsClaimableMem = withdrawsClaimable;
+
+ // Check if the claimable amount is less than the queued amount
+ uint256 queueShortfall = withdrawsQueued - withdrawsClaimableMem;
+
+ // No need to do anything is the withdrawal queue is fully funded
+ if (queueShortfall == 0) {
+ return;
+ }
+
+ uint256 liquidityBalance = IERC20(liquidityAsset).balanceOf(address(this));
+
+ // Of the claimable withdrawal requests, how much is unclaimed?
+ // That is, the amount of the liquidity assets that is currently allocated for the withdrawal queue
+ uint256 allocatedLiquidity = withdrawsClaimableMem - withdrawsClaimed;
+
+ // If there is no unallocated liquidity assets then there is nothing to add to the queue
+ if (liquidityBalance <= allocatedLiquidity) {
+ return;
+ }
+
+ uint256 unallocatedLiquidity = liquidityBalance - allocatedLiquidity;
+
+ // the new claimable amount is the smaller of the queue shortfall or unallocated weth
+ uint256 addedClaimable = queueShortfall < unallocatedLiquidity ? queueShortfall : unallocatedLiquidity;
+
+ // Store the new claimable amount back to storage
+ withdrawsClaimable = SafeCast.toUint128(withdrawsClaimableMem + addedClaimable);
+ }
+
+ /// @dev Calculate how much of the liquidity asset in the ARM is not reserved for the withdrawal queue.
+ // That is, it is available to be swapped.
+ function _liquidityAvailable() internal view returns (uint256) {
+ // The amount of WETH that is still to be claimed in the withdrawal queue
+ uint256 outstandingWithdrawals = withdrawsQueued - withdrawsClaimed;
+
+ // The amount of the liquidity asset is in the ARM
+ uint256 liquidityBalance = IERC20(liquidityAsset).balanceOf(address(this));
+
+ // If there is not enough liquidity assets in the ARM to cover the outstanding withdrawals
+ if (liquidityBalance <= outstandingWithdrawals) {
+ return 0;
+ }
+
+ return liquidityBalance - outstandingWithdrawals;
+ }
+
+ /// @notice The total amount of assets in the ARM and external withdrawal queue,
+ /// less the liquidity assets reserved for the ARM's withdrawal queue and accrued fees.
+ function totalAssets() public view virtual returns (uint256) {
+ uint256 totalAssetsBeforeFees = _rawTotalAssets();
+
+ // If the total assets have decreased, then we don't charge a performance fee
+ if (totalAssetsBeforeFees <= lastTotalAssets) return totalAssetsBeforeFees;
+
+ // Calculate the increase in assets since the last time fees were calculated
+ uint256 assetIncrease = totalAssetsBeforeFees - lastTotalAssets;
+
+ // Calculate the performance fee and remove from the total assets before new fees are removed
+ return totalAssetsBeforeFees - ((assetIncrease * fee) / FEE_SCALE);
+ }
+
+ /// @dev Calculate the total assets in the ARM, external withdrawal queue,
+ /// less liquidity assets reserved for the ARM's withdrawal queue and past accrued fees.
+ /// The accrued fees are from the last time fees were calculated.
+ function _rawTotalAssets() internal view returns (uint256) {
+ // Get the assets in the ARM and external withdrawal queue
+ uint256 assets = token0.balanceOf(address(this)) + token1.balanceOf(address(this)) + _externalWithdrawQueue();
+
+ // Load the queue metadata from storage into memory
+ uint256 queuedMem = withdrawsQueued;
+ uint256 claimedMem = withdrawsClaimed;
+
+ // If the ARM becomes insolvent enough that the total value in the ARM and external withdrawal queue
+ // is less than the outstanding withdrawals.
+ if (assets + claimedMem < queuedMem) {
+ return 0;
+ }
+
+ // Need to remove the liquidity assets that have been reserved for the withdrawal queue
+ // and any accrued fees
+ return assets + claimedMem - queuedMem - feesAccrued;
+ }
+
+ /// @dev Hook for calculating the amount of assets in an external withdrawal queue like Lido or OETH
+ /// This is not the ARM's withdrawal queue
+ function _externalWithdrawQueue() internal view virtual returns (uint256 assets);
+
+ /// @notice Calculates the amount of shares for a given amount of liquidity assets
+ function convertToShares(uint256 assets) public view returns (uint256 shares) {
+ uint256 totalAssetsMem = totalAssets();
+ shares = (totalAssetsMem == 0) ? assets : (assets * totalSupply()) / totalAssetsMem;
+ }
+
+ /// @notice Calculates the amount of liquidity assets for a given amount of shares
+ function convertToAssets(uint256 shares) public view returns (uint256 assets) {
+ assets = (shares * totalAssets()) / totalSupply();
+ }
+
+ /// @notice Set the Liquidity Provider Controller contract address.
+ /// Set to a zero address to disable the controller.
+ function setLiquidityProviderController(address _liquidityProviderController) external onlyOwner {
+ liquidityProviderController = _liquidityProviderController;
+
+ emit LiquidityProviderControllerUpdated(_liquidityProviderController);
+ }
+
+ ////////////////////////////////////////////////////
+ /// Performance Fee Functions
+ ////////////////////////////////////////////////////
+
+ /// @dev Accrues the performance fee based on the increase in total assets
+ /// Needs to be called before any action that changes the liquidity provider shares. eg deposit and redeem
+ function _accruePerformanceFee() internal {
+ uint256 newTotalAssets = _rawTotalAssets();
+
+ // Do not accrued a performance fee if the total assets has decreased
+ if (newTotalAssets <= lastTotalAssets) return;
+
+ uint256 assetIncrease = newTotalAssets - lastTotalAssets;
+ uint256 newFeesAccrued = (assetIncrease * fee) / FEE_SCALE;
+
+ // Save the new accrued fees back to storage
+ feesAccrued = SafeCast.toUint112(feesAccrued + newFeesAccrued);
+ // Save the new total assets back to storage less the new accrued fees.
+ // This is be updated again in the post deposit and post withdraw hooks to include
+ // the assets deposited or withdrawn
+ lastTotalAssets = SafeCast.toUint128(newTotalAssets - newFeesAccrued);
+
+ emit FeeCalculated(newFeesAccrued, assetIncrease);
+ }
+
+ /// @notice Owner sets the performance fee on increased assets
+ /// @param _fee The performance fee measured in basis points (1/100th of a percent)
+ /// 10,000 = 100% performance fee
+ /// 500 = 5% performance fee
+ function setFee(uint256 _fee) external onlyOwner {
+ _setFee(_fee);
+ }
+
+ /// @notice Owner sets the account/contract that receives the performance fee
+ function setFeeCollector(address _feeCollector) external onlyOwner {
+ _setFeeCollector(_feeCollector);
+ }
+
+ function _setFee(uint256 _fee) internal {
+ require(_fee <= FEE_SCALE, "ARM: fee too high");
+
+ // Accrued any performance fees up to this point using the old fee
+ _accruePerformanceFee();
+
+ fee = SafeCast.toUint16(_fee);
+
+ emit FeeUpdated(_fee);
+ }
+
+ function _setFeeCollector(address _feeCollector) internal {
+ require(_feeCollector != address(0), "ARM: invalid fee collector");
+
+ feeCollector = _feeCollector;
+
+ emit FeeCollectorUpdated(_feeCollector);
+ }
+
+ /// @notice Transfer accrued performance fees to the fee collector
+ /// This requires enough liquidity assets in the ARM to cover the accrued fees.
+ function collectFees() external returns (uint256 fees) {
+ // Accrue any performance fees up to this point
+ _accruePerformanceFee();
+
+ // Read the updated accrued fees from storage
+ fees = feesAccrued;
+ require(fees <= IERC20(liquidityAsset).balanceOf(address(this)), "ARM: insufficient liquidity");
+
+ // Reset the accrued fees in storage
+ feesAccrued = 0;
+
+ IERC20(liquidityAsset).transfer(feeCollector, fees);
+
+ emit FeeCollected(feeCollector, fees);
}
}
diff --git a/src/contracts/FixedPriceARM.sol b/src/contracts/FixedPriceARM.sol
deleted file mode 100644
index c6587aa..0000000
--- a/src/contracts/FixedPriceARM.sol
+++ /dev/null
@@ -1,113 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.23;
-
-import {AbstractARM} from "./AbstractARM.sol";
-import {IERC20} from "./Interfaces.sol";
-
-/**
- * @title Abstract support to an ARM with a single buy and sell price.
- * @author Origin Protocol Inc
- */
-abstract contract FixedPriceARM is AbstractARM {
- /**
- * @notice For one `token0` from a Trader, how many `token1` does the pool send.
- * For example, if `token0` is WETH and `token1` is stETH then
- * `traderate0` is the WETH/stETH price.
- * From a Trader's perspective, this is the stETH/WETH buy price.
- * Rate is to 36 decimals (1e36).
- */
- uint256 public traderate0;
- /**
- * @notice For one `token1` from a Trader, how many `token0` does the pool send.
- * For example, if `token0` is WETH and `token1` is stETH then
- * `traderate1` is the stETH/WETH price.
- * From a Trader's perspective, this is the stETH/WETH sell price.
- * Rate is to 36 decimals (1e36).
- */
- uint256 public traderate1;
-
- /// @notice Maximum amount the Operator can set the price from 1 scaled to 36 decimals.
- /// 1e33 is a 0.1% deviation, or 10 basis points.
- uint256 public constant MAX_PRICE_DEVIATION = 1e33;
- /// @notice Scale of the prices.
- uint256 public constant PRICE_SCALE = 1e36;
-
- uint256[48] private _gap;
-
- event TraderateChanged(uint256 traderate0, uint256 traderate1);
-
- function _swapExactTokensForTokens(IERC20 inToken, IERC20 outToken, uint256 amountIn, address to)
- internal
- override
- returns (uint256 amountOut)
- {
- uint256 price;
- if (inToken == token0) {
- require(outToken == token1, "ARM: Invalid out token");
- price = traderate0;
- } else if (inToken == token1) {
- require(outToken == token0, "ARM: Invalid out token");
- price = traderate1;
- } else {
- revert("ARM: Invalid in token");
- }
- amountOut = amountIn * price / PRICE_SCALE;
-
- // Transfer the input tokens from the caller to this ARM contract
- _transferAssetFrom(address(inToken), msg.sender, address(this), amountIn);
-
- // Transfer the output tokens to the recipient
- _transferAsset(address(outToken), to, amountOut);
- }
-
- function _swapTokensForExactTokens(IERC20 inToken, IERC20 outToken, uint256 amountOut, address to)
- internal
- override
- returns (uint256 amountIn)
- {
- uint256 price;
- if (inToken == token0) {
- require(outToken == token1, "ARM: Invalid out token");
- price = traderate0;
- } else if (inToken == token1) {
- require(outToken == token0, "ARM: Invalid out token");
- price = traderate1;
- } else {
- revert("ARM: Invalid in token");
- }
- amountIn = ((amountOut * PRICE_SCALE) / price) + 1; // +1 to always round in our favor
-
- // Transfer the input tokens from the caller to this ARM contract
- _transferAssetFrom(address(inToken), msg.sender, address(this), amountIn);
-
- // Transfer the output tokens to the recipient
- _transferAsset(address(outToken), to, amountOut);
- }
-
- /**
- * @notice Set exchange rates from an operator account from the ARM's perspective.
- * If token 0 is WETH and token 1 is stETH, then both prices will be set using the stETH/WETH price.
- * @param buyT1 The price the ARM buys Token 1 from the Trader, denominated in Token 0, scaled to 36 decimals.
- * From the Trader's perspective, this is the sell price.
- * @param sellT1 The price the ARM sells Token 1 to the Trader, denominated in Token 0, scaled to 36 decimals.
- * From the Trader's perspective, this is the buy price.
- */
- function setPrices(uint256 buyT1, uint256 sellT1) external onlyOperatorOrOwner {
- // Limit funds and loss when called by the Operator
- if (msg.sender == operator) {
- require(sellT1 >= PRICE_SCALE - MAX_PRICE_DEVIATION, "ARM: sell price too low");
- require(buyT1 <= PRICE_SCALE + MAX_PRICE_DEVIATION, "ARM: buy price too high");
- }
- uint256 _traderate0 = 1e72 / sellT1; // base (t0) -> token (t1)
- uint256 _traderate1 = buyT1; // token (t1) -> base (t0)
- _setTraderates(_traderate0, _traderate1);
- }
-
- function _setTraderates(uint256 _traderate0, uint256 _traderate1) internal {
- require((1e72 / (_traderate0)) > _traderate1, "ARM: Price cross");
- traderate0 = _traderate0;
- traderate1 = _traderate1;
-
- emit TraderateChanged(_traderate0, _traderate1);
- }
-}
diff --git a/src/contracts/LidoFixedPriceMultiLpARM.sol b/src/contracts/LidoARM.sol
similarity index 56%
rename from src/contracts/LidoFixedPriceMultiLpARM.sol
rename to src/contracts/LidoARM.sol
index 5b2a1a8..b2aeed5 100644
--- a/src/contracts/LidoFixedPriceMultiLpARM.sol
+++ b/src/contracts/LidoARM.sol
@@ -5,11 +5,7 @@ import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Ini
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {AbstractARM} from "./AbstractARM.sol";
-import {LiquidityProviderControllerARM} from "./LiquidityProviderControllerARM.sol";
-import {FixedPriceARM} from "./FixedPriceARM.sol";
import {LidoLiquidityManager} from "./LidoLiquidityManager.sol";
-import {MultiLP} from "./MultiLP.sol";
-import {PerformanceFee} from "./PerformanceFee.sol";
/**
* @title Lido (stETH) Application Redemption Manager (ARM)
@@ -19,32 +15,23 @@ import {PerformanceFee} from "./PerformanceFee.sol";
* A performance fee is also collected on increases in the ARM's total assets.
* @author Origin Protocol Inc
*/
-contract LidoFixedPriceMultiLpARM is
- Initializable,
- MultiLP,
- PerformanceFee,
- LiquidityProviderControllerARM,
- FixedPriceARM,
- LidoLiquidityManager
-{
+contract LidoARM is Initializable, AbstractARM, LidoLiquidityManager {
/// @param _steth The address of the stETH token
/// @param _weth The address of the WETH token
/// @param _lidoWithdrawalQueue The address of the Lido's withdrawal queue contract
constructor(address _steth, address _weth, address _lidoWithdrawalQueue)
- AbstractARM(_steth, _weth)
- MultiLP(_weth)
- FixedPriceARM()
+ AbstractARM(_steth, _weth, _weth)
LidoLiquidityManager(_steth, _weth, _lidoWithdrawalQueue)
{}
- /// @notice Initialize the contract.
+ /// @notice Initialize the storage variables stored in the proxy contract.
/// The deployer that calls initialize has to approve the this ARM's proxy contract to transfer 1e12 WETH.
/// @param _name The name of the liquidity provider (LP) token.
/// @param _symbol The symbol of the liquidity provider (LP) token.
/// @param _operator The address of the account that can request and claim Lido withdrawals.
/// @param _fee The performance fee that is collected by the feeCollector measured in basis points (1/100th of a percent).
/// 10,000 = 100% performance fee
- /// 500 = 5% performance fee
+ /// 1,500 = 15% performance fee
/// @param _feeCollector The account that can collect the performance fee
/// @param _liquidityProviderController The address of the Liquidity Provider Controller
function initialize(
@@ -55,10 +42,8 @@ contract LidoFixedPriceMultiLpARM is
address _feeCollector,
address _liquidityProviderController
) external initializer {
- _initOwnableOperable(_operator);
- _initMultiLP(_name, _symbol);
- _initPerformanceFee(_fee, _feeCollector);
- _initLPControllerARM(_liquidityProviderController);
+ _initARM(_operator, _name, _symbol, _fee, _feeCollector, _liquidityProviderController);
+ _initLidoLiquidityManager();
}
/**
@@ -67,47 +52,17 @@ contract LidoFixedPriceMultiLpARM is
*
* The MultiLP implementation ensures any WETH reserved for the withdrawal queue is not used in swaps from stETH to WETH.
*/
- function _transferAsset(address asset, address to, uint256 amount) internal override(AbstractARM, MultiLP) {
+ function _transferAsset(address asset, address to, uint256 amount) internal override {
// Add 2 wei if transferring stETH
uint256 transferAmount = asset == address(token0) ? amount + 2 : amount;
- MultiLP._transferAsset(asset, to, transferAmount);
+ super._transferAsset(asset, to, transferAmount);
}
/**
* @dev Calculates the amount of stETH in the Lido Withdrawal Queue.
*/
- function _externalWithdrawQueue() internal view override(MultiLP, LidoLiquidityManager) returns (uint256) {
+ function _externalWithdrawQueue() internal view override(AbstractARM, LidoLiquidityManager) returns (uint256) {
return LidoLiquidityManager._externalWithdrawQueue();
}
-
- /**
- * @dev Is called after assets are transferred to the ARM in the `deposit` method.
- */
- function _postDepositHook(uint256 assets)
- internal
- override(MultiLP, LiquidityProviderControllerARM, PerformanceFee)
- {
- // Store the new total assets after the deposit and performance fee accrued
- PerformanceFee._postDepositHook(assets);
-
- // Check the LP can deposit the assets
- LiquidityProviderControllerARM._postDepositHook(assets);
- }
-
- /**
- * @dev Is called after the performance fee is accrued in the `requestRedeem` method.
- */
- function _postRequestRedeemHook() internal override(MultiLP, PerformanceFee) {
- // Store the new total assets after the withdrawal and performance fee accrued
- PerformanceFee._postRequestRedeemHook();
- }
-
- /**
- * @notice The total amount of assets in the ARM and Lido withdrawal queue,
- * less the WETH reserved for the ARM's withdrawal queue and accrued fees.
- */
- function totalAssets() public view override(MultiLP, PerformanceFee) returns (uint256) {
- return PerformanceFee.totalAssets();
- }
}
diff --git a/src/contracts/LidoLiquidityManager.sol b/src/contracts/LidoLiquidityManager.sol
index 311438b..5b27093 100644
--- a/src/contracts/LidoLiquidityManager.sol
+++ b/src/contracts/LidoLiquidityManager.sol
@@ -23,6 +23,13 @@ abstract contract LidoLiquidityManager is OwnableOperable {
withdrawalQueue = IStETHWithdrawal(_lidoWithdrawalQueue);
}
+ /**
+ * @dev Approve the stETH withdrawal contract. Used for redemption requests.
+ */
+ function _initLidoLiquidityManager() internal {
+ steth.approve(address(withdrawalQueue), type(uint256).max);
+ }
+
/**
* @notice Approve the stETH withdrawal contract. Used for redemption requests.
*/
diff --git a/src/contracts/LiquidityProviderControllerARM.sol b/src/contracts/LiquidityProviderControllerARM.sol
deleted file mode 100644
index 07aefa9..0000000
--- a/src/contracts/LiquidityProviderControllerARM.sol
+++ /dev/null
@@ -1,40 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.23;
-
-import {MultiLP} from "./MultiLP.sol";
-import {ILiquidityProviderController} from "./Interfaces.sol";
-
-/**
- * @title ARM integration to the Liquidity Provider Controller that whitelists liquidity providers
- * and enforces a total assets cap.
- * @author Origin Protocol Inc
- */
-abstract contract LiquidityProviderControllerARM is MultiLP {
- address public liquidityProviderController;
-
- uint256[49] private _gap;
-
- event LiquidityProviderControllerUpdated(address indexed liquidityProviderController);
-
- /// @dev called in the ARM's initialize function to set the Liquidity Provider Controller
- function _initLPControllerARM(address _liquidityProviderController) internal {
- liquidityProviderController = _liquidityProviderController;
-
- emit LiquidityProviderControllerUpdated(_liquidityProviderController);
- }
-
- /// @dev calls the liquidity provider controller if one is configured to check the liquidity provider and total assets caps
- function _postDepositHook(uint256 assets) internal virtual override {
- if (liquidityProviderController != address(0)) {
- ILiquidityProviderController(liquidityProviderController).postDepositHook(msg.sender, assets);
- }
- }
-
- /// @notice Set the Liquidity Provider Controller contract address.
- /// Set to a zero address to disable the controller.
- function setLiquidityProviderController(address _liquidityProviderController) external onlyOwner {
- liquidityProviderController = _liquidityProviderController;
-
- emit LiquidityProviderControllerUpdated(_liquidityProviderController);
- }
-}
diff --git a/src/contracts/MultiLP.sol b/src/contracts/MultiLP.sol
deleted file mode 100644
index 651927e..0000000
--- a/src/contracts/MultiLP.sol
+++ /dev/null
@@ -1,269 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.23;
-
-import {IERC20, ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
-import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
-
-import {AbstractARM} from "./AbstractARM.sol";
-
-/**
- * @title Abstract support to an ARM for multiple Liquidity Providers (LP)
- * @author Origin Protocol Inc
- */
-abstract contract MultiLP is AbstractARM, ERC20Upgradeable {
- /// @notice The delay before a withdrawal request can be claimed in seconds
- uint256 public constant CLAIM_DELAY = 10 minutes;
- /// @dev The amount of shares that are minted to a dead address on initalization
- uint256 internal constant MIN_TOTAL_SUPPLY = 1e12;
- /// @dev The address with no known private key that the initial shares are minted to
- address internal constant DEAD_ACCOUNT = 0x000000000000000000000000000000000000dEaD;
-
- /// @notice The address of the asset that is used to add and remove liquidity. eg WETH
- address internal immutable liquidityAsset;
-
- /// @notice cumulative total of all withdrawal requests included the ones that have already been claimed
- uint128 public withdrawsQueued;
- /// @notice total of all the withdrawal requests that have been claimed
- uint128 public withdrawsClaimed;
- /// @notice cumulative total of all the withdrawal requests that can be claimed including the ones already claimed
- uint128 public withdrawsClaimable;
- /// @notice index of the next withdrawal request starting at 0
- uint128 public nextWithdrawalIndex;
-
- struct WithdrawalRequest {
- address withdrawer;
- bool claimed;
- // When the withdrawal can be claimed
- uint40 claimTimestamp;
- // Amount of assets to withdraw
- uint128 assets;
- // cumulative total of all withdrawal requests including this one.
- // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.
- uint128 queued;
- }
-
- /// @notice Mapping of withdrawal request indices to the user withdrawal request data
- mapping(uint256 requestId => WithdrawalRequest) public withdrawalRequests;
-
- uint256[47] private _gap;
-
- event RedeemRequested(
- address indexed withdrawer, uint256 indexed requestId, uint256 assets, uint256 queued, uint256 claimTimestamp
- );
- event RedeemClaimed(address indexed withdrawer, uint256 indexed requestId, uint256 assets);
-
- constructor(address _liquidityAsset) {
- require(_liquidityAsset == address(token0) || _liquidityAsset == address(token1), "invalid liquidity asset");
- liquidityAsset = _liquidityAsset;
- }
-
- /// @dev called by the concrete contract's `initialize` function
- function _initMultiLP(string calldata _name, string calldata _symbol) internal {
- __ERC20_init(_name, _symbol);
-
- // Transfer a small bit of liquidity from the intializer to this contract
- IERC20(liquidityAsset).transferFrom(msg.sender, address(this), MIN_TOTAL_SUPPLY);
-
- // mint a small amount of shares to a dead account so the total supply can never be zero
- // This avoids donation attacks when there are no assets in the ARM contract
- _mint(DEAD_ACCOUNT, MIN_TOTAL_SUPPLY);
- }
-
- /// @notice Preview the amount of shares that would be minted for a given amount of assets
- /// @param assets The amount of liquidity assets to deposit
- /// @return shares The amount of shares that would be minted
- function previewDeposit(uint256 assets) external view returns (uint256 shares) {
- shares = convertToShares(assets);
- }
-
- /// @notice deposit liquidity assets in exchange for liquidity provider (LP) shares.
- /// The caller needs to have approved the contract to transfer the assets.
- /// @param assets The amount of liquidity assets to deposit
- /// @return shares The amount of shares that were minted
- function deposit(uint256 assets) external returns (uint256 shares) {
- _preDepositHook();
-
- shares = convertToShares(assets);
-
- // Transfer the liquidity asset from the sender to this contract
- IERC20(liquidityAsset).transferFrom(msg.sender, address(this), assets);
-
- // mint shares
- _mint(msg.sender, shares);
-
- _postDepositHook(assets);
- }
-
- function _preDepositHook() internal virtual;
- function _postDepositHook(uint256 assets) internal virtual;
-
- /// @notice Preview the amount of assets that would be received for burning a given amount of shares
- /// @param shares The amount of shares to burn
- /// @return assets The amount of liquidity assets that would be received
- function previewRedeem(uint256 shares) external view returns (uint256 assets) {
- assets = convertToAssets(shares);
- }
-
- /// @notice Request to redeem liquidity provider shares for liquidity assets
- /// @param shares The amount of shares the redeemer wants to burn for liquidity assets
- /// @return requestId The index of the withdrawal request
- /// @return assets The amount of liquidity assets that will be claimable by the redeemer
- function requestRedeem(uint256 shares) external returns (uint256 requestId, uint256 assets) {
- _preWithdrawHook();
-
- // Calculate the amount of assets to transfer to the redeemer
- assets = convertToAssets(shares);
-
- requestId = nextWithdrawalIndex;
- uint128 queued = SafeCast.toUint128(withdrawsQueued + assets);
- uint40 claimTimestamp = uint40(block.timestamp + CLAIM_DELAY);
-
- // Store the next withdrawal request
- nextWithdrawalIndex = SafeCast.toUint128(requestId + 1);
- // Store the updated queued amount which reserves WETH in the withdrawal queue
- withdrawsQueued = queued;
- // Store requests
- withdrawalRequests[requestId] = WithdrawalRequest({
- withdrawer: msg.sender,
- claimed: false,
- claimTimestamp: claimTimestamp,
- assets: SafeCast.toUint128(assets),
- queued: queued
- });
-
- // burn redeemer's shares
- _burn(msg.sender, shares);
-
- _postRequestRedeemHook();
-
- emit RedeemRequested(msg.sender, requestId, assets, queued, claimTimestamp);
- }
-
- function _preWithdrawHook() internal virtual;
- function _postRequestRedeemHook() internal virtual;
-
- /// @notice Claim liquidity assets from a previous withdrawal request after the claim delay has passed
- /// @param requestId The index of the withdrawal request
- /// @return assets The amount of liquidity assets that were transferred to the redeemer
- function claimRedeem(uint256 requestId) external returns (uint256 assets) {
- // Update the ARM's withdrawal queue's claimable amount
- _updateWithdrawalQueueLiquidity();
-
- // Load the structs from storage into memory
- WithdrawalRequest memory request = withdrawalRequests[requestId];
-
- require(request.claimTimestamp <= block.timestamp, "Claim delay not met");
- // If there isn't enough reserved liquidity in the queue to claim
- require(request.queued <= withdrawsClaimable, "Queue pending liquidity");
- require(request.withdrawer == msg.sender, "Not requester");
- require(request.claimed == false, "Already claimed");
-
- // Store the request as claimed
- withdrawalRequests[requestId].claimed = true;
- // Store the updated claimed amount
- withdrawsClaimed += request.assets;
-
- assets = request.assets;
-
- emit RedeemClaimed(msg.sender, requestId, assets);
-
- // transfer the liquidity asset to the withdrawer
- IERC20(liquidityAsset).transfer(msg.sender, assets);
- }
-
- /// @dev Updates the claimable amount in the ARM's withdrawal queue.
- /// That's the amount that is used to check if a request can be claimed or not.
- function _updateWithdrawalQueueLiquidity() internal {
- // Load the claimable amount from storage into memory
- uint256 withdrawsClaimableMem = withdrawsClaimable;
-
- // Check if the claimable amount is less than the queued amount
- uint256 queueShortfall = withdrawsQueued - withdrawsClaimableMem;
-
- // No need to do anything is the withdrawal queue is fully funded
- if (queueShortfall == 0) {
- return;
- }
-
- uint256 liquidityBalance = IERC20(liquidityAsset).balanceOf(address(this));
-
- // Of the claimable withdrawal requests, how much is unclaimed?
- // That is, the amount of the liquidity assets that is currently allocated for the withdrawal queue
- uint256 allocatedLiquidity = withdrawsClaimableMem - withdrawsClaimed;
-
- // If there is no unallocated liquidity assets then there is nothing to add to the queue
- if (liquidityBalance <= allocatedLiquidity) {
- return;
- }
-
- uint256 unallocatedLiquidity = liquidityBalance - allocatedLiquidity;
-
- // the new claimable amount is the smaller of the queue shortfall or unallocated weth
- uint256 addedClaimable = queueShortfall < unallocatedLiquidity ? queueShortfall : unallocatedLiquidity;
-
- // Store the new claimable amount back to storage
- withdrawsClaimable = SafeCast.toUint128(withdrawsClaimableMem + addedClaimable);
- }
-
- /// @dev Calculate how much of the liquidity asset in the ARM is not reserved for the withdrawal queue.
- // That is, it is available to be swapped.
- function _liquidityAvailable() internal view returns (uint256) {
- // The amount of WETH that is still to be claimed in the withdrawal queue
- uint256 outstandingWithdrawals = withdrawsQueued - withdrawsClaimed;
-
- // The amount of the liquidity asset is in the ARM
- uint256 liquidityBalance = IERC20(liquidityAsset).balanceOf(address(this));
-
- // If there is not enough liquidity assets in the ARM to cover the outstanding withdrawals
- if (liquidityBalance <= outstandingWithdrawals) {
- return 0;
- }
-
- return liquidityBalance - outstandingWithdrawals;
- }
-
- /// @dev Ensure any liquidity assets reserved for the withdrawal queue are not used
- /// in swaps that send liquidity assets out of the ARM
- function _transferAsset(address asset, address to, uint256 amount) internal virtual override {
- if (asset == liquidityAsset) {
- require(amount <= _liquidityAvailable(), "ARM: Insufficient liquidity");
- }
-
- IERC20(asset).transfer(to, amount);
- }
-
- /// @notice The total amount of assets in the ARM and external withdrawal queue,
- /// less the liquidity assets reserved for the withdrawal queue
- function totalAssets() public view virtual returns (uint256 assets) {
- // Get the assets in the ARM and external withdrawal queue
- assets = token0.balanceOf(address(this)) + token1.balanceOf(address(this)) + _externalWithdrawQueue();
-
- // Load the queue metadata from storage into memory
- uint256 queuedMem = withdrawsQueued;
- uint256 claimedMem = withdrawsClaimed;
-
- // If the ARM becomes insolvent enough that the total value in the ARM and external withdrawal queue
- // is less than the outstanding withdrawals.
- if (assets + claimedMem < queuedMem) {
- return 0;
- }
-
- // Need to remove the liquidity assets that have been reserved for the withdrawal queue
- return assets + claimedMem - queuedMem;
- }
-
- /// @notice Calculates the amount of shares for a given amount of liquidity assets
- function convertToShares(uint256 assets) public view returns (uint256 shares) {
- uint256 totalAssetsMem = totalAssets();
- shares = (totalAssetsMem == 0) ? assets : (assets * totalSupply()) / totalAssetsMem;
- }
-
- /// @notice Calculates the amount of liquidity assets for a given amount of shares
- function convertToAssets(uint256 shares) public view returns (uint256 assets) {
- assets = (shares * totalAssets()) / totalSupply();
- }
-
- /// @dev Hook for calculating the amount of assets in an external withdrawal queue like Lido or OETH
- /// This is not the ARM's withdrawal queue
- function _externalWithdrawQueue() internal view virtual returns (uint256 assets);
-}
diff --git a/src/contracts/OethARM.sol b/src/contracts/OethARM.sol
index 64174ff..2d546ac 100644
--- a/src/contracts/OethARM.sol
+++ b/src/contracts/OethARM.sol
@@ -17,7 +17,7 @@ contract OethARM is Initializable, OwnerLP, PeggedARM, OethLiquidityManager {
/// @param _weth The address of the WETH token that is being swapped out of this contract.
/// @param _oethVault The address of the OETH Vault proxy.
constructor(address _oeth, address _weth, address _oethVault)
- AbstractARM(_oeth, _weth)
+ AbstractARM(_oeth, _weth, _weth)
PeggedARM(false)
OethLiquidityManager(_oeth, _oethVault)
{}
@@ -28,4 +28,8 @@ contract OethARM is Initializable, OwnerLP, PeggedARM, OethLiquidityManager {
_setOperator(_operator);
_approvals();
}
+
+ function _externalWithdrawQueue() internal view override returns (uint256 assets) {
+ // TODO track OETH sent to the OETH Vault's withdrawal queue
+ }
}
diff --git a/src/contracts/PerformanceFee.sol b/src/contracts/PerformanceFee.sol
deleted file mode 100644
index 32abc8c..0000000
--- a/src/contracts/PerformanceFee.sol
+++ /dev/null
@@ -1,161 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.23;
-
-import {IERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
-import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
-
-import {MultiLP} from "./MultiLP.sol";
-
-/**
- * @title Added a performance fee to an ARM with Liquidity Providers (LP)
- * @author Origin Protocol Inc
- */
-abstract contract PerformanceFee is MultiLP {
- /// @notice The scale of the performance fee
- /// 10,000 = 100% performance fee
- uint256 public constant FEE_SCALE = 10000;
-
- /// @notice The account that can collect the performance fee
- address public feeCollector;
- /// @notice Performance fee that is collected by the feeCollector measured in basis points (1/100th of a percent)
- /// 10,000 = 100% performance fee
- /// 2,000 = 20% performance fee
- /// 500 = 5% performance fee
- uint16 public fee;
- /// @notice The performance fees accrued but not collected.
- /// This is removed from the total assets.
- uint112 public feesAccrued;
- /// @notice The total assets at the last time performance fees were calculated.
- /// This can only go up so is a high watermark.
- uint128 public lastTotalAssets;
-
- uint256[48] private _gap;
-
- event FeeCalculated(uint256 newFeesAccrued, uint256 assetIncrease);
- event FeeCollected(address indexed feeCollector, uint256 fee);
- event FeeUpdated(uint256 fee);
- event FeeCollectorUpdated(address indexed newFeeCollector);
-
- function _initPerformanceFee(uint256 _fee, address _feeCollector) internal {
- // Initialize the last total assets to the current total assets
- // This ensures no performance fee is accrued when the performance fee is calculated when the fee is set
- lastTotalAssets = SafeCast.toUint128(_rawTotalAssets());
- _setFee(_fee);
- _setFeeCollector(_feeCollector);
- }
-
- /// @dev Calculate the performance fee based on the increase in total assets before
- /// the liquidity asset from the deposit is transferred into the ARM
- function _preDepositHook() internal virtual override {
- _calcFee();
- }
-
- /// @dev Calculate the performance fee based on the increase in total assets before
- /// the liquidity asset from the redeem is reserved for the ARM withdrawal queue
- function _preWithdrawHook() internal virtual override {
- _calcFee();
- }
-
- /// @dev Save the new total assets after the deposit and performance fee accrued
- function _postDepositHook(uint256) internal virtual override {
- lastTotalAssets = SafeCast.toUint128(_rawTotalAssets());
- }
-
- /// @dev Save the new total assets after the requestRedeem and performance fee accrued
- function _postRequestRedeemHook() internal virtual override {
- lastTotalAssets = SafeCast.toUint128(_rawTotalAssets());
- }
-
- /// @dev Calculate the performance fee based on the increase in total assets
- /// Needs to be called before any action that changes the liquidity provider shares. eg deposit and redeem
- function _calcFee() internal {
- uint256 newTotalAssets = _rawTotalAssets();
-
- // Do not accrued a performance fee if the total assets has decreased
- if (newTotalAssets <= lastTotalAssets) return;
-
- uint256 assetIncrease = newTotalAssets - lastTotalAssets;
- uint256 newFeesAccrued = (assetIncrease * fee) / FEE_SCALE;
-
- // Save the new accrued fees back to storage
- feesAccrued = SafeCast.toUint112(feesAccrued + newFeesAccrued);
- // Save the new total assets back to storage less the new accrued fees.
- // This is be updated again in the post deposit and post withdraw hooks to include
- // the assets deposited or withdrawn
- lastTotalAssets = SafeCast.toUint128(newTotalAssets - newFeesAccrued);
-
- emit FeeCalculated(newFeesAccrued, assetIncrease);
- }
-
- /// @notice The total amount of assets in the ARM and external withdrawal queue,
- /// less the liquidity assets reserved for the ARM's withdrawal queue and accrued fees.
- function totalAssets() public view virtual override returns (uint256) {
- uint256 totalAssetsBeforeFees = _rawTotalAssets();
-
- // If the total assets have decreased, then we don't charge a performance fee
- if (totalAssetsBeforeFees <= lastTotalAssets) return totalAssetsBeforeFees;
-
- // Calculate the increase in assets since the last time fees were calculated
- uint256 assetIncrease = totalAssetsBeforeFees - lastTotalAssets;
-
- // Calculate the performance fee and remove from the total assets before new fees are removed
- return totalAssetsBeforeFees - ((assetIncrease * fee) / FEE_SCALE);
- }
-
- /// @dev Calculate the total assets in the ARM, external withdrawal queue,
- /// less liquidity assets reserved for the ARM's withdrawal queue and past accrued fees.
- /// The accrued fees are from the last time fees were calculated.
- function _rawTotalAssets() internal view returns (uint256) {
- return super.totalAssets() - feesAccrued;
- }
-
- /// @notice Owner sets the performance fee on increased assets
- /// @param _fee The performance fee measured in basis points (1/100th of a percent)
- /// 10,000 = 100% performance fee
- /// 500 = 5% performance fee
- function setFee(uint256 _fee) external onlyOwner {
- _setFee(_fee);
- }
-
- /// @notice Owner sets the account/contract that receives the performance fee
- function setFeeCollector(address _feeCollector) external onlyOwner {
- _setFeeCollector(_feeCollector);
- }
-
- function _setFee(uint256 _fee) internal {
- require(_fee <= FEE_SCALE, "ARM: fee too high");
-
- // Calculate fees up to this point using the old fee
- _calcFee();
-
- fee = SafeCast.toUint16(_fee);
-
- emit FeeUpdated(_fee);
- }
-
- function _setFeeCollector(address _feeCollector) internal {
- require(_feeCollector != address(0), "ARM: invalid fee collector");
-
- feeCollector = _feeCollector;
-
- emit FeeCollectorUpdated(_feeCollector);
- }
-
- /// @notice Transfer accrued performance fees to the fee collector
- /// This requires enough liquidity assets in the ARM to cover the accrued fees.
- function collectFees() external returns (uint256 fees) {
- // Accrued all fees up to this point
- _calcFee();
-
- // Read the updated accrued fees from storage
- fees = feesAccrued;
- require(fees <= IERC20(liquidityAsset).balanceOf(address(this)), "ARM: insufficient liquidity");
-
- // Reset the accrued fees in storage
- feesAccrued = 0;
-
- IERC20(liquidityAsset).transfer(feeCollector, fees);
-
- emit FeeCollected(feeCollector, fees);
- }
-}
diff --git a/src/contracts/README.md b/src/contracts/README.md
index 494648e..d421790 100644
--- a/src/contracts/README.md
+++ b/src/contracts/README.md
@@ -30,12 +30,12 @@
### Hierarchy
-![Lido ARM Hierarchy](../../docs/LidoFixedPriceMultiLpARMHierarchy.svg)
+![Lido ARM Hierarchy](../../docs/LidoARMHierarchy.svg)
## OETH ARM Squashed
-![Lido ARM Squashed](../../docs/LidoFixedPriceMultiLpARMSquashed.svg)
+![Lido ARM Squashed](../../docs/LidoARMSquashed.svg)
+![Lido ARM Storage](../../docs/LidoARMStorage.svg) -->
diff --git a/test/Base.sol b/test/Base.sol
index 7be4705..f4b4b57 100644
--- a/test/Base.sol
+++ b/test/Base.sol
@@ -7,7 +7,7 @@ import {Test} from "forge-std/Test.sol";
// Contracts
import {Proxy} from "contracts/Proxy.sol";
import {OethARM} from "contracts/OethARM.sol";
-import {LidoFixedPriceMultiLpARM} from "contracts/LidoFixedPriceMultiLpARM.sol";
+import {LidoARM} from "contracts/LidoARM.sol";
import {LiquidityProviderController} from "contracts/LiquidityProviderController.sol";
// Interfaces
@@ -35,7 +35,7 @@ abstract contract Base_Test_ is Test {
Proxy public lidoProxy;
Proxy public lidoOwnerProxy;
OethARM public oethARM;
- LidoFixedPriceMultiLpARM public lidoFixedPriceMultiLpARM;
+ LidoARM public lidoARM;
LiquidityProviderController public liquidityProviderController;
IERC20 public oeth;
diff --git a/test/fork/LidoFixedPriceMultiLpARM/ClaimRedeem.t.sol b/test/fork/LidoFixedPriceMultiLpARM/ClaimRedeem.t.sol
index 6e1bf00..fc738f4 100644
--- a/test/fork/LidoFixedPriceMultiLpARM/ClaimRedeem.t.sol
+++ b/test/fork/LidoFixedPriceMultiLpARM/ClaimRedeem.t.sol
@@ -6,10 +6,9 @@ import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
// Contracts
import {IERC20} from "contracts/Interfaces.sol";
-import {MultiLP} from "contracts/MultiLP.sol";
-import {PerformanceFee} from "contracts/PerformanceFee.sol";
+import {AbstractARM} from "contracts/AbstractARM.sol";
-contract Fork_Concrete_LidoFixedPriceMultiLpARM_ClaimRedeem_Test_ is Fork_Shared_Test_ {
+contract Fork_Concrete_LidoARM_ClaimRedeem_Test_ is Fork_Shared_Test_ {
uint256 private delay;
//////////////////////////////////////////////////////
/// --- SETUP
@@ -18,7 +17,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_ClaimRedeem_Test_ is Fork_Shared
function setUp() public override {
super.setUp();
- delay = lidoFixedPriceMultiLpARM.CLAIM_DELAY();
+ delay = lidoARM.CLAIM_DELAY();
deal(address(weth), address(this), 1_000 ether);
}
@@ -30,57 +29,57 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_ClaimRedeem_Test_ is Fork_Shared
public
setTotalAssetsCap(DEFAULT_AMOUNT + MIN_TOTAL_SUPPLY)
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
- requestRedeemFromLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
+ requestRedeemFromLidoARM(address(this), DEFAULT_AMOUNT)
{
skip(delay - 1);
vm.expectRevert("Claim delay not met");
- lidoFixedPriceMultiLpARM.claimRedeem(0);
+ lidoARM.claimRedeem(0);
}
function test_RevertWhen_ClaimRequest_Because_QueuePendingLiquidity_NoLiquidity()
public
setTotalAssetsCap(DEFAULT_AMOUNT + MIN_TOTAL_SUPPLY)
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
- requestRedeemFromLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
+ requestRedeemFromLidoARM(address(this), DEFAULT_AMOUNT)
{
// Remove all weth liquidity from ARM
- deal(address(weth), address(lidoFixedPriceMultiLpARM), 0);
+ deal(address(weth), address(lidoARM), 0);
// Time jump claim delay
skip(delay);
// Expect revert
vm.expectRevert("Queue pending liquidity");
- lidoFixedPriceMultiLpARM.claimRedeem(0);
+ lidoARM.claimRedeem(0);
}
function test_RevertWhen_ClaimRequest_Because_QueuePendingLiquidity_NoEnoughLiquidity()
public
setTotalAssetsCap(DEFAULT_AMOUNT + MIN_TOTAL_SUPPLY)
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
- requestRedeemFromLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
+ requestRedeemFromLidoARM(address(this), DEFAULT_AMOUNT)
{
// Remove half of weth liquidity from ARM
- uint256 halfAmount = weth.balanceOf(address(lidoFixedPriceMultiLpARM)) / 2;
- deal(address(weth), address(lidoFixedPriceMultiLpARM), halfAmount);
+ uint256 halfAmount = weth.balanceOf(address(lidoARM)) / 2;
+ deal(address(weth), address(lidoARM), halfAmount);
// Time jump claim delay
skip(delay);
// Expect revert
vm.expectRevert("Queue pending liquidity");
- lidoFixedPriceMultiLpARM.claimRedeem(0);
+ lidoARM.claimRedeem(0);
}
function test_RevertWhen_ClaimRequest_Because_NotRequester()
public
setTotalAssetsCap(DEFAULT_AMOUNT + MIN_TOTAL_SUPPLY)
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
- requestRedeemFromLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
+ requestRedeemFromLidoARM(address(this), DEFAULT_AMOUNT)
{
// Time jump claim delay
skip(delay);
@@ -88,21 +87,21 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_ClaimRedeem_Test_ is Fork_Shared
// Expect revert
vm.startPrank(vm.randomAddress());
vm.expectRevert("Not requester");
- lidoFixedPriceMultiLpARM.claimRedeem(0);
+ lidoARM.claimRedeem(0);
}
function test_RevertWhen_ClaimRequest_Because_AlreadyClaimed()
public
setTotalAssetsCap(DEFAULT_AMOUNT + MIN_TOTAL_SUPPLY)
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
- requestRedeemFromLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
+ requestRedeemFromLidoARM(address(this), DEFAULT_AMOUNT)
skipTime(delay)
- claimRequestOnLidoFixedPriceMultiLpARM(address(this), 0)
+ claimRequestOnLidoARM(address(this), 0)
{
// Expect revert
vm.expectRevert("Already claimed");
- lidoFixedPriceMultiLpARM.claimRedeem(0);
+ lidoARM.claimRedeem(0);
}
//////////////////////////////////////////////////////
@@ -113,39 +112,39 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_ClaimRedeem_Test_ is Fork_Shared
public
setTotalAssetsCap(DEFAULT_AMOUNT + MIN_TOTAL_SUPPLY)
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
- requestRedeemFromLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
+ requestRedeemFromLidoARM(address(this), DEFAULT_AMOUNT)
skipTime(delay)
{
// Assertions before
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0); // No perfs so no fees
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY);
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(address(this)), 0);
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY);
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(lidoARM.feesAccrued(), 0); // No perfs so no fees
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY);
+ assertEq(lidoARM.balanceOf(address(this)), 0);
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY);
assertEq(liquidityProviderController.liquidityProviderCaps(address(this)), 0);
assertEqQueueMetadata(DEFAULT_AMOUNT, 0, 0, 1);
assertEqUserRequest(0, address(this), false, block.timestamp, DEFAULT_AMOUNT, DEFAULT_AMOUNT);
// Expected events
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
- emit MultiLP.RedeemClaimed(address(this), 0, DEFAULT_AMOUNT);
+ vm.expectEmit({emitter: address(lidoARM)});
+ emit AbstractARM.RedeemClaimed(address(this), 0, DEFAULT_AMOUNT);
vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(address(lidoFixedPriceMultiLpARM), address(this), DEFAULT_AMOUNT);
+ emit IERC20.Transfer(address(lidoARM), address(this), DEFAULT_AMOUNT);
// Main call
- (uint256 assets) = lidoFixedPriceMultiLpARM.claimRedeem(0);
+ (uint256 assets) = lidoARM.claimRedeem(0);
// Assertions after
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0); // No perfs so no fees
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY);
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(address(this)), 0);
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY);
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(lidoARM.feesAccrued(), 0); // No perfs so no fees
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY);
+ assertEq(lidoARM.balanceOf(address(this)), 0);
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY);
assertEq(liquidityProviderController.liquidityProviderCaps(address(this)), 0);
assertEqQueueMetadata(DEFAULT_AMOUNT, DEFAULT_AMOUNT, DEFAULT_AMOUNT, 1);
assertEqUserRequest(0, address(this), true, block.timestamp, DEFAULT_AMOUNT, DEFAULT_AMOUNT);
@@ -156,40 +155,40 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_ClaimRedeem_Test_ is Fork_Shared
public
setTotalAssetsCap(DEFAULT_AMOUNT + MIN_TOTAL_SUPPLY)
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
- requestRedeemFromLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
+ requestRedeemFromLidoARM(address(this), DEFAULT_AMOUNT)
skipTime(delay)
{
// Assertions before
// Same situation as above
// Swap MIN_TOTAL_SUPPLY from WETH in STETH
- deal(address(weth), address(lidoFixedPriceMultiLpARM), DEFAULT_AMOUNT);
- deal(address(steth), address(lidoFixedPriceMultiLpARM), MIN_TOTAL_SUPPLY);
+ deal(address(weth), address(lidoARM), DEFAULT_AMOUNT);
+ deal(address(steth), address(lidoARM), MIN_TOTAL_SUPPLY);
// Handle lido rounding issue to ensure that balance is exactly MIN_TOTAL_SUPPLY
- if (steth.balanceOf(address(lidoFixedPriceMultiLpARM)) == MIN_TOTAL_SUPPLY - 1) {
- deal(address(steth), address(lidoFixedPriceMultiLpARM), 0);
- deal(address(steth), address(lidoFixedPriceMultiLpARM), MIN_TOTAL_SUPPLY + 1);
+ if (steth.balanceOf(address(lidoARM)) == MIN_TOTAL_SUPPLY - 1) {
+ deal(address(steth), address(lidoARM), 0);
+ deal(address(steth), address(lidoARM), MIN_TOTAL_SUPPLY + 1);
}
// Expected events
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
- emit MultiLP.RedeemClaimed(address(this), 0, DEFAULT_AMOUNT);
+ vm.expectEmit({emitter: address(lidoARM)});
+ emit AbstractARM.RedeemClaimed(address(this), 0, DEFAULT_AMOUNT);
vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(address(lidoFixedPriceMultiLpARM), address(this), DEFAULT_AMOUNT);
+ emit IERC20.Transfer(address(lidoARM), address(this), DEFAULT_AMOUNT);
// Main call
- (uint256 assets) = lidoFixedPriceMultiLpARM.claimRedeem(0);
+ (uint256 assets) = lidoARM.claimRedeem(0);
// Assertions after
- assertApproxEqAbs(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY, 1);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0); // No perfs so no fees
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY);
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(address(this)), 0);
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY);
+ assertApproxEqAbs(steth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY, 1);
+ assertEq(weth.balanceOf(address(lidoARM)), 0);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(lidoARM.feesAccrued(), 0); // No perfs so no fees
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY);
+ assertEq(lidoARM.balanceOf(address(this)), 0);
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY);
assertEq(liquidityProviderController.liquidityProviderCaps(address(this)), 0);
assertEqQueueMetadata(DEFAULT_AMOUNT, DEFAULT_AMOUNT, DEFAULT_AMOUNT, 1);
assertEqUserRequest(0, address(this), true, block.timestamp, DEFAULT_AMOUNT, DEFAULT_AMOUNT);
@@ -200,43 +199,43 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_ClaimRedeem_Test_ is Fork_Shared
public
setTotalAssetsCap(DEFAULT_AMOUNT + MIN_TOTAL_SUPPLY)
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
- requestRedeemFromLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT / 2)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
+ requestRedeemFromLidoARM(address(this), DEFAULT_AMOUNT / 2)
skipTime(delay)
- claimRequestOnLidoFixedPriceMultiLpARM(address(this), 0)
- requestRedeemFromLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT / 2)
+ claimRequestOnLidoARM(address(this), 0)
+ requestRedeemFromLidoARM(address(this), DEFAULT_AMOUNT / 2)
{
// Assertions before
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT / 2);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0); // No perfs so no fees
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY);
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(address(this)), 0);
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY);
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT / 2);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(lidoARM.feesAccrued(), 0); // No perfs so no fees
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY);
+ assertEq(lidoARM.balanceOf(address(this)), 0);
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY);
assertEq(liquidityProviderController.liquidityProviderCaps(address(this)), 0);
assertEqQueueMetadata(DEFAULT_AMOUNT, DEFAULT_AMOUNT / 2, DEFAULT_AMOUNT / 2, 2);
assertEqUserRequest(0, address(this), true, block.timestamp, DEFAULT_AMOUNT / 2, DEFAULT_AMOUNT / 2);
assertEqUserRequest(1, address(this), false, block.timestamp + delay, DEFAULT_AMOUNT / 2, DEFAULT_AMOUNT);
// Expected events
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
- emit MultiLP.RedeemClaimed(address(this), 1, DEFAULT_AMOUNT / 2);
+ vm.expectEmit({emitter: address(lidoARM)});
+ emit AbstractARM.RedeemClaimed(address(this), 1, DEFAULT_AMOUNT / 2);
vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(address(lidoFixedPriceMultiLpARM), address(this), DEFAULT_AMOUNT / 2);
+ emit IERC20.Transfer(address(lidoARM), address(this), DEFAULT_AMOUNT / 2);
// Main call
skip(delay);
- (uint256 assets) = lidoFixedPriceMultiLpARM.claimRedeem(1);
+ (uint256 assets) = lidoARM.claimRedeem(1);
// Assertions after
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0); // No perfs so no fees
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY);
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(address(this)), 0);
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY);
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(lidoARM.feesAccrued(), 0); // No perfs so no fees
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY);
+ assertEq(lidoARM.balanceOf(address(this)), 0);
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY);
assertEq(liquidityProviderController.liquidityProviderCaps(address(this)), 0);
assertEqQueueMetadata(DEFAULT_AMOUNT, DEFAULT_AMOUNT, DEFAULT_AMOUNT, 2);
assertEqUserRequest(0, address(this), true, block.timestamp - delay, DEFAULT_AMOUNT / 2, DEFAULT_AMOUNT / 2);
diff --git a/test/fork/LidoFixedPriceMultiLpARM/ClaimStETHWithdrawalForWETH.t.sol b/test/fork/LidoFixedPriceMultiLpARM/ClaimStETHWithdrawalForWETH.t.sol
index 6b8e9d3..ad75713 100644
--- a/test/fork/LidoFixedPriceMultiLpARM/ClaimStETHWithdrawalForWETH.t.sol
+++ b/test/fork/LidoFixedPriceMultiLpARM/ClaimStETHWithdrawalForWETH.t.sol
@@ -9,7 +9,7 @@ import {IERC20} from "contracts/Interfaces.sol";
import {IStETHWithdrawal} from "contracts/Interfaces.sol";
import {Mainnet} from "contracts/utils/Addresses.sol";
-contract Fork_Concrete_LidoFixedPriceMultiLpARM_RequestStETHWithdrawalForETH_Test_ is Fork_Shared_Test_ {
+contract Fork_Concrete_LidoARM_RequestStETHWithdrawalForETH_Test_ is Fork_Shared_Test_ {
uint256[] amounts0;
uint256[] amounts1;
uint256[] amounts2;
@@ -22,7 +22,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_RequestStETHWithdrawalForETH_Tes
function setUp() public override {
super.setUp();
- deal(address(steth), address(lidoFixedPriceMultiLpARM), 10_000 ether);
+ deal(address(steth), address(lidoARM), 10_000 ether);
amounts0 = new uint256[](0);
@@ -40,61 +40,61 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_RequestStETHWithdrawalForETH_Tes
function test_ClaimStETHWithdrawalForWETH_EmptyList()
public
asLidoFixedPriceMulltiLpARMOperator
- requestStETHWithdrawalForETHOnLidoFixedPriceMultiLpARM(new uint256[](0))
+ requestStETHWithdrawalForETHOnLidoARM(new uint256[](0))
{
- assertEq(address(lidoFixedPriceMultiLpARM).balance, 0);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
+ assertEq(address(lidoARM).balance, 0);
+ assertEq(lidoARM.outstandingEther(), 0);
// Main call
- lidoFixedPriceMultiLpARM.claimStETHWithdrawalForWETH(new uint256[](0));
+ lidoARM.claimStETHWithdrawalForWETH(new uint256[](0));
- assertEq(address(lidoFixedPriceMultiLpARM).balance, 0);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
+ assertEq(address(lidoARM).balance, 0);
+ assertEq(lidoARM.outstandingEther(), 0);
}
function test_ClaimStETHWithdrawalForWETH_SingleRequest()
public
asLidoFixedPriceMulltiLpARMOperator
- approveStETHOnLidoFixedPriceMultiLpARM
- requestStETHWithdrawalForETHOnLidoFixedPriceMultiLpARM(amounts1)
- mockFunctionClaimWithdrawOnLidoFixedPriceMultiLpARM(DEFAULT_AMOUNT)
+ approveStETHOnLidoARM
+ requestStETHWithdrawalForETHOnLidoARM(amounts1)
+ mockFunctionClaimWithdrawOnLidoARM(DEFAULT_AMOUNT)
{
// Assertions before
- uint256 balanceBefore = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), DEFAULT_AMOUNT);
+ uint256 balanceBefore = weth.balanceOf(address(lidoARM));
+ assertEq(lidoARM.outstandingEther(), DEFAULT_AMOUNT);
stETHWithdrawal.getLastRequestId();
uint256[] memory requests = new uint256[](1);
requests[0] = stETHWithdrawal.getLastRequestId();
// Main call
- lidoFixedPriceMultiLpARM.claimStETHWithdrawalForWETH(requests);
+ lidoARM.claimStETHWithdrawalForWETH(requests);
// Assertions after
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), balanceBefore + DEFAULT_AMOUNT);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), balanceBefore + DEFAULT_AMOUNT);
}
function test_ClaimStETHWithdrawalForWETH_MultiRequest()
public
asLidoFixedPriceMulltiLpARMOperator
- approveStETHOnLidoFixedPriceMultiLpARM
- requestStETHWithdrawalForETHOnLidoFixedPriceMultiLpARM(amounts2)
+ approveStETHOnLidoARM
+ requestStETHWithdrawalForETHOnLidoARM(amounts2)
mockCallLidoFindCheckpointHints
- mockFunctionClaimWithdrawOnLidoFixedPriceMultiLpARM(amounts2[0] + amounts2[1])
+ mockFunctionClaimWithdrawOnLidoARM(amounts2[0] + amounts2[1])
{
// Assertions before
- uint256 balanceBefore = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), amounts2[0] + amounts2[1]);
+ uint256 balanceBefore = weth.balanceOf(address(lidoARM));
+ assertEq(lidoARM.outstandingEther(), amounts2[0] + amounts2[1]);
stETHWithdrawal.getLastRequestId();
uint256[] memory requests = new uint256[](2);
requests[0] = stETHWithdrawal.getLastRequestId() - 1;
requests[1] = stETHWithdrawal.getLastRequestId();
// Main call
- lidoFixedPriceMultiLpARM.claimStETHWithdrawalForWETH(requests);
+ lidoARM.claimStETHWithdrawalForWETH(requests);
// Assertions after
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), balanceBefore + amounts2[0] + amounts2[1]);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), balanceBefore + amounts2[0] + amounts2[1]);
}
}
diff --git a/test/fork/LidoFixedPriceMultiLpARM/CollectFees.t.sol b/test/fork/LidoFixedPriceMultiLpARM/CollectFees.t.sol
index c10f272..dd23f07 100644
--- a/test/fork/LidoFixedPriceMultiLpARM/CollectFees.t.sol
+++ b/test/fork/LidoFixedPriceMultiLpARM/CollectFees.t.sol
@@ -6,9 +6,9 @@ import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
// Contracts
import {IERC20} from "contracts/Interfaces.sol";
-import {PerformanceFee} from "contracts/PerformanceFee.sol";
+import {AbstractARM} from "contracts/AbstractARM.sol";
-contract Fork_Concrete_LidoFixedPriceMultiLpARM_CollectFees_Test_ is Fork_Shared_Test_ {
+contract Fork_Concrete_LidoARM_CollectFees_Test_ is Fork_Shared_Test_ {
//////////////////////////////////////////////////////
/// --- SETUP
//////////////////////////////////////////////////////
@@ -22,44 +22,41 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_CollectFees_Test_ is Fork_Shared
/// @notice This test is expected to revert as almost all the liquidity is in stETH
function test_RevertWhen_CollectFees_Because_InsufficientLiquidity()
public
- simulateAssetGainInLidoFixedPriceMultiLpARM(DEFAULT_AMOUNT, address(steth), true)
+ simulateAssetGainInLidoARM(DEFAULT_AMOUNT, address(steth), true)
{
vm.expectRevert("ARM: insufficient liquidity");
- lidoFixedPriceMultiLpARM.collectFees();
+ lidoARM.collectFees();
}
//////////////////////////////////////////////////////
/// --- PASSING TESTS
//////////////////////////////////////////////////////
- function test_CollectFees_Once()
- public
- simulateAssetGainInLidoFixedPriceMultiLpARM(DEFAULT_AMOUNT, address(weth), true)
- {
- address feeCollector = lidoFixedPriceMultiLpARM.feeCollector();
+ function test_CollectFees_Once() public simulateAssetGainInLidoARM(DEFAULT_AMOUNT, address(weth), true) {
+ address feeCollector = lidoARM.feeCollector();
uint256 fee = DEFAULT_AMOUNT * 20 / 100;
// Expected Events
vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(address(lidoFixedPriceMultiLpARM), feeCollector, fee);
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
- emit PerformanceFee.FeeCollected(feeCollector, fee);
+ emit IERC20.Transfer(address(lidoARM), feeCollector, fee);
+ vm.expectEmit({emitter: address(lidoARM)});
+ emit AbstractARM.FeeCollected(feeCollector, fee);
// Main call
- uint256 claimedFee = lidoFixedPriceMultiLpARM.collectFees();
+ uint256 claimedFee = lidoARM.collectFees();
// Assertions after
assertEq(claimedFee, fee);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0);
+ assertEq(lidoARM.feesAccrued(), 0);
}
function test_CollectFees_Twice()
public
- simulateAssetGainInLidoFixedPriceMultiLpARM(DEFAULT_AMOUNT, address(weth), true)
- collectFeesOnLidoFixedPriceMultiLpARM
- simulateAssetGainInLidoFixedPriceMultiLpARM(DEFAULT_AMOUNT, address(weth), true)
+ simulateAssetGainInLidoARM(DEFAULT_AMOUNT, address(weth), true)
+ collectFeesOnLidoARM
+ simulateAssetGainInLidoARM(DEFAULT_AMOUNT, address(weth), true)
{
// Main call
- uint256 claimedFee = lidoFixedPriceMultiLpARM.collectFees();
+ uint256 claimedFee = lidoARM.collectFees();
// Assertions after
assertEq(claimedFee, DEFAULT_AMOUNT * 20 / 100); // This test should pass!
diff --git a/test/fork/LidoFixedPriceMultiLpARM/Constructor.t.sol b/test/fork/LidoFixedPriceMultiLpARM/Constructor.t.sol
index dc7f048..debd3a3 100644
--- a/test/fork/LidoFixedPriceMultiLpARM/Constructor.t.sol
+++ b/test/fork/LidoFixedPriceMultiLpARM/Constructor.t.sol
@@ -4,7 +4,7 @@ pragma solidity 0.8.23;
// Test imports
import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
-contract Fork_Concrete_LidoFixedPriceMultiLpARM_Constructor_Test is Fork_Shared_Test_ {
+contract Fork_Concrete_LidoARM_Constructor_Test is Fork_Shared_Test_ {
//////////////////////////////////////////////////////
/// --- SETUP
//////////////////////////////////////////////////////
@@ -16,18 +16,18 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_Constructor_Test is Fork_Shared_
/// --- PASSING TESTS
//////////////////////////////////////////////////////
function test_Initial_State() public view {
- assertEq(lidoFixedPriceMultiLpARM.name(), "Lido ARM");
- assertEq(lidoFixedPriceMultiLpARM.symbol(), "ARM-ST");
- assertEq(lidoFixedPriceMultiLpARM.owner(), address(this));
- assertEq(lidoFixedPriceMultiLpARM.operator(), operator);
- assertEq(lidoFixedPriceMultiLpARM.feeCollector(), feeCollector);
- assertEq(lidoFixedPriceMultiLpARM.fee(), 2000);
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), 1e12);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0);
+ assertEq(lidoARM.name(), "Lido ARM");
+ assertEq(lidoARM.symbol(), "ARM-ST");
+ assertEq(lidoARM.owner(), address(this));
+ assertEq(lidoARM.operator(), operator);
+ assertEq(lidoARM.feeCollector(), feeCollector);
+ assertEq(lidoARM.fee(), 2000);
+ assertEq(lidoARM.lastTotalAssets(), 1e12);
+ assertEq(lidoARM.feesAccrued(), 0);
// the 20% performance fee is removed on initialization
- assertEq(lidoFixedPriceMultiLpARM.totalAssets(), 1e12);
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), 1e12);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), 1e12);
+ assertEq(lidoARM.totalAssets(), 1e12);
+ assertEq(lidoARM.totalSupply(), 1e12);
+ assertEq(weth.balanceOf(address(lidoARM)), 1e12);
assertEq(liquidityProviderController.totalAssetsCap(), 100 ether);
}
}
diff --git a/test/fork/LidoFixedPriceMultiLpARM/Deposit.t.sol b/test/fork/LidoFixedPriceMultiLpARM/Deposit.t.sol
index c88c02a..9ac0e9b 100644
--- a/test/fork/LidoFixedPriceMultiLpARM/Deposit.t.sol
+++ b/test/fork/LidoFixedPriceMultiLpARM/Deposit.t.sol
@@ -6,27 +6,9 @@ import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
// Contracts
import {IERC20} from "contracts/Interfaces.sol";
-import {MultiLP} from "contracts/MultiLP.sol";
import {LiquidityProviderController} from "contracts/LiquidityProviderController.sol";
-contract Fork_Concrete_LidoFixedPriceMultiLpARM_Deposit_Test_ is Fork_Shared_Test_ {
- /**
- * As Deposit is complex function due to the entanglement of virtual and override functions in inheritance.
- * This is a small recap of the functions that are called in the deposit function.
- * 1. ML: _preDepositHook() -> PF: _calcFee() -> PF: _rawTotalAssets() -> ML: _totalAssets()
- * 2. ML: convertToShares() -> ML: _totalAssets() -> ARM: totalAssets() -> PF : totalAssets() ->
- * -> PF: _rawTotalAssets() -> ML: _totalAssets()
- * 3. ML: _postDepositHook() -> ARM: _postDepositHook() =>
- * | -> LCPARM: postDepositHook() -> LPC: postDepositHook() -> ARM: totalAssets() ->
- * -> PF : totalAssets() -> PF: _rawTotalAssets() -> ML: _totalAssets()
- * | -> PF: _postDepositHook() -> PF: _rawTotalAssets() -> ML: _totalAssets()
- *
- * ML = MultiLP
- * PF = PerformanceFee
- * ARM = LidoFixedPriceMultiLpARM
- * LPC = LiquidityProviderController
- * LCPARM = LiquidityProviderControllerARM
- */
+contract Fork_Concrete_LidoARM_Deposit_Test_ is Fork_Shared_Test_ {
//////////////////////////////////////////////////////
/// --- SETUP
//////////////////////////////////////////////////////
@@ -38,7 +20,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_Deposit_Test_ is Fork_Shared_Tes
// Alice
deal(address(weth), alice, 1_000 ether);
vm.prank(alice);
- weth.approve(address(lidoFixedPriceMultiLpARM), type(uint256).max);
+ weth.approve(address(lidoARM), type(uint256).max);
}
//////////////////////////////////////////////////////
@@ -49,7 +31,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_Deposit_Test_ is Fork_Shared_Tes
setLiquidityProviderCap(address(this), 0)
{
vm.expectRevert("LPC: LP cap exceeded");
- lidoFixedPriceMultiLpARM.deposit(DEFAULT_AMOUNT);
+ lidoARM.deposit(DEFAULT_AMOUNT);
}
function test_RevertWhen_Deposit_Because_LiquidityProviderCapExceeded_WithCapNotNull()
@@ -57,7 +39,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_Deposit_Test_ is Fork_Shared_Tes
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
{
vm.expectRevert("LPC: LP cap exceeded");
- lidoFixedPriceMultiLpARM.deposit(DEFAULT_AMOUNT + 1);
+ lidoARM.deposit(DEFAULT_AMOUNT + 1);
}
function test_RevertWhen_Deposit_Because_LiquidityProviderCapExceeded_WithCapReached()
@@ -65,11 +47,11 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_Deposit_Test_ is Fork_Shared_Tes
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
{
// Initial deposit
- lidoFixedPriceMultiLpARM.deposit(DEFAULT_AMOUNT / 2);
+ lidoARM.deposit(DEFAULT_AMOUNT / 2);
// Cap is now 0.5 ether
vm.expectRevert("LPC: LP cap exceeded");
- lidoFixedPriceMultiLpARM.deposit((DEFAULT_AMOUNT / 2) + 1);
+ lidoARM.deposit((DEFAULT_AMOUNT / 2) + 1);
}
function test_RevertWhen_Deposit_Because_TotalAssetsCapExceeded_WithCapNull()
@@ -78,7 +60,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_Deposit_Test_ is Fork_Shared_Tes
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT + 1)
{
vm.expectRevert("LPC: Total assets cap exceeded");
- lidoFixedPriceMultiLpARM.deposit(DEFAULT_AMOUNT);
+ lidoARM.deposit(DEFAULT_AMOUNT);
}
function test_RevertWhen_Deposit_Because_TotalAssetsCapExceeded_WithCapNotNull()
@@ -87,7 +69,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_Deposit_Test_ is Fork_Shared_Tes
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
{
vm.expectRevert("LPC: Total assets cap exceeded");
- lidoFixedPriceMultiLpARM.deposit(DEFAULT_AMOUNT - MIN_TOTAL_SUPPLY + 1);
+ lidoARM.deposit(DEFAULT_AMOUNT - MIN_TOTAL_SUPPLY + 1);
}
function test_RevertWhen_Deposit_Because_TotalAssetsCapExceeded_WithCapReached()
@@ -95,9 +77,9 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_Deposit_Test_ is Fork_Shared_Tes
setTotalAssetsCap(DEFAULT_AMOUNT)
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
{
- lidoFixedPriceMultiLpARM.deposit(DEFAULT_AMOUNT / 2);
+ lidoARM.deposit(DEFAULT_AMOUNT / 2);
vm.expectRevert("LPC: Total assets cap exceeded");
- lidoFixedPriceMultiLpARM.deposit((DEFAULT_AMOUNT / 2) - MIN_TOTAL_SUPPLY + 1); // This should revert!
+ lidoARM.deposit((DEFAULT_AMOUNT / 2) - MIN_TOTAL_SUPPLY + 1); // This should revert!
}
//////////////////////////////////////////////////////
@@ -113,37 +95,37 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_Deposit_Test_ is Fork_Shared_Tes
{
uint256 amount = DEFAULT_AMOUNT;
// Assertions Before
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0); // No perfs so no fees
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY);
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(address(this)), 0); // Ensure no shares before
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY); // Minted to dead on deploy
- assertEq(lidoFixedPriceMultiLpARM.totalAssets(), MIN_TOTAL_SUPPLY);
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(lidoARM.feesAccrued(), 0); // No perfs so no fees
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY);
+ assertEq(lidoARM.balanceOf(address(this)), 0); // Ensure no shares before
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY); // Minted to dead on deploy
+ assertEq(lidoARM.totalAssets(), MIN_TOTAL_SUPPLY);
assertEq(liquidityProviderController.liquidityProviderCaps(address(this)), amount);
assertEqQueueMetadata(0, 0, 0, 0);
// Expected events
vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(address(this), address(lidoFixedPriceMultiLpARM), amount);
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
+ emit IERC20.Transfer(address(this), address(lidoARM), amount);
+ vm.expectEmit({emitter: address(lidoARM)});
emit IERC20.Transfer(address(0), address(this), amount); // shares == amount here
vm.expectEmit({emitter: address(liquidityProviderController)});
emit LiquidityProviderController.LiquidityProviderCap(address(this), 0);
// Main call
- uint256 shares = lidoFixedPriceMultiLpARM.deposit(amount);
+ uint256 shares = lidoARM.deposit(amount);
// Assertions After
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY + amount);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0); // No perfs so no fees
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + amount);
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(address(this)), shares);
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY + amount);
- assertEq(lidoFixedPriceMultiLpARM.totalAssets(), MIN_TOTAL_SUPPLY + amount);
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY + amount);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(lidoARM.feesAccrued(), 0); // No perfs so no fees
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + amount);
+ assertEq(lidoARM.balanceOf(address(this)), shares);
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY + amount);
+ assertEq(lidoARM.totalAssets(), MIN_TOTAL_SUPPLY + amount);
assertEq(liquidityProviderController.liquidityProviderCaps(address(this)), 0); // All the caps are used
assertEqQueueMetadata(0, 0, 0, 0);
assertEq(shares, amount); // No perfs, so 1 ether * totalSupply (1e12) / totalAssets (1e12) = 1 ether
@@ -155,41 +137,41 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_Deposit_Test_ is Fork_Shared_Tes
public
setTotalAssetsCap(DEFAULT_AMOUNT * 2 + MIN_TOTAL_SUPPLY)
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT * 2)
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
{
uint256 amount = DEFAULT_AMOUNT;
// Assertions Before
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY + amount);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0); // No perfs so no fees
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + amount);
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(address(this)), amount);
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY + amount); // Minted to dead on deploy
- assertEq(lidoFixedPriceMultiLpARM.totalAssets(), MIN_TOTAL_SUPPLY + amount);
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY + amount);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(lidoARM.feesAccrued(), 0); // No perfs so no fees
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + amount);
+ assertEq(lidoARM.balanceOf(address(this)), amount);
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY + amount); // Minted to dead on deploy
+ assertEq(lidoARM.totalAssets(), MIN_TOTAL_SUPPLY + amount);
assertEq(liquidityProviderController.liquidityProviderCaps(address(this)), amount);
assertEqQueueMetadata(0, 0, 0, 0);
// Expected events
vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(address(this), address(lidoFixedPriceMultiLpARM), amount);
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
+ emit IERC20.Transfer(address(this), address(lidoARM), amount);
+ vm.expectEmit({emitter: address(lidoARM)});
emit IERC20.Transfer(address(0), address(this), amount); // shares == amount here
vm.expectEmit({emitter: address(liquidityProviderController)});
emit LiquidityProviderController.LiquidityProviderCap(address(this), 0);
// Main call
- uint256 shares = lidoFixedPriceMultiLpARM.deposit(amount);
+ uint256 shares = lidoARM.deposit(amount);
// Assertions After
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY + amount * 2);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0); // No perfs so no fees
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + amount * 2);
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(address(this)), shares * 2);
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY + amount * 2);
- assertEq(lidoFixedPriceMultiLpARM.totalAssets(), MIN_TOTAL_SUPPLY + amount * 2);
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY + amount * 2);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(lidoARM.feesAccrued(), 0); // No perfs so no fees
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + amount * 2);
+ assertEq(lidoARM.balanceOf(address(this)), shares * 2);
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY + amount * 2);
+ assertEq(lidoARM.totalAssets(), MIN_TOTAL_SUPPLY + amount * 2);
assertEq(liquidityProviderController.liquidityProviderCaps(address(this)), 0); // All the caps are used
assertEqQueueMetadata(0, 0, 0, 0);
assertEq(shares, amount); // No perfs, so 1 ether * totalSupply (1e18 + 1e12) / totalAssets (1e18 + 1e12) = 1 ether
@@ -202,42 +184,42 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_Deposit_Test_ is Fork_Shared_Tes
setTotalAssetsCap(DEFAULT_AMOUNT * 2 + MIN_TOTAL_SUPPLY)
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
setLiquidityProviderCap(alice, DEFAULT_AMOUNT)
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
{
uint256 amount = DEFAULT_AMOUNT;
// Assertions Before
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY + amount);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0); // No perfs so no fees
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + amount);
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(alice), 0);
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY + amount); // Minted to dead on deploy
- assertEq(lidoFixedPriceMultiLpARM.totalAssets(), MIN_TOTAL_SUPPLY + amount);
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY + amount);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(lidoARM.feesAccrued(), 0); // No perfs so no fees
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + amount);
+ assertEq(lidoARM.balanceOf(alice), 0);
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY + amount); // Minted to dead on deploy
+ assertEq(lidoARM.totalAssets(), MIN_TOTAL_SUPPLY + amount);
assertEq(liquidityProviderController.liquidityProviderCaps(alice), amount);
assertEqQueueMetadata(0, 0, 0, 0);
// Expected events
vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(alice, address(lidoFixedPriceMultiLpARM), amount);
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
+ emit IERC20.Transfer(alice, address(lidoARM), amount);
+ vm.expectEmit({emitter: address(lidoARM)});
emit IERC20.Transfer(address(0), alice, amount); // shares == amount here
vm.expectEmit({emitter: address(liquidityProviderController)});
emit LiquidityProviderController.LiquidityProviderCap(alice, 0);
vm.prank(alice);
// Main call
- uint256 shares = lidoFixedPriceMultiLpARM.deposit(amount);
+ uint256 shares = lidoARM.deposit(amount);
// Assertions After
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY + amount * 2);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0); // No perfs so no fees
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + amount * 2);
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(alice), shares);
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY + amount * 2);
- assertEq(lidoFixedPriceMultiLpARM.totalAssets(), MIN_TOTAL_SUPPLY + amount * 2);
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY + amount * 2);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(lidoARM.feesAccrued(), 0); // No perfs so no fees
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + amount * 2);
+ assertEq(lidoARM.balanceOf(alice), shares);
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY + amount * 2);
+ assertEq(lidoARM.totalAssets(), MIN_TOTAL_SUPPLY + amount * 2);
assertEq(liquidityProviderController.liquidityProviderCaps(alice), 0); // All the caps are used
assertEqQueueMetadata(0, 0, 0, 0);
assertEq(shares, amount); // No perfs, so 1 ether * totalSupply (1e18 + 1e12) / totalAssets (1e18 + 1e12) = 1 ether
@@ -251,59 +233,55 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_Deposit_Test_ is Fork_Shared_Tes
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
{
// simulate asset gain
- uint256 balanceBefore = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 balanceBefore = weth.balanceOf(address(lidoARM));
uint256 assetGain = DEFAULT_AMOUNT;
- deal(address(weth), address(lidoFixedPriceMultiLpARM), balanceBefore + assetGain);
+ deal(address(weth), address(lidoARM), balanceBefore + assetGain);
// Assertions Before
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY + assetGain);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0, "Outstanding ether before");
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0, "fee accrued before"); // No perfs so no fees
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY, "last total assets before");
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(address(this)), 0, "user shares before"); // Ensure no shares before
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY, "Total supply before"); // Minted to dead on deploy
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY + assetGain);
+ assertEq(lidoARM.outstandingEther(), 0, "Outstanding ether before");
+ assertEq(lidoARM.feesAccrued(), 0, "fee accrued before"); // No perfs so no fees
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY, "last total assets before");
+ assertEq(lidoARM.balanceOf(address(this)), 0, "user shares before"); // Ensure no shares before
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY, "Total supply before"); // Minted to dead on deploy
// 80% of the asset gain goes to the total assets
- assertEq(lidoFixedPriceMultiLpARM.totalAssets(), balanceBefore + assetGain * 80 / 100, "Total assets before");
+ assertEq(lidoARM.totalAssets(), balanceBefore + assetGain * 80 / 100, "Total assets before");
assertEq(liquidityProviderController.liquidityProviderCaps(address(this)), DEFAULT_AMOUNT, "lp cap before");
assertEqQueueMetadata(0, 0, 0, 0);
// 20% of the asset gain goes to the performance fees
uint256 feesAccrued = assetGain * 20 / 100;
- uint256 rawTotalAsset = weth.balanceOf(address(lidoFixedPriceMultiLpARM)) - feesAccrued; // No steth and no externalWithdrawQueue
+ uint256 rawTotalAsset = weth.balanceOf(address(lidoARM)) - feesAccrued; // No steth and no externalWithdrawQueue
uint256 depositedAssets = DEFAULT_AMOUNT;
uint256 expectedShares = depositedAssets * MIN_TOTAL_SUPPLY / rawTotalAsset;
// Expected events
vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(address(this), address(lidoFixedPriceMultiLpARM), depositedAssets);
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
+ emit IERC20.Transfer(address(this), address(lidoARM), depositedAssets);
+ vm.expectEmit({emitter: address(lidoARM)});
emit IERC20.Transfer(address(0), address(this), expectedShares);
vm.expectEmit({emitter: address(liquidityProviderController)});
emit LiquidityProviderController.LiquidityProviderCap(address(this), 0);
// deposit assets
- uint256 shares = lidoFixedPriceMultiLpARM.deposit(depositedAssets);
+ uint256 shares = lidoARM.deposit(depositedAssets);
assertEq(shares, expectedShares, "minted shares");
// No perfs, so 1 ether * totalSupply (1e12) / totalAssets (1e12) = 1 ether
// Assertions After
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0, "stETH balance after");
+ assertEq(steth.balanceOf(address(lidoARM)), 0, "stETH balance after");
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY + assetGain + depositedAssets, "WETH balance after");
+ assertEq(lidoARM.outstandingEther(), 0, "Outstanding ether after");
+ assertEq(lidoARM.feesAccrued(), feesAccrued, "fees accrued after"); // No perfs so no fees
assertEq(
- weth.balanceOf(address(lidoFixedPriceMultiLpARM)),
- MIN_TOTAL_SUPPLY + assetGain + depositedAssets,
- "WETH balance after"
- );
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0, "Outstanding ether after");
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), feesAccrued, "fees accrued after"); // No perfs so no fees
- assertEq(
- lidoFixedPriceMultiLpARM.lastTotalAssets(),
+ lidoARM.lastTotalAssets(),
MIN_TOTAL_SUPPLY + (assetGain * 80 / 100) + depositedAssets,
"last total assets after"
);
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(address(this)), expectedShares, "user shares after");
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY + expectedShares, "total supply after");
+ assertEq(lidoARM.balanceOf(address(this)), expectedShares, "user shares after");
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY + expectedShares, "total supply after");
assertEq(liquidityProviderController.liquidityProviderCaps(address(this)), 0, "lp cap after"); // All the caps are used
assertEqQueueMetadata(0, 0, 0, 0);
}
@@ -315,32 +293,30 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_Deposit_Test_ is Fork_Shared_Tes
setTotalAssetsCap(DEFAULT_AMOUNT * 3 + MIN_TOTAL_SUPPLY)
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
setLiquidityProviderCap(alice, DEFAULT_AMOUNT * 5)
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
{
// set stETH/WETH buy price to 1
- lidoFixedPriceMultiLpARM.setPrices(1e36, 1e36 + 1);
+ lidoARM.setPrices(1e36, 1e36 + 1);
// User Swap stETH for 3/4 of WETH in the ARM
deal(address(steth), address(this), DEFAULT_AMOUNT);
- lidoFixedPriceMultiLpARM.swapTokensForExactTokens(
- steth, weth, 3 * DEFAULT_AMOUNT / 4, DEFAULT_AMOUNT, address(this)
- );
+ lidoARM.swapTokensForExactTokens(steth, weth, 3 * DEFAULT_AMOUNT / 4, DEFAULT_AMOUNT, address(this));
// First user requests a full withdrawal
- uint256 firstUserShares = lidoFixedPriceMultiLpARM.balanceOf(address(this));
- lidoFixedPriceMultiLpARM.requestRedeem(firstUserShares);
+ uint256 firstUserShares = lidoARM.balanceOf(address(this));
+ lidoARM.requestRedeem(firstUserShares);
// Assertions Before
uint256 stethBalanceBefore = 3 * DEFAULT_AMOUNT / 4;
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), stethBalanceBefore, "stETH ARM balance before");
+ assertEq(steth.balanceOf(address(lidoARM)), stethBalanceBefore, "stETH ARM balance before");
uint256 wethBalanceBefore = MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT - 3 * DEFAULT_AMOUNT / 4;
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), wethBalanceBefore, "WETH ARM balance before");
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0, "Outstanding ether before");
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0, "Fees accrued before");
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY, "last total assets before");
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(alice), 0, "alice shares before");
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY, "total supply before");
- assertEq(lidoFixedPriceMultiLpARM.totalAssets(), MIN_TOTAL_SUPPLY, "total assets before");
+ assertEq(weth.balanceOf(address(lidoARM)), wethBalanceBefore, "WETH ARM balance before");
+ assertEq(lidoARM.outstandingEther(), 0, "Outstanding ether before");
+ assertEq(lidoARM.feesAccrued(), 0, "Fees accrued before");
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY, "last total assets before");
+ assertEq(lidoARM.balanceOf(alice), 0, "alice shares before");
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY, "total supply before");
+ assertEq(lidoARM.totalAssets(), MIN_TOTAL_SUPPLY, "total assets before");
assertEq(liquidityProviderController.liquidityProviderCaps(alice), DEFAULT_AMOUNT * 5, "lp cap before");
assertEqQueueMetadata(DEFAULT_AMOUNT, 0, 0, 1);
@@ -348,27 +324,25 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_Deposit_Test_ is Fork_Shared_Tes
// Expected events
vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(alice, address(lidoFixedPriceMultiLpARM), amount);
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
+ emit IERC20.Transfer(alice, address(lidoARM), amount);
+ vm.expectEmit({emitter: address(lidoARM)});
emit IERC20.Transfer(address(0), alice, amount); // shares == amount here
vm.expectEmit({emitter: address(liquidityProviderController)});
emit LiquidityProviderController.LiquidityProviderCap(alice, DEFAULT_AMOUNT * 3);
vm.prank(alice);
// Main call
- uint256 shares = lidoFixedPriceMultiLpARM.deposit(amount);
+ uint256 shares = lidoARM.deposit(amount);
// Assertions After
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), stethBalanceBefore, "stETH ARM balance after");
- assertEq(
- weth.balanceOf(address(lidoFixedPriceMultiLpARM)), wethBalanceBefore + amount, "WETH ARM balance after"
- );
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0, "Outstanding ether after");
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0, "Fees accrued after"); // No perfs so no fees
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + amount, "last total assets after");
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(alice), shares, "alice shares after");
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY + amount, "total supply after");
- assertEq(lidoFixedPriceMultiLpARM.totalAssets(), MIN_TOTAL_SUPPLY + amount, "total assets after");
+ assertEq(steth.balanceOf(address(lidoARM)), stethBalanceBefore, "stETH ARM balance after");
+ assertEq(weth.balanceOf(address(lidoARM)), wethBalanceBefore + amount, "WETH ARM balance after");
+ assertEq(lidoARM.outstandingEther(), 0, "Outstanding ether after");
+ assertEq(lidoARM.feesAccrued(), 0, "Fees accrued after"); // No perfs so no fees
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + amount, "last total assets after");
+ assertEq(lidoARM.balanceOf(alice), shares, "alice shares after");
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY + amount, "total supply after");
+ assertEq(lidoARM.totalAssets(), MIN_TOTAL_SUPPLY + amount, "total assets after");
assertEq(liquidityProviderController.liquidityProviderCaps(alice), DEFAULT_AMOUNT * 3, "alice cap after"); // All the caps are used
// withdrawal request is now claimable
assertEqQueueMetadata(DEFAULT_AMOUNT, 0, 0, 1);
diff --git a/test/fork/LidoFixedPriceMultiLpARM/RequestRedeem.t.sol b/test/fork/LidoFixedPriceMultiLpARM/RequestRedeem.t.sol
index 4e8ff32..dc5b949 100644
--- a/test/fork/LidoFixedPriceMultiLpARM/RequestRedeem.t.sol
+++ b/test/fork/LidoFixedPriceMultiLpARM/RequestRedeem.t.sol
@@ -6,10 +6,9 @@ import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
// Contracts
import {IERC20} from "contracts/Interfaces.sol";
-import {MultiLP} from "contracts/MultiLP.sol";
-import {PerformanceFee} from "contracts/PerformanceFee.sol";
+import {AbstractARM} from "contracts/AbstractARM.sol";
-contract Fork_Concrete_LidoFixedPriceMultiLpARM_RequestRedeem_Test_ is Fork_Shared_Test_ {
+contract Fork_Concrete_LidoARM_RequestRedeem_Test_ is Fork_Shared_Test_ {
//////////////////////////////////////////////////////
/// --- SETUP
//////////////////////////////////////////////////////
@@ -27,40 +26,40 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_RequestRedeem_Test_ is Fork_Shar
public
setTotalAssetsCap(DEFAULT_AMOUNT + MIN_TOTAL_SUPPLY)
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
{
// Assertions Before
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0); // No perfs so no fees
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(address(this)), DEFAULT_AMOUNT);
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(lidoARM.feesAccrued(), 0); // No perfs so no fees
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
+ assertEq(lidoARM.balanceOf(address(this)), DEFAULT_AMOUNT);
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
assertEq(liquidityProviderController.liquidityProviderCaps(address(this)), 0);
assertEqQueueMetadata(0, 0, 0, 0);
- uint256 delay = lidoFixedPriceMultiLpARM.CLAIM_DELAY();
+ uint256 delay = lidoARM.CLAIM_DELAY();
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
+ vm.expectEmit({emitter: address(lidoARM)});
emit IERC20.Transfer(address(this), address(0), DEFAULT_AMOUNT);
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
- emit MultiLP.RedeemRequested(address(this), 0, DEFAULT_AMOUNT, DEFAULT_AMOUNT, block.timestamp + delay);
+ vm.expectEmit({emitter: address(lidoARM)});
+ emit AbstractARM.RedeemRequested(address(this), 0, DEFAULT_AMOUNT, DEFAULT_AMOUNT, block.timestamp + delay);
// Main Call
- (uint256 requestId, uint256 assets) = lidoFixedPriceMultiLpARM.requestRedeem(DEFAULT_AMOUNT);
+ (uint256 requestId, uint256 assets) = lidoARM.requestRedeem(DEFAULT_AMOUNT);
// Assertions After
assertEq(requestId, 0); // First request
assertEqQueueMetadata(DEFAULT_AMOUNT, 0, 0, 1); // One request in the queue
assertEqUserRequest(0, address(this), false, block.timestamp + delay, DEFAULT_AMOUNT, DEFAULT_AMOUNT); // Requested the full amount
assertEq(assets, DEFAULT_AMOUNT, "Wrong amount of assets"); // As no profits, assets returned are the same as deposited
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0); // No perfs so no fees
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY);
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(address(this)), 0);
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY);
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(lidoARM.feesAccrued(), 0); // No perfs so no fees
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY);
+ assertEq(lidoARM.balanceOf(address(this)), 0);
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY);
assertEq(liquidityProviderController.liquidityProviderCaps(address(this)), 0);
}
@@ -69,30 +68,30 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_RequestRedeem_Test_ is Fork_Shar
public
setTotalAssetsCap(DEFAULT_AMOUNT + MIN_TOTAL_SUPPLY)
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
- requestRedeemFromLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT / 4)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
+ requestRedeemFromLidoARM(address(this), DEFAULT_AMOUNT / 4)
{
// Assertions Before
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0); // No perfs so no fees
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT * 3 / 4);
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(address(this)), DEFAULT_AMOUNT * 3 / 4);
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT * 3 / 4);
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(lidoARM.feesAccrued(), 0); // No perfs so no fees
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT * 3 / 4);
+ assertEq(lidoARM.balanceOf(address(this)), DEFAULT_AMOUNT * 3 / 4);
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT * 3 / 4);
assertEq(liquidityProviderController.liquidityProviderCaps(address(this)), 0); // Down only
assertEqQueueMetadata(DEFAULT_AMOUNT / 4, 0, 0, 1);
- uint256 delay = lidoFixedPriceMultiLpARM.CLAIM_DELAY();
+ uint256 delay = lidoARM.CLAIM_DELAY();
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
+ vm.expectEmit({emitter: address(lidoARM)});
emit IERC20.Transfer(address(this), address(0), DEFAULT_AMOUNT / 2);
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
- emit MultiLP.RedeemRequested(
+ vm.expectEmit({emitter: address(lidoARM)});
+ emit AbstractARM.RedeemRequested(
address(this), 1, DEFAULT_AMOUNT / 2, DEFAULT_AMOUNT * 3 / 4, block.timestamp + delay
);
// Main Call
- (uint256 requestId, uint256 assets) = lidoFixedPriceMultiLpARM.requestRedeem(DEFAULT_AMOUNT / 2);
+ (uint256 requestId, uint256 assets) = lidoARM.requestRedeem(DEFAULT_AMOUNT / 2);
// Assertions After
assertEq(requestId, 1); // Second request
@@ -101,13 +100,13 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_RequestRedeem_Test_ is Fork_Shar
1, address(this), false, block.timestamp + delay, DEFAULT_AMOUNT / 2, DEFAULT_AMOUNT * 3 / 4
);
assertEq(assets, DEFAULT_AMOUNT / 2, "Wrong amount of assets"); // As no profits, assets returned are the same as deposited
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), 0); // No perfs so no fees
- assertEq(lidoFixedPriceMultiLpARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT * 1 / 4);
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(address(this)), DEFAULT_AMOUNT * 1 / 4);
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT * 1 / 4);
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(lidoARM.feesAccrued(), 0); // No perfs so no fees
+ assertEq(lidoARM.lastTotalAssets(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT * 1 / 4);
+ assertEq(lidoARM.balanceOf(address(this)), DEFAULT_AMOUNT * 1 / 4);
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT * 1 / 4);
assertEq(liquidityProviderController.liquidityProviderCaps(address(this)), 0); // Down only
}
@@ -116,41 +115,37 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_RequestRedeem_Test_ is Fork_Shar
public
setTotalAssetsCap(DEFAULT_AMOUNT + MIN_TOTAL_SUPPLY)
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
{
// Assertions Before
// Not needed as the same as in `test_RequestRedeem_AfterFirstDeposit_NoPerfs_EmptyWithdrawQueue`
// Simulate assets gain in ARM
uint256 assetsGain = DEFAULT_AMOUNT;
- deal(
- address(weth),
- address(lidoFixedPriceMultiLpARM),
- weth.balanceOf(address(lidoFixedPriceMultiLpARM)) + assetsGain
- );
+ deal(address(weth), address(lidoARM), weth.balanceOf(address(lidoARM)) + assetsGain);
// Calculate expected values
uint256 feeAccrued = assetsGain * 20 / 100; // 20% fee
- uint256 totalAsset = weth.balanceOf(address(lidoFixedPriceMultiLpARM)) - feeAccrued;
+ uint256 totalAsset = weth.balanceOf(address(lidoARM)) - feeAccrued;
uint256 expectedAssets = DEFAULT_AMOUNT * totalAsset / (MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
uint256 expectedAssetsDead = MIN_TOTAL_SUPPLY * totalAsset / (MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
- emit PerformanceFee.FeeCalculated(feeAccrued, assetsGain);
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
+ vm.expectEmit({emitter: address(lidoARM)});
+ emit AbstractARM.FeeCalculated(feeAccrued, assetsGain);
+ vm.expectEmit({emitter: address(lidoARM)});
emit IERC20.Transfer(address(this), address(0), DEFAULT_AMOUNT);
// Main call
- lidoFixedPriceMultiLpARM.requestRedeem(DEFAULT_AMOUNT);
+ lidoARM.requestRedeem(DEFAULT_AMOUNT);
- uint256 delay = lidoFixedPriceMultiLpARM.CLAIM_DELAY();
+ uint256 delay = lidoARM.CLAIM_DELAY();
// Assertions After
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT * 2); // +perfs
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), feeAccrued);
- assertApproxEqAbs(lidoFixedPriceMultiLpARM.lastTotalAssets(), expectedAssetsDead, 1); // 1 wei of error
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(address(this)), 0);
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY);
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT * 2); // +perfs
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(lidoARM.feesAccrued(), feeAccrued);
+ assertApproxEqAbs(lidoARM.lastTotalAssets(), expectedAssetsDead, 1); // 1 wei of error
+ assertEq(lidoARM.balanceOf(address(this)), 0);
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY);
assertEq(liquidityProviderController.liquidityProviderCaps(address(this)), 0);
assertEqQueueMetadata(expectedAssets, 0, 0, 1);
assertEqUserRequest(0, address(this), false, block.timestamp + delay, expectedAssets, expectedAssets);
@@ -161,39 +156,35 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_RequestRedeem_Test_ is Fork_Shar
public
setTotalAssetsCap(DEFAULT_AMOUNT + MIN_TOTAL_SUPPLY)
setLiquidityProviderCap(address(this), DEFAULT_AMOUNT)
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
{
// Assertions Before
// Not needed as the same as in `test_RequestRedeem_AfterFirstDeposit_NoPerfs_EmptyWithdrawQueue`
// Simulate assets loss in ARM
uint256 assetsLoss = DEFAULT_AMOUNT / 10; // 0.1 ether of loss
- deal(
- address(weth),
- address(lidoFixedPriceMultiLpARM),
- weth.balanceOf(address(lidoFixedPriceMultiLpARM)) - assetsLoss
- );
+ deal(address(weth), address(lidoARM), weth.balanceOf(address(lidoARM)) - assetsLoss);
// Calculate expected values
uint256 feeAccrued = 0; // No profits
- uint256 totalAsset = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 totalAsset = weth.balanceOf(address(lidoARM));
uint256 expectedAssets = DEFAULT_AMOUNT * totalAsset / (MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
uint256 expectedAssetsDead = MIN_TOTAL_SUPPLY * totalAsset / (MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
+ vm.expectEmit({emitter: address(lidoARM)});
emit IERC20.Transfer(address(this), address(0), DEFAULT_AMOUNT);
// Main call
- lidoFixedPriceMultiLpARM.requestRedeem(DEFAULT_AMOUNT);
+ lidoARM.requestRedeem(DEFAULT_AMOUNT);
- uint256 delay = lidoFixedPriceMultiLpARM.CLAIM_DELAY();
+ uint256 delay = lidoARM.CLAIM_DELAY();
// Assertions After
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
- assertEq(weth.balanceOf(address(lidoFixedPriceMultiLpARM)), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT - assetsLoss);
- assertEq(lidoFixedPriceMultiLpARM.outstandingEther(), 0);
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), feeAccrued);
- assertApproxEqAbs(lidoFixedPriceMultiLpARM.lastTotalAssets(), expectedAssetsDead, 1); // 1 wei of error
- assertEq(lidoFixedPriceMultiLpARM.balanceOf(address(this)), 0);
- assertEq(lidoFixedPriceMultiLpARM.totalSupply(), MIN_TOTAL_SUPPLY);
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
+ assertEq(weth.balanceOf(address(lidoARM)), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT - assetsLoss);
+ assertEq(lidoARM.outstandingEther(), 0);
+ assertEq(lidoARM.feesAccrued(), feeAccrued);
+ assertApproxEqAbs(lidoARM.lastTotalAssets(), expectedAssetsDead, 1); // 1 wei of error
+ assertEq(lidoARM.balanceOf(address(this)), 0);
+ assertEq(lidoARM.totalSupply(), MIN_TOTAL_SUPPLY);
assertEq(liquidityProviderController.liquidityProviderCaps(address(this)), 0);
assertEqQueueMetadata(expectedAssets, 0, 0, 1);
assertEqUserRequest(0, address(this), false, block.timestamp + delay, expectedAssets, expectedAssets);
diff --git a/test/fork/LidoFixedPriceMultiLpARM/RequestStETHWithdrawalForETH.t.sol b/test/fork/LidoFixedPriceMultiLpARM/RequestStETHWithdrawalForETH.t.sol
index 1b3c259..8a4d896 100644
--- a/test/fork/LidoFixedPriceMultiLpARM/RequestStETHWithdrawalForETH.t.sol
+++ b/test/fork/LidoFixedPriceMultiLpARM/RequestStETHWithdrawalForETH.t.sol
@@ -7,14 +7,14 @@ import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
// Contracts
import {IERC20} from "contracts/Interfaces.sol";
-contract Fork_Concrete_LidoFixedPriceMultiLpARM_RequestStETHWithdrawalForETH_Test_ is Fork_Shared_Test_ {
+contract Fork_Concrete_LidoARM_RequestStETHWithdrawalForETH_Test_ is Fork_Shared_Test_ {
//////////////////////////////////////////////////////
/// --- SETUP
//////////////////////////////////////////////////////
function setUp() public override {
super.setUp();
- deal(address(steth), address(lidoFixedPriceMultiLpARM), 10_000 ether);
+ deal(address(steth), address(lidoARM), 10_000 ether);
}
//////////////////////////////////////////////////////
@@ -22,59 +22,46 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_RequestStETHWithdrawalForETH_Tes
//////////////////////////////////////////////////////
function test_RevertWhen_RequestStETHWithdrawalForETH_NotOperator() public asRandomAddress {
vm.expectRevert("ARM: Only operator or owner can call this function.");
- lidoFixedPriceMultiLpARM.requestStETHWithdrawalForETH(new uint256[](0));
- }
-
- function test_RevertWhen_RequestStETHWithdrawalForETH_Because_AllowanceExceeded()
- public
- asLidoFixedPriceMulltiLpARMOperator
- {
- uint256[] memory amounts = new uint256[](1);
- amounts[0] = DEFAULT_AMOUNT;
-
- vm.expectRevert("ALLOWANCE_EXCEEDED");
- lidoFixedPriceMultiLpARM.requestStETHWithdrawalForETH(amounts);
+ lidoARM.requestStETHWithdrawalForETH(new uint256[](0));
}
function test_RevertWhen_RequestStETHWithdrawalForETH_Because_BalanceExceeded()
public
asLidoFixedPriceMulltiLpARMOperator
- approveStETHOnLidoFixedPriceMultiLpARM
+ approveStETHOnLidoARM
{
// Remove all stETH from the contract
- deal(address(steth), address(lidoFixedPriceMultiLpARM), 0);
+ deal(address(steth), address(lidoARM), 0);
uint256[] memory amounts = new uint256[](1);
amounts[0] = DEFAULT_AMOUNT;
vm.expectRevert("BALANCE_EXCEEDED");
- lidoFixedPriceMultiLpARM.requestStETHWithdrawalForETH(amounts);
+ lidoARM.requestStETHWithdrawalForETH(amounts);
}
//////////////////////////////////////////////////////
/// --- PASSING TESTS
//////////////////////////////////////////////////////
function test_RequestStETHWithdrawalForETH_EmptyList() public asLidoFixedPriceMulltiLpARMOperator {
- uint256[] memory requestIds = lidoFixedPriceMultiLpARM.requestStETHWithdrawalForETH(new uint256[](0));
+ uint256[] memory requestIds = lidoARM.requestStETHWithdrawalForETH(new uint256[](0));
assertEq(requestIds.length, 0);
}
function test_RequestStETHWithdrawalForETH_SingleAmount_1ether()
public
asLidoFixedPriceMulltiLpARMOperator
- approveStETHOnLidoFixedPriceMultiLpARM
+ approveStETHOnLidoARM
{
uint256[] memory amounts = new uint256[](1);
amounts[0] = DEFAULT_AMOUNT;
// Expected events
vm.expectEmit({emitter: address(steth)});
- emit IERC20.Transfer(
- address(lidoFixedPriceMultiLpARM), address(lidoFixedPriceMultiLpARM.withdrawalQueue()), amounts[0]
- );
+ emit IERC20.Transfer(address(lidoARM), address(lidoARM.withdrawalQueue()), amounts[0]);
// Main call
- uint256[] memory requestIds = lidoFixedPriceMultiLpARM.requestStETHWithdrawalForETH(amounts);
+ uint256[] memory requestIds = lidoARM.requestStETHWithdrawalForETH(amounts);
assertEq(requestIds.length, 1);
assertGt(requestIds[0], 0);
@@ -83,19 +70,17 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_RequestStETHWithdrawalForETH_Tes
function test_RequestStETHWithdrawalForETH_SingleAmount_1000ethers()
public
asLidoFixedPriceMulltiLpARMOperator
- approveStETHOnLidoFixedPriceMultiLpARM
+ approveStETHOnLidoARM
{
uint256[] memory amounts = new uint256[](1);
amounts[0] = 1_000 ether;
// Expected events
vm.expectEmit({emitter: address(steth)});
- emit IERC20.Transfer(
- address(lidoFixedPriceMultiLpARM), address(lidoFixedPriceMultiLpARM.withdrawalQueue()), amounts[0]
- );
+ emit IERC20.Transfer(address(lidoARM), address(lidoARM.withdrawalQueue()), amounts[0]);
// Main call
- uint256[] memory requestIds = lidoFixedPriceMultiLpARM.requestStETHWithdrawalForETH(amounts);
+ uint256[] memory requestIds = lidoARM.requestStETHWithdrawalForETH(amounts);
assertEq(requestIds.length, 1);
assertGt(requestIds[0], 0);
@@ -104,7 +89,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_RequestStETHWithdrawalForETH_Tes
function test_RequestStETHWithdrawalForETH_MultipleAmount()
public
asLidoFixedPriceMulltiLpARMOperator
- approveStETHOnLidoFixedPriceMultiLpARM
+ approveStETHOnLidoARM
{
uint256 length = _bound(vm.randomUint(), 2, 10);
uint256[] memory amounts = new uint256[](length);
@@ -113,7 +98,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_RequestStETHWithdrawalForETH_Tes
}
// Main call
- uint256[] memory requestIds = lidoFixedPriceMultiLpARM.requestStETHWithdrawalForETH(amounts);
+ uint256[] memory requestIds = lidoARM.requestStETHWithdrawalForETH(amounts);
uint256 initialRequestId = requestIds[0];
assertGt(initialRequestId, 0);
diff --git a/test/fork/LidoFixedPriceMultiLpARM/Setters.t.sol b/test/fork/LidoFixedPriceMultiLpARM/Setters.t.sol
index 1881d65..4cf049c 100644
--- a/test/fork/LidoFixedPriceMultiLpARM/Setters.t.sol
+++ b/test/fork/LidoFixedPriceMultiLpARM/Setters.t.sol
@@ -6,11 +6,9 @@ import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
// Contracts
import {IERC20} from "contracts/Interfaces.sol";
-import {MultiLP} from "contracts/MultiLP.sol";
-import {PerformanceFee} from "contracts/PerformanceFee.sol";
-import {LiquidityProviderControllerARM} from "contracts/LiquidityProviderControllerARM.sol";
+import {AbstractARM} from "contracts/AbstractARM.sol";
-contract Fork_Concrete_lidoFixedPriceMulltiLpARM_Setters_Test_ is Fork_Shared_Test_ {
+contract Fork_Concrete_lidoARM_Setters_Test_ is Fork_Shared_Test_ {
//////////////////////////////////////////////////////
/// --- SETUP
//////////////////////////////////////////////////////
@@ -23,55 +21,52 @@ contract Fork_Concrete_lidoFixedPriceMulltiLpARM_Setters_Test_ is Fork_Shared_Te
//////////////////////////////////////////////////////
function test_RevertWhen_PerformanceFee_SetFee_Because_NotOwner() public asRandomAddress {
vm.expectRevert("ARM: Only owner can call this function.");
- lidoFixedPriceMultiLpARM.setFee(0);
+ lidoARM.setFee(0);
}
- function test_RevertWhen_PerformanceFee_SetFee_Because_FeeIsTooHigh() public asLidoFixedPriceMultiLpARMOwner {
- uint256 max = lidoFixedPriceMultiLpARM.FEE_SCALE();
+ function test_RevertWhen_PerformanceFee_SetFee_Because_FeeIsTooHigh() public asLidoARMOwner {
+ uint256 max = lidoARM.FEE_SCALE();
vm.expectRevert("ARM: fee too high");
- lidoFixedPriceMultiLpARM.setFee(max + 1);
+ lidoARM.setFee(max + 1);
}
function test_RevertWhen_PerformanceFee_SetFeeCollector_Because_NotOwner() public asRandomAddress {
vm.expectRevert("ARM: Only owner can call this function.");
- lidoFixedPriceMultiLpARM.setFeeCollector(address(0));
+ lidoARM.setFeeCollector(address(0));
}
- function test_RevertWhen_PerformanceFee_SetFeeCollector_Because_FeeCollectorIsZero()
- public
- asLidoFixedPriceMultiLpARMOwner
- {
+ function test_RevertWhen_PerformanceFee_SetFeeCollector_Because_FeeCollectorIsZero() public asLidoARMOwner {
vm.expectRevert("ARM: invalid fee collector");
- lidoFixedPriceMultiLpARM.setFeeCollector(address(0));
+ lidoARM.setFeeCollector(address(0));
}
//////////////////////////////////////////////////////
/// --- PERFORMANCE FEE - PASSING TEST
//////////////////////////////////////////////////////
- function test_PerformanceFee_SetFee_() public asLidoFixedPriceMultiLpARMOwner {
- uint256 feeBefore = lidoFixedPriceMultiLpARM.fee();
+ function test_PerformanceFee_SetFee_() public asLidoARMOwner {
+ uint256 feeBefore = lidoARM.fee();
- uint256 newFee = _bound(vm.randomUint(), 0, lidoFixedPriceMultiLpARM.FEE_SCALE());
+ uint256 newFee = _bound(vm.randomUint(), 0, lidoARM.FEE_SCALE());
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
- emit PerformanceFee.FeeUpdated(newFee);
- lidoFixedPriceMultiLpARM.setFee(newFee);
+ vm.expectEmit({emitter: address(lidoARM)});
+ emit AbstractARM.FeeUpdated(newFee);
+ lidoARM.setFee(newFee);
- assertEq(lidoFixedPriceMultiLpARM.fee(), newFee);
- assertNotEq(feeBefore, lidoFixedPriceMultiLpARM.fee());
+ assertEq(lidoARM.fee(), newFee);
+ assertNotEq(feeBefore, lidoARM.fee());
}
- function test_PerformanceFee_SetFeeCollector() public asLidoFixedPriceMultiLpARMOwner {
- address feeCollectorBefore = lidoFixedPriceMultiLpARM.feeCollector();
+ function test_PerformanceFee_SetFeeCollector() public asLidoARMOwner {
+ address feeCollectorBefore = lidoARM.feeCollector();
address newFeeCollector = vm.randomAddress();
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
- emit PerformanceFee.FeeCollectorUpdated(newFeeCollector);
- lidoFixedPriceMultiLpARM.setFeeCollector(newFeeCollector);
+ vm.expectEmit({emitter: address(lidoARM)});
+ emit AbstractARM.FeeCollectorUpdated(newFeeCollector);
+ lidoARM.setFeeCollector(newFeeCollector);
- assertEq(lidoFixedPriceMultiLpARM.feeCollector(), newFeeCollector);
- assertNotEq(feeCollectorBefore, lidoFixedPriceMultiLpARM.feeCollector());
+ assertEq(lidoARM.feeCollector(), newFeeCollector);
+ assertNotEq(feeCollectorBefore, lidoARM.feeCollector());
}
//////////////////////////////////////////////////////
@@ -79,46 +74,46 @@ contract Fork_Concrete_lidoFixedPriceMulltiLpARM_Setters_Test_ is Fork_Shared_Te
//////////////////////////////////////////////////////
function test_RevertWhen_SetPrices_Because_PriceCross() public {
vm.expectRevert("ARM: Price cross");
- lidoFixedPriceMultiLpARM.setPrices(90 * 1e33, 89 * 1e33);
+ lidoARM.setPrices(90 * 1e33, 89 * 1e33);
vm.expectRevert("ARM: Price cross");
- lidoFixedPriceMultiLpARM.setPrices(72, 70);
+ lidoARM.setPrices(72, 70);
vm.expectRevert("ARM: Price cross");
- lidoFixedPriceMultiLpARM.setPrices(1005 * 1e33, 1000 * 1e33);
+ lidoARM.setPrices(1005 * 1e33, 1000 * 1e33);
// Both set to 1.0
vm.expectRevert("ARM: Price cross");
- lidoFixedPriceMultiLpARM.setPrices(1e36, 1e36);
+ lidoARM.setPrices(1e36, 1e36);
}
function test_RevertWhen_FixedPriceARM_SetPrices_Because_PriceRange() public asLidoFixedPriceMulltiLpARMOperator {
// buy price 11 basis points higher than 1.0
vm.expectRevert("ARM: buy price too high");
- lidoFixedPriceMultiLpARM.setPrices(10011e32, 10020e32);
+ lidoARM.setPrices(1.0011 * 1e36, 1.002 * 1e36);
// sell price 11 basis points lower than 1.0
vm.expectRevert("ARM: sell price too low");
- lidoFixedPriceMultiLpARM.setPrices(9980e32, 9989e32);
+ lidoARM.setPrices(0.998 * 1e36, 0.9989 * 1e36);
// Forgot to scale up to 36 decimals
vm.expectRevert("ARM: sell price too low");
- lidoFixedPriceMultiLpARM.setPrices(1e18, 1e18);
+ lidoARM.setPrices(1e18, 1e18);
}
function test_RevertWhen_FixedPriceARM_SetPrices_Because_NotOwnerOrOperator() public asRandomAddress {
vm.expectRevert("ARM: Only operator or owner can call this function.");
- lidoFixedPriceMultiLpARM.setPrices(0, 0);
+ lidoARM.setPrices(0, 0);
}
- function test_SellPriceCannotCrossOne() public asLidoFixedPriceMulltiLpARMOperator {
+ function test_SellPriceCannotCrossOneByMoreThanTenBps() public asLidoFixedPriceMulltiLpARMOperator {
vm.expectRevert("ARM: sell price too low");
- lidoFixedPriceMulltiLpARM.setPrices(0.9997 * 1e36, 0.99999 * 1e36);
+ lidoARM.setPrices(0.998 * 1e36, 0.9989 * 1e36);
}
- function test_BuyPriceCannotCrossOne() public asLidoFixedPriceMulltiLpARMOperator {
+ function test_BuyPriceCannotCrossOneByMoreThanTenBps() public asLidoFixedPriceMulltiLpARMOperator {
vm.expectRevert("ARM: buy price too high");
- lidoFixedPriceMulltiLpARM.setPrices(1.0 * 1e36, 1.0001 * 1e36);
+ lidoARM.setPrices(1.0011 * 1e36, 1.002 * 1e36);
}
//////////////////////////////////////////////////////
@@ -126,27 +121,27 @@ contract Fork_Concrete_lidoFixedPriceMulltiLpARM_Setters_Test_ is Fork_Shared_Te
//////////////////////////////////////////////////////
function test_FixedPriceARM_SetPrices_Operator() public asLidoFixedPriceMulltiLpARMOperator {
// buy price 10 basis points higher than 1.0
- lidoFixedPriceMultiLpARM.setPrices(1001e33, 1002e33);
+ lidoARM.setPrices(1001e33, 1002e33);
// sell price 10 basis points lower than 1.0
- lidoFixedPriceMultiLpARM.setPrices(9980e32, 9991e32);
+ lidoARM.setPrices(9980e32, 9991e32);
// 2% of one basis point spread
- lidoFixedPriceMultiLpARM.setPrices(999999e30, 1000001e30);
+ lidoARM.setPrices(999999e30, 1000001e30);
- lidoFixedPriceMultiLpARM.setPrices(992 * 1e33, 1001 * 1e33);
- lidoFixedPriceMultiLpARM.setPrices(1001 * 1e33, 1004 * 1e33);
- lidoFixedPriceMultiLpARM.setPrices(992 * 1e33, 2000 * 1e33);
+ lidoARM.setPrices(992 * 1e33, 1001 * 1e33);
+ lidoARM.setPrices(1001 * 1e33, 1004 * 1e33);
+ lidoARM.setPrices(992 * 1e33, 2000 * 1e33);
// Check the traderates
- assertEq(lidoFixedPriceMultiLpARM.traderate0(), 500 * 1e33);
- assertEq(lidoFixedPriceMultiLpARM.traderate1(), 992 * 1e33);
+ assertEq(lidoARM.traderate0(), 500 * 1e33);
+ assertEq(lidoARM.traderate1(), 992 * 1e33);
}
function test_FixedPriceARM_SetPrices_Owner() public {
// buy price 11 basis points higher than 1.0
- lidoFixedPriceMultiLpARM.setPrices(10011e32, 10020e32);
+ lidoARM.setPrices(10011e32, 10020e32);
// sell price 11 basis points lower than 1.0
- lidoFixedPriceMultiLpARM.setPrices(9980e32, 9989e32);
+ lidoARM.setPrices(9980e32, 9989e32);
}
//////////////////////////////////////////////////////
@@ -154,12 +149,12 @@ contract Fork_Concrete_lidoFixedPriceMulltiLpARM_Setters_Test_ is Fork_Shared_Te
//////////////////////////////////////////////////////
function test_RevertWhen_Ownable_SetOwner_Because_NotOwner() public asRandomAddress {
vm.expectRevert("ARM: Only owner can call this function.");
- lidoFixedPriceMultiLpARM.setOwner(address(0));
+ lidoARM.setOwner(address(0));
}
function test_RevertWhen_Ownable_SetOperator_Because_NotOwner() public asRandomAddress {
vm.expectRevert("ARM: Only owner can call this function.");
- lidoFixedPriceMultiLpARM.setOperator(address(0));
+ lidoARM.setOperator(address(0));
}
//////////////////////////////////////////////////////
@@ -170,19 +165,19 @@ contract Fork_Concrete_lidoFixedPriceMulltiLpARM_Setters_Test_ is Fork_Shared_Te
asRandomAddress
{
vm.expectRevert("ARM: Only owner can call this function.");
- lidoFixedPriceMultiLpARM.setLiquidityProviderController(address(0));
+ lidoARM.setLiquidityProviderController(address(0));
}
//////////////////////////////////////////////////////
/// --- LIQUIIDITY PROVIDER CONTROLLER - PASSING TESTS
//////////////////////////////////////////////////////
- function test_LiquidityProviderController_SetLiquidityProvider() public asLidoFixedPriceMultiLpARMOwner {
+ function test_LiquidityProviderController_SetLiquidityProvider() public asLidoARMOwner {
address newLiquidityProviderController = vm.randomAddress();
- vm.expectEmit({emitter: address(lidoFixedPriceMultiLpARM)});
- emit LiquidityProviderControllerARM.LiquidityProviderControllerUpdated(newLiquidityProviderController);
- lidoFixedPriceMultiLpARM.setLiquidityProviderController(newLiquidityProviderController);
+ vm.expectEmit({emitter: address(lidoARM)});
+ emit AbstractARM.LiquidityProviderControllerUpdated(newLiquidityProviderController);
+ lidoARM.setLiquidityProviderController(newLiquidityProviderController);
- assertEq(lidoFixedPriceMultiLpARM.liquidityProviderController(), newLiquidityProviderController);
+ assertEq(lidoARM.liquidityProviderController(), newLiquidityProviderController);
}
}
diff --git a/test/fork/LidoFixedPriceMultiLpARM/SwapExactTokensForTokens.t.sol b/test/fork/LidoFixedPriceMultiLpARM/SwapExactTokensForTokens.t.sol
index 9f2f14b..219b322 100644
--- a/test/fork/LidoFixedPriceMultiLpARM/SwapExactTokensForTokens.t.sol
+++ b/test/fork/LidoFixedPriceMultiLpARM/SwapExactTokensForTokens.t.sol
@@ -6,7 +6,7 @@ import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
import {IERC20} from "contracts/Interfaces.sol";
-contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is Fork_Shared_Test_ {
+contract Fork_Concrete_LidoARM_SwapExactTokensForTokens_Test is Fork_Shared_Test_ {
//////////////////////////////////////////////////////
/// --- CONSTANTS
//////////////////////////////////////////////////////
@@ -26,17 +26,17 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
deal(address(weth), address(this), 1_000 ether);
deal(address(steth), address(this), 1_000 ether);
- deal(address(weth), address(lidoFixedPriceMultiLpARM), 1_000 ether);
- deal(address(steth), address(lidoFixedPriceMultiLpARM), 1_000 ether);
+ deal(address(weth), address(lidoARM), 1_000 ether);
+ deal(address(steth), address(lidoARM), 1_000 ether);
}
//////////////////////////////////////////////////////
/// --- REVERTING TESTS
//////////////////////////////////////////////////////
function test_RevertWhen_SwapExactTokensForTokens_Because_InvalidTokenOut1() public {
- lidoFixedPriceMultiLpARM.token0();
+ lidoARM.token0();
vm.expectRevert("ARM: Invalid out token");
- lidoFixedPriceMultiLpARM.swapExactTokensForTokens(
+ lidoARM.swapExactTokensForTokens(
steth, // inToken
badToken, // outToken
1, // amountIn
@@ -47,7 +47,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
function test_RevertWhen_SwapExactTokensForTokens_Because_InvalidTokenOut0() public {
vm.expectRevert("ARM: Invalid out token");
- lidoFixedPriceMultiLpARM.swapExactTokensForTokens(
+ lidoARM.swapExactTokensForTokens(
weth, // inToken
badToken, // outToken
1, // amountIn
@@ -58,7 +58,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
function test_RevertWhen_SwapExactTokensForTokens_Because_InvalidTokenIn() public {
vm.expectRevert("ARM: Invalid in token");
- lidoFixedPriceMultiLpARM.swapExactTokensForTokens(
+ lidoARM.swapExactTokensForTokens(
badToken, // inToken
steth, // outToken
1, // amountIn
@@ -69,7 +69,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
function test_RevertWhen_SwapExactTokensForTokens_Because_BothInvalidTokens() public {
vm.expectRevert("ARM: Invalid in token");
- lidoFixedPriceMultiLpARM.swapExactTokensForTokens(
+ lidoARM.swapExactTokensForTokens(
badToken, // inToken
badToken, // outToken
1, // amountIn
@@ -82,7 +82,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
uint256 initialBalance = weth.balanceOf(address(this));
vm.expectRevert();
- lidoFixedPriceMultiLpARM.swapExactTokensForTokens(
+ lidoARM.swapExactTokensForTokens(
weth, // inToken
steth, // outToken
initialBalance + 1, // amountIn
@@ -92,7 +92,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
initialBalance = steth.balanceOf(address(this));
vm.expectRevert("BALANCE_EXCEEDED"); // Lido error
- lidoFixedPriceMultiLpARM.swapExactTokensForTokens(
+ lidoARM.swapExactTokensForTokens(
steth, // inToken
weth, // outToken
initialBalance + 3, // amountIn
@@ -102,11 +102,11 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
}
function test_RevertWhen_SwapExactTokensForTokens_Because_NotEnoughTokenOut() public {
- uint256 initialBalance = steth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 initialBalance = steth.balanceOf(address(lidoARM));
deal(address(weth), address(this), initialBalance * 2);
vm.expectRevert("BALANCE_EXCEEDED"); // Lido error
- lidoFixedPriceMultiLpARM.swapExactTokensForTokens(
+ lidoARM.swapExactTokensForTokens(
weth, // inToken
steth, // outToken
initialBalance * 2, // amountIn
@@ -114,10 +114,10 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
address(this) // to
);
- initialBalance = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ initialBalance = weth.balanceOf(address(lidoARM));
deal(address(steth), address(this), initialBalance * 2);
vm.expectRevert("ARM: Insufficient liquidity");
- lidoFixedPriceMultiLpARM.swapExactTokensForTokens(
+ lidoARM.swapExactTokensForTokens(
steth, // inToken
weth, // outToken
initialBalance * 2, // amountIn
@@ -127,11 +127,11 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
}
function test_RevertWhen_SwapExactTokensForTokens_Because_InsufficientOutputAmount() public {
- deal(address(steth), address(lidoFixedPriceMultiLpARM), 100 wei);
+ deal(address(steth), address(lidoARM), 100 wei);
// Test for this function signature: swapExactTokensForTokens(IERC20,IERC20,uint56,uint256,address)
vm.expectRevert("ARM: Insufficient output amount");
- lidoFixedPriceMultiLpARM.swapExactTokensForTokens(
+ lidoARM.swapExactTokensForTokens(
weth, // inToken
steth, // outToken
1, // amountIn
@@ -144,7 +144,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
path[0] = address(weth);
path[1] = address(steth);
vm.expectRevert("ARM: Insufficient output amount");
- lidoFixedPriceMultiLpARM.swapExactTokensForTokens(
+ lidoARM.swapExactTokensForTokens(
1, // amountIn
1_000 ether, // amountOutMin
path, // path
@@ -155,7 +155,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
function test_RevertWhen_SwapExactTokensForTokens_Because_InvalidePathLength() public {
vm.expectRevert("ARM: Invalid path length");
- lidoFixedPriceMultiLpARM.swapExactTokensForTokens(
+ lidoARM.swapExactTokensForTokens(
1, // amountIn
1, // amountOutMin
new address[](3), // path
@@ -166,7 +166,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
function test_RevertWhen_SwapExactTokensForTokens_Because_DeadlineExpired() public {
vm.expectRevert("ARM: Deadline expired");
- lidoFixedPriceMultiLpARM.swapExactTokensForTokens(
+ lidoARM.swapExactTokensForTokens(
1, // amountIn
1, // amountOutMin
new address[](2), // path
@@ -187,18 +187,18 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
// State before
uint256 balanceWETHBeforeThis = weth.balanceOf(address(this));
uint256 balanceSTETHBeforeThis = steth.balanceOf(address(this));
- uint256 balanceWETHBeforeARM = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- uint256 balanceSTETHBeforeARM = steth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 balanceWETHBeforeARM = weth.balanceOf(address(lidoARM));
+ uint256 balanceSTETHBeforeARM = steth.balanceOf(address(lidoARM));
// Get minimum amount of STETH to receive
- uint256 traderates1 = lidoFixedPriceMultiLpARM.traderate1();
+ uint256 traderates1 = lidoARM.traderate1();
uint256 minAmount = amountIn * traderates1 / 1e36;
// Expected events: Already checked in fuzz tests
uint256[] memory outputs = new uint256[](2);
// Main call
- outputs = lidoFixedPriceMultiLpARM.swapExactTokensForTokens(
+ outputs = lidoARM.swapExactTokensForTokens(
amountIn, // amountIn
minAmount, // amountOutMin
path, // path
@@ -209,8 +209,8 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
// State after
uint256 balanceWETHAfterThis = weth.balanceOf(address(this));
uint256 balanceSTETHAfterThis = steth.balanceOf(address(this));
- uint256 balanceWETHAfterARM = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- uint256 balanceSTETHAfterARM = steth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 balanceWETHAfterARM = weth.balanceOf(address(lidoARM));
+ uint256 balanceSTETHAfterARM = steth.balanceOf(address(lidoARM));
// Assertions
assertEq(balanceWETHBeforeThis, balanceWETHAfterThis + amountIn);
@@ -230,18 +230,18 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
// State before
uint256 balanceWETHBeforeThis = weth.balanceOf(address(this));
uint256 balanceSTETHBeforeThis = steth.balanceOf(address(this));
- uint256 balanceWETHBeforeARM = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- uint256 balanceSTETHBeforeARM = steth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 balanceWETHBeforeARM = weth.balanceOf(address(lidoARM));
+ uint256 balanceSTETHBeforeARM = steth.balanceOf(address(lidoARM));
// Get minimum amount of WETH to receive
- uint256 traderates0 = lidoFixedPriceMultiLpARM.traderate0();
+ uint256 traderates0 = lidoARM.traderate0();
uint256 minAmount = amountIn * traderates0 / 1e36;
// Expected events: Already checked in fuzz tests
uint256[] memory outputs = new uint256[](2);
// Main call
- outputs = lidoFixedPriceMultiLpARM.swapExactTokensForTokens(
+ outputs = lidoARM.swapExactTokensForTokens(
amountIn, // amountIn
minAmount, // amountOutMin
path, // path
@@ -252,8 +252,8 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
// State after
uint256 balanceWETHAfterThis = weth.balanceOf(address(this));
uint256 balanceSTETHAfterThis = steth.balanceOf(address(this));
- uint256 balanceWETHAfterARM = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- uint256 balanceSTETHAfterARM = steth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 balanceWETHAfterARM = weth.balanceOf(address(lidoARM));
+ uint256 balanceSTETHAfterARM = steth.balanceOf(address(lidoARM));
// Assertions
assertEq(balanceWETHBeforeThis + minAmount, balanceWETHAfterThis);
@@ -277,11 +277,11 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
// Use random price between 0.98 and 1 for traderate1,
// Traderate0 value doesn't matter as it is not used in this test.
price = _bound(price, MIN_PRICE0, MAX_PRICE0);
- lidoFixedPriceMultiLpARM.setPrices(price, MAX_PRICE1);
+ lidoARM.setPrices(price, MAX_PRICE1);
// Set random amount of stETH in the ARM
stethReserve = _bound(stethReserve, 0, MAX_STETH_RESERVE);
- deal(address(steth), address(lidoFixedPriceMultiLpARM), stethReserve);
+ deal(address(steth), address(lidoARM), stethReserve);
// Calculate maximum amount of WETH to swap
// It is ok to take 100% of the balance of stETH of the ARM as the price is below 1.
@@ -291,20 +291,20 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
// State before
uint256 balanceWETHBeforeThis = weth.balanceOf(address(this));
uint256 balanceSTETHBeforeThis = steth.balanceOf(address(this));
- uint256 balanceWETHBeforeARM = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- uint256 balanceSTETHBeforeARM = steth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 balanceWETHBeforeARM = weth.balanceOf(address(lidoARM));
+ uint256 balanceSTETHBeforeARM = steth.balanceOf(address(lidoARM));
// Get minimum amount of STETH to receive
- uint256 traderates1 = lidoFixedPriceMultiLpARM.traderate1();
+ uint256 traderates1 = lidoARM.traderate1();
uint256 minAmount = amountIn * traderates1 / 1e36;
// Expected events
vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(address(this), address(lidoFixedPriceMultiLpARM), amountIn);
+ emit IERC20.Transfer(address(this), address(lidoARM), amountIn);
vm.expectEmit({emitter: address(steth)});
- emit IERC20.Transfer(address(lidoFixedPriceMultiLpARM), address(this), minAmount + STETH_ERROR_ROUNDING);
+ emit IERC20.Transfer(address(lidoARM), address(this), minAmount + STETH_ERROR_ROUNDING);
// Main call
- lidoFixedPriceMultiLpARM.swapExactTokensForTokens(
+ lidoARM.swapExactTokensForTokens(
weth, // inToken
steth, // outToken
amountIn, // amountIn
@@ -315,8 +315,8 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
// State after
uint256 balanceWETHAfterThis = weth.balanceOf(address(this));
uint256 balanceSTETHAfterThis = steth.balanceOf(address(this));
- uint256 balanceWETHAfterARM = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- uint256 balanceSTETHAfterARM = steth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 balanceWETHAfterARM = weth.balanceOf(address(lidoARM));
+ uint256 balanceSTETHAfterARM = steth.balanceOf(address(lidoARM));
// Assertions
assertEq(balanceWETHBeforeThis, balanceWETHAfterThis + amountIn);
@@ -333,11 +333,11 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
// Use random price between MIN_PRICE1 and MAX_PRICE1 for traderate1,
// Traderate0 value doesn't matter as it is not used in this test.
price = _bound(price, MIN_PRICE1, MAX_PRICE1);
- lidoFixedPriceMultiLpARM.setPrices(MIN_PRICE0, price);
+ lidoARM.setPrices(MIN_PRICE0, price);
// Set random amount of WETH in the ARM
wethReserve = _bound(wethReserve, 0, MAX_WETH_RESERVE);
- deal(address(weth), address(lidoFixedPriceMultiLpARM), wethReserve);
+ deal(address(weth), address(lidoARM), wethReserve);
// Calculate maximum amount of stETH to swap
// As the price is below 1, we can take 100% of the balance of WETH of the ARM.
@@ -347,21 +347,21 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
// State before
uint256 balanceWETHBeforeThis = weth.balanceOf(address(this));
uint256 balanceSTETHBeforeThis = steth.balanceOf(address(this));
- uint256 balanceWETHBeforeARM = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- uint256 balanceSTETHBeforeARM = steth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 balanceWETHBeforeARM = weth.balanceOf(address(lidoARM));
+ uint256 balanceSTETHBeforeARM = steth.balanceOf(address(lidoARM));
// Get minimum amount of WETH to receive
- uint256 traderates0 = lidoFixedPriceMultiLpARM.traderate0();
+ uint256 traderates0 = lidoARM.traderate0();
uint256 minAmount = amountIn * traderates0 / 1e36;
// Expected events
vm.expectEmit({emitter: address(steth)});
- emit IERC20.Transfer(address(this), address(lidoFixedPriceMultiLpARM), amountIn);
+ emit IERC20.Transfer(address(this), address(lidoARM), amountIn);
vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(address(lidoFixedPriceMultiLpARM), address(this), minAmount);
+ emit IERC20.Transfer(address(lidoARM), address(this), minAmount);
// Main call
- lidoFixedPriceMultiLpARM.swapExactTokensForTokens(
+ lidoARM.swapExactTokensForTokens(
steth, // inToken
weth, // outToken
amountIn, // amountIn
@@ -372,8 +372,8 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapExactTokensForTokens_Test is
// State after
uint256 balanceWETHAfterThis = weth.balanceOf(address(this));
uint256 balanceSTETHAfterThis = steth.balanceOf(address(this));
- uint256 balanceWETHAfterARM = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- uint256 balanceSTETHAfterARM = steth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 balanceWETHAfterARM = weth.balanceOf(address(lidoARM));
+ uint256 balanceSTETHAfterARM = steth.balanceOf(address(lidoARM));
// Assertions
assertEq(balanceWETHBeforeThis + minAmount, balanceWETHAfterThis);
diff --git a/test/fork/LidoFixedPriceMultiLpARM/SwapTokensForExactTokens.t.sol b/test/fork/LidoFixedPriceMultiLpARM/SwapTokensForExactTokens.t.sol
index ee59dc0..28eb17f 100644
--- a/test/fork/LidoFixedPriceMultiLpARM/SwapTokensForExactTokens.t.sol
+++ b/test/fork/LidoFixedPriceMultiLpARM/SwapTokensForExactTokens.t.sol
@@ -6,7 +6,7 @@ import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
import {IERC20} from "contracts/Interfaces.sol";
-contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is Fork_Shared_Test_ {
+contract Fork_Concrete_LidoARM_SwapTokensForExactTokens_Test is Fork_Shared_Test_ {
//////////////////////////////////////////////////////
/// --- CONSTANTS
//////////////////////////////////////////////////////
@@ -26,17 +26,17 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
deal(address(weth), address(this), 1_000 ether);
deal(address(steth), address(this), 1_000 ether);
- deal(address(weth), address(lidoFixedPriceMultiLpARM), 1_000 ether);
- deal(address(steth), address(lidoFixedPriceMultiLpARM), 1_000 ether);
+ deal(address(weth), address(lidoARM), 1_000 ether);
+ deal(address(steth), address(lidoARM), 1_000 ether);
}
//////////////////////////////////////////////////////
/// --- REVERTING TESTS
//////////////////////////////////////////////////////
function test_RevertWhen_SwapTokensForExactTokens_Because_InvalidTokenOut1() public {
- lidoFixedPriceMultiLpARM.token0();
+ lidoARM.token0();
vm.expectRevert("ARM: Invalid out token");
- lidoFixedPriceMultiLpARM.swapTokensForExactTokens(
+ lidoARM.swapTokensForExactTokens(
steth, // inToken
badToken, // outToken
1, // amountOut
@@ -47,7 +47,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
function test_RevertWhen_SwapTokensForExactTokens_Because_InvalidTokenOut0() public {
vm.expectRevert("ARM: Invalid out token");
- lidoFixedPriceMultiLpARM.swapTokensForExactTokens(
+ lidoARM.swapTokensForExactTokens(
weth, // inToken
badToken, // outToken
1, // amountOut
@@ -58,7 +58,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
function test_RevertWhen_SwapTokensForExactTokens_Because_InvalidTokenIn() public {
vm.expectRevert("ARM: Invalid in token");
- lidoFixedPriceMultiLpARM.swapTokensForExactTokens(
+ lidoARM.swapTokensForExactTokens(
badToken, // inToken
steth, // outToken
1, // amountOut
@@ -69,7 +69,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
function test_RevertWhen_SwapTokensForExactTokens_Because_BothInvalidTokens() public {
vm.expectRevert("ARM: Invalid in token");
- lidoFixedPriceMultiLpARM.swapTokensForExactTokens(
+ lidoARM.swapTokensForExactTokens(
badToken, // inToken
badToken, // outToken
1, // amountOut
@@ -82,7 +82,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
deal(address(weth), address(this), 0);
vm.expectRevert();
- lidoFixedPriceMultiLpARM.swapTokensForExactTokens(
+ lidoARM.swapTokensForExactTokens(
weth, // inToken
steth, // outToken
1, // amountOut
@@ -92,7 +92,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
deal(address(steth), address(this), 0);
vm.expectRevert();
- lidoFixedPriceMultiLpARM.swapTokensForExactTokens(
+ lidoARM.swapTokensForExactTokens(
steth, // inToken
weth, // outToken
STETH_ERROR_ROUNDING + 1, // amountOut *
@@ -106,7 +106,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
deal(address(weth), address(this), 0);
vm.expectRevert();
- lidoFixedPriceMultiLpARM.swapTokensForExactTokens(
+ lidoARM.swapTokensForExactTokens(
weth, // inToken
steth, // outToken
1 ether, // amountOut
@@ -116,7 +116,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
deal(address(steth), address(this), 0);
vm.expectRevert("BALANCE_EXCEEDED"); // Lido error
- lidoFixedPriceMultiLpARM.swapTokensForExactTokens(
+ lidoARM.swapTokensForExactTokens(
steth, // inToken
weth, // outToken
1 ether, // amountOut
@@ -126,11 +126,11 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
}
function test_RevertWhen_SwapTokensForExactTokens_Because_InsufficientOutputAmount() public {
- deal(address(steth), address(lidoFixedPriceMultiLpARM), 100 wei);
+ deal(address(steth), address(lidoARM), 100 wei);
// Test for this function signature: swapTokensForExactTokens(IERC20,IERC20,uint56,uint256,address)
vm.expectRevert("ARM: Excess input amount");
- lidoFixedPriceMultiLpARM.swapTokensForExactTokens(
+ lidoARM.swapTokensForExactTokens(
weth, // inToken
steth, // outToken
1, // amountOut
@@ -143,7 +143,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
path[0] = address(weth);
path[1] = address(steth);
vm.expectRevert("ARM: Excess input amount");
- lidoFixedPriceMultiLpARM.swapTokensForExactTokens(
+ lidoARM.swapTokensForExactTokens(
1, // amountOut
0, // amountInMax
path, // path
@@ -154,7 +154,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
function test_RevertWhen_SwapTokensForExactTokens_Because_InvalidePathLength() public {
vm.expectRevert("ARM: Invalid path length");
- lidoFixedPriceMultiLpARM.swapTokensForExactTokens(
+ lidoARM.swapTokensForExactTokens(
1, // amountOut
1, // amountInMax
new address[](3), // path
@@ -165,7 +165,7 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
function test_RevertWhen_SwapTokensForExactTokens_Because_DeadlineExpired() public {
vm.expectRevert("ARM: Deadline expired");
- lidoFixedPriceMultiLpARM.swapTokensForExactTokens(
+ lidoARM.swapTokensForExactTokens(
1, // amountOut
1, // amountInMax
new address[](2), // path
@@ -186,18 +186,18 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
// State before
uint256 balanceWETHBeforeThis = weth.balanceOf(address(this));
uint256 balanceSTETHBeforeThis = steth.balanceOf(address(this));
- uint256 balanceWETHBeforeARM = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- uint256 balanceSTETHBeforeARM = steth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 balanceWETHBeforeARM = weth.balanceOf(address(lidoARM));
+ uint256 balanceSTETHBeforeARM = steth.balanceOf(address(lidoARM));
// Get minimum amount of STETH to receive
- uint256 traderates1 = lidoFixedPriceMultiLpARM.traderate1();
+ uint256 traderates1 = lidoARM.traderate1();
uint256 amountIn = (amountOut * 1e36 / traderates1) + 1;
// Expected events: Already checked in fuzz tests
uint256[] memory outputs = new uint256[](2);
// Main call
- outputs = lidoFixedPriceMultiLpARM.swapTokensForExactTokens(
+ outputs = lidoARM.swapTokensForExactTokens(
amountOut, // amountOut
amountIn, // amountInMax
path, // path
@@ -208,8 +208,8 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
// State after
uint256 balanceWETHAfterThis = weth.balanceOf(address(this));
uint256 balanceSTETHAfterThis = steth.balanceOf(address(this));
- uint256 balanceWETHAfterARM = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- uint256 balanceSTETHAfterARM = steth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 balanceWETHAfterARM = weth.balanceOf(address(lidoARM));
+ uint256 balanceSTETHAfterARM = steth.balanceOf(address(lidoARM));
// Assertions
assertEq(balanceWETHBeforeThis, balanceWETHAfterThis + amountIn);
@@ -229,18 +229,18 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
// State before
uint256 balanceWETHBeforeThis = weth.balanceOf(address(this));
uint256 balanceSTETHBeforeThis = steth.balanceOf(address(this));
- uint256 balanceWETHBeforeARM = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- uint256 balanceSTETHBeforeARM = steth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 balanceWETHBeforeARM = weth.balanceOf(address(lidoARM));
+ uint256 balanceSTETHBeforeARM = steth.balanceOf(address(lidoARM));
// Get minimum amount of WETH to receive
- uint256 traderates0 = lidoFixedPriceMultiLpARM.traderate0();
+ uint256 traderates0 = lidoARM.traderate0();
uint256 amountIn = (amountOut * 1e36 / traderates0) + 1;
// Expected events: Already checked in fuzz tests
uint256[] memory outputs = new uint256[](2);
// Main call
- outputs = lidoFixedPriceMultiLpARM.swapTokensForExactTokens(
+ outputs = lidoARM.swapTokensForExactTokens(
amountOut, // amountOut
amountIn, // amountInMax
path, // path
@@ -251,8 +251,8 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
// State after
uint256 balanceWETHAfterThis = weth.balanceOf(address(this));
uint256 balanceSTETHAfterThis = steth.balanceOf(address(this));
- uint256 balanceWETHAfterARM = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- uint256 balanceSTETHAfterARM = steth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 balanceWETHAfterARM = weth.balanceOf(address(lidoARM));
+ uint256 balanceSTETHAfterARM = steth.balanceOf(address(lidoARM));
// Assertions
assertEq(balanceWETHBeforeThis + amountOut, balanceWETHAfterThis);
@@ -276,11 +276,11 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
// Use random price between 0.98 and 1 for traderate1,
// Traderate0 value doesn't matter as it is not used in this test.
price = _bound(price, MIN_PRICE0, MAX_PRICE0);
- lidoFixedPriceMultiLpARM.setPrices(price, MAX_PRICE1);
+ lidoARM.setPrices(price, MAX_PRICE1);
// Set random amount of stETH in the ARM
stethReserve = _bound(stethReserve, 0, MAX_STETH_RESERVE);
- deal(address(steth), address(lidoFixedPriceMultiLpARM), stethReserve);
+ deal(address(steth), address(lidoARM), stethReserve);
// Calculate maximum amount of WETH to swap
// It is ok to take 100% of the balance of stETH of the ARM as the price is below 1.
@@ -290,20 +290,20 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
// State before
uint256 balanceWETHBeforeThis = weth.balanceOf(address(this));
uint256 balanceSTETHBeforeThis = steth.balanceOf(address(this));
- uint256 balanceWETHBeforeARM = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- uint256 balanceSTETHBeforeARM = steth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 balanceWETHBeforeARM = weth.balanceOf(address(lidoARM));
+ uint256 balanceSTETHBeforeARM = steth.balanceOf(address(lidoARM));
// Get minimum amount of STETH to receive
- uint256 traderates1 = lidoFixedPriceMultiLpARM.traderate1();
+ uint256 traderates1 = lidoARM.traderate1();
uint256 amountIn = (amountOut * 1e36 / traderates1) + 1;
// Expected events
vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(address(this), address(lidoFixedPriceMultiLpARM), amountIn);
+ emit IERC20.Transfer(address(this), address(lidoARM), amountIn);
vm.expectEmit({emitter: address(steth)});
- emit IERC20.Transfer(address(lidoFixedPriceMultiLpARM), address(this), amountOut + STETH_ERROR_ROUNDING);
+ emit IERC20.Transfer(address(lidoARM), address(this), amountOut + STETH_ERROR_ROUNDING);
// Main call
- lidoFixedPriceMultiLpARM.swapTokensForExactTokens(
+ lidoARM.swapTokensForExactTokens(
weth, // inToken
steth, // outToken
amountOut, // amountOut
@@ -314,8 +314,8 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
// State after
uint256 balanceWETHAfterThis = weth.balanceOf(address(this));
uint256 balanceSTETHAfterThis = steth.balanceOf(address(this));
- uint256 balanceWETHAfterARM = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- uint256 balanceSTETHAfterARM = steth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 balanceWETHAfterARM = weth.balanceOf(address(lidoARM));
+ uint256 balanceSTETHAfterARM = steth.balanceOf(address(lidoARM));
// Assertions
assertEq(balanceWETHBeforeThis, balanceWETHAfterThis + amountIn);
@@ -334,11 +334,11 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
// Use random price between MIN_PRICE1 and MAX_PRICE1 for traderate1,
// Traderate0 value doesn't matter as it is not used in this test.
price = _bound(price, MIN_PRICE1, MAX_PRICE1);
- lidoFixedPriceMultiLpARM.setPrices(MIN_PRICE0, price);
+ lidoARM.setPrices(MIN_PRICE0, price);
// Set random amount of WETH in the ARM
wethReserve = _bound(wethReserve, 0, MAX_WETH_RESERVE);
- deal(address(weth), address(lidoFixedPriceMultiLpARM), wethReserve);
+ deal(address(weth), address(lidoARM), wethReserve);
// Calculate maximum amount of stETH to swap
// As the price is below 1, we can take 100% of the balance of WETH of the ARM.
@@ -348,21 +348,21 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
// State before
uint256 balanceWETHBeforeThis = weth.balanceOf(address(this));
uint256 balanceSTETHBeforeThis = steth.balanceOf(address(this));
- uint256 balanceWETHBeforeARM = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- uint256 balanceSTETHBeforeARM = steth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 balanceWETHBeforeARM = weth.balanceOf(address(lidoARM));
+ uint256 balanceSTETHBeforeARM = steth.balanceOf(address(lidoARM));
// Get minimum amount of WETH to receive
- uint256 traderates0 = lidoFixedPriceMultiLpARM.traderate0();
+ uint256 traderates0 = lidoARM.traderate0();
uint256 amountIn = (amountOut * 1e36 / traderates0) + 1;
// Expected events
vm.expectEmit({emitter: address(steth)});
- emit IERC20.Transfer(address(this), address(lidoFixedPriceMultiLpARM), amountIn);
+ emit IERC20.Transfer(address(this), address(lidoARM), amountIn);
vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(address(lidoFixedPriceMultiLpARM), address(this), amountOut);
+ emit IERC20.Transfer(address(lidoARM), address(this), amountOut);
// Main call
- lidoFixedPriceMultiLpARM.swapTokensForExactTokens(
+ lidoARM.swapTokensForExactTokens(
steth, // inToken
weth, // outToken
amountOut, // amountOut
@@ -373,8 +373,8 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_SwapTokensForExactTokens_Test is
// State after
uint256 balanceWETHAfterThis = weth.balanceOf(address(this));
uint256 balanceSTETHAfterThis = steth.balanceOf(address(this));
- uint256 balanceWETHAfterARM = weth.balanceOf(address(lidoFixedPriceMultiLpARM));
- uint256 balanceSTETHAfterARM = steth.balanceOf(address(lidoFixedPriceMultiLpARM));
+ uint256 balanceWETHAfterARM = weth.balanceOf(address(lidoARM));
+ uint256 balanceSTETHAfterARM = steth.balanceOf(address(lidoARM));
// Assertions
assertEq(balanceWETHBeforeThis + amountOut, balanceWETHAfterThis);
diff --git a/test/fork/LidoFixedPriceMultiLpARM/TotalAssets.t.sol b/test/fork/LidoFixedPriceMultiLpARM/TotalAssets.t.sol
index 16d9633..4599b4b 100644
--- a/test/fork/LidoFixedPriceMultiLpARM/TotalAssets.t.sol
+++ b/test/fork/LidoFixedPriceMultiLpARM/TotalAssets.t.sol
@@ -9,10 +9,9 @@ import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
// Contracts
import {IERC20} from "contracts/Interfaces.sol";
-import {MultiLP} from "contracts/MultiLP.sol";
-import {PerformanceFee} from "contracts/PerformanceFee.sol";
+import {AbstractARM} from "contracts/AbstractARM.sol";
-contract Fork_Concrete_LidoFixedPriceMultiLpARM_TotalAssets_Test_ is Fork_Shared_Test_ {
+contract Fork_Concrete_LidoARM_TotalAssets_Test_ is Fork_Shared_Test_ {
//////////////////////////////////////////////////////
/// --- SETUP
//////////////////////////////////////////////////////
@@ -26,162 +25,130 @@ contract Fork_Concrete_LidoFixedPriceMultiLpARM_TotalAssets_Test_ is Fork_Shared
liquidityProviderController.setTotalAssetsCap(type(uint256).max);
// Approve STETH for Lido
- lidoFixedPriceMultiLpARM.approveStETH();
+ lidoARM.approveStETH();
deal(address(weth), address(this), 1_000 ether);
- weth.approve(address(lidoFixedPriceMultiLpARM), type(uint256).max);
- }
-
- //////////////////////////////////////////////////////
- /// --- REVERTING TEST
- //////////////////////////////////////////////////////
- function test_RevertWhen_TotalAssets_Because_MathError()
- public
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
- simulateAssetGainInLidoFixedPriceMultiLpARM(DEFAULT_AMOUNT, address(weth), true)
- requestRedeemFromLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
- simulateAssetGainInLidoFixedPriceMultiLpARM(DEFAULT_AMOUNT * 2, address(weth), false)
- {
- vm.expectRevert(stdError.arithmeticError);
- lidoFixedPriceMultiLpARM.totalAssets();
+ weth.approve(address(lidoARM), type(uint256).max);
}
//////////////////////////////////////////////////////
/// --- PASSING TEST
//////////////////////////////////////////////////////
function test_TotalAssets_AfterInitialization() public view {
- assertEq(lidoFixedPriceMultiLpARM.totalAssets(), MIN_TOTAL_SUPPLY);
+ assertEq(lidoARM.totalAssets(), MIN_TOTAL_SUPPLY);
}
- function test_TotalAssets_AfterDeposit_NoAssetGainOrLoss()
- public
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
- {
- assertEq(lidoFixedPriceMultiLpARM.totalAssets(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
+ function test_TotalAssets_AfterDeposit_NoAssetGainOrLoss() public depositInLidoARM(address(this), DEFAULT_AMOUNT) {
+ assertEq(lidoARM.totalAssets(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT);
}
function test_TotalAssets_AfterDeposit_WithAssetGain_InWETH()
public
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
{
// Simulate asset gain
uint256 assetGain = DEFAULT_AMOUNT / 2;
- deal(
- address(weth),
- address(lidoFixedPriceMultiLpARM),
- weth.balanceOf(address(lidoFixedPriceMultiLpARM)) + assetGain
- );
+ deal(address(weth), address(lidoARM), weth.balanceOf(address(lidoARM)) + assetGain);
// Calculate Fees
uint256 fee = assetGain * 20 / 100; // 20% fee
- assertEq(lidoFixedPriceMultiLpARM.totalAssets(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT + assetGain - fee);
+ assertEq(lidoARM.totalAssets(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT + assetGain - fee);
}
function test_TotalAssets_AfterDeposit_WithAssetGain_InSTETH()
public
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
{
- assertEq(steth.balanceOf(address(lidoFixedPriceMultiLpARM)), 0);
+ assertEq(steth.balanceOf(address(lidoARM)), 0);
// Simulate asset gain
uint256 assetGain = DEFAULT_AMOUNT / 2 + 1;
// We are sure that steth balance is empty, so we can deal directly final amount.
- deal(address(steth), address(lidoFixedPriceMultiLpARM), assetGain);
+ deal(address(steth), address(lidoARM), assetGain);
// Calculate Fees
uint256 fee = assetGain * 20 / 100; // 20% fee
assertApproxEqAbs(
- lidoFixedPriceMultiLpARM.totalAssets(),
- MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT + assetGain - fee,
- STETH_ERROR_ROUNDING
+ lidoARM.totalAssets(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT + assetGain - fee, STETH_ERROR_ROUNDING
);
}
function test_TotalAssets_AfterDeposit_WithAssetLoss_InWETH()
public
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
{
// Simulate asset loss
uint256 assetLoss = DEFAULT_AMOUNT / 2;
- deal(
- address(weth),
- address(lidoFixedPriceMultiLpARM),
- weth.balanceOf(address(lidoFixedPriceMultiLpARM)) - assetLoss
- );
+ deal(address(weth), address(lidoARM), weth.balanceOf(address(lidoARM)) - assetLoss);
- assertEq(lidoFixedPriceMultiLpARM.totalAssets(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT - assetLoss);
+ assertEq(lidoARM.totalAssets(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT - assetLoss);
}
function test_TotalAssets_AfterDeposit_WithAssetLoss_InSTETH()
public
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
{
// Simulate Swap at 1:1 between WETH and stETH
uint256 swapAmount = DEFAULT_AMOUNT / 2;
- deal(
- address(weth),
- address(lidoFixedPriceMultiLpARM),
- weth.balanceOf(address(lidoFixedPriceMultiLpARM)) - swapAmount
- );
+ deal(address(weth), address(lidoARM), weth.balanceOf(address(lidoARM)) - swapAmount);
// Then simulate a loss on stETH, do all in the same deal
uint256 assetLoss = swapAmount / 2;
- deal(address(steth), address(lidoFixedPriceMultiLpARM), swapAmount / 2);
+ deal(address(steth), address(lidoARM), swapAmount / 2);
- assertApproxEqAbs(
- lidoFixedPriceMultiLpARM.totalAssets(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT - assetLoss, STETH_ERROR_ROUNDING
- );
+ assertApproxEqAbs(lidoARM.totalAssets(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT - assetLoss, STETH_ERROR_ROUNDING);
}
function test_TotalAssets_After_WithdrawingFromLido() public {
// Simulate a Swap at 1:1 between WETH and stETH using initial liquidity
uint256 swapAmount = MIN_TOTAL_SUPPLY / 2;
- deal(
- address(weth),
- address(lidoFixedPriceMultiLpARM),
- weth.balanceOf(address(lidoFixedPriceMultiLpARM)) - swapAmount
- );
- deal(address(steth), address(lidoFixedPriceMultiLpARM), swapAmount); // Empty stETH balance, so we can deal directly
+ deal(address(weth), address(lidoARM), weth.balanceOf(address(lidoARM)) - swapAmount);
+ deal(address(steth), address(lidoARM), swapAmount); // Empty stETH balance, so we can deal directly
- uint256 totalAssetsBefore = lidoFixedPriceMultiLpARM.totalAssets();
+ uint256 totalAssetsBefore = lidoARM.totalAssets();
// Request a redeem on Lido
uint256[] memory amounts = new uint256[](1);
amounts[0] = swapAmount;
- lidoFixedPriceMultiLpARM.requestStETHWithdrawalForETH(amounts);
+ lidoARM.requestStETHWithdrawalForETH(amounts);
// Check total assets after withdrawal is the same as before
- assertApproxEqAbs(lidoFixedPriceMultiLpARM.totalAssets(), totalAssetsBefore, STETH_ERROR_ROUNDING);
+ assertApproxEqAbs(lidoARM.totalAssets(), totalAssetsBefore, STETH_ERROR_ROUNDING);
}
function test_TotalAssets_With_FeeAccrued_NotNull() public {
uint256 assetGain = DEFAULT_AMOUNT;
// Simulate asset gain
- deal(
- address(weth),
- address(lidoFixedPriceMultiLpARM),
- weth.balanceOf(address(lidoFixedPriceMultiLpARM)) + assetGain
- );
+ deal(address(weth), address(lidoARM), weth.balanceOf(address(lidoARM)) + assetGain);
// User deposit, this will trigger a fee calculation
- lidoFixedPriceMultiLpARM.deposit(DEFAULT_AMOUNT);
+ lidoARM.deposit(DEFAULT_AMOUNT);
// Assert fee accrued is not null
- assertEq(lidoFixedPriceMultiLpARM.feesAccrued(), assetGain * 20 / 100);
+ assertEq(lidoARM.feesAccrued(), assetGain * 20 / 100);
- assertEq(
- lidoFixedPriceMultiLpARM.totalAssets(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT + assetGain - assetGain * 20 / 100
- );
+ assertEq(lidoARM.totalAssets(), MIN_TOTAL_SUPPLY + DEFAULT_AMOUNT + assetGain - assetGain * 20 / 100);
}
function test_TotalAssets_When_ARMIsInsolvent()
public
- depositInLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
- requestRedeemFromLidoFixedPriceMultiLpARM(address(this), DEFAULT_AMOUNT)
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
+ requestRedeemFromLidoARM(address(this), DEFAULT_AMOUNT)
{
// Simulate a loss of assets
- deal(address(weth), address(lidoFixedPriceMultiLpARM), DEFAULT_AMOUNT - 1);
+ deal(address(weth), address(lidoARM), DEFAULT_AMOUNT - 1);
- assertEq(lidoFixedPriceMultiLpARM.totalAssets(), 0);
+ assertEq(lidoARM.totalAssets(), 0);
+ }
+
+ function test_RevertWhen_TotalAssets_Because_MathError()
+ public
+ depositInLidoARM(address(this), DEFAULT_AMOUNT)
+ simulateAssetGainInLidoARM(DEFAULT_AMOUNT, address(weth), true)
+ requestRedeemFromLidoARM(address(this), DEFAULT_AMOUNT)
+ simulateAssetGainInLidoARM(DEFAULT_AMOUNT * 2, address(weth), false)
+ {
+ // vm.expectRevert(stdError.arithmeticError);
+ assertEq(lidoARM.totalAssets(), 0);
}
}
diff --git a/test/fork/shared/Shared.sol b/test/fork/shared/Shared.sol
index 99824b3..dda8910 100644
--- a/test/fork/shared/Shared.sol
+++ b/test/fork/shared/Shared.sol
@@ -10,7 +10,7 @@ import {Modifiers} from "test/fork/utils/Modifiers.sol";
// Contracts
import {Proxy} from "contracts/Proxy.sol";
import {OethARM} from "contracts/OethARM.sol";
-import {LidoFixedPriceMultiLpARM} from "contracts/LidoFixedPriceMultiLpARM.sol";
+import {LidoARM} from "contracts/LidoARM.sol";
import {LiquidityProviderController} from "contracts/LiquidityProviderController.sol";
// Interfaces
@@ -139,17 +139,16 @@ abstract contract Fork_Shared_Test_ is Modifiers {
liquidityProviderController.setLiquidityProviderCaps(liquidityProviders, 20 ether);
liquidityProviderController.setTotalAssetsCap(100 ether);
- // --- Deploy LidoFixedPriceMultiLpARM implementation ---
+ // --- Deploy LidoARM implementation ---
// Deploy LidoARM implementation.
- LidoFixedPriceMultiLpARM lidoImpl =
- new LidoFixedPriceMultiLpARM(address(steth), address(weth), Mainnet.LIDO_WITHDRAWAL);
+ LidoARM lidoImpl = new LidoARM(address(steth), address(weth), Mainnet.LIDO_WITHDRAWAL);
// Deployer will need WETH to initialize the ARM.
deal(address(weth), address(this), 1e12);
weth.approve(address(lidoProxy), type(uint256).max);
steth.approve(address(lidoProxy), type(uint256).max);
- // Initialize Proxy with LidoFixedPriceMultiLpARM implementation.
+ // Initialize Proxy with LidoARM implementation.
data = abi.encodeWithSignature(
"initialize(string,string,address,uint256,address,address)",
"Lido ARM",
@@ -162,10 +161,10 @@ abstract contract Fork_Shared_Test_ is Modifiers {
lidoProxy.initialize(address(lidoImpl), address(this), data);
// Set the Proxy as the LidoARM.
- lidoFixedPriceMultiLpARM = LidoFixedPriceMultiLpARM(payable(address(lidoProxy)));
+ lidoARM = LidoARM(payable(address(lidoProxy)));
// set prices
- lidoFixedPriceMultiLpARM.setPrices(992 * 1e33, 1001 * 1e33);
+ lidoARM.setPrices(992 * 1e33, 1001 * 1e33);
}
function _label() internal {
@@ -176,7 +175,7 @@ abstract contract Fork_Shared_Test_ is Modifiers {
vm.label(address(vault), "OETH VAULT");
vm.label(address(oethARM), "OETH ARM");
vm.label(address(proxy), "OETH ARM PROXY");
- vm.label(address(lidoFixedPriceMultiLpARM), "LIDO ARM");
+ vm.label(address(lidoARM), "LIDO ARM");
vm.label(address(lidoProxy), "LIDO ARM PROXY");
vm.label(address(liquidityProviderController), "LIQUIDITY PROVIDER CONTROLLER");
vm.label(operator, "OPERATOR");
diff --git a/test/fork/utils/Helpers.sol b/test/fork/utils/Helpers.sol
index b4bfc70..9223da7 100644
--- a/test/fork/utils/Helpers.sol
+++ b/test/fork/utils/Helpers.sol
@@ -40,10 +40,10 @@ abstract contract Helpers is Base_Test_ {
uint256 expectedClaimed,
uint256 expectedNextIndex
) public view {
- assertEq(lidoFixedPriceMultiLpARM.withdrawsQueued(), expectedQueued, "metadata queued");
- assertEq(lidoFixedPriceMultiLpARM.withdrawsClaimable(), expectedClaimable, "metadata claimable");
- assertEq(lidoFixedPriceMultiLpARM.withdrawsClaimed(), expectedClaimed, "metadata claimed");
- assertEq(lidoFixedPriceMultiLpARM.nextWithdrawalIndex(), expectedNextIndex, "metadata nextWithdrawalIndex");
+ assertEq(lidoARM.withdrawsQueued(), expectedQueued, "metadata queued");
+ assertEq(lidoARM.withdrawsClaimable(), expectedClaimable, "metadata claimable");
+ assertEq(lidoARM.withdrawsClaimed(), expectedClaimed, "metadata claimed");
+ assertEq(lidoARM.nextWithdrawalIndex(), expectedNextIndex, "metadata nextWithdrawalIndex");
}
/// @notice Asserts the equality bewteen value of `withdrawalRequests()` and the expected values.
@@ -56,7 +56,7 @@ abstract contract Helpers is Base_Test_ {
uint256 queued
) public view {
(address _withdrawer, bool _claimed, uint40 _claimTimestamp, uint128 _assets, uint128 _queued) =
- lidoFixedPriceMultiLpARM.withdrawalRequests(requestId);
+ lidoARM.withdrawalRequests(requestId);
assertEq(_withdrawer, withdrawer, "Wrong withdrawer");
assertEq(_claimed, claimed, "Wrong claimed");
assertEq(_claimTimestamp, claimTimestamp, "Wrong claimTimestamp");
diff --git a/test/fork/utils/MockCall.sol b/test/fork/utils/MockCall.sol
index e1d4f23..1a6de11 100644
--- a/test/fork/utils/MockCall.sol
+++ b/test/fork/utils/MockCall.sol
@@ -33,18 +33,18 @@ library MockCall {
contract MockLidoWithdraw {
ETHSender public immutable ethSender;
- address public immutable lidoFixedPriceMultiLpARM;
+ address public immutable lidoARM;
constructor(address _lidoFixedPriceMulltiLpARM) {
ethSender = new ETHSender();
- lidoFixedPriceMultiLpARM = _lidoFixedPriceMulltiLpARM;
+ lidoARM = _lidoFixedPriceMulltiLpARM;
}
/// @notice Mock the call to the Lido contract's `claimWithdrawals` function.
/// @dev as it is not possible to transfer ETH from the mocked contract (seems to be an issue with forge)
/// we use the ETHSender contract intermediary to send the ETH to the target contract.
function claimWithdrawals(uint256[] memory, uint256[] memory) external {
- ethSender.sendETH(lidoFixedPriceMultiLpARM);
+ ethSender.sendETH(lidoARM);
}
}
diff --git a/test/fork/utils/Modifiers.sol b/test/fork/utils/Modifiers.sol
index f9c592c..23b69cd 100644
--- a/test/fork/utils/Modifiers.sol
+++ b/test/fork/utils/Modifiers.sol
@@ -37,14 +37,14 @@ abstract contract Modifiers is Helpers {
/// @notice Impersonate the operator of LidoOwnerLpARM contract.
modifier asLidoFixedPriceMulltiLpARMOperator() {
- vm.startPrank(lidoFixedPriceMultiLpARM.operator());
+ vm.startPrank(lidoARM.operator());
_;
vm.stopPrank();
}
- /// @notice Impersonate the owner of LidoFixedPriceMultiLpARM contract.
- modifier asLidoFixedPriceMultiLpARMOwner() {
- vm.startPrank(lidoFixedPriceMultiLpARM.owner());
+ /// @notice Impersonate the owner of LidoARM contract.
+ modifier asLidoARMOwner() {
+ vm.startPrank(lidoARM.owner());
_;
vm.stopPrank();
}
@@ -77,8 +77,8 @@ abstract contract Modifiers is Helpers {
_;
}
- /// @notice Deposit WETH into the LidoFixedPriceMultiLpARM contract.
- modifier depositInLidoFixedPriceMultiLpARM(address user, uint256 amount) {
+ /// @notice Deposit WETH into the LidoARM contract.
+ modifier depositInLidoARM(address user, uint256 amount) {
// Todo: extend this logic to other modifier if needed
(VmSafe.CallerMode mode, address _address, address _origin) = vm.readCallers();
vm.stopPrank();
@@ -89,8 +89,8 @@ abstract contract Modifiers is Helpers {
// Deal amount as "extra" to user
deal(address(weth), user, amount + balance);
vm.startPrank(user);
- weth.approve(address(lidoFixedPriceMultiLpARM), type(uint256).max);
- lidoFixedPriceMultiLpARM.deposit(amount);
+ weth.approve(address(lidoARM), type(uint256).max);
+ lidoARM.deposit(amount);
vm.stopPrank();
if (mode == VmSafe.CallerMode.Prank) {
@@ -101,14 +101,14 @@ abstract contract Modifiers is Helpers {
_;
}
- /// @notice Request redeem from LidoFixedPriceMultiLpARM contract.
- modifier requestRedeemFromLidoFixedPriceMultiLpARM(address user, uint256 amount) {
+ /// @notice Request redeem from LidoARM contract.
+ modifier requestRedeemFromLidoARM(address user, uint256 amount) {
// Todo: extend this logic to other modifier if needed
(VmSafe.CallerMode mode, address _address, address _origin) = vm.readCallers();
vm.stopPrank();
vm.startPrank(user);
- lidoFixedPriceMultiLpARM.requestRedeem(amount);
+ lidoARM.requestRedeem(amount);
vm.stopPrank();
if (mode == VmSafe.CallerMode.Prank) {
@@ -119,14 +119,14 @@ abstract contract Modifiers is Helpers {
_;
}
- /// @notice Claim redeem from LidoFixedPriceMultiLpARM contract.
- modifier claimRequestOnLidoFixedPriceMultiLpARM(address user, uint256 requestId) {
+ /// @notice Claim redeem from LidoARM contract.
+ modifier claimRequestOnLidoARM(address user, uint256 requestId) {
// Todo: extend this logic to other modifier if needed
(VmSafe.CallerMode mode, address _address, address _origin) = vm.readCallers();
vm.stopPrank();
vm.startPrank(user);
- lidoFixedPriceMultiLpARM.claimRedeem(requestId);
+ lidoARM.claimRedeem(requestId);
vm.stopPrank();
if (mode == VmSafe.CallerMode.Prank) {
@@ -137,24 +137,16 @@ abstract contract Modifiers is Helpers {
_;
}
- /// @notice Simulate asset gain or loss in LidoFixedPriceMultiLpARM contract.
- modifier simulateAssetGainInLidoFixedPriceMultiLpARM(uint256 assetGain, address token, bool gain) {
+ /// @notice Simulate asset gain or loss in LidoARM contract.
+ modifier simulateAssetGainInLidoARM(uint256 assetGain, address token, bool gain) {
// Todo: extend this logic to other modifier if needed
(VmSafe.CallerMode mode, address _address, address _origin) = vm.readCallers();
vm.stopPrank();
if (gain) {
- deal(
- token,
- address(lidoFixedPriceMultiLpARM),
- IERC20(token).balanceOf(address(lidoFixedPriceMultiLpARM)) + uint256(assetGain)
- );
+ deal(token, address(lidoARM), IERC20(token).balanceOf(address(lidoARM)) + uint256(assetGain));
} else {
- deal(
- token,
- address(lidoFixedPriceMultiLpARM),
- IERC20(token).balanceOf(address(lidoFixedPriceMultiLpARM)) - uint256(assetGain)
- );
+ deal(token, address(lidoARM), IERC20(token).balanceOf(address(lidoARM)) - uint256(assetGain));
}
if (mode == VmSafe.CallerMode.Prank) {
@@ -165,20 +157,20 @@ abstract contract Modifiers is Helpers {
_;
}
- /// @notice Collect fees on LidoFixedPriceMultiLpARM contract.
- modifier collectFeesOnLidoFixedPriceMultiLpARM() {
- lidoFixedPriceMultiLpARM.collectFees();
+ /// @notice Collect fees on LidoARM contract.
+ modifier collectFeesOnLidoARM() {
+ lidoARM.collectFees();
_;
}
- /// @notice Approve stETH on LidoFixedPriceMultiLpARM contract.
- modifier approveStETHOnLidoFixedPriceMultiLpARM() {
+ /// @notice Approve stETH on LidoARM contract.
+ modifier approveStETHOnLidoARM() {
// Todo: extend this logic to other modifier if needed
(VmSafe.CallerMode mode, address _address, address _origin) = vm.readCallers();
vm.stopPrank();
- vm.prank(lidoFixedPriceMultiLpARM.owner());
- lidoFixedPriceMultiLpARM.approveStETH();
+ vm.prank(lidoARM.owner());
+ lidoARM.approveStETH();
if (mode == VmSafe.CallerMode.Prank) {
vm.prank(_address, _origin);
@@ -188,14 +180,14 @@ abstract contract Modifiers is Helpers {
_;
}
- /// @notice Request stETH withdrawal for ETH on LidoFixedPriceMultiLpARM contract.
- modifier requestStETHWithdrawalForETHOnLidoFixedPriceMultiLpARM(uint256[] memory amounts) {
+ /// @notice Request stETH withdrawal for ETH on LidoARM contract.
+ modifier requestStETHWithdrawalForETHOnLidoARM(uint256[] memory amounts) {
// Todo: extend this logic to other modifier if needed
(VmSafe.CallerMode mode, address _address, address _origin) = vm.readCallers();
vm.stopPrank();
- vm.prank(lidoFixedPriceMultiLpARM.owner());
- lidoFixedPriceMultiLpARM.requestStETHWithdrawalForETH(amounts);
+ vm.prank(lidoARM.owner());
+ lidoARM.requestStETHWithdrawalForETH(amounts);
if (mode == VmSafe.CallerMode.Prank) {
vm.prank(_address, _origin);
@@ -222,14 +214,14 @@ abstract contract Modifiers is Helpers {
}
/// @notice mock call for `claimWithdrawals` on lido withdraw contracts.
- /// @dev this will send eth directly to the lidoFixedPriceMultiLpARM contract.
- modifier mockFunctionClaimWithdrawOnLidoFixedPriceMultiLpARM(uint256 amount) {
+ /// @dev this will send eth directly to the lidoARM contract.
+ modifier mockFunctionClaimWithdrawOnLidoARM(uint256 amount) {
// Todo: extend this logic to other modifier if needed
(VmSafe.CallerMode mode, address _address, address _origin) = vm.readCallers();
vm.stopPrank();
// Deploy fake lido withdraw contract
- MockLidoWithdraw mocklidoWithdraw = new MockLidoWithdraw(address(lidoFixedPriceMultiLpARM));
+ MockLidoWithdraw mocklidoWithdraw = new MockLidoWithdraw(address(lidoARM));
// Give ETH to the ETH Sender contract
vm.deal(address(mocklidoWithdraw.ethSender()), amount);
// Mock all the call to the fake lido withdraw contract
diff --git a/test/smoke/LidoARMSmokeTest.t.sol b/test/smoke/LidoARMSmokeTest.t.sol
index 081f8e1..1852417 100644
--- a/test/smoke/LidoARMSmokeTest.t.sol
+++ b/test/smoke/LidoARMSmokeTest.t.sol
@@ -6,7 +6,7 @@ import {Test, console2} from "forge-std/Test.sol";
import {AbstractSmokeTest} from "./AbstractSmokeTest.sol";
import {IERC20} from "contracts/Interfaces.sol";
-import {LidoFixedPriceMultiLpARM} from "contracts/LidoFixedPriceMultiLpARM.sol";
+import {LidoARM} from "contracts/LidoARM.sol";
import {Proxy} from "contracts/Proxy.sol";
import {Mainnet} from "contracts/utils/Addresses.sol";
import {console} from "forge-std/console.sol";
@@ -17,7 +17,7 @@ contract Fork_LidoARM_Smoke_Test is AbstractSmokeTest {
IERC20 weth;
IERC20 steth;
Proxy proxy;
- LidoFixedPriceMultiLpARM lidoARM;
+ LidoARM lidoARM;
address operator;
function setUp() public {
@@ -30,7 +30,7 @@ contract Fork_LidoARM_Smoke_Test is AbstractSmokeTest {
vm.label(address(operator), "OPERATOR");
proxy = Proxy(deployManager.getDeployment("LIDO_ARM"));
- lidoARM = LidoFixedPriceMultiLpARM(payable(deployManager.getDeployment("LIDO_ARM")));
+ lidoARM = LidoARM(payable(deployManager.getDeployment("LIDO_ARM")));
// Only fuzz from this address. Big speedup on fork.
targetSender(address(this));