diff --git a/Makefile b/Makefile
index be1e153d..36e08d01 100644
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,7 @@ snapshot:
# Tests
test-std:
- forge test --summary --fail-fast --show-progress
+ forge test --summary --fail-fast --show-progress -vvv
test:
@FOUNDRY_NO_MATCH_CONTRACT=Fuzzer $(MAKE) test-std
@@ -42,7 +42,7 @@ test-all:
@$(MAKE) test-std
test-invariant-lido:
- @FOUNDRY_INVARIANT_FAIL_ON_REVERT=false FOUNDRY_MATCH_CONTRACT=FuzzerFoundry_OethARM $(MAKE) test-std
+ @FOUNDRY_INVARIANT_FAIL_ON_REVERT=false FOUNDRY_MATCH_CONTRACT=FuzzerFoundry_LidoARM $(MAKE) test-std
test-invariant-origin:
@FOUNDRY_INVARIANT_FAIL_ON_REVERT=true FOUNDRY_MATCH_CONTRACT=FuzzerFoundry_OriginARM $(MAKE) test-std
diff --git a/README.md b/README.md
index 467a609a..45ced935 100644
--- a/README.md
+++ b/README.md
@@ -245,9 +245,10 @@ If the verification doesn't work with the deployment, it can be done separately
For example
```
-# Verify OethARM
-forge verify-contract 0xd8fF298eAed581f74ab845Af62C48aCF85B2f05e OethARM \
- --constructor-args $(cast abi-encode "constructor(address,address,address)" 0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 0x39254033945AA2E4809Cc2977E7087BEE48bd7Ab )
+# Verify LidoARM
+forge verify-contract 0xeC6FdCc3904F8dD6a9cbbBCC41B741df5963B42E LidoARM \
+ --constructor-args $(cast abi-encode "constructor(address,address,address,uint256,uint256,int256)" 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1 600 0 0 )
+
# Verify Proxy
forge verify-contract 0x6bac785889A4127dB0e0CeFEE88E0a9F1Aaf3cC7 Proxy
diff --git a/docs/OEthARMHierarchy.svg b/docs/OEthARMHierarchy.svg
deleted file mode 100644
index 89dbae31..00000000
--- a/docs/OEthARMHierarchy.svg
+++ /dev/null
@@ -1,113 +0,0 @@
-
-
-
-
-
diff --git a/docs/OEthARMSquashed.svg b/docs/OEthARMSquashed.svg
deleted file mode 100644
index 62cc57f9..00000000
--- a/docs/OEthARMSquashed.svg
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
-
-
-
diff --git a/docs/OEthARMStorage.svg b/docs/OEthARMStorage.svg
deleted file mode 100644
index 05a02ce2..00000000
--- a/docs/OEthARMStorage.svg
+++ /dev/null
@@ -1,57 +0,0 @@
-
-
-
-
-
diff --git a/docs/OriginARMHierarchy.svg b/docs/OriginARMHierarchy.svg
new file mode 100644
index 00000000..3d21b159
--- /dev/null
+++ b/docs/OriginARMHierarchy.svg
@@ -0,0 +1,60 @@
+
+
+
+
+
diff --git a/docs/OriginARMPublicSquashed.svg b/docs/OriginARMPublicSquashed.svg
new file mode 100644
index 00000000..b65e6e4d
--- /dev/null
+++ b/docs/OriginARMPublicSquashed.svg
@@ -0,0 +1,108 @@
+
+
+
+
+
diff --git a/docs/OriginARMSquashed.svg b/docs/OriginARMSquashed.svg
new file mode 100644
index 00000000..8540d3e3
--- /dev/null
+++ b/docs/OriginARMSquashed.svg
@@ -0,0 +1,135 @@
+
+
+
+
+
diff --git a/docs/generate.sh b/docs/generate.sh
index 3c607ab1..c51df7d4 100644
--- a/docs/generate.sh
+++ b/docs/generate.sh
@@ -6,13 +6,6 @@ sol2uml storage ../src/contracts -c Proxy -o ProxyStorage.svg \
-sn eip1967.proxy.implementation,eip1967.proxy.admin \
-st address,address
-sol2uml ../src/contracts -v -hv -hf -he -hs -hl -hi -b OethARM -o OethARMHierarchy.svg
-sol2uml ../src/contracts -s -d 0 -b OethARM -o OethARMSquashed.svg
-sol2uml storage ../src/contracts -c OethARM -o OethARMStorage.svg \
- -sn eip1967.proxy.implementation,eip1967.proxy.admin \
- -st address,address \
- --hideExpand gap,_gap
-
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
@@ -21,6 +14,15 @@ sol2uml storage ../src/contracts,../lib -c LidoARM -o LidoARMStorage.svg \
-st address,address \
--hideExpand gap,_gap
+sol2uml ../src/contracts -v -hv -hf -he -hs -hl -hi -b OriginARM -o OriginARMHierarchy.svg
+sol2uml ../src/contracts -s -d 0 -b OriginARM -o OriginARMSquashed.svg
+sol2uml ../src/contracts -hp -s -d 0 -b OriginARM -o OriginARMPublicSquashed.svg
+sol2uml storage ../src/contracts,../lib -c OriginARM -o OriginARMStorage.svg \
+ -sn eip1967.proxy.implementation,eip1967.proxy.admin \
+ -st address,address \
+ --hideExpand gap,_gap
+
+
sol2uml ../src/contracts -v -hv -hf -he -hs -hl -hi -b CapManager -o CapManagerHierarchy.svg
sol2uml ../src/contracts -s -d 0 -b CapManager -o CapManagerSquashed.svg
diff --git a/docs/plantuml/originContracts.png b/docs/plantuml/originContracts.png
new file mode 100644
index 00000000..e3e31351
Binary files /dev/null and b/docs/plantuml/originContracts.png differ
diff --git a/docs/plantuml/originContracts.puml b/docs/plantuml/originContracts.puml
new file mode 100644
index 00000000..c53cfd4d
--- /dev/null
+++ b/docs/plantuml/originContracts.puml
@@ -0,0 +1,34 @@
+@startuml
+
+!$originColor = DeepSkyBlue
+' !$originColor = WhiteSmoke
+!$newColor = LightGreen
+!$changedColor = Orange
+!$thirdPartyColor = WhiteSmoke
+
+' legend
+' blue - Origin
+' ' green - new
+' ' orange - changed
+' white - 3rd Party
+' end legend
+
+title "Origin OETH Automated Redemption Manager (ARM) Contract Dependencies"
+
+
+object "ZapperOriginARM" as zap <> #$originColor {
+}
+
+object "OriginARM" as arm <><> #$originColor {
+ shares: ARM-oETH-WETH
+ assets: oETH, WETH
+}
+
+object "OETHVault" as oethVault <><> #$thirdPartyColor {
+ assets: oETH, WETH
+}
+
+zap <..> arm
+arm ..> oethVault
+
+@enduml
\ No newline at end of file
diff --git a/foundry.toml b/foundry.toml
index 5803d379..85c172c9 100644
--- a/foundry.toml
+++ b/foundry.toml
@@ -6,7 +6,7 @@ verbosity = 3
sender = "0x0165C55EF814dEFdd658532A48Bd17B2c8356322"
tx_origin = "0x0165C55EF814dEFdd658532A48Bd17B2c8356322"
auto_detect_remappings = false
-gas_reports = ["OethARM", "Proxy", "LidoARM", "OriginARM"]
+gas_reports = ["Proxy", "LidoARM", "OriginARM"]
fs_permissions = [{ access = "read-write", path = "./build" }]
extra_output_files = ["metadata"]
ignored_warnings_from = ["src/contracts/Proxy.sol"]
diff --git a/script/deploy/DeployManager.sol b/script/deploy/DeployManager.sol
index 7aa9052a..f83458b9 100644
--- a/script/deploy/DeployManager.sol
+++ b/script/deploy/DeployManager.sol
@@ -6,14 +6,10 @@ import {VmSafe} from "forge-std/Vm.sol";
import {stdJson} from "forge-std/StdJson.sol";
import {AbstractDeployScript} from "./AbstractDeployScript.sol";
-import {DeployCoreMainnetScript} from "./mainnet/001_DeployCoreScript.sol";
-import {UpgradeMainnetScript} from "./mainnet/002_UpgradeScript.sol";
import {UpgradeLidoARMMainnetScript} from "./mainnet/003_UpgradeLidoARMScript.sol";
import {UpdateCrossPriceMainnetScript} from "./mainnet/004_UpdateCrossPriceScript.sol";
import {RegisterLidoWithdrawalsScript} from "./mainnet/005_RegisterLidoWithdrawalsScript.sol";
import {ChangeFeeCollectorScript} from "./mainnet/006_ChangeFeeCollector.sol";
-import {DeployCoreHoleskyScript} from "./holesky/001_DeployCoreScript.sol";
-import {UpgradeHoleskyScript} from "./holesky/002_UpgradeScript.sol";
import {DeployOriginARMProxyScript} from "./sonic/001_DeployOriginARMProxy.sol";
import {DeployOriginARMScript} from "./sonic/002_DeployOriginARM.sol";
import {UpgradeOriginARMScript} from "./sonic/003_UpgradeOriginARM.sol";
@@ -24,6 +20,7 @@ import {UpgradeLidoARMSetBufferScript} from "./mainnet/009_UpgradeLidoARMSetBuff
import {UpgradeOriginARMSetBufferScript} from "./sonic/005_UpgradeOriginARMSetBufferScript.sol";
import {UpgradeLidoARMAssetScript} from "./mainnet/010_UpgradeLidoARMAssetScript.sol";
import {DeployEtherFiARMScript} from "./mainnet/011_DeployEtherFiARMScript.sol";
+import {UpgradeOETHARMScript} from "./mainnet/012_UpgradeOETHARMScript.sol";
contract DeployManager is Script {
using stdJson for string;
@@ -73,8 +70,6 @@ contract DeployManager is Script {
function run() external {
if (block.chainid == 1 || block.chainid == 31337) {
// TODO: Use vm.readDir to recursively build this?
- _runDeployFile(new DeployCoreMainnetScript());
- _runDeployFile(new UpgradeMainnetScript(getDeployment("OETH_ARM")));
_runDeployFile(new UpgradeLidoARMMainnetScript());
_runDeployFile(new UpdateCrossPriceMainnetScript());
_runDeployFile(new RegisterLidoWithdrawalsScript());
@@ -84,10 +79,9 @@ contract DeployManager is Script {
_runDeployFile(new DeployPendleAdaptor());
_runDeployFile(new UpgradeLidoARMAssetScript());
_runDeployFile(new DeployEtherFiARMScript());
+ _runDeployFile(new UpgradeOETHARMScript());
} else if (block.chainid == 17000) {
// Holesky
- _runDeployFile(new DeployCoreHoleskyScript());
- _runDeployFile(new UpgradeHoleskyScript(getDeployment("OETH_ARM")));
} else if (block.chainid == 146) {
// Sonic
console.log("Deploying Origin ARM");
diff --git a/script/deploy/holesky/001_DeployCoreScript.sol b/script/deploy/holesky/001_DeployCoreScript.sol
deleted file mode 100644
index 8650642e..00000000
--- a/script/deploy/holesky/001_DeployCoreScript.sol
+++ /dev/null
@@ -1,33 +0,0 @@
-// SPDX-License-Identifier: MIT
-
-pragma solidity 0.8.23;
-
-import "forge-std/console.sol";
-import {Vm} from "forge-std/Vm.sol";
-
-import {OethARM} from "contracts/OethARM.sol";
-import {Proxy} from "contracts/Proxy.sol";
-import {Holesky} from "contracts/utils/Addresses.sol";
-import {AbstractDeployScript} from "../AbstractDeployScript.sol";
-
-contract DeployCoreHoleskyScript is AbstractDeployScript {
- string public constant override DEPLOY_NAME = "001_CoreHolesky";
- bool public constant override proposalExecuted = false;
-
- function _execute() internal override {
- console.log("Deploy:", DEPLOY_NAME);
- console.log("------------");
-
- // 1. Deploy proxy contracts
- Proxy proxy = new Proxy();
- _recordDeploy("OETH_ARM", address(proxy));
-
- // 2. Deploy implementation
- OethARM implementation = new OethARM(Holesky.OETH, Holesky.WETH, Holesky.OETH_VAULT);
- _recordDeploy("OETH_ARM_IMPL", address(implementation));
-
- // 3. Initialize proxy, set the owner and operator to the RELAYER and approve the OETH Vault to transfer OETH
- bytes memory data = abi.encodeWithSignature("initialize(address)", Holesky.RELAYER);
- proxy.initialize(address(implementation), Holesky.RELAYER, data);
- }
-}
diff --git a/script/deploy/holesky/002_UpgradeScript.sol b/script/deploy/holesky/002_UpgradeScript.sol
deleted file mode 100644
index 30dd8b2f..00000000
--- a/script/deploy/holesky/002_UpgradeScript.sol
+++ /dev/null
@@ -1,38 +0,0 @@
-// SPDX-License-Identifier: MIT
-
-pragma solidity 0.8.23;
-
-import "forge-std/console.sol";
-import {Vm} from "forge-std/Vm.sol";
-
-import {OethARM} from "contracts/OethARM.sol";
-import {Proxy} from "contracts/Proxy.sol";
-import {Holesky} from "contracts/utils/Addresses.sol";
-import {AbstractDeployScript} from "../AbstractDeployScript.sol";
-
-contract UpgradeHoleskyScript is AbstractDeployScript {
- string public constant override DEPLOY_NAME = "002_UpgradeHolesky";
- bool public constant override proposalExecuted = false;
-
- address newImpl;
- Proxy internal proxy;
-
- constructor(address _proxy) {
- proxy = Proxy(payable(_proxy));
- }
-
- function _execute() internal override {
- console.log("Deploy:", DEPLOY_NAME);
- console.log("------------");
-
- // 1. Deploy new implementation
- newImpl = address(new OethARM(Holesky.OETH, Holesky.WETH, Holesky.OETH_VAULT));
- _recordDeploy("OETH_ARM_IMPL", newImpl);
- }
-
- function _fork() internal override {
- // Upgrade the proxy
- vm.prank(Holesky.RELAYER);
- proxy.upgradeTo(newImpl);
- }
-}
diff --git a/script/deploy/mainnet/001_DeployCoreScript.sol b/script/deploy/mainnet/001_DeployCoreScript.sol
deleted file mode 100644
index 2b97c617..00000000
--- a/script/deploy/mainnet/001_DeployCoreScript.sol
+++ /dev/null
@@ -1,53 +0,0 @@
-// SPDX-License-Identifier: MIT
-
-pragma solidity 0.8.23;
-
-import "forge-std/console.sol";
-import {Vm} from "forge-std/Vm.sol";
-
-import {OethARM} from "contracts/OethARM.sol";
-import {Proxy} from "contracts/Proxy.sol";
-import {Mainnet} from "contracts/utils/Addresses.sol";
-import {GovProposal, GovSixHelper} from "contracts/utils/GovSixHelper.sol";
-import {AbstractDeployScript} from "../AbstractDeployScript.sol";
-
-contract DeployCoreMainnetScript is AbstractDeployScript {
- using GovSixHelper for GovProposal;
-
- GovProposal public govProposal;
-
- string public constant override DEPLOY_NAME = "001_CoreMainnet";
- bool public constant override proposalExecuted = true;
-
- function _execute() internal override {
- console.log("Deploy:", DEPLOY_NAME);
- console.log("------------");
-
- // 1. Deploy proxy contracts
- Proxy proxy = new Proxy();
- _recordDeploy("OETH_ARM", address(proxy));
-
- // 2. Deploy implementation
- OethARM implementation = new OethARM(Mainnet.OETH, Mainnet.WETH, Mainnet.OETH_VAULT);
- _recordDeploy("OETH_ARM_IMPL", address(implementation));
-
- // 3. Initialize proxy, set the owner to TIMELOCK, set the operator to the OETH Relayer and approve the OETH Vault to transfer OETH
- bytes memory data = abi.encodeWithSignature("initialize(address)", Mainnet.OETH_RELAYER);
- proxy.initialize(address(implementation), Mainnet.TIMELOCK, data);
- }
-
- function _buildGovernanceProposal() internal override {
- // govProposal.setDescription("Setup OETH ARM Contract");
-
- // NOTE: This has already been done during deployment
- // but doing this here to test governance flow.
-
- // Set operator
- // govProposal.action(deployedContracts["OETH_ARM"], "initialize(address)", abi.encode(Mainnet.OETH_RELAYER));
- }
-
- function _fork() internal override {
- // Simulate on fork
- // govProposal.simulate();
- }
-}
diff --git a/script/deploy/mainnet/002_UpgradeScript.sol b/script/deploy/mainnet/002_UpgradeScript.sol
deleted file mode 100644
index f9804f80..00000000
--- a/script/deploy/mainnet/002_UpgradeScript.sol
+++ /dev/null
@@ -1,39 +0,0 @@
-// SPDX-License-Identifier: MIT
-
-pragma solidity 0.8.23;
-
-import "forge-std/console.sol";
-import {Vm} from "forge-std/Vm.sol";
-
-import {OethARM} from "contracts/OethARM.sol";
-import {Proxy} from "contracts/Proxy.sol";
-import {Mainnet} from "contracts/utils/Addresses.sol";
-import {AbstractDeployScript} from "../AbstractDeployScript.sol";
-
-contract UpgradeMainnetScript is AbstractDeployScript {
- string public constant override DEPLOY_NAME = "002_UpgradeMainnet";
- bool public constant override proposalExecuted = true;
-
- address newImpl;
- Proxy internal proxy;
-
- constructor(address _proxy) {
- proxy = Proxy(payable(_proxy));
- }
-
- function _execute() internal override {
- console.log("Deploy:", DEPLOY_NAME);
- console.log("------------");
-
- // 1. Deploy new implementation
- newImpl = address(new OethARM(Mainnet.OETH, Mainnet.WETH, Mainnet.OETH_VAULT));
- _recordDeploy("OETH_ARM_IMPL", newImpl);
- }
-
- function _fork() internal override {
- // Upgrade the proxy
- vm.prank(Mainnet.TIMELOCK);
- proxy.upgradeTo(newImpl);
- console.log("OethARM upgraded");
- }
-}
diff --git a/script/deploy/mainnet/005_RegisterLidoWithdrawalsScript.sol b/script/deploy/mainnet/005_RegisterLidoWithdrawalsScript.sol
index 7fd9fafb..0a16afb1 100644
--- a/script/deploy/mainnet/005_RegisterLidoWithdrawalsScript.sol
+++ b/script/deploy/mainnet/005_RegisterLidoWithdrawalsScript.sol
@@ -3,7 +3,6 @@
pragma solidity 0.8.23;
import "forge-std/console.sol";
-import {Vm} from "forge-std/Vm.sol";
import {LidoARM} from "contracts/LidoARM.sol";
import {Mainnet} from "contracts/utils/Addresses.sol";
diff --git a/script/deploy/mainnet/012_UpgradeOETHARMScript.sol b/script/deploy/mainnet/012_UpgradeOETHARMScript.sol
new file mode 100644
index 00000000..282085df
--- /dev/null
+++ b/script/deploy/mainnet/012_UpgradeOETHARMScript.sol
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.23;
+
+// Foundry imports
+import {console} from "forge-std/console.sol";
+
+// Contract imports
+import {Proxy} from "contracts/Proxy.sol";
+import {Mainnet} from "contracts/utils/Addresses.sol";
+import {OriginARM} from "contracts/OriginARM.sol";
+import {IERC20} from "contracts/Interfaces.sol";
+
+// Deployment imports
+import {GovProposal, GovSixHelper} from "contracts/utils/GovSixHelper.sol";
+import {AbstractDeployScript} from "../AbstractDeployScript.sol";
+
+contract UpgradeOETHARMScript is AbstractDeployScript {
+ using GovSixHelper for GovProposal;
+
+ GovProposal public govProposal;
+
+ string public constant override DEPLOY_NAME = "012_UpgradeOETHARMScript";
+ bool public constant override proposalExecuted = false;
+
+ Proxy morphoMarketProxy;
+ OriginARM originARMImpl;
+ OriginARM oethARM;
+
+ function _execute() internal override {
+ console.log("Deploy:", DEPLOY_NAME);
+ console.log("------------");
+
+ // 1. Deploy new Origin implementation
+ uint256 claimDelay = tenderlyTestnet ? 1 minutes : 10 minutes;
+ originARMImpl = new OriginARM(Mainnet.OETH, Mainnet.WETH, Mainnet.OETH_VAULT, claimDelay, 1e7, 1e18);
+ _recordDeploy("OETH_ARM_IMPL", address(originARMImpl));
+
+ console.log("Finished deploying", DEPLOY_NAME);
+ }
+
+ function _buildGovernanceProposal() internal override {
+ govProposal.setDescription("Update OETH ARM to use Origin ARM contract");
+
+ // 1. Transfer OETH out of the existing OETH ARM, to have a clean assets per share ratio.
+ uint256 balanceOETH = IERC20(Mainnet.OETH).balanceOf(deployedContracts["OETH_ARM"]);
+ govProposal.action(
+ deployedContracts["OETH_ARM"],
+ "transferToken(address,address,uint256)",
+ abi.encode(Mainnet.OETH, Mainnet.TREASURY_LP, balanceOETH)
+ );
+
+ // 2. Transfer WETH out of the existing OETH ARM, to have a clean assets per share ratio.
+ uint256 balanceWETH = IERC20(Mainnet.WETH).balanceOf(deployedContracts["OETH_ARM"]);
+ govProposal.action(
+ deployedContracts["OETH_ARM"],
+ "transferToken(address,address,uint256)",
+ abi.encode(Mainnet.WETH, Mainnet.TREASURY_LP, balanceWETH)
+ );
+
+ // 3. Timelock needs to approve the OETH ARM to pull WETH for initialization.
+ govProposal.action(Mainnet.WETH, "approve(address,uint256)", abi.encode(deployedContracts["OETH_ARM"], 1e12));
+
+ // 4. Upgrade the OETH ARM implementation, and initialize.
+ bytes memory initializeData = abi.encodeWithSelector(
+ OriginARM.initialize.selector,
+ "Origin ARM",
+ "ARM-WETH-OETH",
+ Mainnet.ARM_RELAYER,
+ 2000, // 20% performance fee
+ Mainnet.ARM_BUYBACK,
+ address(0)
+ );
+
+ govProposal.action(
+ deployedContracts["OETH_ARM"],
+ "upgradeToAndCall(address,bytes)",
+ abi.encode(deployedContracts["OETH_ARM_IMPL"], initializeData)
+ );
+
+ govProposal.simulate();
+ }
+}
diff --git a/script/deploy/sonic/001_DeployOriginARMProxy.sol b/script/deploy/sonic/001_DeployOriginARMProxy.sol
index b2a453c9..63a84203 100644
--- a/script/deploy/sonic/001_DeployOriginARMProxy.sol
+++ b/script/deploy/sonic/001_DeployOriginARMProxy.sol
@@ -3,7 +3,6 @@
pragma solidity 0.8.23;
import "forge-std/console.sol";
-import {Vm} from "forge-std/Vm.sol";
import {Proxy} from "contracts/Proxy.sol";
import {AbstractDeployScript} from "../AbstractDeployScript.sol";
diff --git a/src/contracts/Interfaces.sol b/src/contracts/Interfaces.sol
index 3f36b906..623002c6 100644
--- a/src/contracts/Interfaces.sol
+++ b/src/contracts/Interfaces.sol
@@ -13,100 +13,6 @@ interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
}
-interface IOethARM {
- function token0() external returns (address);
- function token1() external returns (address);
- function owner() external returns (address);
-
- /**
- * @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
- * at least amountIn on the input token.
- *
- * @param inToken Input token.
- * @param outToken Output token.
- * @param amountIn The amount of input tokens to send.
- * @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert.
- * @param to Recipient of the output tokens.
- */
- function swapExactTokensForTokens(
- IERC20 inToken,
- IERC20 outToken,
- uint256 amountIn,
- uint256 amountOutMin,
- address to
- ) external;
-
- /**
- * @notice Uniswap V2 Router compatible interface. 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
- * at least amountIn on the input token.
- *
- * @param amountIn The amount of input tokens to send.
- * @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert.
- * @param path The input and output token addresses.
- * @param to Recipient of the output tokens.
- * @param deadline Unix timestamp after which the transaction will revert.
- * @return amounts The input and output token amounts.
- */
- function swapExactTokensForTokens(
- uint256 amountIn,
- uint256 amountOutMin,
- address[] calldata path,
- address to,
- uint256 deadline
- ) external returns (uint256[] memory amounts);
-
- /**
- * @notice Receive an exact amount of output tokens for as few input tokens as possible.
- * msg.sender should have already given the router an allowance of
- * at least amountInMax on the input token.
- *
- * @param inToken Input token.
- * @param outToken Output token.
- * @param amountOut The amount of output tokens to receive.
- * @param amountInMax The maximum amount of input tokens that can be required before the transaction reverts.
- * @param to Recipient of the output tokens.
- */
- function swapTokensForExactTokens(
- IERC20 inToken,
- IERC20 outToken,
- uint256 amountOut,
- uint256 amountInMax,
- address to
- ) external;
-
- /**
- * @notice Uniswap V2 Router compatible interface. Receive an exact amount of
- * output tokens for as few input tokens as possible.
- * msg.sender should have already given the router an allowance of
- * at least amountInMax on the input token.
- *
- * @param amountOut The amount of output tokens to receive.
- * @param amountInMax The maximum amount of input tokens that can be required before the transaction reverts.
- * @param path The input and output token addresses.
- * @param to Recipient of the output tokens.
- * @param deadline Unix timestamp after which the transaction will revert.
- * @return amounts The input and output token amounts.
- */
- function swapTokensForExactTokens(
- uint256 amountOut,
- uint256 amountInMax,
- address[] calldata path,
- address to,
- uint256 deadline
- ) external returns (uint256[] memory amounts);
-
- function setOwner(address newOwner) external;
- function transferToken(address token, address to, uint256 amount) external;
-
- // From OethLiquidityManager
- function requestWithdrawal(uint256 amount) external returns (uint256 requestId, uint256 queued);
- function claimWithdrawal(uint256 requestId) external;
- function claimWithdrawals(uint256[] calldata requestIds) external;
-}
-
interface ILiquidityProviderARM is IERC20 {
function previewDeposit(uint256 assets) external returns (uint256 shares);
function deposit(uint256 assets) external returns (uint256 shares);
@@ -319,6 +225,7 @@ interface IEETHWithdrawalNFT {
}
interface IEETHRedemptionManager {
+ function redeemEEth(uint256 amount, address receiver) external;
function redeemWeEth(uint256 amount, address receiver) external;
function canRedeem(uint256 amount) external view returns (bool);
}
diff --git a/src/contracts/OethARM.sol b/src/contracts/OethARM.sol
deleted file mode 100644
index 027448ff..00000000
--- a/src/contracts/OethARM.sol
+++ /dev/null
@@ -1,35 +0,0 @@
-// SPDX-License-Identifier: BUSL-1.1
-pragma solidity ^0.8.23;
-
-import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
-
-import {AbstractARM} from "./AbstractARM.sol";
-import {PeggedARM} from "./PeggedARM.sol";
-import {OwnerLP} from "./OwnerLP.sol";
-import {OethLiquidityManager} from "./OethLiquidityManager.sol";
-
-/**
- * @title Origin Ether (OETH) Automated Redemption Manager (ARM)
- * @author Origin Protocol Inc
- */
-contract OethARM is Initializable, OwnerLP, PeggedARM, OethLiquidityManager {
- /// @param _oeth The address of the OETH token that is being swapped into this contract.
- /// @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, _weth, 10 minutes, 0, 0)
- PeggedARM(false)
- OethLiquidityManager(_oeth, _oethVault)
- {}
-
- /// @notice Initialize the contract.
- /// @param _operator The address of the account that can request and claim OETH withdrawals from the OETH Vault.
- function initialize(address _operator) external initializer {
- _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/OethLiquidityManager.sol b/src/contracts/OethLiquidityManager.sol
deleted file mode 100644
index 21517ca8..00000000
--- a/src/contracts/OethLiquidityManager.sol
+++ /dev/null
@@ -1,62 +0,0 @@
-// SPDX-License-Identifier: BUSL-1.1
-pragma solidity ^0.8.23;
-
-import {OwnableOperable} from "./OwnableOperable.sol";
-import {IERC20, IOriginVault} from "./Interfaces.sol";
-
-/**
- * @title Manages OETH liquidity against the OETH Vault.
- * @author Origin Protocol Inc
- */
-contract OethLiquidityManager is OwnableOperable {
- address public immutable oeth;
- address public immutable oethVault;
-
- /// @param _oeth The address of the OETH token.
- /// @param _oethVault The address of the OETH Vault proxy.
- constructor(address _oeth, address _oethVault) {
- oeth = _oeth;
- oethVault = _oethVault;
- }
-
- /**
- * @notice Approve the OETH Vault to transfer OETH from this cont4act.
- */
- function approvals() external onlyOwner {
- _approvals();
- }
-
- function _approvals() internal {
- IERC20(oeth).approve(oethVault, type(uint256).max);
- }
-
- /**
- * @notice Request withdrawal of WETH from the OETH Vault.
- * @param amount The amount of OETH to burn and WETH to withdraw.
- */
- function requestWithdrawal(uint256 amount)
- external
- onlyOperatorOrOwner
- returns (uint256 requestId, uint256 queued)
- {
- return IOriginVault(oethVault).requestWithdrawal(amount);
- }
-
- /**
- * @notice Claim previously requested withdrawal of WETH from the OETH Vault.
- * The Vault's claimable WETH needs to be greater than or equal to the queued amount of the request.
- * @param requestId The ID of the OETH Vault's withdrawal request.
- */
- function claimWithdrawal(uint256 requestId) external onlyOperatorOrOwner {
- IOriginVault(oethVault).claimWithdrawal(requestId);
- }
-
- /**
- * @notice Claim multiple previously requested withdrawals of WETH from the OETH Vault.
- * The Vault's claimable WETH needs to be greater than or equal to the queued amount of the request.
- * @param requestIds List of request IDs from the OETH Vault's withdrawal requests.
- */
- function claimWithdrawals(uint256[] memory requestIds) external onlyOperatorOrOwner {
- IOriginVault(oethVault).claimWithdrawals(requestIds);
- }
-}
diff --git a/src/contracts/OwnerLP.sol b/src/contracts/OwnerLP.sol
deleted file mode 100644
index 6778172a..00000000
--- a/src/contracts/OwnerLP.sol
+++ /dev/null
@@ -1,14 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.23;
-
-import {Ownable} from "./Ownable.sol";
-import {IERC20} from "./Interfaces.sol";
-
-abstract contract OwnerLP is Ownable {
- /**
- * @notice Owner can transfer out any ERC20 token.
- */
- function transferToken(address token, address to, uint256 amount) external onlyOwner {
- IERC20(token).transfer(to, amount);
- }
-}
diff --git a/src/contracts/PeggedARM.sol b/src/contracts/PeggedARM.sol
deleted file mode 100644
index 9a2f59ae..00000000
--- a/src/contracts/PeggedARM.sol
+++ /dev/null
@@ -1,49 +0,0 @@
-// SPDX-License-Identifier: BUSL-1.1
-pragma solidity ^0.8.23;
-
-import {AbstractARM} from "./AbstractARM.sol";
-import {IERC20} from "./Interfaces.sol";
-
-abstract contract PeggedARM is AbstractARM {
- /// @notice If true, the ARM contract can swap in both directions between token0 and token1.
- bool public immutable bothDirections;
-
- constructor(bool _bothDirections) {
- bothDirections = _bothDirections;
- }
-
- function _swapExactTokensForTokens(IERC20 inToken, IERC20 outToken, uint256 amountIn, address to)
- internal
- override
- returns (uint256 amountOut)
- {
- return _swap(inToken, outToken, amountIn, to);
- }
-
- function _swapTokensForExactTokens(IERC20 inToken, IERC20 outToken, uint256 amountOut, address to)
- internal
- override
- returns (uint256 amountIn)
- {
- return _swap(inToken, outToken, amountOut, to);
- }
-
- function _swap(IERC20 inToken, IERC20 outToken, uint256 amount, address to) internal returns (uint256) {
- if (bothDirections) {
- require(
- inToken == token0 && outToken == token1 || inToken == token1 && outToken == token0, "ARM: Invalid swap"
- );
- } else {
- require(inToken == token0 && outToken == token1, "ARM: Invalid swap");
- }
-
- // Transfer the input tokens from the caller to this ARM contract
- require(inToken.transferFrom(msg.sender, address(this), amount), "failed transfer in");
-
- // Transfer the same amount of output tokens to the recipient
- require(outToken.transfer(to, amount), "failed transfer out");
-
- // 1:1 swaps so the exact amount is returned as the calculated amount
- return amount;
- }
-}
diff --git a/src/contracts/utils/Addresses.sol b/src/contracts/utils/Addresses.sol
index f7f24a71..8c9f4660 100644
--- a/src/contracts/utils/Addresses.sol
+++ b/src/contracts/utils/Addresses.sol
@@ -30,6 +30,7 @@ library Mainnet {
address public constant EETH = 0x35fA164735182de50811E8e2E824cFb9B6118ac2;
address public constant WEETH = 0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee;
address public constant STETH = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84;
+ address public constant WOETH = 0xDcEe70654261AF21C44c093C300eD3Bb97b78192;
address public constant WSTETH = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0;
address public constant MORPHO = 0x58D97B57BB95320F9a05dC918Aef65434969c2B2;
diff --git a/test/Base.sol b/test/Base.sol
index 234a59f3..86cf685d 100644
--- a/test/Base.sol
+++ b/test/Base.sol
@@ -6,7 +6,6 @@ import {Test} from "forge-std/Test.sol";
// Contracts
import {Proxy} from "contracts/Proxy.sol";
-import {OethARM} from "contracts/OethARM.sol";
import {LidoARM} from "contracts/LidoARM.sol";
import {EtherFiARM} from "contracts/EtherFiARM.sol";
import {OriginARM} from "contracts/OriginARM.sol";
@@ -37,14 +36,12 @@ abstract contract Base_Test_ is Test {
//////////////////////////////////////////////////////
/// --- CONTRACTS
//////////////////////////////////////////////////////
- Proxy public proxy;
Proxy public lpcProxy;
Proxy public lidoProxy;
Proxy public etherfiProxy;
Proxy public originARMProxy;
Proxy public harvesterProxy;
Proxy public morphoMarketProxy;
- OethARM public oethARM;
LidoARM public lidoARM;
EtherFiARM public etherfiARM;
SonicHarvester public harvester;
@@ -105,11 +102,9 @@ abstract contract Base_Test_ is Test {
/// @notice Better if called once all contract have been depoyed.
function labelAll() public virtual {
// Contracts
- _labelNotNull(address(proxy), "DEFAULT PROXY");
_labelNotNull(address(lpcProxy), "LPC PROXY");
_labelNotNull(address(lidoProxy), "LIDO ARM PROXY");
_labelNotNull(address(etherfiProxy), "ETHERFI ARM PROXY");
- _labelNotNull(address(oethARM), "OETH ARM");
_labelNotNull(address(lidoARM), "LIDO ARM");
_labelNotNull(address(originARM), "ORIGIN ARM");
_labelNotNull(address(capManager), "CAP MANAGER");
diff --git a/test/fork/EtherFiARM/RequestWithdraw.t.sol b/test/fork/EtherFiARM/RequestWithdraw.t.sol
index 2e761d84..f1c47b85 100644
--- a/test/fork/EtherFiARM/RequestWithdraw.t.sol
+++ b/test/fork/EtherFiARM/RequestWithdraw.t.sol
@@ -2,7 +2,6 @@
pragma solidity 0.8.23;
// Test
-import {Mainnet} from "src/contracts/utils/Addresses.sol";
import {Fork_Shared_Test} from "test/fork/EtherFiARM/shared/Shared.sol";
contract Fork_Concrete_EtherFiARM_RequestWithdraw_Test_ is Fork_Shared_Test {
diff --git a/test/fork/Harvester/Swap.sol b/test/fork/Harvester/Swap.sol
index eb833ac1..4bba23f8 100644
--- a/test/fork/Harvester/Swap.sol
+++ b/test/fork/Harvester/Swap.sol
@@ -5,7 +5,6 @@ import {Sonic} from "contracts/utils/Addresses.sol";
import {SonicHarvester} from "contracts/SonicHarvester.sol";
import {Fork_Shared_Test} from "test/fork/Harvester/shared/Shared.sol";
-import {console} from "forge-std/console.sol";
contract Fork_Concrete_Harvester_Swap_Test_ is Fork_Shared_Test {
address public constant OS_WHALE = 0x9F0dF7799f6FDAd409300080cfF680f5A23df4b1;
diff --git a/test/fork/LidoFixedPriceMultiLpARM/ClaimRedeem.t.sol b/test/fork/LidoARM/ClaimRedeem.t.sol
similarity index 100%
rename from test/fork/LidoFixedPriceMultiLpARM/ClaimRedeem.t.sol
rename to test/fork/LidoARM/ClaimRedeem.t.sol
diff --git a/test/fork/LidoFixedPriceMultiLpARM/ClaimStETHWithdrawalForWETH.t.sol b/test/fork/LidoARM/ClaimStETHWithdrawalForWETH.t.sol
similarity index 96%
rename from test/fork/LidoFixedPriceMultiLpARM/ClaimStETHWithdrawalForWETH.t.sol
rename to test/fork/LidoARM/ClaimStETHWithdrawalForWETH.t.sol
index 5ea698e8..00dff276 100644
--- a/test/fork/LidoFixedPriceMultiLpARM/ClaimStETHWithdrawalForWETH.t.sol
+++ b/test/fork/LidoARM/ClaimStETHWithdrawalForWETH.t.sol
@@ -5,11 +5,11 @@ pragma solidity 0.8.23;
import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
// Contracts
-import {IERC20, IStETHWithdrawal} from "contracts/Interfaces.sol";
+import {IStETHWithdrawal} from "contracts/Interfaces.sol";
import {LidoARM} from "contracts/LidoARM.sol";
import {Mainnet} from "contracts/utils/Addresses.sol";
-contract Fork_Concrete_LidoARM_RequestLidoWithdrawals_Test_ is Fork_Shared_Test_ {
+contract Fork_Concrete_LidoARM_ClaimLidoWithdrawals_Test_ is Fork_Shared_Test_ {
uint256[] amounts0;
uint256[] amounts1;
uint256[] amounts2;
diff --git a/test/fork/LidoFixedPriceMultiLpARM/CollectFees.t.sol b/test/fork/LidoARM/CollectFees.t.sol
similarity index 100%
rename from test/fork/LidoFixedPriceMultiLpARM/CollectFees.t.sol
rename to test/fork/LidoARM/CollectFees.t.sol
diff --git a/test/fork/LidoFixedPriceMultiLpARM/Constructor.t.sol b/test/fork/LidoARM/Constructor.t.sol
similarity index 95%
rename from test/fork/LidoFixedPriceMultiLpARM/Constructor.t.sol
rename to test/fork/LidoARM/Constructor.t.sol
index 03462efb..934d62df 100644
--- a/test/fork/LidoFixedPriceMultiLpARM/Constructor.t.sol
+++ b/test/fork/LidoARM/Constructor.t.sol
@@ -2,6 +2,7 @@
pragma solidity 0.8.23;
// Test imports
+import {Mainnet} from "src/contracts/utils/Addresses.sol";
import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
contract Fork_Concrete_LidoARM_Constructor_Test is Fork_Shared_Test_ {
diff --git a/test/fork/LidoFixedPriceMultiLpARM/Deposit.t.sol b/test/fork/LidoARM/Deposit.t.sol
similarity index 100%
rename from test/fork/LidoFixedPriceMultiLpARM/Deposit.t.sol
rename to test/fork/LidoARM/Deposit.t.sol
diff --git a/test/fork/LidoARM/Proxy.t.sol b/test/fork/LidoARM/Proxy.t.sol
new file mode 100644
index 00000000..6c238c8e
--- /dev/null
+++ b/test/fork/LidoARM/Proxy.t.sol
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.23;
+
+// Contracts
+import {LidoARM} from "contracts/LidoARM.sol";
+
+// Test imports
+import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
+
+// Utils
+import {Mainnet} from "contracts/utils/Addresses.sol";
+
+/// @notice The purpose of this contract is to test the `Proxy` contract.
+contract Fork_Concrete_LidoARM_Proxy_Test_ is Fork_Shared_Test_ {
+ //////////////////////////////////////////////////////
+ /// --- SETUP
+ //////////////////////////////////////////////////////
+ function setUp() public virtual override {
+ super.setUp();
+ lidoProxy.setOwner(Mainnet.TIMELOCK);
+ }
+
+ //////////////////////////////////////////////////////
+ /// --- REVERTING TESTS
+ //////////////////////////////////////////////////////
+ function test_RevertWhen_UnauthorizedAccess() public {
+ vm.startPrank(address(0x123));
+ vm.expectRevert("ARM: Only owner can call this function.");
+ lidoProxy.setOwner(deployer);
+
+ vm.expectRevert("ARM: Only owner can call this function.");
+ lidoProxy.initialize(address(this), address(this), "");
+
+ vm.expectRevert("ARM: Only owner can call this function.");
+ lidoProxy.upgradeTo(address(this));
+
+ vm.expectRevert("ARM: Only owner can call this function.");
+ lidoProxy.upgradeToAndCall(address(this), "");
+ vm.stopPrank();
+ }
+
+ //////////////////////////////////////////////////////
+ /// --- PASSING TESTS
+ //////////////////////////////////////////////////////
+ function test_Upgrade() public asLidoARMOwner {
+ address owner = Mainnet.TIMELOCK;
+
+ // Deploy new implementation
+ LidoARM newImplementation = new LidoARM(Mainnet.STETH, Mainnet.WETH, Mainnet.OETH_VAULT, 10 minutes, 0, 0);
+ lidoProxy.upgradeTo(address(newImplementation));
+ assertEq(lidoProxy.implementation(), address(newImplementation));
+
+ // Ensure ownership was preserved.
+ assertEq(lidoProxy.owner(), owner);
+ assertEq(lidoARM.owner(), owner);
+
+ // Ensure the storage was preserved through the upgrade.
+ assertEq(address(lidoARM.token0()), Mainnet.WETH);
+ assertEq(address(lidoARM.token1()), Mainnet.STETH);
+ }
+
+ function test_UpgradeAndCall() public asLidoARMOwner {
+ address owner = Mainnet.TIMELOCK;
+
+ // Deploy new implementation
+ LidoARM newImplementation = new LidoARM(Mainnet.STETH, Mainnet.WETH, Mainnet.OETH_VAULT, 10 minutes, 0, 0);
+ bytes memory data = abi.encodeWithSignature("setOperator(address)", address(0x123));
+
+ lidoProxy.upgradeToAndCall(address(newImplementation), data);
+ assertEq(lidoProxy.implementation(), address(newImplementation));
+
+ // Ensure ownership was preserved.
+ assertEq(lidoProxy.owner(), owner);
+ assertEq(lidoARM.owner(), owner);
+
+ // Ensure the post upgrade code was run
+ assertEq(lidoARM.operator(), address(0x123));
+ }
+}
diff --git a/test/fork/LidoFixedPriceMultiLpARM/RequestRedeem.t.sol b/test/fork/LidoARM/RequestRedeem.t.sol
similarity index 100%
rename from test/fork/LidoFixedPriceMultiLpARM/RequestRedeem.t.sol
rename to test/fork/LidoARM/RequestRedeem.t.sol
diff --git a/test/fork/LidoFixedPriceMultiLpARM/RequestStETHWithdrawalForETH.t.sol b/test/fork/LidoARM/RequestStETHWithdrawalForETH.t.sol
similarity index 100%
rename from test/fork/LidoFixedPriceMultiLpARM/RequestStETHWithdrawalForETH.t.sol
rename to test/fork/LidoARM/RequestStETHWithdrawalForETH.t.sol
diff --git a/test/fork/LidoFixedPriceMultiLpARM/SetCrossPrice.t.sol b/test/fork/LidoARM/SetCrossPrice.t.sol
similarity index 100%
rename from test/fork/LidoFixedPriceMultiLpARM/SetCrossPrice.t.sol
rename to test/fork/LidoARM/SetCrossPrice.t.sol
diff --git a/test/fork/LidoFixedPriceMultiLpARM/Setters.t.sol b/test/fork/LidoARM/Setters.t.sol
similarity index 99%
rename from test/fork/LidoFixedPriceMultiLpARM/Setters.t.sol
rename to test/fork/LidoARM/Setters.t.sol
index 9de35b6f..9b625227 100644
--- a/test/fork/LidoFixedPriceMultiLpARM/Setters.t.sol
+++ b/test/fork/LidoARM/Setters.t.sol
@@ -5,11 +5,10 @@ pragma solidity 0.8.23;
import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
// Contracts
-import {IERC20} from "contracts/Interfaces.sol";
import {AbstractARM} from "contracts/AbstractARM.sol";
import {CapManager} from "contracts/CapManager.sol";
-contract Fork_Concrete_lidoARM_Setters_Test_ is Fork_Shared_Test_ {
+contract Fork_Concrete_LidoARM_Setters_Test_ is Fork_Shared_Test_ {
address[] testProviders;
//////////////////////////////////////////////////////
diff --git a/test/fork/LidoFixedPriceMultiLpARM/SwapExactTokensForTokens.t.sol b/test/fork/LidoARM/SwapExactTokensForTokens.t.sol
similarity index 100%
rename from test/fork/LidoFixedPriceMultiLpARM/SwapExactTokensForTokens.t.sol
rename to test/fork/LidoARM/SwapExactTokensForTokens.t.sol
diff --git a/test/fork/LidoFixedPriceMultiLpARM/SwapTokensForExactTokens.t.sol b/test/fork/LidoARM/SwapTokensForExactTokens.t.sol
similarity index 100%
rename from test/fork/LidoFixedPriceMultiLpARM/SwapTokensForExactTokens.t.sol
rename to test/fork/LidoARM/SwapTokensForExactTokens.t.sol
diff --git a/test/fork/LidoFixedPriceMultiLpARM/TotalAssets.t.sol b/test/fork/LidoARM/TotalAssets.t.sol
similarity index 98%
rename from test/fork/LidoFixedPriceMultiLpARM/TotalAssets.t.sol
rename to test/fork/LidoARM/TotalAssets.t.sol
index 84078e1b..f77ec6fb 100644
--- a/test/fork/LidoFixedPriceMultiLpARM/TotalAssets.t.sol
+++ b/test/fork/LidoARM/TotalAssets.t.sol
@@ -7,10 +7,6 @@ import {stdError} from "forge-std/StdError.sol";
// Test imports
import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
-// Contracts
-import {IERC20} from "contracts/Interfaces.sol";
-import {AbstractARM} from "contracts/AbstractARM.sol";
-
contract Fork_Concrete_LidoARM_TotalAssets_Test_ is Fork_Shared_Test_ {
//////////////////////////////////////////////////////
/// --- SETUP
diff --git a/test/fork/OethARM/Ownable.t.sol b/test/fork/OethARM/Ownable.t.sol
deleted file mode 100644
index 02240846..00000000
--- a/test/fork/OethARM/Ownable.t.sol
+++ /dev/null
@@ -1,49 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity 0.8.23;
-
-// Test imports
-import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
-
-// Utils
-import {Mainnet} from "contracts/utils/Addresses.sol";
-
-/// @notice The purpose of this contract is to test the `Ownable` contract.
-contract Fork_Concrete_OethARM_Ownable_Test_ is Fork_Shared_Test_ {
- //////////////////////////////////////////////////////
- /// --- REVERTING TESTS
- //////////////////////////////////////////////////////
- function test_RevertWhen_SetOperator_Because_NotOwner() public {
- vm.expectRevert("ARM: Only owner can call this function.");
- vm.prank(alice);
- oethARM.setOperator(deployer);
- }
-
- function test_RevertWhen_SetOwner_Because_NotOwner() public {
- vm.expectRevert("ARM: Only owner can call this function.");
- vm.prank(alice);
- oethARM.setOwner(deployer);
- }
-
- //////////////////////////////////////////////////////
- /// --- PASSING TESTS
- //////////////////////////////////////////////////////
- function test_SetOperator() public asOwner {
- // Assertions before
- assertEq(oethARM.operator(), operator);
-
- oethARM.setOperator(alice);
-
- // Assertions after
- assertEq(oethARM.operator(), alice);
- }
-
- function test_SetOwner() public asOwner {
- // Assertions before
- assertEq(oethARM.owner(), Mainnet.TIMELOCK);
-
- oethARM.setOwner(alice);
-
- // Assertions after
- assertEq(oethARM.owner(), alice);
- }
-}
diff --git a/test/fork/OethARM/Proxy.t.sol b/test/fork/OethARM/Proxy.t.sol
deleted file mode 100644
index e55f2512..00000000
--- a/test/fork/OethARM/Proxy.t.sol
+++ /dev/null
@@ -1,69 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity 0.8.23;
-
-// Contracts
-import {OethARM} from "contracts/OethARM.sol";
-
-// Test imports
-import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
-
-// Utils
-import {Mainnet} from "contracts/utils/Addresses.sol";
-
-/// @notice The purpose of this contract is to test the `Proxy` contract.
-contract Fork_Concrete_OethARM_Proxy_Test_ is Fork_Shared_Test_ {
- //////////////////////////////////////////////////////
- /// --- REVERTING TESTS
- //////////////////////////////////////////////////////
- function test_RevertWhen_UnauthorizedAccess() public {
- vm.expectRevert("ARM: Only owner can call this function.");
- proxy.setOwner(deployer);
-
- vm.expectRevert("ARM: Only owner can call this function.");
- proxy.initialize(address(this), address(this), "");
-
- vm.expectRevert("ARM: Only owner can call this function.");
- proxy.upgradeTo(address(this));
-
- vm.expectRevert("ARM: Only owner can call this function.");
- proxy.upgradeToAndCall(address(this), "");
- }
-
- //////////////////////////////////////////////////////
- /// --- PASSING TESTS
- //////////////////////////////////////////////////////
- function test_Upgrade() public asOwner {
- address owner = Mainnet.TIMELOCK;
-
- // Deploy new implementation
- OethARM newImplementation = new OethARM(Mainnet.OETH, Mainnet.WETH, Mainnet.OETH_VAULT);
- proxy.upgradeTo(address(newImplementation));
- assertEq(proxy.implementation(), address(newImplementation));
-
- // Ensure ownership was preserved.
- assertEq(proxy.owner(), owner);
- assertEq(oethARM.owner(), owner);
-
- // Ensure the storage was preserved through the upgrade.
- assertEq(address(oethARM.token0()), Mainnet.OETH);
- assertEq(address(oethARM.token1()), Mainnet.WETH);
- }
-
- function test_UpgradeAndCall() public asOwner {
- address owner = Mainnet.TIMELOCK;
-
- // Deploy new implementation
- OethARM newImplementation = new OethARM(Mainnet.OETH, Mainnet.WETH, Mainnet.OETH_VAULT);
- bytes memory data = abi.encodeWithSignature("setOperator(address)", address(0x123));
-
- proxy.upgradeToAndCall(address(newImplementation), data);
- assertEq(proxy.implementation(), address(newImplementation));
-
- // Ensure ownership was preserved.
- assertEq(proxy.owner(), owner);
- assertEq(oethARM.owner(), owner);
-
- // Ensure the post upgrade code was run
- assertEq(oethARM.operator(), address(0x123));
- }
-}
diff --git a/test/fork/OethARM/SwapExactTokensForTokens.t.sol b/test/fork/OethARM/SwapExactTokensForTokens.t.sol
deleted file mode 100644
index 111afa2a..00000000
--- a/test/fork/OethARM/SwapExactTokensForTokens.t.sol
+++ /dev/null
@@ -1,132 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity 0.8.23;
-
-// Test imports
-import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
-
-// Interfaces
-import {IERC20} from "contracts/Interfaces.sol";
-
-/// @notice The purpose of this contract is to test the `swapExactTokensForTokens` function in the `OethARM` contract.
-contract Fork_Concrete_OethARM_SwapExactTokensForTokens_Test_ is Fork_Shared_Test_ {
- address[] path;
-
- //////////////////////////////////////////////////////
- /// --- SETUP
- //////////////////////////////////////////////////////
- function setUp() public override {
- super.setUp();
-
- path = new address[](2);
- path[0] = address(oeth);
- path[1] = address(weth);
-
- // Deal tokens
- deal(address(oeth), address(this), 100 ether);
- deal(address(weth), address(oethARM), 100 ether);
- deal(address(oeth), address(oethARM), 100 ether);
-
- // Approve tokens
- oeth.approve(address(oethARM), type(uint256).max);
- }
-
- //////////////////////////////////////////////////////
- /// --- REVERTING TESTS
- //////////////////////////////////////////////////////
- function test_RevertWhen_SwapExactTokensForTokens_Simple_Because_InsufficientOutputAmount() public {
- vm.expectRevert("ARM: Insufficient output amount");
- oethARM.swapExactTokensForTokens(oeth, weth, 10 ether, 11 ether, address(this));
- }
-
- function test_RevertWhen_SwapExactTokensForTokens_Simple_Because_InvalidSwap_TokenIn() public {
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapExactTokensForTokens(weth, weth, 10 ether, 10 ether, address(this));
- }
-
- function test_RevertWhen_SwapExactTokensForTokens_Simple_Because_InvalidSwap_TokenOut() public {
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapExactTokensForTokens(oeth, oeth, 10 ether, 10 ether, address(this));
- }
-
- function test_RevertWhen_SwapExactTokensForTokens_Complex_Because_InsuficientOutputAmount() public {
- vm.expectRevert("ARM: Insufficient output amount");
- oethARM.swapExactTokensForTokens(10 ether, 11 ether, path, address(this), block.timestamp + 10);
- }
-
- function test_RevertWhen_SwapExactTokensForTokens_Complex_Because_InvalidPathLength() public {
- vm.expectRevert("ARM: Invalid path length");
- oethARM.swapExactTokensForTokens(10 ether, 10 ether, new address[](3), address(this), 0);
- }
-
- function test_RevertWhen_SwapExactTokensForTokens_Complex_Because_DeadlineExpired() public {
- vm.expectRevert("ARM: Deadline expired");
- oethARM.swapExactTokensForTokens(10 ether, 10 ether, path, address(this), 0);
- }
-
- function test_RevertWhen_SwapExactTokensForTokens_Complex_Because_InvalidSwap_TokenIn() public {
- path[0] = address(weth);
- path[1] = address(weth);
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapExactTokensForTokens(10 ether, 10 ether, path, address(this), block.timestamp + 10);
- }
-
- function test_RevertWhen_SwapExactTokensForTokens_Complex_Because_InvalidSwap_TokenOut() public {
- path[0] = address(oeth);
- path[1] = address(oeth);
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapExactTokensForTokens(10 ether, 10 ether, path, address(this), block.timestamp + 10);
- }
-
- //////////////////////////////////////////////////////
- /// --- PASSING TESTS
- //////////////////////////////////////////////////////
- function test_SwapExactTokensForTokens_Simple() public {
- // Assertions before
- assertEq(weth.balanceOf(address(this)), 0 ether, "WETH balance user");
- assertEq(oeth.balanceOf(address(this)), 100 ether, "OETH balance user");
- assertEq(weth.balanceOf(address(oethARM)), 100 ether, "OETH balance ARM");
- assertEq(weth.balanceOf(address(oethARM)), 100 ether, "WETH balance ARM");
-
- // Expected events
- vm.expectEmit({emitter: address(oeth)});
- emit IERC20.Transfer(address(this), address(oethARM), 10 ether);
- vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(address(oethARM), address(this), 10 ether);
- // Main call
- oethARM.swapExactTokensForTokens(oeth, weth, 10 ether, 10 ether, address(this));
-
- // Assertions after
- assertEq(weth.balanceOf(address(this)), 10 ether, "WETH balance user");
- assertEq(oeth.balanceOf(address(this)), 90 ether, "OETH balance");
- assertEq(weth.balanceOf(address(oethARM)), 90 ether, "WETH balance ARM");
- assertEq(oeth.balanceOf(address(oethARM)), 110 ether, "OETH balance ARM");
- }
-
- function test_SwapExactTokensForTokens_Complex() public {
- // Assertions before
- assertEq(weth.balanceOf(address(this)), 0 ether, "WETH balance user");
- assertEq(oeth.balanceOf(address(this)), 100 ether, "OETH balance user");
- assertEq(weth.balanceOf(address(oethARM)), 100 ether, "OETH balance ARM");
- assertEq(weth.balanceOf(address(oethARM)), 100 ether, "WETH balance ARM");
-
- path[0] = address(oeth);
- path[1] = address(weth);
-
- // Expected events
- vm.expectEmit({emitter: address(oeth)});
- emit IERC20.Transfer(address(this), address(oethARM), 10 ether);
- vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(address(oethARM), address(this), 10 ether);
- // Main call
- uint256[] memory amounts =
- oethARM.swapExactTokensForTokens(10 ether, 10 ether, path, address(this), block.timestamp + 1000);
-
- // Assertions after
- assertEq(amounts[0], 10 ether, "Amounts[0]");
- assertEq(amounts[1], 10 ether, "Amounts[1]");
- assertEq(weth.balanceOf(address(this)), 10 ether, "WETH balance user");
- assertEq(oeth.balanceOf(address(this)), 90 ether, "OETH balance");
- assertEq(weth.balanceOf(address(oethARM)), 90 ether, "WETH balance ARM");
- assertEq(oeth.balanceOf(address(oethARM)), 110 ether, "OETH balance ARM");
- }
-}
diff --git a/test/fork/OethARM/SwapTokensForExactTokens.t.sol b/test/fork/OethARM/SwapTokensForExactTokens.t.sol
deleted file mode 100644
index 3e012379..00000000
--- a/test/fork/OethARM/SwapTokensForExactTokens.t.sol
+++ /dev/null
@@ -1,131 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity 0.8.23;
-
-// Test imports
-import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
-
-// Interfaces
-import {IERC20} from "contracts/Interfaces.sol";
-
-/// @notice The purpose of this contract is to test the `swapTokensForExactTokens` function in the `OethARM` contract.
-contract Fork_Concrete_OethARM_SwapTokensForExactTokens_Test_ is Fork_Shared_Test_ {
- address[] path;
-
- //////////////////////////////////////////////////////
- /// --- SETUP
- //////////////////////////////////////////////////////
- function setUp() public override {
- super.setUp();
-
- path = new address[](2);
- path[0] = address(oeth);
- path[1] = address(weth);
-
- // Deal tokens
- deal(address(oeth), address(this), 100 ether);
- deal(address(weth), address(oethARM), 100 ether);
- deal(address(oeth), address(oethARM), 100 ether);
-
- // Approve tokens
- oeth.approve(address(oethARM), type(uint256).max);
- }
-
- //////////////////////////////////////////////////////
- /// --- REVERTING TESTS
- //////////////////////////////////////////////////////
- function test_RevertWhen_SwapTokensForExactTokens_Simple_Because_InsufficientOutputAmount() public {
- vm.expectRevert("ARM: Excess input amount");
- oethARM.swapTokensForExactTokens(oeth, weth, 10 ether, 9 ether, address(this));
- }
-
- function test_RevertWhen_SwapTokensForExactTokens_Simple_Because_InvalidSwap_TokenIn() public {
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapTokensForExactTokens(weth, weth, 10 ether, 10 ether, address(this));
- }
-
- function test_RevertWhen_SwapTokensForExactTokens_Simple_Because_InvalidSwap_TokenOut() public {
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapTokensForExactTokens(oeth, oeth, 10 ether, 10 ether, address(this));
- }
-
- function test_RevertWhen_SwapTokensForExactTokens_Complex_Because_InsufficientOutputAmount() public {
- vm.expectRevert("ARM: Excess input amount");
- oethARM.swapTokensForExactTokens(10 ether, 9 ether, path, address(this), block.timestamp + 10);
- }
-
- function test_RevertWhen_SwapTokensForExactTokens_Complex_Because_InvalidPathLength() public {
- vm.expectRevert("ARM: Invalid path length");
- oethARM.swapTokensForExactTokens(10 ether, 10 ether, new address[](3), address(this), block.timestamp + 10);
- }
-
- function test_RevertWhen_SwapTokensForExactTokens_Complex_Because_DeadlineExpired() public {
- vm.expectRevert("ARM: Deadline expired");
- oethARM.swapTokensForExactTokens(10 ether, 10 ether, path, address(this), block.timestamp - 1);
- }
-
- function test_RevertWhen_SwapTokensForExactTokens_Complex_Because_InvalidSwap_TokenIn() public {
- path[0] = address(weth);
- path[1] = address(weth);
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapTokensForExactTokens(10 ether, 10 ether, path, address(this), block.timestamp + 10);
- }
-
- function test_RevertWhen_SwapTokensForExactTokens_Complex_Because_InvalidSwap_TokenOut() public {
- path[0] = address(oeth);
- path[1] = address(oeth);
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapTokensForExactTokens(10 ether, 10 ether, path, address(this), block.timestamp + 10);
- }
-
- //////////////////////////////////////////////////////
- /// --- PASSING TESTS
- //////////////////////////////////////////////////////
- function test_SwapTokensForExactTokens_Simple() public {
- // Assertions before
- assertEq(weth.balanceOf(address(this)), 0 ether, "WETH balance user");
- assertEq(oeth.balanceOf(address(this)), 100 ether, "OETH balance user");
- assertEq(weth.balanceOf(address(oethARM)), 100 ether, "OETH balance ARM");
- assertEq(weth.balanceOf(address(oethARM)), 100 ether, "WETH balance ARM");
-
- // Expected events
- vm.expectEmit({emitter: address(oeth)});
- emit IERC20.Transfer(address(this), address(oethARM), 10 ether);
- vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(address(oethARM), address(this), 10 ether);
- // Main call
- oethARM.swapTokensForExactTokens(oeth, weth, 10 ether, 10 ether, address(this));
-
- // Assertions after
- assertEq(weth.balanceOf(address(this)), 10 ether, "WETH balance user");
- assertEq(oeth.balanceOf(address(this)), 90 ether, "OETH balance");
- assertEq(weth.balanceOf(address(oethARM)), 90 ether, "WETH balance ARM");
- assertEq(oeth.balanceOf(address(oethARM)), 110 ether, "OETH balance ARM");
- }
-
- function test_SwapTokensForExactTokens_Complex() public {
- // Assertions before
- assertEq(weth.balanceOf(address(this)), 0 ether, "WETH balance user");
- assertEq(oeth.balanceOf(address(this)), 100 ether, "OETH balance user");
- assertEq(weth.balanceOf(address(oethARM)), 100 ether, "OETH balance ARM");
- assertEq(weth.balanceOf(address(oethARM)), 100 ether, "WETH balance ARM");
-
- path[0] = address(oeth);
- path[1] = address(weth);
- // Expected events
- vm.expectEmit({emitter: address(oeth)});
- emit IERC20.Transfer(address(this), address(oethARM), 10 ether);
- vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(address(oethARM), address(this), 10 ether);
- // Main call
- uint256[] memory amounts =
- oethARM.swapTokensForExactTokens(10 ether, 10 ether, path, address(this), block.timestamp + 1000);
-
- // Assertions after
- assertEq(amounts[0], 10 ether, "Amounts[0]");
- assertEq(amounts[1], 10 ether, "Amounts[1]");
- assertEq(weth.balanceOf(address(this)), 10 ether, "WETH balance user");
- assertEq(oeth.balanceOf(address(this)), 90 ether, "OETH balance");
- assertEq(weth.balanceOf(address(oethARM)), 90 ether, "WETH balance ARM");
- assertEq(oeth.balanceOf(address(oethARM)), 110 ether, "OETH balance ARM");
- }
-}
diff --git a/test/fork/OethARM/Transfer.t.sol b/test/fork/OethARM/Transfer.t.sol
deleted file mode 100644
index 90832e33..00000000
--- a/test/fork/OethARM/Transfer.t.sol
+++ /dev/null
@@ -1,57 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity 0.8.23;
-
-// Test imports
-import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
-
-// Interfaces
-import {IERC20} from "contracts/Interfaces.sol";
-
-/// @notice The purpose of this contract is to test the `transferToken` and `transferEth` functions in the `OethARM` contract.
-contract Fork_Concrete_OethARM_Transfer_Test_ is Fork_Shared_Test_ {
- bool public shouldRevertOnReceive;
-
- //////////////////////////////////////////////////////
- /// --- SETUP
- //////////////////////////////////////////////////////
-
- function setUp() public override {
- super.setUp();
-
- // Deal tokens
- deal(address(oethARM), 100 ether);
- deal(address(weth), address(oethARM), 100 ether);
- }
-
- //////////////////////////////////////////////////////
- /// --- REVERTING TESTS
- //////////////////////////////////////////////////////
- function test_RevertWhen_TransferToken_Because_NotOwner() public {
- vm.expectRevert("ARM: Only owner can call this function.");
- oethARM.transferToken(address(0), address(0), 0);
- }
-
- //////////////////////////////////////////////////////
- /// --- PASSING TESTS
- //////////////////////////////////////////////////////
- function test_TransferToken() public asOwner {
- // Assertions before
- assertEq(weth.balanceOf(address(this)), 0);
- assertEq(weth.balanceOf(address(oethARM)), 100 ether);
-
- vm.expectEmit({emitter: address(weth)});
- emit IERC20.Transfer(address(oethARM), address(this), 10 ether);
- oethARM.transferToken(address(weth), address(this), 10 ether);
-
- // Assertions after
- assertEq(weth.balanceOf(address(this)), 10 ether);
- assertEq(weth.balanceOf(address(oethARM)), 90 ether);
- }
-
- //////////////////////////////////////////////////////
- /// --- RECEIVE
- //////////////////////////////////////////////////////
- receive() external payable {
- if (shouldRevertOnReceive) revert();
- }
-}
diff --git a/test/fork/OethARM/Withdraw.t.sol b/test/fork/OethARM/Withdraw.t.sol
deleted file mode 100644
index f63728ee..00000000
--- a/test/fork/OethARM/Withdraw.t.sol
+++ /dev/null
@@ -1,105 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity 0.8.23;
-
-// Test imports
-import {Fork_Shared_Test_} from "test/fork/shared/Shared.sol";
-
-// Interfaces
-import {IERC20} from "contracts/Interfaces.sol";
-
-/// @notice The purpose of this contract is to test the `requestWithdrawal`,
-/// `claimWithdrawal` and `claimWithdrawals` functions in the `OethARM` contract.
-contract Fork_Concrete_OethARM_Withdraw_Test_ is Fork_Shared_Test_ {
- //////////////////////////////////////////////////////
- /// --- SETUP
- //////////////////////////////////////////////////////
- function setUp() public override {
- super.setUp();
-
- // Deal tokens
- deal(address(oeth), address(oethARM), 10 ether);
- deal(address(weth), address(vault), 10 ether);
-
- // Remove solvency check
- vm.prank(vault.governor());
- vault.setMaxSupplyDiff(0);
- }
-
- //////////////////////////////////////////////////////
- /// --- REVERTING TESTS
- //////////////////////////////////////////////////////
- function test_RevertWhen_RequestWithdraw() public {
- vm.expectRevert("ARM: Only operator or owner can call this function.");
- oethARM.requestWithdrawal(1 ether);
- }
-
- function test_RevertWhen_ClaimWithdraw() public {
- vm.expectRevert("ARM: Only operator or owner can call this function.");
- oethARM.claimWithdrawal(0);
- }
-
- function test_RevertWhen_ClaimWithdraws() public {
- vm.expectRevert("ARM: Only operator or owner can call this function.");
- oethARM.claimWithdrawals(new uint256[](0));
- }
-
- //////////////////////////////////////////////////////
- /// --- PASSING TESTS
- //////////////////////////////////////////////////////
- function test_RequestWithdraw() public asOwner mockCallDripperCollect {
- (uint128 queuedBefore,,, uint128 nextWithdrawalIndex) = vault.withdrawalQueueMetadata();
- vm.expectEmit({emitter: address(oeth)});
- emit IERC20.Transfer(address(oethARM), address(0), 1 ether);
- (uint256 requestId, uint256 queued) = oethARM.requestWithdrawal(1 ether);
-
- // Assertions after
- assertEq(requestId, nextWithdrawalIndex, "Request ID");
- assertEq(queued, queuedBefore + 1 ether, "Queued amount should be 1 ether");
- assertEq(oeth.balanceOf(address(oethARM)), 9 ether, "OETH balance should be 99 ether");
- }
-
- function test_ClaimWithdraw_() public asOwner mockCallDripperCollect {
- // First request withdrawal
- (uint256 requestId,) = oethARM.requestWithdrawal(1 ether);
-
- // Add more liquidity to facilitate withdrawal
- (uint128 queued,, uint128 claimed,) = vault.withdrawalQueueMetadata();
- deal(address(weth), address(vault), queued - claimed + 1 ether);
-
- // Add liquidity to the withdrawal queue
- vault.addWithdrawalQueueLiquidity();
-
- // Skip delay
- skip(10 minutes);
-
- // Then claim withdrawal
- oethARM.claimWithdrawal(requestId);
-
- // Assertions after
- assertEq(weth.balanceOf(address(oethARM)), 1 ether, "WETH balance should be 1 ether");
- }
-
- function test_ClaimWithdraws() public asOwner mockCallDripperCollect {
- (,,, uint128 nextWithdrawalIndex) = vault.withdrawalQueueMetadata();
-
- // First request withdrawal
- oethARM.requestWithdrawal(1 ether);
- oethARM.requestWithdrawal(1 ether);
-
- // Add more liquidity to facilitate withdrawal
- (uint128 queued,, uint128 claimed,) = vault.withdrawalQueueMetadata();
- deal(address(weth), address(vault), queued - claimed + 2 ether);
-
- // Skip withdrawal queue delay
- skip(10 minutes);
-
- uint256[] memory requestIds = new uint256[](2);
- requestIds[0] = nextWithdrawalIndex;
- requestIds[1] = nextWithdrawalIndex + 1;
- // Then claim withdrawal
- oethARM.claimWithdrawals(requestIds);
-
- // Assertions after
- assertEq(weth.balanceOf(address(oethARM)), 2 ether, "WETH balance should be 1 ether");
- }
-}
diff --git a/test/fork/shared/Shared.sol b/test/fork/shared/Shared.sol
index b583f31a..707dde99 100644
--- a/test/fork/shared/Shared.sol
+++ b/test/fork/shared/Shared.sol
@@ -9,7 +9,6 @@ import {Modifiers} from "test/fork/utils/Modifiers.sol";
// Contracts
import {Proxy} from "contracts/Proxy.sol";
-import {OethARM} from "contracts/OethARM.sol";
import {LidoARM} from "contracts/LidoARM.sol";
import {CapManager} from "contracts/CapManager.sol";
import {ZapperLidoARM} from "contracts/ZapperLidoARM.sol";
@@ -20,7 +19,6 @@ import {IOriginVault} from "contracts/Interfaces.sol";
// Utils
import {Mainnet} from "contracts/utils/Addresses.sol";
-import {AddressResolver} from "contracts/utils/Addresses.sol";
/// @notice This contract should inherit (directly or indirectly) from `Base_Test_`.
/// It should be used to setup the FORK test ONLY!
@@ -106,27 +104,14 @@ abstract contract Fork_Shared_Test_ is Modifiers {
function _deployContracts() internal {
// --- Deploy all proxies ---
- proxy = new Proxy();
lpcProxy = new Proxy();
lidoProxy = new Proxy();
-
- // --- Deploy OethARM implementation ---
- // Deploy OethARM implementation.
- address implementation = address(new OethARM(address(oeth), address(weth), address(vault)));
- vm.label(implementation, "OETH ARM IMPLEMENTATION");
-
- // Initialize Proxy with OethARM implementation.
- bytes memory data = abi.encodeWithSignature("initialize(address)", operator);
- proxy.initialize(implementation, governor, data);
-
- // Set the Proxy as the OethARM.
- oethARM = OethARM(address(proxy));
-
// --- Deploy CapManager implementation ---
// Deploy CapManager implementation.
CapManager capManagerImpl = new CapManager(address(lidoProxy));
// Initialize Proxy with CapManager implementation.
+ bytes memory data = abi.encodeWithSignature("initialize(address)", operator);
lpcProxy.initialize(address(capManagerImpl), address(this), data);
// Set the Proxy as the CapManager.
@@ -176,8 +161,6 @@ abstract contract Fork_Shared_Test_ is Modifiers {
vm.label(address(steth), "stETH");
vm.label(address(badToken), "BAD TOKEN");
vm.label(address(vault), "OETH VAULT");
- vm.label(address(oethARM), "OETH ARM");
- vm.label(address(proxy), "OETH ARM PROXY");
vm.label(address(lidoARM), "LIDO ARM");
vm.label(address(lidoProxy), "LIDO ARM PROXY");
vm.label(address(capManager), "LIQUIDITY PROVIDER CONTROLLER");
diff --git a/test/fork/utils/Modifiers.sol b/test/fork/utils/Modifiers.sol
index f55933d4..753aac74 100644
--- a/test/fork/utils/Modifiers.sol
+++ b/test/fork/utils/Modifiers.sol
@@ -21,13 +21,6 @@ abstract contract Modifiers is Helpers {
vm.stopPrank();
}
- /// @notice Impersonate the owner of the OethARM contract.
- modifier asOwner() {
- vm.startPrank(oethARM.owner());
- _;
- vm.stopPrank();
- }
-
/// @notice Impersonate the governor of the vault.
modifier asGovernor() {
vm.startPrank(vault.governor());
diff --git a/test/invariants/LidoARM/FuzzerFoundry.sol b/test/invariants/LidoARM/FuzzerFoundry.sol
index df7815ca..f5c6a1a4 100644
--- a/test/invariants/LidoARM/FuzzerFoundry.sol
+++ b/test/invariants/LidoARM/FuzzerFoundry.sol
@@ -4,7 +4,7 @@ pragma solidity 0.8.23;
// Test imports
import {TargetFunction} from "test/invariants/LidoARM/TargetFunction.sol";
-contract FuzzerFoundry_OethARM is TargetFunction {
+contract FuzzerFoundry_LidoARM is TargetFunction {
uint256 private constant NUM_LPS = 4;
uint256 private constant NUM_SWAPS = 3;
uint256 private constant MAX_WETH_PER_USERS = 1_000_000 ether;
diff --git a/test/invariants/LidoARM/Unit.sol b/test/invariants/LidoARM/Unit.sol
index 65497401..ba3cbcbd 100644
--- a/test/invariants/LidoARM/Unit.sol
+++ b/test/invariants/LidoARM/Unit.sol
@@ -2,13 +2,13 @@
pragma solidity 0.8.23;
import {Test} from "forge-std/Test.sol";
-import {FuzzerFoundry_OethARM} from "test/invariants/LidoARM/FuzzerFoundry.sol";
+import {FuzzerFoundry_LidoARM} from "test/invariants/LidoARM/FuzzerFoundry.sol";
contract Unit is Test {
- FuzzerFoundry_OethARM f;
+ FuzzerFoundry_LidoARM f;
function setUp() public {
- f = new FuzzerFoundry_OethARM();
+ f = new FuzzerFoundry_LidoARM();
f.setUp();
}
diff --git a/test/smoke/EtherFiARMSmokeTest.t.sol b/test/smoke/EtherFiARMSmokeTest.t.sol
index b5756604..d9c4b0a8 100644
--- a/test/smoke/EtherFiARMSmokeTest.t.sol
+++ b/test/smoke/EtherFiARMSmokeTest.t.sol
@@ -1,11 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
-import {Test, console2} from "forge-std/Test.sol";
-
import {AbstractSmokeTest} from "./AbstractSmokeTest.sol";
-import {IERC20, IEETHWithdrawal, IEETHWithdrawalNFT} from "contracts/Interfaces.sol";
+import {IERC20, IEETHWithdrawalNFT} from "contracts/Interfaces.sol";
import {EtherFiARM} from "contracts/EtherFiARM.sol";
import {CapManager} from "contracts/CapManager.sol";
import {Proxy} from "contracts/Proxy.sol";
diff --git a/test/smoke/LidoARMSmokeTest.t.sol b/test/smoke/LidoARMSmokeTest.t.sol
index 62c83c01..45a9dfda 100644
--- a/test/smoke/LidoARMSmokeTest.t.sol
+++ b/test/smoke/LidoARMSmokeTest.t.sol
@@ -1,8 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
-import {Test, console2} from "forge-std/Test.sol";
-
import {AbstractSmokeTest} from "./AbstractSmokeTest.sol";
import {IERC20, IStETHWithdrawal} from "contracts/Interfaces.sol";
diff --git a/test/smoke/OethARMSmokeTest.t.sol b/test/smoke/OethARMSmokeTest.t.sol
index ed15f0d6..dcc19b2d 100644
--- a/test/smoke/OethARMSmokeTest.t.sol
+++ b/test/smoke/OethARMSmokeTest.t.sol
@@ -1,22 +1,22 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
-import {Test, console2} from "forge-std/Test.sol";
+import {Test} from "forge-std/Test.sol";
import {AbstractSmokeTest} from "./AbstractSmokeTest.sol";
import {IERC20} from "contracts/Interfaces.sol";
-import {OethARM} from "contracts/OethARM.sol";
import {Proxy} from "contracts/Proxy.sol";
import {Mainnet} from "contracts/utils/Addresses.sol";
+import {OriginARM} from "contracts/OriginARM.sol";
-contract Fork_OethARM_Smoke_Test is AbstractSmokeTest {
+contract Fork_OriginARM_Smoke_Test is AbstractSmokeTest {
IERC20 BAD_TOKEN = IERC20(makeAddr("bad token"));
IERC20 weth;
IERC20 oeth;
Proxy proxy;
- OethARM oethARM;
+ OriginARM originARM;
address operator;
function setUp() public {
@@ -29,61 +29,224 @@ contract Fork_OethARM_Smoke_Test is AbstractSmokeTest {
vm.label(address(operator), "OPERATOR");
proxy = Proxy(payable(deployManager.getDeployment("OETH_ARM")));
- oethARM = OethARM(deployManager.getDeployment("OETH_ARM"));
+ originARM = OriginARM(deployManager.getDeployment("OETH_ARM"));
- _dealWETH(address(oethARM), 100 ether);
- _dealOETH(address(oethARM), 100 ether);
+ _dealWETH(address(originARM), 100 ether);
+ _dealOETH(address(originARM), 100 ether);
// Only fuzz from this address. Big speedup on fork.
targetSender(address(this));
}
- function test_swapExactTokensForTokens() external {
- _swapExactTokensForTokens(oeth, weth, 10 ether, 10 ether);
+ ////////////////////////////////////////////////////
+ /// --- HELPERS
+ ////////////////////////////////////////////////////
+ function _dealWETH(address to, uint256 amount) internal {
+ deal(address(weth), to, amount);
+ }
+
+ // Helper functions to deal tokens from whales, because oeth is rebasing, so deal() doesn't work
+ function _dealOETH(address to, uint256 amount) internal {
+ vm.prank(Mainnet.WOETH);
+ oeth.transfer(to, amount);
+ }
+
+ ////////////////////////////////////////////////////
+ /// --- INITIAL CONFIG
+ ////////////////////////////////////////////////////
+ function test_initialConfig() external view {
+ // Ownership and fees
+ assertEq(originARM.name(), "Origin ARM", "Name");
+ assertEq(originARM.symbol(), "ARM-WETH-OETH", "Symbol");
+ assertEq(originARM.owner(), Mainnet.TIMELOCK, "Owner");
+ assertEq(originARM.operator(), Mainnet.ARM_RELAYER, "Operator");
+ assertEq(originARM.feeCollector(), Mainnet.ARM_BUYBACK, "Fee collector");
+ assertEq((100 * uint256(originARM.fee())) / originARM.FEE_SCALE(), 20, "Performance fee as a percentage");
+
+ // Assets
+ assertEq(address(originARM.token0()), address(weth), "token0");
+ assertEq(address(originARM.token1()), address(oeth), "token1");
+ assertEq(originARM.liquidityAsset(), Mainnet.WETH, "liquidity asset");
+ assertEq(originARM.baseAsset(), Mainnet.OETH, "base asset");
+ assertEq(originARM.asset(), Mainnet.WETH, "ERC-4626 asset");
+
+ // Prices
+ assertNotEq(originARM.crossPrice(), 0, "cross price");
+ assertNotEq(originARM.traderate0(), 0, "traderate0");
+ assertNotEq(originARM.traderate1(), 0, "traderate1");
+
+ // Redemption
+ assertEq(address(originARM.vault()), Mainnet.OETH_VAULT, "OETH Vault");
+ assertEq(originARM.claimDelay(), 10 minutes, "claim delay");
}
- function test_swapTokensForExactTokens() external {
- _swapTokensForExactTokens(oeth, weth, 10 ether, 10 ether);
+ ////////////////////////////////////////////////////
+ /// --- SWAP TESTS
+ ////////////////////////////////////////////////////
+
+ function test_swap_exact_oeth_for_weth() external {
+ // trader sells OETH and buys WETH, the ARM buys OETH as a
+ // 4 bps discount
+ _swapExactTokensForTokens(oeth, weth, 0.9996e36, 100 ether);
+ // 10 bps discount
+ _swapExactTokensForTokens(oeth, weth, 0.999e36, 1e15);
+ // 20 bps discount
+ _swapExactTokensForTokens(oeth, weth, 0.998e36, 1 ether);
}
- function _swapExactTokensForTokens(IERC20 inToken, IERC20 outToken, uint256 amountIn, uint256 expectedOut)
- internal
- {
+ function test_swap_exact_weth_for_oeth() external {
+ // For this test, we need to set the cross price to 0.9999e36, which requires
+ // moving out all OETH from the ARM.
+ vm.startPrank(address(originARM));
+ oeth.transfer(address(this), oeth.balanceOf(address(originARM)));
+ vm.stopPrank();
+ vm.prank(Mainnet.TIMELOCK);
+ originARM.setCrossPrice(0.9999e36);
+
+ // trader buys OETH and sells WETH, the ARM sells OETH at a
+ // 0.5 bps discount
+ _swapExactTokensForTokens(weth, oeth, 0.99995e36, 10 ether);
+ // 1 bps discount
+ _swapExactTokensForTokens(weth, oeth, 0.9999e36, 100 ether);
+ }
+
+ function _swapExactTokensForTokens(IERC20 inToken, IERC20 outToken, uint256 price, uint256 amountIn) internal {
+ uint256 expectedOut;
if (inToken == weth) {
- _dealWETH(address(this), amountIn + 1000);
+ // Trader is buying stETH and selling WETH
+ // the ARM is selling stETH and buying WETH
+ deal(address(weth), address(this), 1_000_000 ether);
+ _dealOETH(address(originARM), 1000 ether);
+
+ expectedOut = amountIn * 1e36 / price;
+
+ vm.prank(Mainnet.ARM_RELAYER);
+ originARM.setPrices(price - 2e32, price);
} else {
- _dealOETH(address(this), amountIn + 1000);
+ // Trader is selling stETH and buying WETH
+ // the ARM is buying stETH and selling WETH
+ _dealOETH(address(this), 1000 ether);
+ deal(address(weth), address(originARM), 1_000_000 ether);
+
+ expectedOut = amountIn * price / 1e36;
+
+ vm.prank(Mainnet.ARM_RELAYER);
+ originARM.setPrices(price, 1e36);
}
// Approve the ARM to transfer the input token of the swap.
- inToken.approve(address(oethARM), amountIn);
+ inToken.approve(address(originARM), amountIn);
uint256 startIn = inToken.balanceOf(address(this));
uint256 startOut = outToken.balanceOf(address(this));
- oethARM.swapExactTokensForTokens(inToken, outToken, amountIn, 0, address(this));
- assertEq(inToken.balanceOf(address(this)), startIn - amountIn, "In actual");
- assertEq(outToken.balanceOf(address(this)), startOut + expectedOut, "Out actual");
+
+ originARM.swapExactTokensForTokens(inToken, outToken, amountIn, 0, address(this));
+
+ assertApproxEqAbs(inToken.balanceOf(address(this)), startIn - amountIn, 2, "In actual");
+ assertApproxEqAbs(outToken.balanceOf(address(this)), startOut + expectedOut, 2, "Out actual");
}
- function _swapTokensForExactTokens(IERC20 inToken, IERC20 outToken, uint256 amountIn, uint256 expectedOut)
- internal
- {
+ function test_swap_oeth_for_exact_weth() external {
+ // trader sells OETH and buys WETH, the ARM buys OETH at a
+ // 4 bps discount
+ _swapTokensForExactTokens(oeth, weth, 0.9996e36, 10 ether);
+ // 10 bps discount
+ _swapTokensForExactTokens(oeth, weth, 0.999e36, 100 ether);
+ // 50 bps discount
+ _swapTokensForExactTokens(oeth, weth, 0.995e36, 10 ether);
+ }
+
+ function test_swap_weth_for_exact_oeth() external {
+ // For this test, we need to set the cross price to 0.9999e36, which requires
+ // moving out all OETH from the ARM.
+ vm.startPrank(address(originARM));
+ oeth.transfer(address(this), oeth.balanceOf(address(originARM)));
+ vm.stopPrank();
+ vm.prank(Mainnet.TIMELOCK);
+ originARM.setCrossPrice(0.9999e36);
+
+ // trader buys OETH and sells WETH, the ARM sells OETH at a
+ // 0.5 bps discount
+ _swapTokensForExactTokens(weth, oeth, 0.99995e36, 10 ether);
+ // 1 bps discount
+ _swapTokensForExactTokens(weth, oeth, 0.9999e36, 100 ether);
+ }
+
+ function _swapTokensForExactTokens(IERC20 inToken, IERC20 outToken, uint256 price, uint256 amountOut) internal {
+ uint256 expectedIn;
if (inToken == weth) {
- _dealWETH(address(this), amountIn + 1000);
+ // Trader is buying stETH and selling WETH
+ // the ARM is selling stETH and buying WETH
+ deal(address(weth), address(this), 1_000_000 ether);
+ _dealOETH(address(originARM), 1000 ether);
+
+ expectedIn = amountOut * price / 1e36;
+
+ vm.prank(Mainnet.ARM_RELAYER);
+ originARM.setPrices(price - 2e32, price);
} else {
- _dealOETH(address(this), amountIn + 1000);
+ // Trader is selling stETH and buying WETH
+ // the ARM is buying stETH and selling WETH
+ _dealOETH(address(this), 1000 ether);
+ deal(address(weth), address(originARM), 1_000_000 ether);
+
+ expectedIn = amountOut * 1e36 / price + 3;
+
+ vm.prank(Mainnet.ARM_RELAYER);
+ originARM.setPrices(price, 1e36);
}
// Approve the ARM to transfer the input token of the swap.
- inToken.approve(address(oethARM), amountIn);
+ inToken.approve(address(originARM), expectedIn + 10000);
uint256 startIn = inToken.balanceOf(address(this));
+ uint256 startOut = outToken.balanceOf(address(this));
+
+ originARM.swapTokensForExactTokens(inToken, outToken, amountOut, 3 * amountOut, address(this));
+
+ assertApproxEqAbs(inToken.balanceOf(address(this)), startIn - expectedIn, 3, "In actual");
+ assertApproxEqAbs(outToken.balanceOf(address(this)), startOut + amountOut, 3, "Out actual");
+ }
- oethARM.swapTokensForExactTokens(inToken, outToken, expectedOut, 3 * expectedOut, address(this));
- assertEq(inToken.balanceOf(address(this)), startIn - amountIn, "In actual");
- assertEq(outToken.balanceOf(address(this)), expectedOut, "Out actual");
+ function test_wrongInTokenExactIn() external {
+ vm.expectRevert("ARM: Invalid in token");
+ originARM.swapExactTokensForTokens(BAD_TOKEN, oeth, 10 ether, 0, address(this));
+ vm.expectRevert("ARM: Invalid in token");
+ originARM.swapExactTokensForTokens(BAD_TOKEN, weth, 10 ether, 0, address(this));
+ }
+
+ function test_wrongOutTokenExactIn() external {
+ vm.expectRevert("ARM: Invalid out token");
+ originARM.swapTokensForExactTokens(weth, BAD_TOKEN, 10 ether, 10 ether, address(this));
+ vm.expectRevert("ARM: Invalid out token");
+ originARM.swapTokensForExactTokens(oeth, BAD_TOKEN, 10 ether, 10 ether, address(this));
+ vm.expectRevert("ARM: Invalid out token");
+ originARM.swapTokensForExactTokens(weth, weth, 10 ether, 10 ether, address(this));
+ vm.expectRevert("ARM: Invalid out token");
+ originARM.swapTokensForExactTokens(oeth, oeth, 10 ether, 10 ether, address(this));
}
+ function test_wrongInTokenExactOut() external {
+ vm.expectRevert("ARM: Invalid in token");
+ originARM.swapTokensForExactTokens(BAD_TOKEN, oeth, 10 ether, 10 ether, address(this));
+ vm.expectRevert("ARM: Invalid in token");
+ originARM.swapTokensForExactTokens(BAD_TOKEN, weth, 10 ether, 10 ether, address(this));
+ }
+
+ function test_wrongOutTokenExactOut() external {
+ vm.expectRevert("ARM: Invalid out token");
+ originARM.swapTokensForExactTokens(weth, BAD_TOKEN, 10 ether, 10 ether, address(this));
+ vm.expectRevert("ARM: Invalid out token");
+ originARM.swapTokensForExactTokens(oeth, BAD_TOKEN, 10 ether, 10 ether, address(this));
+ vm.expectRevert("ARM: Invalid out token");
+ originARM.swapTokensForExactTokens(weth, weth, 10 ether, 10 ether, address(this));
+ vm.expectRevert("ARM: Invalid out token");
+ originARM.swapTokensForExactTokens(oeth, oeth, 10 ether, 10 ether, address(this));
+ }
+
+ ////////////////////////////////////////////////////
+ /// --- AUTHORIZATION
+ ////////////////////////////////////////////////////
function test_unauthorizedAccess() external {
- address RANDOM_ADDRESS = 0xfEEDBeef00000000000000000000000000000000;
+ address RANDOM_ADDRESS = vm.randomAddress();
vm.startPrank(RANDOM_ADDRESS);
// Proxy's restricted methods.
@@ -101,87 +264,57 @@ contract Fork_OethARM_Smoke_Test is AbstractSmokeTest {
// Implementation's restricted methods.
vm.expectRevert("ARM: Only owner can call this function.");
- oethARM.setOwner(RANDOM_ADDRESS);
- }
-
- function test_wrongInTokenExactIn() external {
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapExactTokensForTokens(BAD_TOKEN, oeth, 10 ether, 0, address(this));
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapExactTokensForTokens(BAD_TOKEN, weth, 10 ether, 0, address(this));
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapExactTokensForTokens(weth, weth, 10 ether, 0, address(this));
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapExactTokensForTokens(oeth, oeth, 10 ether, 0, address(this));
- }
-
- function test_wrongOutTokenExactIn() external {
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapTokensForExactTokens(weth, BAD_TOKEN, 10 ether, 10 ether, address(this));
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapTokensForExactTokens(oeth, BAD_TOKEN, 10 ether, 10 ether, address(this));
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapTokensForExactTokens(weth, weth, 10 ether, 10 ether, address(this));
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapTokensForExactTokens(oeth, oeth, 10 ether, 10 ether, address(this));
- }
-
- function test_wrongInTokenExactOut() external {
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapTokensForExactTokens(BAD_TOKEN, oeth, 10 ether, 10 ether, address(this));
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapTokensForExactTokens(BAD_TOKEN, weth, 10 ether, 10 ether, address(this));
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapTokensForExactTokens(weth, weth, 10 ether, 10 ether, address(this));
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapTokensForExactTokens(oeth, oeth, 10 ether, 10 ether, address(this));
- }
-
- function test_wrongOutTokenExactOut() external {
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapTokensForExactTokens(weth, BAD_TOKEN, 10 ether, 10 ether, address(this));
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapTokensForExactTokens(oeth, BAD_TOKEN, 10 ether, 10 ether, address(this));
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapTokensForExactTokens(weth, weth, 10 ether, 10 ether, address(this));
- vm.expectRevert("ARM: Invalid swap");
- oethARM.swapTokensForExactTokens(oeth, oeth, 10 ether, 10 ether, address(this));
- }
-
- function test_collectTokens() external {
- vm.startPrank(Mainnet.TIMELOCK);
-
- oethARM.transferToken(address(weth), address(this), weth.balanceOf(address(oethARM)));
- assertGt(weth.balanceOf(address(this)), 50 ether);
- assertEq(weth.balanceOf(address(oethARM)), 0);
-
- oethARM.transferToken(address(oeth), address(this), oeth.balanceOf(address(oethARM)));
- assertGt(oeth.balanceOf(address(this)), 50 ether);
- assertLt(oeth.balanceOf(address(oethARM)), 3);
-
+ originARM.setOwner(RANDOM_ADDRESS);
vm.stopPrank();
- }
-
- function _dealOETH(address to, uint256 amount) internal {
- vm.prank(0xDcEe70654261AF21C44c093C300eD3Bb97b78192);
- oeth.transfer(to, amount);
- }
- function _dealWETH(address to, uint256 amount) internal {
- deal(address(weth), to, amount);
+ vm.expectRevert("ARM: Only owner can call this function.");
+ vm.prank(operator);
+ originARM.setOperator(operator);
}
- /* Operator Tests */
-
function test_setOperator() external {
vm.prank(Mainnet.TIMELOCK);
- oethARM.setOperator(address(this));
- assertEq(oethARM.operator(), address(this));
+ originARM.setOperator(address(this));
+ assertEq(originARM.operator(), address(this));
}
- function test_nonOwnerCannotSetOperator() external {
- vm.expectRevert("ARM: Only owner can call this function.");
- vm.prank(operator);
- oethARM.setOperator(operator);
+ ////////////////////////////////////////////////////
+ /// --- VAULT WITHDRAWALS
+ ////////////////////////////////////////////////////
+ function test_request_origin_withdrawal() external {
+ _dealOETH(address(originARM), 10 ether);
+ vm.prank(Mainnet.ARM_RELAYER);
+ uint256 requestId = originARM.requestOriginWithdrawal(10 ether);
+ assertNotEq(requestId, 0);
+ }
+
+ function test_claim_origin_withdrawal() external {
+ // Cheat section
+ // Deal OETH to the ARM, in order to have some asset to withdraw
+ _dealOETH(address(originARM), 10 ether);
+ // Deal WETH to this test account to mint OETH in the Vault, directly increasing
+ // the Vault's liquidity doesn't work because of the "Backing supply liquidity error" check
+ _dealWETH(address(this), 10_000 ether);
+ (bool success,) =
+ Mainnet.WETH.call(abi.encodeWithSignature("approve(address,uint256)", Mainnet.OETH_VAULT, 10_000 ether));
+ require(success, "Approve failed");
+ (success,) = Mainnet.OETH_VAULT
+ .call(abi.encodeWithSignature("mint(address,uint256,uint256)", Mainnet.WETH, 10_000 ether, 0));
+ require(success, "Mint failed");
+ // End cheat section
+
+ // Request a withdrawal
+ vm.prank(Mainnet.ARM_RELAYER);
+ uint256 requestId = originARM.requestOriginWithdrawal(10 ether);
+
+ // Fast forward time by 1 day to pass the claim delay
+ vm.warp(block.timestamp + 1 days);
+
+ // Claim the withdrawal
+ uint256[] memory requestIds = new uint256[](1);
+ requestIds[0] = requestId;
+
+ uint256 amountClaimed = originARM.claimOriginWithdrawals(requestIds);
+ assertEq(amountClaimed, 10 ether);
}
}