From 0892f75c02b9531abfde9a80041bd16f0893ec6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Fingen?= Date: Sun, 25 Aug 2024 21:10:43 +0100 Subject: [PATCH] chore: Move zappers to deployment contract --- .../Zappers/Interfaces/ILeverageZapper.sol | 4 + .../INonfungiblePositionManager.sol | 0 .../Exchanges/UniswapV3}/IPoolInitializer.sol | 0 .../Exchanges/UniswapV3/IUniswapV3Factory.sol | 64 ++++++ contracts/src/test/Invariants.t.sol | 2 +- contracts/src/test/SPInvariants.t.sol | 2 +- contracts/src/test/TestContracts/BaseTest.sol | 7 + .../src/test/TestContracts/Deployment.t.sol | 190 ++++++++++++++++-- .../src/test/TestContracts/DevTestSetup.sol | 7 +- contracts/src/test/liquidationsLST.t.sol | 2 +- contracts/src/test/multicollateral.t.sol | 2 +- contracts/src/test/shutdown.t.sol | 2 +- contracts/src/test/zapperGasComp.t.sol | 10 +- contracts/src/test/zapperLeverage.t.sol | 174 ++++++---------- contracts/src/test/zapperWETH.t.sol | 10 +- 15 files changed, 337 insertions(+), 139 deletions(-) rename contracts/src/{test/TestContracts/Interfaces => Zappers/Modules/Exchanges/UniswapV3}/INonfungiblePositionManager.sol (100%) rename contracts/src/{test/TestContracts/Interfaces => Zappers/Modules/Exchanges/UniswapV3}/IPoolInitializer.sol (100%) create mode 100644 contracts/src/Zappers/Modules/Exchanges/UniswapV3/IUniswapV3Factory.sol diff --git a/contracts/src/Zappers/Interfaces/ILeverageZapper.sol b/contracts/src/Zappers/Interfaces/ILeverageZapper.sol index e5f716b61..5f66b07e1 100644 --- a/contracts/src/Zappers/Interfaces/ILeverageZapper.sol +++ b/contracts/src/Zappers/Interfaces/ILeverageZapper.sol @@ -2,6 +2,8 @@ pragma solidity ^0.8.0; +import "./IExchange.sol"; + interface ILeverageZapper { struct OpenLeveragedTroveParams { address owner; @@ -31,6 +33,8 @@ interface ILeverageZapper { uint256 minBoldAmount; } + function exchange() external returns (IExchange); + function openLeveragedTroveWithRawETH(OpenLeveragedTroveParams calldata _params) external payable; function leverUpTrove(LeverUpTroveParams calldata _params) external; diff --git a/contracts/src/test/TestContracts/Interfaces/INonfungiblePositionManager.sol b/contracts/src/Zappers/Modules/Exchanges/UniswapV3/INonfungiblePositionManager.sol similarity index 100% rename from contracts/src/test/TestContracts/Interfaces/INonfungiblePositionManager.sol rename to contracts/src/Zappers/Modules/Exchanges/UniswapV3/INonfungiblePositionManager.sol diff --git a/contracts/src/test/TestContracts/Interfaces/IPoolInitializer.sol b/contracts/src/Zappers/Modules/Exchanges/UniswapV3/IPoolInitializer.sol similarity index 100% rename from contracts/src/test/TestContracts/Interfaces/IPoolInitializer.sol rename to contracts/src/Zappers/Modules/Exchanges/UniswapV3/IPoolInitializer.sol diff --git a/contracts/src/Zappers/Modules/Exchanges/UniswapV3/IUniswapV3Factory.sol b/contracts/src/Zappers/Modules/Exchanges/UniswapV3/IUniswapV3Factory.sol new file mode 100644 index 000000000..1ce33c793 --- /dev/null +++ b/contracts/src/Zappers/Modules/Exchanges/UniswapV3/IUniswapV3Factory.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + +interface IUniswapV3Factory { + /// @notice Emitted when the owner of the factory is changed + /// @param oldOwner The owner before the owner was changed + /// @param newOwner The owner after the owner was changed + event OwnerChanged(address indexed oldOwner, address indexed newOwner); + + /// @notice Emitted when a pool is created + /// @param token0 The first token of the pool by address sort order + /// @param token1 The second token of the pool by address sort order + /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip + /// @param tickSpacing The minimum number of ticks between initialized ticks + /// @param pool The address of the created pool + event PoolCreated( + address indexed token0, address indexed token1, uint24 indexed fee, int24 tickSpacing, address pool + ); + + /// @notice Emitted when a new fee amount is enabled for pool creation via the factory + /// @param fee The enabled fee, denominated in hundredths of a bip + /// @param tickSpacing The minimum number of ticks between initialized ticks for pools created with the given fee + event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing); + + /// @notice Returns the current owner of the factory + /// @dev Can be changed by the current owner via setOwner + /// @return The address of the factory owner + function owner() external view returns (address); + + /// @notice Returns the tick spacing for a given fee amount, if enabled, or 0 if not enabled + /// @dev A fee amount can never be removed, so this value should be hard coded or cached in the calling context + /// @param fee The enabled fee, denominated in hundredths of a bip. Returns 0 in case of unenabled fee + /// @return The tick spacing + function feeAmountTickSpacing(uint24 fee) external view returns (int24); + + /// @notice Returns the pool address for a given pair of tokens and a fee, or address 0 if it does not exist + /// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order + /// @param tokenA The contract address of either token0 or token1 + /// @param tokenB The contract address of the other token + /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip + /// @return pool The pool address + function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool); + + /// @notice Creates a pool for the given two tokens and fee + /// @param tokenA One of the two tokens in the desired pool + /// @param tokenB The other of the two tokens in the desired pool + /// @param fee The desired fee for the pool + /// @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0. tickSpacing is retrieved + /// from the fee. The call will revert if the pool already exists, the fee is invalid, or the token arguments + /// are invalid. + /// @return pool The address of the newly created pool + function createPool(address tokenA, address tokenB, uint24 fee) external returns (address pool); + + /// @notice Updates the owner of the factory + /// @dev Must be called by the current owner + /// @param _owner The new owner of the factory + function setOwner(address _owner) external; + + /// @notice Enables a fee amount with the given tickSpacing + /// @dev Fee amounts may never be removed once enabled + /// @param fee The fee amount to enable, denominated in hundredths of a bip (i.e. 1e-6) + /// @param tickSpacing The spacing between ticks to be enforced for all pools created with the given fee amount + function enableFeeAmount(uint24 fee, int24 tickSpacing) external; +} diff --git a/contracts/src/test/Invariants.t.sol b/contracts/src/test/Invariants.t.sol index 813d93dbf..9fbce5430 100644 --- a/contracts/src/test/Invariants.t.sol +++ b/contracts/src/test/Invariants.t.sol @@ -69,7 +69,7 @@ contract InvariantsTest is Logging, BaseInvariantTest, BaseMultiCollateralTest { TestDeployer deployer = new TestDeployer(); Contracts memory contracts; - (contracts.branches, contracts.collateralRegistry, contracts.boldToken, contracts.hintHelpers,, contracts.weth) + (contracts.branches, contracts.collateralRegistry, contracts.boldToken, contracts.hintHelpers,, contracts.weth,) = deployer.deployAndConnectContractsMultiColl(paramsList); setupContracts(contracts); diff --git a/contracts/src/test/SPInvariants.t.sol b/contracts/src/test/SPInvariants.t.sol index c7b8f50f7..eab9e4acf 100644 --- a/contracts/src/test/SPInvariants.t.sol +++ b/contracts/src/test/SPInvariants.t.sol @@ -16,7 +16,7 @@ contract SPInvariantsTest is BaseInvariantTest { super.setUp(); TestDeployer deployer = new TestDeployer(); - (TestDeployer.LiquityContractsDev memory contracts,, IBoldToken boldToken, HintHelpers hintHelpers,,) = + (TestDeployer.LiquityContractsDev memory contracts,, IBoldToken boldToken, HintHelpers hintHelpers,,,) = deployer.deployAndConnectContracts(); stabilityPool = contracts.stabilityPool; diff --git a/contracts/src/test/TestContracts/BaseTest.sol b/contracts/src/test/TestContracts/BaseTest.sol index 2ac0d6c7b..ca4536d67 100644 --- a/contracts/src/test/TestContracts/BaseTest.sol +++ b/contracts/src/test/TestContracts/BaseTest.sol @@ -16,6 +16,9 @@ import "./PriceFeedTestnet.sol"; import "../../Interfaces/IInterestRouter.sol"; import "../../GasPool.sol"; import "../../HintHelpers.sol"; +import "../../Zappers/WETHZapper.sol"; +import "../../Zappers/GasCompZapper.sol"; +import "../../Zappers/LeverageLSTZapper.sol"; import {mulDivCeil} from "../Utils/Math.sol"; import {Logging} from "../Utils/Logging.sol"; import {StringFormatting} from "../Utils/StringFormatting.sol"; @@ -47,6 +50,10 @@ contract BaseTest is TestAccounts, Logging { IERC20 collToken; HintHelpers hintHelpers; IWETH WETH; // used for gas compensation + WETHZapper wethZapper; + GasCompZapper gasCompZapper; + LeverageLSTZapper leverageZapperCurve; + LeverageLSTZapper leverageZapperUniV3; // Structs for use in test where we need to bi-pass "stack-too-deep" errors struct ABCDEF { diff --git a/contracts/src/test/TestContracts/Deployment.t.sol b/contracts/src/test/TestContracts/Deployment.t.sol index 0140d2810..e7318ea62 100644 --- a/contracts/src/test/TestContracts/Deployment.t.sol +++ b/contracts/src/test/TestContracts/Deployment.t.sol @@ -19,6 +19,19 @@ import "../../TroveNFT.sol"; import "../../CollateralRegistry.sol"; import "../../MockInterestRouter.sol"; import "./PriceFeedTestnet.sol"; +import "../../Zappers/WETHZapper.sol"; +import "../../Zappers/GasCompZapper.sol"; +import "../../Zappers/LeverageLSTZapper.sol"; +import "../../Zappers/Modules/FlashLoans/BalancerFlashLoan.sol"; +import "../../Zappers/Interfaces/IFlashLoanProvider.sol"; +import "../../Zappers/Interfaces/IExchange.sol"; +import "../../Zappers/Modules/Exchanges/Curve/ICurveFactory.sol"; +import "../../Zappers/Modules/Exchanges/Curve/ICurvePool.sol"; +import "../../Zappers/Modules/Exchanges/CurveExchange.sol"; +import "../../Zappers/Modules/Exchanges/UniswapV3/ISwapRouter.sol"; +import "../../Zappers/Modules/Exchanges/UniswapV3/IQuoterV2.sol"; +import "../../Zappers/Modules/Exchanges/UniV3Exchange.sol"; +import "../../Zappers/Modules/Exchanges/UniswapV3/INonfungiblePositionManager.sol"; import {WETHTester} from "./WETHTester.sol"; import {ERC20Faucet} from "./ERC20Faucet.sol"; @@ -35,6 +48,13 @@ uint256 constant _48_HOURS = 172800; // TODO: Split dev and mainnet contract TestDeployer { + ICurveFactory constant curveFactory = ICurveFactory(0x98EE851a00abeE0d95D08cF4CA2BdCE32aeaAF7F); + ISwapRouter constant uniV3Router = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564); + IQuoterV2 constant uniV3Quoter = IQuoterV2(0x61fFE014bA17989E743c5F6cB21bF9697530B21e); + INonfungiblePositionManager constant uniV3PositionManager = + INonfungiblePositionManager(0xC36442b4a4522E871399CD717aBDD847Ab11FE88); + uint24 constant UNIV3_FEE = 3000; // 0.3% + bytes32 constant SALT = keccak256("LiquityV2"); struct LiquityContractsDev { @@ -69,6 +89,13 @@ contract TestDeployer { IERC20 collToken; } + struct Zappers { + WETHZapper wethZapper; + GasCompZapper gasCompZapper; + LeverageLSTZapper leverageZapperCurve; + LeverageLSTZapper leverageZapperUniV3; + } + struct LiquityContractAddresses { address activePool; address borrowerOperations; @@ -96,7 +123,6 @@ contract TestDeployer { IERC20[] collaterals; IAddressesRegistry[] addressesRegistries; ITroveManager[] troveManagers; - LiquityContractsDev contracts; bytes bytecode; address boldTokenAddress; uint256 i; @@ -109,6 +135,7 @@ contract TestDeployer { IBoldToken boldToken; HintHelpers hintHelpers; MultiTroveGetter multiTroveGetter; + Zappers[] zappersArray; } struct DeploymentVarsMainnet { @@ -163,7 +190,8 @@ contract TestDeployer { IBoldToken boldToken, HintHelpers hintHelpers, MultiTroveGetter multiTroveGetter, - IWETH WETH // for gas compensation + IWETH WETH, // for gas compensation + Zappers memory zappers ) { return deployAndConnectContracts(TroveManagerParams(150e16, 110e16, 110e16, 5e16, 10e16)); @@ -177,17 +205,20 @@ contract TestDeployer { IBoldToken boldToken, HintHelpers hintHelpers, MultiTroveGetter multiTroveGetter, - IWETH WETH // for gas compensation + IWETH WETH, // for gas compensation + Zappers memory zappers ) { LiquityContractsDev[] memory contractsArray; TroveManagerParams[] memory troveManagerParamsArray = new TroveManagerParams[](1); + Zappers[] memory zappersArray; troveManagerParamsArray[0] = troveManagerParams; - (contractsArray, collateralRegistry, boldToken, hintHelpers, multiTroveGetter, WETH) = + (contractsArray, collateralRegistry, boldToken, hintHelpers, multiTroveGetter, WETH, zappersArray) = deployAndConnectContractsMultiColl(troveManagerParamsArray); contracts = contractsArray[0]; + zappers = zappersArray[0]; } function deployAndConnectContractsMultiColl(TroveManagerParams[] memory troveManagerParamsArray) @@ -198,7 +229,8 @@ contract TestDeployer { IBoldToken boldToken, HintHelpers hintHelpers, MultiTroveGetter multiTroveGetter, - IWETH WETH // for gas compensation + IWETH WETH, // for gas compensation + Zappers[] memory zappersArray ) { // used for gas compensation and as collateral of the first branch @@ -206,7 +238,7 @@ contract TestDeployer { 100 ether, // _tapAmount 1 days // _tapPeriod ); - (contractsArray, collateralRegistry, boldToken, hintHelpers, multiTroveGetter) = + (contractsArray, collateralRegistry, boldToken, hintHelpers, multiTroveGetter, zappersArray) = deployAndConnectContracts(troveManagerParamsArray, WETH); } @@ -217,7 +249,8 @@ contract TestDeployer { ICollateralRegistry collateralRegistry, IBoldToken boldToken, HintHelpers hintHelpers, - MultiTroveGetter multiTroveGetter + MultiTroveGetter multiTroveGetter, + Zappers[] memory zappersArray ) { DeploymentVarsDev memory vars; @@ -229,6 +262,7 @@ contract TestDeployer { assert(address(boldToken) == vars.boldTokenAddress); contractsArray = new LiquityContractsDev[](vars.numCollaterals); + zappersArray = new Zappers[](vars.numCollaterals); vars.collaterals = new IERC20[](vars.numCollaterals); vars.addressesRegistries = new IAddressesRegistry[](vars.numCollaterals); vars.troveManagers = new ITroveManager[](vars.numCollaterals); @@ -257,7 +291,7 @@ contract TestDeployer { hintHelpers = new HintHelpers(collateralRegistry); multiTroveGetter = new MultiTroveGetter(collateralRegistry); - vars.contracts = _deployAndConnectCollateralContractsDev( + (contractsArray[0], zappersArray[0]) = _deployAndConnectCollateralContractsDev( _WETH, boldToken, collateralRegistry, @@ -267,11 +301,10 @@ contract TestDeployer { hintHelpers, multiTroveGetter ); - contractsArray[0] = vars.contracts; // Deploy the remaining branches with LST collateral for (vars.i = 1; vars.i < vars.numCollaterals; vars.i++) { - vars.contracts = _deployAndConnectCollateralContractsDev( + (contractsArray[vars.i], zappersArray[vars.i]) = _deployAndConnectCollateralContractsDev( vars.collaterals[vars.i], boldToken, collateralRegistry, @@ -281,7 +314,6 @@ contract TestDeployer { hintHelpers, multiTroveGetter ); - contractsArray[vars.i] = vars.contracts; } boldToken.setCollateralRegistry(address(collateralRegistry)); @@ -315,7 +347,7 @@ contract TestDeployer { address _troveManagerAddress, IHintHelpers _hintHelpers, IMultiTroveGetter _multiTroveGetter - ) internal returns (LiquityContractsDev memory contracts) { + ) internal returns (LiquityContractsDev memory contracts, Zappers memory zappers) { LiquityContractAddresses memory addresses; contracts.collToken = _collToken; @@ -400,6 +432,10 @@ contract TestDeployer { address(contracts.borrowerOperations), address(contracts.activePool) ); + + // deploy zappers + (zappers.gasCompZapper, zappers.wethZapper, zappers.leverageZapperCurve, zappers.leverageZapperUniV3) = + _deployZappers(contracts.addressesRegistry, contracts.collToken, _boldToken, _weth, contracts.priceFeed, false); } // Creates individual PriceFeed contracts based on oracle addresses. @@ -432,6 +468,7 @@ contract TestDeployer { vars.numCollaterals = 5; result.contractsArray = new LiquityContracts[](vars.numCollaterals); + result.zappersArray = new Zappers[](vars.numCollaterals); vars.priceFeeds = new IPriceFeed[](vars.numCollaterals); vars.collaterals = new IERC20[](vars.numCollaterals); vars.addressesRegistries = new IAddressesRegistry[](vars.numCollaterals); @@ -527,7 +564,7 @@ contract TestDeployer { // Deploy each set of core contracts for (vars.i = 0; vars.i < vars.numCollaterals; vars.i++) { - result.contractsArray[vars.i] = _deployAndConnectCollateralContractsMainnet( + (result.contractsArray[vars.i], result.zappersArray[vars.i]) = _deployAndConnectCollateralContractsMainnet( vars.collaterals[vars.i], vars.priceFeeds[vars.i], result.boldToken, @@ -571,7 +608,7 @@ contract TestDeployer { address _troveManagerAddress, IHintHelpers _hintHelpers, IMultiTroveGetter _multiTroveGetter - ) internal returns (LiquityContracts memory contracts) { + ) internal returns (LiquityContracts memory contracts, Zappers memory zappers) { LiquityContractAddresses memory addresses; contracts.collToken = _collToken; contracts.priceFeed = _priceFeed; @@ -655,5 +692,130 @@ contract TestDeployer { address(contracts.borrowerOperations), address(contracts.activePool) ); + + // deploy zappers + (zappers.gasCompZapper, zappers.wethZapper, zappers.leverageZapperCurve, zappers.leverageZapperUniV3) = + _deployZappers(contracts.addressesRegistry, contracts.collToken, _boldToken, _weth, contracts.priceFeed, true); + } + + function _deployZappers( + IAddressesRegistry _addressesRegistry, + IERC20 _collToken, + IBoldToken _boldToken, + IWETH _weth, + IPriceFeed _priceFeed, + bool mainnet + ) + internal + returns ( + GasCompZapper gasCompZapper, + WETHZapper wethZapper, + LeverageLSTZapper leverageZapperCurve, + LeverageLSTZapper leverageZapperUniV3 + ) + { + if (_collToken == _weth) { + wethZapper = new WETHZapper(_addressesRegistry); + } else { + gasCompZapper = new GasCompZapper(_addressesRegistry); + } + + if (mainnet) { + (leverageZapperCurve, leverageZapperUniV3) = + _deployLeverageZappers(_addressesRegistry, _collToken, _boldToken, _priceFeed); + } + + return (gasCompZapper, wethZapper, leverageZapperCurve, leverageZapperUniV3); + } + + function _deployLeverageZappers( + IAddressesRegistry _addressesRegistry, + IERC20 _collToken, + IBoldToken _boldToken, + IPriceFeed _priceFeed + ) internal returns (LeverageLSTZapper, LeverageLSTZapper) { + IFlashLoanProvider flashLoanProvider = new BalancerFlashLoan(); + + LeverageLSTZapper leverageZapperCurve = + _deployCurveLeverageZapper(_addressesRegistry, _collToken, _boldToken, _priceFeed, flashLoanProvider); + LeverageLSTZapper leverageZapperUniV3 = + _deployUniV3LeverageZapper(_addressesRegistry, _collToken, _boldToken, _priceFeed, flashLoanProvider); + + return (leverageZapperCurve, leverageZapperUniV3); + } + + function _deployCurveLeverageZapper( + IAddressesRegistry _addressesRegistry, + IERC20 _collToken, + IBoldToken _boldToken, + IPriceFeed _priceFeed, + IFlashLoanProvider _flashLoanProvider + ) internal returns (LeverageLSTZapper) { + uint256 price = _priceFeed.fetchPrice(); + + // deploy Curve Twocrypto NG pool + address[2] memory coins; + coins[0] = address(_boldToken); + coins[1] = address(_collToken); + ICurvePool curvePool = curveFactory.deploy_pool( + "LST-Bold pool", + "LBLD", + coins, + 0, // implementation id + 400000, // A + 145000000000000, // gamma + 26000000, // mid_fee + 45000000, // out_fee + 230000000000000, // fee_gamma + 2000000000000, // allowed_extra_profit + 146000000000000, // adjustment_step + 600, // ma_exp_time + price // initial_price + ); + + IExchange curveExchange = new CurveExchange(_collToken, _boldToken, curvePool, 1, 0); + LeverageLSTZapper leverageZapperCurve = + new LeverageLSTZapper(_addressesRegistry, _flashLoanProvider, curveExchange); + + return leverageZapperCurve; + } + + struct UniV3Vars { + IExchange uniV3Exchange; + uint256 price; + address[2] tokens; + } + + function _deployUniV3LeverageZapper( + IAddressesRegistry _addressesRegistry, + IERC20 _collToken, + IBoldToken _boldToken, + IPriceFeed _priceFeed, + IFlashLoanProvider _flashLoanProvider + ) internal returns (LeverageLSTZapper) { + UniV3Vars memory vars; + vars.uniV3Exchange = new UniV3Exchange(_collToken, _boldToken, UNIV3_FEE, uniV3Router, uniV3Quoter); + LeverageLSTZapper leverageZapperUniV3 = + new LeverageLSTZapper(_addressesRegistry, _flashLoanProvider, vars.uniV3Exchange); + + // Create Uni V3 pool + vars.price = _priceFeed.fetchPrice(); + if (address(_boldToken) < address(_collToken)) { + //console2.log("b < c"); + vars.tokens[0] = address(_boldToken); + vars.tokens[1] = address(_collToken); + } else { + //console2.log("c < b"); + vars.tokens[0] = address(_collToken); + vars.tokens[1] = address(_boldToken); + } + uniV3PositionManager.createAndInitializePoolIfNecessary( + vars.tokens[0], // token0, + vars.tokens[1], // token1, + UNIV3_FEE, // fee, + UniV3Exchange(address(vars.uniV3Exchange)).priceToSqrtPrice(_boldToken, _collToken, vars.price) // sqrtPriceX96 + ); + + return leverageZapperUniV3; } } diff --git a/contracts/src/test/TestContracts/DevTestSetup.sol b/contracts/src/test/TestContracts/DevTestSetup.sol index de431535f..fd2acbdd8 100644 --- a/contracts/src/test/TestContracts/DevTestSetup.sol +++ b/contracts/src/test/TestContracts/DevTestSetup.sol @@ -49,7 +49,8 @@ contract DevTestSetup is BaseTest { TestDeployer deployer = new TestDeployer(); TestDeployer.LiquityContractsDev memory contracts; - (contracts, collateralRegistry, boldToken, hintHelpers,, WETH) = deployer.deployAndConnectContracts(); + TestDeployer.Zappers memory zappers; + (contracts, collateralRegistry, boldToken, hintHelpers,, WETH, zappers) = deployer.deployAndConnectContracts(); addressesRegistry = contracts.addressesRegistry; collToken = contracts.collToken; activePool = contracts.activePool; @@ -62,6 +63,10 @@ contract DevTestSetup is BaseTest { stabilityPool = contracts.stabilityPool; troveManager = contracts.troveManager; mockInterestRouter = contracts.interestRouter; + wethZapper = zappers.wethZapper; + gasCompZapper = zappers.gasCompZapper; + leverageZapperCurve = zappers.leverageZapperCurve; + leverageZapperUniV3 = zappers.leverageZapperUniV3; // Give some Coll to test accounts, and approve it to BorrowerOperations uint256 initialCollAmount = 1000_000e18; diff --git a/contracts/src/test/liquidationsLST.t.sol b/contracts/src/test/liquidationsLST.t.sol index 2914c3d18..d99fd5a25 100644 --- a/contracts/src/test/liquidationsLST.t.sol +++ b/contracts/src/test/liquidationsLST.t.sol @@ -24,7 +24,7 @@ contract LiquidationsLSTTest is DevTestSetup { TestDeployer deployer = new TestDeployer(); TestDeployer.LiquityContractsDev memory contracts; - (contracts, collateralRegistry, boldToken,,,) = + (contracts, collateralRegistry, boldToken,,,,) = deployer.deployAndConnectContracts(TestDeployer.TroveManagerParams(160e16, 120e16, 1.2 ether, 5e16, 10e16)); collToken = contracts.collToken; activePool = contracts.activePool; diff --git a/contracts/src/test/multicollateral.t.sol b/contracts/src/test/multicollateral.t.sol index 93699593b..e5d5b2a8e 100644 --- a/contracts/src/test/multicollateral.t.sol +++ b/contracts/src/test/multicollateral.t.sol @@ -74,7 +74,7 @@ contract MulticollateralTest is DevTestSetup { TestDeployer deployer = new TestDeployer(); TestDeployer.LiquityContractsDev[] memory _contractsArray; - (_contractsArray, collateralRegistry, boldToken,,, WETH) = + (_contractsArray, collateralRegistry, boldToken,,, WETH,) = deployer.deployAndConnectContractsMultiColl(troveManagerParamsArray); // Unimplemented feature (...):Copying of type struct LiquityContracts memory[] memory to storage not yet supported. for (uint256 c = 0; c < NUM_COLLATERALS; c++) { diff --git a/contracts/src/test/shutdown.t.sol b/contracts/src/test/shutdown.t.sol index c6e4187dd..540297b93 100644 --- a/contracts/src/test/shutdown.t.sol +++ b/contracts/src/test/shutdown.t.sol @@ -34,7 +34,7 @@ contract ShutdownTest is DevTestSetup { TestDeployer deployer = new TestDeployer(); TestDeployer.LiquityContractsDev[] memory _contractsArray; - (_contractsArray, collateralRegistry, boldToken,,, WETH) = + (_contractsArray, collateralRegistry, boldToken,,, WETH,) = deployer.deployAndConnectContractsMultiColl(troveManagerParamsArray); // Unimplemented feature (...):Copying of type struct LiquityContracts memory[] memory to storage not yet supported. for (uint256 c = 0; c < NUM_COLLATERALS; c++) { diff --git a/contracts/src/test/zapperGasComp.t.sol b/contracts/src/test/zapperGasComp.t.sol index ea9c31005..1a21afb7e 100644 --- a/contracts/src/test/zapperGasComp.t.sol +++ b/contracts/src/test/zapperGasComp.t.sol @@ -7,8 +7,6 @@ import "./TestContracts/WETH.sol"; import "../Zappers/GasCompZapper.sol"; contract ZapperGasCompTest is DevTestSetup { - GasCompZapper gasCompZapper; - function setUp() public override { // Start tests at a non-zero timestamp vm.warp(block.timestamp + 600); @@ -34,7 +32,9 @@ contract ZapperGasCompTest is DevTestSetup { TestDeployer deployer = new TestDeployer(); TestDeployer.LiquityContractsDev[] memory contractsArray; - (contractsArray, collateralRegistry, boldToken,,) = deployer.deployAndConnectContracts(troveManagerParams, WETH); + TestDeployer.Zappers[] memory zappersArray; + (contractsArray, collateralRegistry, boldToken,,, zappersArray) = + deployer.deployAndConnectContracts(troveManagerParams, WETH); // Set price feeds contractsArray[1].priceFeed.setPrice(2000e18); @@ -45,9 +45,7 @@ contract ZapperGasCompTest is DevTestSetup { troveManager = contractsArray[1].troveManager; troveNFT = contractsArray[1].troveNFT; collToken = contractsArray[1].collToken; - - // Deploy zapper (TODO: should we move it to deployment contract?) - gasCompZapper = new GasCompZapper(addressesRegistry); + gasCompZapper = zappersArray[1].gasCompZapper; // Give some Collateral to test accounts uint256 initialCollateralAmount = 10_000e18; diff --git a/contracts/src/test/zapperLeverage.t.sol b/contracts/src/test/zapperLeverage.t.sol index 2c19e00ae..de2bf35af 100644 --- a/contracts/src/test/zapperLeverage.t.sol +++ b/contracts/src/test/zapperLeverage.t.sol @@ -5,36 +5,40 @@ pragma solidity ^0.8.18; import "./TestContracts/DevTestSetup.sol"; import "./TestContracts/WETH.sol"; import "../Zappers/LeverageLSTZapper.sol"; -import "../Zappers/Modules/FlashLoans/BalancerFlashLoan.sol"; -import "../Zappers/Modules/Exchanges/Curve/ICurveFactory.sol"; import "../Zappers/Modules/Exchanges/Curve/ICurvePool.sol"; import "../Zappers/Modules/Exchanges/CurveExchange.sol"; -import "../Zappers/Modules/Exchanges/UniswapV3/ISwapRouter.sol"; -import "../Zappers/Modules/Exchanges/UniswapV3/IQuoterV2.sol"; import "../Zappers/Modules/Exchanges/UniswapV3/IUniswapV3Pool.sol"; -import "./TestContracts/Interfaces/INonfungiblePositionManager.sol"; import "../Zappers/Modules/Exchanges/UniV3Exchange.sol"; +import "../Zappers/Modules/Exchanges/UniswapV3/INonfungiblePositionManager.sol"; +import "../Zappers/Modules/Exchanges/UniswapV3/IUniswapV3Factory.sol"; import "./Utils/UniPriceConverter.sol"; contract ZapperLeverageLSTMainnet is DevTestSetup { using StringFormatting for uint256; - ICurveFactory constant curveFactory = ICurveFactory(0x98EE851a00abeE0d95D08cF4CA2BdCE32aeaAF7F); - ISwapRouter constant uniV3Router = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564); - IQuoterV2 constant uniV3Quoter = IQuoterV2(0x61fFE014bA17989E743c5F6cB21bF9697530B21e); INonfungiblePositionManager constant uniV3PositionManager = INonfungiblePositionManager(0xC36442b4a4522E871399CD717aBDD847Ab11FE88); + IUniswapV3Factory constant uniswapV3Factory = IUniswapV3Factory(0x1F98431c8aD98523631AE4a59f267346ea31F984); uint24 constant UNIV3_FEE = 3000; // 0.3% uint256 constant NUM_COLLATERALS = 5; - LeverageLSTZapper[NUM_COLLATERALS] leverageZapperCurveArray; - LeverageLSTZapper[NUM_COLLATERALS] leverageZapperUniV3Array; - IExchange[NUM_COLLATERALS] curveExchangeArray; - IExchange[NUM_COLLATERALS] uniV3ExchangeArray; + LeverageLSTZapper[] leverageZapperCurveArray; + LeverageLSTZapper[] leverageZapperUniV3Array; TestDeployer.LiquityContracts[] contractsArray; + struct LeverVars { + uint256 price; + uint256 currentCR; + uint256 currentLR; + uint256 currentCollAmount; + uint256 flashLoanAmount; + uint256 expectedBoldAmount; + uint256 maxNetDebtIncrease; + uint256 effectiveBoldAmount; + } + struct TestVars { uint256 collAmount; uint256 initialLeverageRatio; @@ -84,29 +88,15 @@ contract ZapperLeverageLSTMainnet is DevTestSetup { // Record contracts for (uint256 c = 0; c < NUM_COLLATERALS; c++) { contractsArray.push(result.contractsArray[c]); + leverageZapperCurveArray.push(result.zappersArray[c].leverageZapperCurve); + leverageZapperUniV3Array.push(result.zappersArray[c].leverageZapperUniV3); } - // Deploy zapper (TODO: should we move it to deployment.sol?) - BalancerFlashLoan flashLoanProvider = new BalancerFlashLoan(); - - // Curve version // Bootstrap Curve pools - ICurvePool[] memory curvePools; - curvePools = deployCurveV2Pools(result.contractsArray); - for (uint256 c = 0; c < NUM_COLLATERALS; c++) { - curveExchangeArray[c] = new CurveExchange(contractsArray[c].collToken, boldToken, curvePools[c], 1, 0); - leverageZapperCurveArray[c] = - new LeverageLSTZapper(contractsArray[c].addressesRegistry, flashLoanProvider, curveExchangeArray[c]); - } - // Uni V3 version - for (uint256 c = 0; c < NUM_COLLATERALS; c++) { - uniV3ExchangeArray[c] = - new UniV3Exchange(contractsArray[c].collToken, boldToken, UNIV3_FEE, uniV3Router, uniV3Quoter); - leverageZapperUniV3Array[c] = - new LeverageLSTZapper(contractsArray[c].addressesRegistry, flashLoanProvider, uniV3ExchangeArray[c]); - } + fundCurveV2Pools(result.contractsArray, result.zappersArray); + // Bootstrap UniV3 pools - deployUniV3Pools(result.contractsArray); + fundUniV3Pools(result.contractsArray); // Give some Collateral to test accounts uint256 initialCollateralAmount = 10_000e18; @@ -126,34 +116,13 @@ contract ZapperLeverageLSTMainnet is DevTestSetup { } } - function deployCurveV2Pools(TestDeployer.LiquityContracts[] memory _contractsArray) - internal - returns (ICurvePool[] memory curvePools) - { - curvePools = new ICurvePool[](NUM_COLLATERALS); - + function fundCurveV2Pools( + TestDeployer.LiquityContracts[] memory _contractsArray, + TestDeployer.Zappers[] memory _zappersArray + ) internal { for (uint256 i = 0; i < NUM_COLLATERALS; i++) { uint256 price = _contractsArray[i].priceFeed.fetchPrice(); - - // deploy Curve Twocrypto NG pool - address[2] memory coins; - coins[0] = address(boldToken); - coins[1] = address(_contractsArray[i].collToken); - curvePools[i] = curveFactory.deploy_pool( - "LST-Bold pool", - "LBLD", - coins, - 0, // implementation id - 400000, // A - 145000000000000, // gamma - 26000000, // mid_fee - 45000000, // out_fee - 230000000000000, // fee_gamma - 2000000000000, // allowed_extra_profit - 146000000000000, // adjustment_step - 600, // ma_exp_time - price // initial_price - ); + ICurvePool curvePool = CurveExchange(address(_zappersArray[i].leverageZapperCurve.exchange())).curvePool(); // Add liquidity uint256 collAmount = 1000 ether; @@ -162,17 +131,17 @@ contract ZapperLeverageLSTMainnet is DevTestSetup { deal(address(boldToken), A, boldAmount); vm.startPrank(A); // approve - _contractsArray[i].collToken.approve(address(curvePools[i]), collAmount); - boldToken.approve(address(curvePools[i]), boldAmount); + _contractsArray[i].collToken.approve(address(curvePool), collAmount); + boldToken.approve(address(curvePool), boldAmount); uint256[2] memory amounts; amounts[0] = boldAmount; amounts[1] = collAmount; - curvePools[i].add_liquidity(amounts, 0); + curvePool.add_liquidity(amounts, 0); vm.stopPrank(); } } - function deployUniV3Pools(TestDeployer.LiquityContracts[] memory _contractsArray) internal { + function fundUniV3Pools(TestDeployer.LiquityContracts[] memory _contractsArray) internal { for (uint256 i = 0; i < NUM_COLLATERALS; i++) { uint256 price = _contractsArray[i].priceFeed.fetchPrice(); //console2.log(price, "price"); @@ -196,17 +165,6 @@ contract ZapperLeverageLSTMainnet is DevTestSetup { amounts[1] = boldAmount; } - // Create Uni V3 pool - address uniV3PoolAddress = uniV3PositionManager.createAndInitializePoolIfNecessary( - tokens[0], // token0, - tokens[1], // token1, - UNIV3_FEE, // fee, - UniV3Exchange(address(uniV3ExchangeArray[i])).priceToSqrtPrice( - boldToken, _contractsArray[i].collToken, price - ) // sqrtPriceX96 - ); - //console2.log(uniV3PoolAddress, "uniV3PoolAddress"); - // Add liquidity vm.startPrank(A); @@ -218,6 +176,9 @@ contract ZapperLeverageLSTMainnet is DevTestSetup { boldToken.approve(address(uniV3PositionManager), boldAmount); // mint new position + address uniV3PoolAddress = + uniswapV3Factory.getPool(address(boldToken), address(_contractsArray[i].collToken), UNIV3_FEE); + //console2.log(uniV3PoolAddress, "uniV3PoolAddress"); int24 TICK_SPACING = IUniswapV3Pool(uniV3PoolAddress).tickSpacing(); (, int24 tick,,,,,) = IUniswapV3Pool(uniV3PoolAddress).slot0(); int24 tickLower = (tick - 6000) / TICK_SPACING * TICK_SPACING; @@ -249,28 +210,28 @@ contract ZapperLeverageLSTMainnet is DevTestSetup { /* function openLeveragedTroveWithCurve(uint256 _collAmount, uint256 _leverageRatio) internal returns (uint256) { - return openLeveragedTrove(leverageZapperCurve, curveExchange, _collAmount, _leverageRatio); + return openLeveragedTrove(leverageZapperCurve, _collAmount, _leverageRatio); } function openLeveragedTroveWithUniV3(uint256 _collAmount, uint256 _leverageRatio) internal returns (uint256) { - return openLeveragedTrove(leverageZapperUniV3, curveExchange, _collAmount, _leverageRatio); + return openLeveragedTrove(leverageZapperUniV3, _collAmount, _leverageRatio); } */ function openLeveragedTrove( ILeverageZapper _leverageZapper, - IExchange _exchange, uint256 _collAmount, uint256 _leverageRatio, IPriceFeed _priceFeed ) internal returns (uint256) { uint256 price = _priceFeed.fetchPrice(); + IExchange exchange = _leverageZapper.exchange(); // This should be done in the frontend uint256 flashLoanAmount = _collAmount * (_leverageRatio - DECIMAL_PRECISION) / DECIMAL_PRECISION; uint256 expectedBoldAmount = flashLoanAmount * price / DECIMAL_PRECISION; uint256 maxNetDebt = expectedBoldAmount * 105 / 100; // slippage - uint256 effectiveBoldAmount = _exchange.getBoldAmountToSwap(expectedBoldAmount, maxNetDebt, flashLoanAmount); + uint256 effectiveBoldAmount = exchange.getBoldAmountToSwap(expectedBoldAmount, maxNetDebt, flashLoanAmount); ILeverageZapper.OpenLeveragedTroveParams memory params = ILeverageZapper.OpenLeveragedTroveParams({ owner: A, @@ -296,18 +257,18 @@ contract ZapperLeverageLSTMainnet is DevTestSetup { function testCanOpenTroveWithCurve() external { for (uint256 i = 0; i < NUM_COLLATERALS; i++) { - _testCanOpenTrove(leverageZapperCurveArray[i], curveExchangeArray[i], i); + _testCanOpenTrove(leverageZapperCurveArray[i], i); } } function testCanOpenTroveWithUniV3() external { for (uint256 i = 0; i < NUM_COLLATERALS; i++) { if (i == 2) continue; // TODO!! - _testCanOpenTrove(leverageZapperUniV3Array[i], uniV3ExchangeArray[i], i); + _testCanOpenTrove(leverageZapperUniV3Array[i], i); } } - function _testCanOpenTrove(ILeverageZapper _leverageZapper, IExchange _exchange, uint256 _branch) internal { + function _testCanOpenTrove(ILeverageZapper _leverageZapper, uint256 _branch) internal { uint256 collAmount = 10 ether; uint256 leverageRatio = 2e18; uint256 resultingCollateralRatio = _leverageZapper.leverageRatioToCollateralRatio(leverageRatio); @@ -316,7 +277,7 @@ contract ZapperLeverageLSTMainnet is DevTestSetup { uint256 collBalanceBefore = contractsArray[_branch].collToken.balanceOf(A); uint256 troveId = - openLeveragedTrove(_leverageZapper, _exchange, collAmount, leverageRatio, contractsArray[_branch].priceFeed); + openLeveragedTrove(_leverageZapper, collAmount, leverageRatio, contractsArray[_branch].priceFeed); // Checks uint256 price = contractsArray[_branch].priceFeed.fetchPrice(); @@ -386,69 +347,70 @@ contract ZapperLeverageLSTMainnet is DevTestSetup { // Lever up /* function leverUpTroveWithCurve(uint256 _troveId, uint256 _leverageRatio) internal returns (uint256) { - return leverUpTrove(leverageZapperCurve, curveExchange, _troveId, _leverageRatio); + return leverUpTrove(leverageZapperCurve, _troveId, _leverageRatio); } function leverUpTroveWithUniV3(uint256 _troveId, uint256 _leverageRatio) internal returns (uint256) { - return leverUpTrove(leverageZapperUniV3, uniV3Exchange, _troveId, _leverageRatio); + return leverUpTrove(leverageZapperUniV3, _troveId, _leverageRatio); } */ function leverUpTrove( ILeverageZapper _leverageZapper, - IExchange _exchange, uint256 _troveId, uint256 _leverageRatio, ITroveManager _troveManager, IPriceFeed _priceFeed ) internal returns (uint256) { - uint256 price = _priceFeed.fetchPrice(); + LeverVars memory vars; + vars.price = _priceFeed.fetchPrice(); + IExchange exchange = _leverageZapper.exchange(); // This should be done in the frontend - uint256 currentCR = _troveManager.getCurrentICR(_troveId, price); - uint256 currentLR = _leverageZapper.leverageRatioToCollateralRatio(currentCR); - assertGt(_leverageRatio, currentLR, "Leverage ratio should increase"); - uint256 currentCollAmount = getTroveEntireColl(_troveManager, _troveId); - uint256 flashLoanAmount = currentCollAmount * _leverageRatio / currentLR - currentCollAmount; - uint256 expectedBoldAmount = flashLoanAmount * price / DECIMAL_PRECISION; - uint256 maxNetDebtIncrease = expectedBoldAmount * 105 / 100; // slippage + vars.currentCR = _troveManager.getCurrentICR(_troveId, vars.price); + vars.currentLR = _leverageZapper.leverageRatioToCollateralRatio(vars.currentCR); + assertGt(_leverageRatio, vars.currentLR, "Leverage ratio should increase"); + vars.currentCollAmount = getTroveEntireColl(_troveManager, _troveId); + vars.flashLoanAmount = vars.currentCollAmount * _leverageRatio / vars.currentLR - vars.currentCollAmount; + vars.expectedBoldAmount = vars.flashLoanAmount * vars.price / DECIMAL_PRECISION; + vars.maxNetDebtIncrease = vars.expectedBoldAmount * 105 / 100; // slippage // The actual bold we need, capped by the slippage above, to get flash loan amount - uint256 effectiveBoldAmount = - _exchange.getBoldAmountToSwap(expectedBoldAmount, maxNetDebtIncrease, flashLoanAmount); + vars.effectiveBoldAmount = + exchange.getBoldAmountToSwap(vars.expectedBoldAmount, vars.maxNetDebtIncrease, vars.flashLoanAmount); ILeverageZapper.LeverUpTroveParams memory params = ILeverageZapper.LeverUpTroveParams({ troveId: _troveId, - flashLoanAmount: flashLoanAmount, - boldAmount: effectiveBoldAmount, + flashLoanAmount: vars.flashLoanAmount, + boldAmount: vars.effectiveBoldAmount, maxUpfrontFee: 1000e18 }); vm.startPrank(A); _leverageZapper.leverUpTrove(params); vm.stopPrank(); - return flashLoanAmount; + return vars.flashLoanAmount; } function testCanLeverUpTroveWithCurve() external { for (uint256 i = 0; i < NUM_COLLATERALS; i++) { - _testCanLeverUpTrove(leverageZapperCurveArray[i], curveExchangeArray[i], i); + _testCanLeverUpTrove(leverageZapperCurveArray[i], i); } } function testCanLeverUpTroveWithUniV3() external { for (uint256 i = 0; i < NUM_COLLATERALS; i++) { if (i == 2) continue; // TODO!! - _testCanLeverUpTrove(leverageZapperUniV3Array[i], uniV3ExchangeArray[i], i); + _testCanLeverUpTrove(leverageZapperUniV3Array[i], i); } } - function _testCanLeverUpTrove(ILeverageZapper _leverageZapper, IExchange _exchange, uint256 _branch) internal { + function _testCanLeverUpTrove(ILeverageZapper _leverageZapper, uint256 _branch) internal { TestVars memory vars; vars.collAmount = 10 ether; vars.initialLeverageRatio = 2e18; vars.troveId = openLeveragedTrove( - _leverageZapper, _exchange, vars.collAmount, vars.initialLeverageRatio, contractsArray[_branch].priceFeed + _leverageZapper, vars.collAmount, vars.initialLeverageRatio, contractsArray[_branch].priceFeed ); vars.initialDebt = getTroveEntireDebt(contractsArray[_branch].troveManager, vars.troveId); @@ -460,7 +422,6 @@ contract ZapperLeverageLSTMainnet is DevTestSetup { vars.flashLoanAmount = leverUpTrove( _leverageZapper, - _exchange, vars.troveId, vars.newLeverageRatio, contractsArray[_branch].troveManager, @@ -563,24 +524,23 @@ contract ZapperLeverageLSTMainnet is DevTestSetup { function testCanLeverDownTroveWithCurve() external { for (uint256 i = 0; i < NUM_COLLATERALS; i++) { - _testCanLeverDownTrove(leverageZapperCurveArray[i], curveExchangeArray[i], i); + _testCanLeverDownTrove(leverageZapperCurveArray[i], i); } } function testCanLeverDownTroveWithUniV3() external { for (uint256 i = 0; i < NUM_COLLATERALS; i++) { if (i == 2) continue; // TODO!! - _testCanLeverDownTrove(leverageZapperUniV3Array[i], uniV3ExchangeArray[i], i); + _testCanLeverDownTrove(leverageZapperUniV3Array[i], i); } } - function _testCanLeverDownTrove(ILeverageZapper _leverageZapper, IExchange _exchange, uint256 _branch) internal { + function _testCanLeverDownTrove(ILeverageZapper _leverageZapper, uint256 _branch) internal { uint256 collAmount = 10 ether; uint256 initialLeverageRatio = 2e18; - uint256 troveId = openLeveragedTrove( - _leverageZapper, _exchange, collAmount, initialLeverageRatio, contractsArray[_branch].priceFeed - ); + uint256 troveId = + openLeveragedTrove(_leverageZapper, collAmount, initialLeverageRatio, contractsArray[_branch].priceFeed); uint256 initialDebt = getTroveEntireDebt(contractsArray[_branch].troveManager, troveId); uint256 newLeverageRatio = 1.5e18; diff --git a/contracts/src/test/zapperWETH.t.sol b/contracts/src/test/zapperWETH.t.sol index 11f9d9dfb..fa6617809 100644 --- a/contracts/src/test/zapperWETH.t.sol +++ b/contracts/src/test/zapperWETH.t.sol @@ -7,8 +7,6 @@ import "./TestContracts/WETH.sol"; import "../Zappers/WETHZapper.sol"; contract ZapperWETHTest is DevTestSetup { - WETHZapper wethZapper; - function setUp() public override { // Start tests at a non-zero timestamp vm.warp(block.timestamp + 600); @@ -33,7 +31,9 @@ contract ZapperWETHTest is DevTestSetup { TestDeployer deployer = new TestDeployer(); TestDeployer.LiquityContractsDev[] memory contractsArray; - (contractsArray, collateralRegistry, boldToken,,) = deployer.deployAndConnectContracts(troveManagerParams, WETH); + TestDeployer.Zappers[] memory zappersArray; + (contractsArray, collateralRegistry, boldToken,,, zappersArray) = + deployer.deployAndConnectContracts(troveManagerParams, WETH); // Set price feeds contractsArray[0].priceFeed.setPrice(2000e18); @@ -52,9 +52,7 @@ contract ZapperWETHTest is DevTestSetup { borrowerOperations = contractsArray[0].borrowerOperations; troveManager = contractsArray[0].troveManager; troveNFT = contractsArray[0].troveNFT; - - // Deploy zapper (TODO: should we move it to deployment contract?) - wethZapper = new WETHZapper(addressesRegistry); + wethZapper = zappersArray[0].wethZapper; } function testCanOpenTrove() external {