From df32ca82a68dad139aa70a1d8a765242210440ba Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Thu, 21 Mar 2024 15:52:43 -0500 Subject: [PATCH 01/21] removed duplicate util --- test/utils/BaseTest.sol | 67 ----------------------------------------- 1 file changed, 67 deletions(-) diff --git a/test/utils/BaseTest.sol b/test/utils/BaseTest.sol index af46591e2..501a890c7 100644 --- a/test/utils/BaseTest.sol +++ b/test/utils/BaseTest.sol @@ -121,71 +121,4 @@ contract BaseTest is Test { token.approve(hyperdrive, type(uint256).max); } } - - function assertWithDelta( - uint256 _value, - int256 _delta, - uint256 _targetValue - ) public { - bool positiveDelta = _delta >= 0; - - if (positiveDelta) { - assertTrue( - _targetValue >= _value, - "_targetValue should be greater than or equal to _value" - ); - } else { - assertTrue( - _value > _targetValue, - "_targetValue should be less than _value" - ); - } - - uint256 upperBound = positiveDelta ? _value + uint256(_delta) : _value; - uint256 lowerBound = !positiveDelta - ? _value - uint256(-_delta) - : _value; - - // targetValue must be within the range - if (_targetValue < lowerBound || _targetValue > upperBound) { - assertGe(_targetValue, lowerBound, "exceeds lower bound"); - assertLe(_targetValue, upperBound, "exceeds upper bound"); - return; - } - - // If the delta is positive it indicates the target value is value + delta - if (positiveDelta) { - uint256 valueToTarget = _targetValue - _value; - if (valueToTarget < uint256(_delta)) { - console2.log( - "Precision increased by: %s", - uint256(_delta) - valueToTarget - ); - console2.log("Old Delta: %s", _delta); - console2.log("New Delta: %s", valueToTarget); - } else { - assertEq( - upperBound, - _targetValue, - "expected upperBound to match _targetValue" - ); - } - } else { - uint256 valueToTarget = _value - _targetValue; - if (valueToTarget < uint256(-_delta)) { - console2.log( - "Precision increased by: %s", - uint256(-_delta) - valueToTarget - ); - console2.log("Old Delta: %s", _delta); - console2.log("New Delta: -%s", valueToTarget); - } else { - assertEq( - lowerBound, - _targetValue, - "expected lowerBound to match _targetValue" - ); - } - } - } } From 8b8193c9832e4601a2fbd534b4951784d3369a66 Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Thu, 21 Mar 2024 15:53:19 -0500 Subject: [PATCH 02/21] Create IntegrationTest.sol --- test/utils/IntegrationTest.sol | 329 +++++++++++++++++++++++++++++++++ 1 file changed, 329 insertions(+) create mode 100644 test/utils/IntegrationTest.sol diff --git a/test/utils/IntegrationTest.sol b/test/utils/IntegrationTest.sol new file mode 100644 index 000000000..fe3fe7f17 --- /dev/null +++ b/test/utils/IntegrationTest.sol @@ -0,0 +1,329 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.20; + +import { ERC20ForwarderFactory } from "contracts/src/token/ERC20ForwarderFactory.sol"; +import { HyperdriveFactory } from "contracts/src/factory/HyperdriveFactory.sol"; +import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; + +import { AssetId } from "contracts/src/libraries/AssetId.sol"; +import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; + +import { Lib } from "test/utils/Lib.sol"; +import { HyperdriveTest } from "test/utils/HyperdriveTest.sol"; +import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; + +import { HyperdriveUtils } from "test/utils/HyperdriveUtils.sol"; + +abstract contract IntegrationTest is HyperdriveTest { + using Lib for *; + using FixedPointMath for uint256; + + uint256 internal constant FIXED_RATE = 0.05e18; + address internal ETH_WHALE = 0x00000000219ab540356cBB839Cbe05303d7705Fa; + + struct IntegrationConfig { + address[] whaleAccounts; + IERC20 token; + IERC20 baseToken; + uint256 shareTolerance; + } + + IntegrationConfig internal config; + + HyperdriveFactory factory; + address deployerCoordinator; + + constructor(IntegrationConfig storage _config) { + config = _config; + } + + function setUp() public virtual override { + super.setUp(); + + // _beforeSetUp(); + + // Fund Accounts + address[] memory accounts = new address[](3); + accounts[0] = alice; + accounts[1] = bob; + accounts[2] = celine; + for (uint256 i = 0; i < config.whaleAccounts.length; i++) { + fundAccounts( + address(hyperdrive), + config.token, + config.whaleAccounts[i], + accounts + ); + } + vm.deal(alice, 20_000e18); + vm.deal(bob, 20_000e18); + vm.deal(celine, 20_000e18); + + // _afterSetup(); + + deployFactory(); + deployerCoordinator = deployCoordinator(); + factory.addDeployerCoordinator(deployerCoordinator); + + deployTargets(); + + // Start recording event logs. + vm.recordLogs(); + } + + function deployTargets() internal { + IHyperdrive.PoolDeployConfig memory poolConfig = IHyperdrive + .PoolDeployConfig({ + baseToken: config.baseToken, + linkerFactory: factory.linkerFactory(), + linkerCodeHash: factory.linkerCodeHash(), + minimumShareReserves: 1e15, + minimumTransactionAmount: 1e16, + positionDuration: POSITION_DURATION, + checkpointDuration: CHECKPOINT_DURATION, + timeStretch: 0, + governance: factory.hyperdriveGovernance(), + feeCollector: factory.feeCollector(), + sweepCollector: factory.sweepCollector(), + fees: IHyperdrive.Fees({ + curve: 0, + flat: 0, + governanceLP: 0, + governanceZombie: 0 + }) + }); + + deployTargets( + factory, + alice, + bytes32(uint256(0xdeadbeef)), + bytes32(uint256(0xdeadbabe)), + 10_000e18, + poolConfig + ); + } + + function deployTargets( + HyperdriveFactory _factory, + address deployer, + bytes32 deploymentId, + bytes32 deploymentSalt, + uint256 contribution, + IHyperdrive.PoolDeployConfig memory poolConfig + ) public { + vm.startPrank(deployer); + + _factory.deployTarget( + deploymentId, + deployerCoordinator, + poolConfig, + new bytes(0), + FIXED_RATE, + FIXED_RATE, + 0, + deploymentSalt + ); + _factory.deployTarget( + deploymentId, + deployerCoordinator, + poolConfig, + new bytes(0), + FIXED_RATE, + FIXED_RATE, + 1, + deploymentSalt + ); + _factory.deployTarget( + deploymentId, + deployerCoordinator, + poolConfig, + new bytes(0), + FIXED_RATE, + FIXED_RATE, + 2, + deploymentSalt + ); + _factory.deployTarget( + deploymentId, + deployerCoordinator, + poolConfig, + new bytes(0), + FIXED_RATE, + FIXED_RATE, + 3, + deploymentSalt + ); + _factory.deployTarget( + deploymentId, + deployerCoordinator, + poolConfig, + new bytes(0), + FIXED_RATE, + FIXED_RATE, + 4, + deploymentSalt + ); + + config.token.approve(deployerCoordinator, contribution); + hyperdrive = _factory.deployAndInitialize( + deploymentId, + deployerCoordinator, + poolConfig, + new bytes(0), + contribution, + FIXED_RATE, + FIXED_RATE, + IHyperdrive.Options({ + asBase: false, + destination: deployer, + extraData: new bytes(0) + }), + deploymentSalt + ); + + // Ensure that Alice received the correct amount of LP tokens. She should + // receive LP shares totaling the amount of shares that she contributed + // minus the shares set aside for the minimum share reserves and the + // zero address's initial LP contribution. + assertApproxEqAbs( + hyperdrive.balanceOf(AssetId._LP_ASSET_ID, deployer), + contribution - 2 * hyperdrive.getPoolConfig().minimumShareReserves, + config.shareTolerance + ); + + // beforeDeployAndInitialize(); + + // hyperdrive = factory.deployAndInitialize( + // bytes32(uint256(0xdeadbeef)), + // deployerCoordinator, + // config, + // new bytes(0), + // contribution, + // FIXED_RATE, + // FIXED_RATE, + // IHyperdrive.Options({ + // asBase: false, + // destination: alice, + // extraData: new bytes(0) + // }), + // bytes32(uint256(0xdeadbabe)) + // ); + } + + function deployFactory() internal { + // Deploy the hyperdrive factory. + vm.startPrank(deployer); + address[] memory defaults = new address[](1); + defaults[0] = bob; + forwarderFactory = new ERC20ForwarderFactory(); + factory = new HyperdriveFactory( + HyperdriveFactory.FactoryConfig({ + governance: alice, + hyperdriveGovernance: bob, + feeCollector: celine, + sweepCollector: sweepCollector, + defaultPausers: defaults, + checkpointDurationResolution: 1 hours, + minCheckpointDuration: 8 hours, + maxCheckpointDuration: 1 days, + minPositionDuration: 7 days, + maxPositionDuration: 10 * 365 days, + minFixedAPR: 0.001e18, + maxFixedAPR: 0.5e18, + minTimeStretchAPR: 0.005e18, + maxTimeStretchAPR: 0.5e18, + minFees: IHyperdrive.Fees({ + curve: 0, + flat: 0, + governanceLP: 0, + governanceZombie: 0 + }), + maxFees: IHyperdrive.Fees({ + curve: ONE, + flat: ONE, + governanceLP: ONE, + governanceZombie: ONE + }), + linkerFactory: address(forwarderFactory), + linkerCodeHash: forwarderFactory.ERC20LINK_HASH() + }) + ); + } + + function getProtocolSharePrice() internal virtual returns (uint256); + + function deployCoordinator() internal virtual returns (address); + + function test__deployAndInitialize__asShares() external { + IHyperdrive.PoolDeployConfig memory poolConfig = IHyperdrive + .PoolDeployConfig({ + baseToken: config.baseToken, + linkerFactory: factory.linkerFactory(), + linkerCodeHash: factory.linkerCodeHash(), + minimumShareReserves: 1e15, + minimumTransactionAmount: 1e16, + positionDuration: POSITION_DURATION, + checkpointDuration: CHECKPOINT_DURATION, + timeStretch: 0, + governance: factory.hyperdriveGovernance(), + feeCollector: factory.feeCollector(), + sweepCollector: factory.sweepCollector(), + fees: IHyperdrive.Fees({ + curve: 0, + flat: 0, + governanceLP: 0, + governanceZombie: 0 + }) + }); + + uint256 bobBalanceBefore = address(bob).balance; + uint256 contribution = 5_000e18; + + deployTargets( + factory, + bob, + bytes32(uint256(0xbeefbabe)), + bytes32(uint256(0xdeadfade)), + contribution, + poolConfig + ); + + assertEq(address(bob).balance, bobBalanceBefore); + + // Ensure that the decimals are set correctly. + assertEq(hyperdrive.decimals(), 18); + + // Ensure that Bob received the correct amount of LP tokens. He should + // receive LP shares totaling the amount of shares that he contributed + // minus the shares set aside for the minimum share reserves and the + // zero address's initial LP contribution. + assertApproxEqAbs( + hyperdrive.balanceOf(AssetId._LP_ASSET_ID, bob), + contribution.divDown( + hyperdrive.getPoolConfig().initialVaultSharePrice + ) - 2 * hyperdrive.getPoolConfig().minimumShareReserves, + config.shareTolerance + ); + + // Ensure that the share reserves and LP total supply are equal and correct. + assertEq(hyperdrive.getPoolInfo().shareReserves, contribution); + assertEq( + hyperdrive.getPoolInfo().lpTotalSupply, + hyperdrive.getPoolInfo().shareReserves - + poolConfig.minimumShareReserves + ); + + // Verify that the correct events were emitted. + verifyFactoryEvents( + deployerCoordinator, + hyperdrive, + bob, + contribution, + FIXED_RATE, + false, + poolConfig.minimumShareReserves, + new bytes(0), + config.shareTolerance + ); + } +} From 5ecfdd56eb81f7588edf3f74fe44d1220179b2b7 Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Thu, 21 Mar 2024 15:53:40 -0500 Subject: [PATCH 03/21] replace setup with test suite in reth --- test/instances/reth/RETHHyperdrive.t.sol | 345 +++-------------------- 1 file changed, 35 insertions(+), 310 deletions(-) diff --git a/test/instances/reth/RETHHyperdrive.t.sol b/test/instances/reth/RETHHyperdrive.t.sol index f69bb1e64..72924a5fd 100644 --- a/test/instances/reth/RETHHyperdrive.t.sol +++ b/test/instances/reth/RETHHyperdrive.t.sol @@ -8,7 +8,7 @@ import { ETH } from "contracts/src/libraries/Constants.sol"; import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; import { HyperdriveFactory } from "contracts/src/factory/HyperdriveFactory.sol"; import { HyperdriveMath } from "contracts/src/libraries/HyperdriveMath.sol"; -import { HyperdriveTest } from "test/utils/HyperdriveTest.sol"; +import { IntegrationTest } from "test/utils/IntegrationTest.sol"; import { HyperdriveUtils } from "test/utils/HyperdriveUtils.sol"; import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; @@ -28,12 +28,12 @@ import { RETHTarget3Deployer } from "contracts/src/deployers/reth/RETHTarget3Dep import { RETHTarget4Deployer } from "contracts/src/deployers/reth/RETHTarget4Deployer.sol"; import { stdStorage, StdStorage } from "forge-std/Test.sol"; -contract RETHHyperdriveTest is HyperdriveTest { +contract RETHHyperdriveTest is IntegrationTest { using FixedPointMath for uint256; using Lib for *; using stdStorage for StdStorage; - uint256 internal constant FIXED_RATE = 0.05e18; + // uint256 internal constant FIXED_RATE = 0.05e18; IRocketStorage internal constant ROCKET_STORAGE = IRocketStorage(0x1d8f8f00cfa6758d7bE78336684788Fb0ee0Fa46); @@ -42,14 +42,39 @@ contract RETHHyperdriveTest is HyperdriveTest { IRocketDepositPool rocketDepositPool; address internal RETH_WHALE = 0xCc9EE9483f662091a1de4795249E24aC0aC2630f; - address internal ETH_WHALE = 0x00000000219ab540356cBB839Cbe05303d7705Fa; + // address internal ETH_WHALE = 0x00000000219ab540356cBB839Cbe05303d7705Fa; - HyperdriveFactory factory; - address deployerCoordinator; + // HyperdriveFactory factory; + // address deployerCoordinator; - function setUp() public override __mainnet_fork(19_429_100) { - super.setUp(); + address[] internal whaleAccounts = [RETH_WHALE]; + IntegrationConfig internal __testConfig = + IntegrationConfig( + whaleAccounts, + IERC20(0xae78736Cd615f374D3085123A210448E74Fc6393), + IERC20(ETH), + 0 + ); + constructor() IntegrationTest(__testConfig) {} + + function deployCoordinator() internal override returns (address) { + vm.startPrank(alice); + return + address( + new RETHHyperdriveDeployerCoordinator( + address(new RETHHyperdriveCoreDeployer(ROCKET_STORAGE)), + address(new RETHTarget0Deployer(ROCKET_STORAGE)), + address(new RETHTarget1Deployer(ROCKET_STORAGE)), + address(new RETHTarget2Deployer(ROCKET_STORAGE)), + address(new RETHTarget3Deployer(ROCKET_STORAGE)), + address(new RETHTarget4Deployer(ROCKET_STORAGE)), + ROCKET_STORAGE + ) + ); + } + + function setUp() public override __mainnet_fork(19_429_100) { // Fetching the rETH token contract address from storage. address rocketTokenRETHAddress = ROCKET_STORAGE.getAddress( keccak256(abi.encodePacked("contract.address", "rocketTokenRETH")) @@ -72,180 +97,8 @@ contract RETHHyperdriveTest is HyperdriveTest { ); rocketDepositPool = IRocketDepositPool(rocketDepositPoolAddress); - // Fund the test accounts with rETH and ETH. - address[] memory accounts = new address[](3); - accounts[0] = alice; - accounts[1] = bob; - accounts[2] = celine; - fundAccounts( - address(hyperdrive), - IERC20(rocketTokenRETH), - RETH_WHALE, - accounts - ); - vm.deal(alice, 20_000e18); - vm.deal(bob, 20_000e18); - vm.deal(celine, 20_000e18); - // Deal ETH to the rocket token address to increase liquidity - // for withdrawals. - vm.deal(rocketTokenRETHAddress, 50_000e18); - - // Deploy the hyperdrive factory. - vm.startPrank(deployer); - address[] memory defaults = new address[](1); - defaults[0] = bob; - forwarderFactory = new ERC20ForwarderFactory(); - factory = new HyperdriveFactory( - HyperdriveFactory.FactoryConfig({ - governance: alice, - hyperdriveGovernance: bob, - feeCollector: celine, - sweepCollector: sweepCollector, - defaultPausers: defaults, - checkpointDurationResolution: 1 hours, - minCheckpointDuration: 8 hours, - maxCheckpointDuration: 1 days, - minPositionDuration: 7 days, - maxPositionDuration: 10 * 365 days, - minFixedAPR: 0.001e18, - maxFixedAPR: 0.5e18, - minTimeStretchAPR: 0.005e18, - maxTimeStretchAPR: 0.5e18, - minFees: IHyperdrive.Fees({ - curve: 0, - flat: 0, - governanceLP: 0, - governanceZombie: 0 - }), - maxFees: IHyperdrive.Fees({ - curve: ONE, - flat: ONE, - governanceLP: ONE, - governanceZombie: ONE - }), - linkerFactory: address(forwarderFactory), - linkerCodeHash: forwarderFactory.ERC20LINK_HASH() - }) - ); - - // Deploy the hyperdrive deployers and register the deployer coordinator - // in the factory. - vm.stopPrank(); - vm.startPrank(alice); - deployerCoordinator = address( - new RETHHyperdriveDeployerCoordinator( - address(new RETHHyperdriveCoreDeployer(ROCKET_STORAGE)), - address(new RETHTarget0Deployer(ROCKET_STORAGE)), - address(new RETHTarget1Deployer(ROCKET_STORAGE)), - address(new RETHTarget2Deployer(ROCKET_STORAGE)), - address(new RETHTarget3Deployer(ROCKET_STORAGE)), - address(new RETHTarget4Deployer(ROCKET_STORAGE)), - ROCKET_STORAGE - ) - ); - factory.addDeployerCoordinator(address(deployerCoordinator)); - - // Alice deploys the hyperdrive instance. - IHyperdrive.PoolDeployConfig memory config = IHyperdrive - .PoolDeployConfig({ - baseToken: IERC20(ETH), - linkerFactory: factory.linkerFactory(), - linkerCodeHash: factory.linkerCodeHash(), - minimumShareReserves: 1e15, - minimumTransactionAmount: 1e16, - positionDuration: POSITION_DURATION, - checkpointDuration: CHECKPOINT_DURATION, - timeStretch: 0, - governance: factory.hyperdriveGovernance(), - feeCollector: factory.feeCollector(), - sweepCollector: factory.sweepCollector(), - fees: IHyperdrive.Fees({ - curve: 0, - flat: 0, - governanceLP: 0, - governanceZombie: 0 - }) - }); - uint256 contribution = 10_000e18; - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 0, - bytes32(uint256(0xdeadbabe)) - ); - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 1, - bytes32(uint256(0xdeadbabe)) - ); - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 2, - bytes32(uint256(0xdeadbabe)) - ); - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 3, - bytes32(uint256(0xdeadbabe)) - ); - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 4, - bytes32(uint256(0xdeadbabe)) - ); - rocketTokenRETH.approve(deployerCoordinator, contribution); - hyperdrive = factory.deployAndInitialize( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - contribution, - FIXED_RATE, - FIXED_RATE, - IHyperdrive.Options({ - asBase: false, - destination: alice, - extraData: new bytes(0) - }), - bytes32(uint256(0xdeadbabe)) - ); - - // Ensure that Alice received the correct amount of LP tokens. She should - // receive LP shares totaling the amount of shares that she contributed - // minus the shares set aside for the minimum share reserves and the - // zero address's initial LP contribution. - assertApproxEqAbs( - hyperdrive.balanceOf(AssetId._LP_ASSET_ID, alice), - contribution - 2 * hyperdrive.getPoolConfig().minimumShareReserves, - 1e5 - ); - - // Start recording event logs. - vm.recordLogs(); + vm.deal(address(rocketTokenRETH), 50_000e18); + super.setUp(); } /// Getters /// @@ -263,134 +116,6 @@ contract RETHHyperdriveTest is HyperdriveTest { /// Deploy and Initialize /// - function test__reth__deployAndInitialize() external { - // Deploy and Initialize the rETH hyperdrive instance. - vm.stopPrank(); - vm.startPrank(bob); - uint256 bobBalanceBefore = address(bob).balance; - IHyperdrive.PoolDeployConfig memory config = IHyperdrive - .PoolDeployConfig({ - baseToken: IERC20(ETH), - governance: factory.hyperdriveGovernance(), - feeCollector: factory.feeCollector(), - sweepCollector: factory.sweepCollector(), - linkerFactory: factory.linkerFactory(), - linkerCodeHash: factory.linkerCodeHash(), - minimumShareReserves: 1e15, - minimumTransactionAmount: 1e16, - positionDuration: POSITION_DURATION, - checkpointDuration: CHECKPOINT_DURATION, - timeStretch: 0, - fees: IHyperdrive.Fees({ - curve: 0, - flat: 0, - governanceLP: 0, - governanceZombie: 0 - }) - }); - uint256 contribution = 5_000e18; - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 0, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 1, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 2, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 3, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 4, - bytes32(uint256(0xdeadfade)) - ); - rocketTokenRETH.approve(deployerCoordinator, contribution); - hyperdrive = factory.deployAndInitialize( - bytes32(uint256(0xbeefbabe)), - address(deployerCoordinator), - config, - new bytes(0), - contribution, - FIXED_RATE, - FIXED_RATE, - IHyperdrive.Options({ - asBase: false, - destination: bob, - extraData: new bytes(0) - }), - bytes32(uint256(0xdeadfade)) - ); - assertEq(address(bob).balance, bobBalanceBefore); - - // Ensure that the decimals are set correctly. - assertEq(hyperdrive.decimals(), 18); - - // Ensure that Bob received the correct amount of LP tokens. He should - // receive LP shares totaling the amount of shares that he contributed - // minus the shares set aside for the minimum share reserves and the - // zero address's initial LP contribution. - assertApproxEqAbs( - hyperdrive.balanceOf(AssetId._LP_ASSET_ID, bob), - contribution - 2 * hyperdrive.getPoolConfig().minimumShareReserves, - 1e5 - ); - - // Ensure that the share reserves and LP total supply are equal and correct. - assertEq(hyperdrive.getPoolInfo().shareReserves, contribution); - assertEq( - hyperdrive.getPoolInfo().lpTotalSupply, - hyperdrive.getPoolInfo().shareReserves - config.minimumShareReserves - ); - - // Verify that the correct events were emitted. - verifyFactoryEvents( - deployerCoordinator, - hyperdrive, - bob, - contribution, - FIXED_RATE, - false, - config.minimumShareReserves, - new bytes(0), - 0 - ); - } - /// Price Per Share /// function test_pricePerVaultShare(uint256 basePaid) external { From 3f619ae83fc2d1bb632a18bd76434f4437b7b401 Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Thu, 21 Mar 2024 16:04:26 -0500 Subject: [PATCH 04/21] reth impl of deployAndInitAsShares --- test/instances/reth/RETHHyperdrive.t.sol | 4 +++ test/utils/IntegrationTest.sol | 37 ++++-------------------- 2 files changed, 10 insertions(+), 31 deletions(-) diff --git a/test/instances/reth/RETHHyperdrive.t.sol b/test/instances/reth/RETHHyperdrive.t.sol index 72924a5fd..7ab3e7d7c 100644 --- a/test/instances/reth/RETHHyperdrive.t.sol +++ b/test/instances/reth/RETHHyperdrive.t.sol @@ -58,6 +58,10 @@ contract RETHHyperdriveTest is IntegrationTest { constructor() IntegrationTest(__testConfig) {} + function getProtocolSharePrice() internal override returns (uint256) { + return rocketTokenRETH.getExchangeRate(); + } + function deployCoordinator() internal override returns (address) { vm.startPrank(alice); return diff --git a/test/utils/IntegrationTest.sol b/test/utils/IntegrationTest.sol index fe3fe7f17..75fee5dfd 100644 --- a/test/utils/IntegrationTest.sol +++ b/test/utils/IntegrationTest.sol @@ -180,34 +180,6 @@ abstract contract IntegrationTest is HyperdriveTest { }), deploymentSalt ); - - // Ensure that Alice received the correct amount of LP tokens. She should - // receive LP shares totaling the amount of shares that she contributed - // minus the shares set aside for the minimum share reserves and the - // zero address's initial LP contribution. - assertApproxEqAbs( - hyperdrive.balanceOf(AssetId._LP_ASSET_ID, deployer), - contribution - 2 * hyperdrive.getPoolConfig().minimumShareReserves, - config.shareTolerance - ); - - // beforeDeployAndInitialize(); - - // hyperdrive = factory.deployAndInitialize( - // bytes32(uint256(0xdeadbeef)), - // deployerCoordinator, - // config, - // new bytes(0), - // contribution, - // FIXED_RATE, - // FIXED_RATE, - // IHyperdrive.Options({ - // asBase: false, - // destination: alice, - // extraData: new bytes(0) - // }), - // bytes32(uint256(0xdeadbabe)) - // ); } function deployFactory() internal { @@ -278,13 +250,16 @@ abstract contract IntegrationTest is HyperdriveTest { uint256 bobBalanceBefore = address(bob).balance; uint256 contribution = 5_000e18; + uint256 contributionShares = contribution.divDown( + getProtocolSharePrice() + ); deployTargets( factory, bob, bytes32(uint256(0xbeefbabe)), bytes32(uint256(0xdeadfade)), - contribution, + contributionShares, poolConfig ); @@ -306,7 +281,7 @@ abstract contract IntegrationTest is HyperdriveTest { ); // Ensure that the share reserves and LP total supply are equal and correct. - assertEq(hyperdrive.getPoolInfo().shareReserves, contribution); + assertEq(hyperdrive.getPoolInfo().shareReserves, contributionShares); assertEq( hyperdrive.getPoolInfo().lpTotalSupply, hyperdrive.getPoolInfo().shareReserves - @@ -318,7 +293,7 @@ abstract contract IntegrationTest is HyperdriveTest { deployerCoordinator, hyperdrive, bob, - contribution, + contributionShares, FIXED_RATE, false, poolConfig.minimumShareReserves, From 2067df36dcacff66abac71387019cff08c9517fd Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Thu, 21 Mar 2024 18:10:01 -0500 Subject: [PATCH 05/21] steth and reth deployment test passing suite --- test/instances/reth/RETHHyperdrive.t.sol | 17 +- test/instances/steth/StETHHyperdrive.t.sol | 492 ++------------------- test/utils/IntegrationTest.sol | 268 +++++++---- 3 files changed, 234 insertions(+), 543 deletions(-) diff --git a/test/instances/reth/RETHHyperdrive.t.sol b/test/instances/reth/RETHHyperdrive.t.sol index 7ab3e7d7c..818ce7e6c 100644 --- a/test/instances/reth/RETHHyperdrive.t.sol +++ b/test/instances/reth/RETHHyperdrive.t.sol @@ -53,15 +53,26 @@ contract RETHHyperdriveTest is IntegrationTest { whaleAccounts, IERC20(0xae78736Cd615f374D3085123A210448E74Fc6393), IERC20(ETH), - 0 + 0, + 1e16 ); constructor() IntegrationTest(__testConfig) {} - function getProtocolSharePrice() internal override returns (uint256) { - return rocketTokenRETH.getExchangeRate(); + function getProtocolSharePrice() + internal + override + returns (uint256, uint256, uint256) + { + return ( + rocketTokenRETH.getExchangeRate(), + rocketTokenRETH.getExchangeRate(), + rocketTokenRETH.getExchangeRate() + ); } + function test__deployAndInitialize__asBase() external override {} + function deployCoordinator() internal override returns (address) { vm.startPrank(alice); return diff --git a/test/instances/steth/StETHHyperdrive.t.sol b/test/instances/steth/StETHHyperdrive.t.sol index dbda405d3..8d346dc91 100644 --- a/test/instances/steth/StETHHyperdrive.t.sol +++ b/test/instances/steth/StETHHyperdrive.t.sol @@ -20,16 +20,16 @@ import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol" import { HyperdriveMath } from "contracts/src/libraries/HyperdriveMath.sol"; import { ERC20ForwarderFactory } from "contracts/src/token/ERC20ForwarderFactory.sol"; import { ERC20Mintable } from "contracts/test/ERC20Mintable.sol"; -import { HyperdriveTest } from "test/utils/HyperdriveTest.sol"; +import { IntegrationTest } from "test/utils/IntegrationTest.sol"; import { HyperdriveUtils } from "test/utils/HyperdriveUtils.sol"; import { Lib } from "test/utils/Lib.sol"; -contract StETHHyperdriveTest is HyperdriveTest { +contract StETHHyperdriveTest is IntegrationTest { using FixedPointMath for uint256; using Lib for *; using stdStorage for StdStorage; - uint256 internal constant FIXED_RATE = 0.05e18; + // uint256 internal constant FIXED_RATE = 0.05e18; // The Lido storage location that tracks buffered ether reserves. We can // simulate the accrual of interest by updating this value. @@ -40,468 +40,60 @@ contract StETHHyperdriveTest is HyperdriveTest { ILido(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84); address internal STETH_WHALE = 0x1982b2F5814301d4e9a8b0201555376e62F82428; - address internal ETH_WHALE = 0x00000000219ab540356cBB839Cbe05303d7705Fa; + // address internal ETH_WHALE = 0x00000000219ab540356cBB839Cbe05303d7705Fa; - HyperdriveFactory factory; - address deployerCoordinator; + // HyperdriveFactory factory; + // address deployerCoordinator; - function setUp() public override __mainnet_fork(17_376_154) { - super.setUp(); + address[] internal whaleAccounts = [STETH_WHALE]; + IntegrationConfig internal __testConfig = + IntegrationConfig(whaleAccounts, IERC20(LIDO), IERC20(ETH), 1e5, 1e15); - // Deploy the hyperdrive factory. - vm.startPrank(deployer); - address[] memory defaults = new address[](1); - defaults[0] = bob; - forwarderFactory = new ERC20ForwarderFactory(); - factory = new HyperdriveFactory( - HyperdriveFactory.FactoryConfig({ - governance: alice, - hyperdriveGovernance: bob, - feeCollector: feeCollector, - sweepCollector: sweepCollector, - defaultPausers: defaults, - checkpointDurationResolution: 1 hours, - minCheckpointDuration: 8 hours, - maxCheckpointDuration: 1 days, - minPositionDuration: 7 days, - maxPositionDuration: 10 * 365 days, - minFixedAPR: 0.001e18, - maxFixedAPR: 0.5e18, - minTimeStretchAPR: 0.005e18, - maxTimeStretchAPR: 0.5e18, - minFees: IHyperdrive.Fees({ - curve: 0, - flat: 0, - governanceLP: 0, - governanceZombie: 0 - }), - maxFees: IHyperdrive.Fees({ - curve: ONE, - flat: ONE, - governanceLP: ONE, - governanceZombie: ONE - }), - linkerFactory: address(forwarderFactory), - linkerCodeHash: forwarderFactory.ERC20LINK_HASH() - }) - ); + constructor() IntegrationTest(__testConfig) {} - // Deploy the hyperdrive deployers and register the deployer coordinator - // in the factory. - vm.stopPrank(); + function deployCoordinator() internal override returns (address) { vm.startPrank(alice); - deployerCoordinator = address( - new StETHHyperdriveDeployerCoordinator( - address(new StETHHyperdriveCoreDeployer(LIDO)), - address(new StETHTarget0Deployer(LIDO)), - address(new StETHTarget1Deployer(LIDO)), - address(new StETHTarget2Deployer(LIDO)), - address(new StETHTarget3Deployer(LIDO)), - address(new StETHTarget4Deployer(LIDO)), - LIDO - ) - ); - factory.addDeployerCoordinator(address(deployerCoordinator)); - - // Alice deploys the hyperdrive instance. - IHyperdrive.PoolDeployConfig memory config = IHyperdrive - .PoolDeployConfig({ - baseToken: IERC20(ETH), - linkerFactory: factory.linkerFactory(), - linkerCodeHash: factory.linkerCodeHash(), - minimumShareReserves: 1e15, - minimumTransactionAmount: 1e15, - positionDuration: POSITION_DURATION, - checkpointDuration: CHECKPOINT_DURATION, - timeStretch: 0, - governance: factory.hyperdriveGovernance(), - feeCollector: factory.feeCollector(), - sweepCollector: factory.sweepCollector(), - fees: IHyperdrive.Fees({ - curve: 0, - flat: 0, - governanceLP: 0, - governanceZombie: 0 - }) - }); - uint256 contribution = 10_000e18; - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 0, - bytes32(uint256(0xdeadbabe)) - ); - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 1, - bytes32(uint256(0xdeadbabe)) - ); - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 2, - bytes32(uint256(0xdeadbabe)) - ); - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 3, - bytes32(uint256(0xdeadbabe)) - ); - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 4, - bytes32(uint256(0xdeadbabe)) - ); - hyperdrive = factory.deployAndInitialize{ value: contribution }( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - contribution, - FIXED_RATE, - FIXED_RATE, - IHyperdrive.Options({ - asBase: true, - destination: alice, - extraData: new bytes(0) - }), - bytes32(uint256(0xdeadbabe)) - ); - - // Ensure that Bob received the correct amount of LP tokens. She should - // receive LP shares totaling the amount of shares that she contributed - // minus the shares set aside for the minimum share reserves and the - // zero address's initial LP contribution. - assertApproxEqAbs( - hyperdrive.balanceOf(AssetId._LP_ASSET_ID, alice), - contribution.divDown( - hyperdrive.getPoolConfig().initialVaultSharePrice - ) - 2 * hyperdrive.getPoolConfig().minimumShareReserves, - 1e5 - ); - - // Fund the test accounts with stETH and ETH. - address[] memory accounts = new address[](3); - accounts[0] = alice; - accounts[1] = bob; - accounts[2] = celine; - fundAccounts(address(hyperdrive), IERC20(LIDO), STETH_WHALE, accounts); - vm.deal(alice, 20_000e18); - vm.deal(bob, 20_000e18); - vm.deal(celine, 20_000e18); - - // Start recording event logs. - vm.recordLogs(); - } - - /// Getters /// - - function test_getters() external { - assertEq( - address(IStETHHyperdrive(address(hyperdrive)).lido()), - address(LIDO) - ); + return + address( + new StETHHyperdriveDeployerCoordinator( + address(new StETHHyperdriveCoreDeployer(LIDO)), + address(new StETHTarget0Deployer(LIDO)), + address(new StETHTarget1Deployer(LIDO)), + address(new StETHTarget2Deployer(LIDO)), + address(new StETHTarget3Deployer(LIDO)), + address(new StETHTarget4Deployer(LIDO)), + LIDO + ) + ); } - /// Deploy and Initialize /// + function setUp() public override __mainnet_fork(17_376_154) { + super.setUp(); - function test__steth__deployAndInitialize__asBase() external { - // Deploy and Initialize the stETH hyperdrive instance. Excess ether is - // sent, and should be returned to the sender. - vm.stopPrank(); vm.startPrank(bob); - uint256 bobBalanceBefore = address(bob).balance; - IHyperdrive.PoolDeployConfig memory config = IHyperdrive - .PoolDeployConfig({ - baseToken: IERC20(ETH), - governance: factory.hyperdriveGovernance(), - feeCollector: factory.feeCollector(), - sweepCollector: factory.sweepCollector(), - linkerFactory: factory.linkerFactory(), - linkerCodeHash: factory.linkerCodeHash(), - minimumShareReserves: 1e15, - minimumTransactionAmount: 1e15, - positionDuration: POSITION_DURATION, - checkpointDuration: CHECKPOINT_DURATION, - timeStretch: 0, - fees: IHyperdrive.Fees({ - curve: 0, - flat: 0, - governanceLP: 0, - governanceZombie: 0 - }) - }); - uint256 contribution = 5_000e18; - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 0, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 1, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 2, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 3, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 4, - bytes32(uint256(0xdeadfade)) - ); - hyperdrive = factory.deployAndInitialize{ value: contribution + 1e18 }( - bytes32(uint256(0xbeefbabe)), - address(deployerCoordinator), - config, - new bytes(0), - contribution, - FIXED_RATE, - FIXED_RATE, - IHyperdrive.Options({ - asBase: true, - destination: bob, - extraData: new bytes(0) - }), - bytes32(uint256(0xdeadfade)) - ); - assertEq(address(bob).balance, bobBalanceBefore - contribution); - - // Ensure that the decimals are set correctly. - assertEq(hyperdrive.decimals(), 18); - - // Ensure that Bob received the correct amount of LP tokens. He should - // receive LP shares totaling the amount of shares that he contributed - // minus the shares set aside for the minimum share reserves and the - // zero address's initial LP contribution. - assertApproxEqAbs( - hyperdrive.balanceOf(AssetId._LP_ASSET_ID, bob), - contribution.divDown( - hyperdrive.getPoolConfig().initialVaultSharePrice - ) - 2 * hyperdrive.getPoolConfig().minimumShareReserves, - 1e5 - ); - - // Ensure that the share reserves and LP total supply are equal and correct. - assertApproxEqAbs( - hyperdrive.getPoolInfo().shareReserves, - contribution.mulDivDown( - LIDO.getTotalShares(), - LIDO.getTotalPooledEther() - ), - 1 - ); - assertEq( - hyperdrive.getPoolInfo().lpTotalSupply, - hyperdrive.getPoolInfo().shareReserves - config.minimumShareReserves - ); - - // Verify that the correct events were emitted. - verifyFactoryEvents( - deployerCoordinator, - hyperdrive, - bob, - contribution, - FIXED_RATE, - true, - config.minimumShareReserves, - new bytes(0), - // NOTE: Tolerance since stETH uses mulDivDown for share calculations. - 1e5 - ); + LIDO.approve(address(hyperdrive), 100_000e18); } - function test__steth__deployAndInitialize__asShares() external { - // Deploy and Initialize the stETH hyperdrive instance. Excess ether is - // sent, and should be returned to the sender. - vm.stopPrank(); - vm.startPrank(bob); - uint256 contributionShares = 5_000e18; - uint256 contribution = LIDO.getPooledEthByShares(contributionShares); - LIDO.submit{ value: contribution }(address(0)); - LIDO.approve(deployerCoordinator, contribution); - IHyperdrive.PoolDeployConfig memory config = IHyperdrive - .PoolDeployConfig({ - baseToken: IERC20(ETH), - governance: factory.hyperdriveGovernance(), - feeCollector: factory.feeCollector(), - sweepCollector: factory.sweepCollector(), - linkerFactory: factory.linkerFactory(), - linkerCodeHash: factory.linkerCodeHash(), - minimumShareReserves: 1e15, - minimumTransactionAmount: 1e15, - positionDuration: POSITION_DURATION, - checkpointDuration: CHECKPOINT_DURATION, - timeStretch: 0, - fees: IHyperdrive.Fees({ - curve: 0, - flat: 0, - governanceLP: 0, - governanceZombie: 0 - }) - }); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 0, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 1, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 2, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 3, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 4, - bytes32(uint256(0xdeadfade)) - ); - hyperdrive = factory.deployAndInitialize( - bytes32(uint256(0xbeefbabe)), - address(deployerCoordinator), - config, - new bytes(0), - contributionShares, - FIXED_RATE, - FIXED_RATE, - IHyperdrive.Options({ - asBase: false, - destination: bob, - extraData: new bytes(0) - }), - bytes32(uint256(0xdeadfade)) + function getProtocolSharePrice() + internal + override + returns (uint256, uint256, uint256) + { + uint256 totalPooledEther = LIDO.getTotalPooledEther(); + uint256 totalShares = LIDO.getTotalShares(); + return ( + totalPooledEther, + totalShares, + totalPooledEther.divDown(totalShares) ); + } - // Ensure that the decimals are set correctly. - assertEq(hyperdrive.decimals(), 18); - - // Ensure that Bob received the correct amount of LP tokens. He should - // receive LP shares totaling the amount of shares that he contributed - // minus the shares set aside for the minimum share reserves and the - // zero address's initial LP contribution. - assertApproxEqAbs( - hyperdrive.balanceOf(AssetId._LP_ASSET_ID, bob), - contribution.divDown( - hyperdrive.getPoolConfig().initialVaultSharePrice - ) - 2 * hyperdrive.getPoolConfig().minimumShareReserves, - 1e5 - ); + /// Getters /// - // Ensure that the share reserves and LP total supply are equal and correct. - assertApproxEqAbs( - hyperdrive.getPoolInfo().shareReserves, - contribution.mulDivDown( - LIDO.getTotalShares(), - LIDO.getTotalPooledEther() - ), - 1 - ); + function test_getters() external { assertEq( - hyperdrive.getPoolInfo().lpTotalSupply, - hyperdrive.getPoolInfo().shareReserves - config.minimumShareReserves - ); - - // Verify that the correct events were emitted. - verifyFactoryEvents( - deployerCoordinator, - hyperdrive, - bob, - contributionShares, - FIXED_RATE, - false, - config.minimumShareReserves, - new bytes(0), - // NOTE: Tolerance since stETH uses mulDivDown for share calculations. - 1e5 + address(IStETHHyperdrive(address(hyperdrive)).lido()), + address(LIDO) ); } diff --git a/test/utils/IntegrationTest.sol b/test/utils/IntegrationTest.sol index 75fee5dfd..c1f590203 100644 --- a/test/utils/IntegrationTest.sol +++ b/test/utils/IntegrationTest.sol @@ -11,6 +11,7 @@ import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; import { Lib } from "test/utils/Lib.sol"; import { HyperdriveTest } from "test/utils/HyperdriveTest.sol"; import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; +import { ETH } from "contracts/src/libraries/Constants.sol"; import { HyperdriveUtils } from "test/utils/HyperdriveUtils.sol"; @@ -19,6 +20,8 @@ abstract contract IntegrationTest is HyperdriveTest { using FixedPointMath for uint256; uint256 internal constant FIXED_RATE = 0.05e18; + // bytes32 internal constant DEPLOYMENT_SALT = bytes32(uint256(0xdeadbabe)); + address internal ETH_WHALE = 0x00000000219ab540356cBB839Cbe05303d7705Fa; struct IntegrationConfig { @@ -26,6 +29,7 @@ abstract contract IntegrationTest is HyperdriveTest { IERC20 token; IERC20 baseToken; uint256 shareTolerance; + uint256 minTransactionAmount; } IntegrationConfig internal config; @@ -33,8 +37,14 @@ abstract contract IntegrationTest is HyperdriveTest { HyperdriveFactory factory; address deployerCoordinator; + IHyperdrive.PoolDeployConfig internal poolConfig; + + bool internal immutable isBaseETH; + constructor(IntegrationConfig storage _config) { config = _config; + + isBaseETH = config.baseToken == IERC20(ETH); } function setUp() public virtual override { @@ -65,55 +75,32 @@ abstract contract IntegrationTest is HyperdriveTest { deployerCoordinator = deployCoordinator(); factory.addDeployerCoordinator(deployerCoordinator); - deployTargets(); - - // Start recording event logs. - vm.recordLogs(); - } - - function deployTargets() internal { - IHyperdrive.PoolDeployConfig memory poolConfig = IHyperdrive - .PoolDeployConfig({ - baseToken: config.baseToken, - linkerFactory: factory.linkerFactory(), - linkerCodeHash: factory.linkerCodeHash(), - minimumShareReserves: 1e15, - minimumTransactionAmount: 1e16, - positionDuration: POSITION_DURATION, - checkpointDuration: CHECKPOINT_DURATION, - timeStretch: 0, - governance: factory.hyperdriveGovernance(), - feeCollector: factory.feeCollector(), - sweepCollector: factory.sweepCollector(), - fees: IHyperdrive.Fees({ - curve: 0, - flat: 0, - governanceLP: 0, - governanceZombie: 0 - }) - }); - deployTargets( - factory, - alice, + // alice, bytes32(uint256(0xdeadbeef)), bytes32(uint256(0xdeadbabe)), 10_000e18, - poolConfig + false ); + + // Start recording event logs. + vm.recordLogs(); } + // function isBaseETH() internal returns (bool) { + // return asBase && config.baseToken; + // } + function deployTargets( - HyperdriveFactory _factory, - address deployer, + // address deployer, bytes32 deploymentId, bytes32 deploymentSalt, uint256 contribution, - IHyperdrive.PoolDeployConfig memory poolConfig - ) public { - vm.startPrank(deployer); + bool asBase + ) internal { + vm.startPrank(alice); - _factory.deployTarget( + factory.deployTarget( deploymentId, deployerCoordinator, poolConfig, @@ -123,7 +110,7 @@ abstract contract IntegrationTest is HyperdriveTest { 0, deploymentSalt ); - _factory.deployTarget( + factory.deployTarget( deploymentId, deployerCoordinator, poolConfig, @@ -133,7 +120,7 @@ abstract contract IntegrationTest is HyperdriveTest { 1, deploymentSalt ); - _factory.deployTarget( + factory.deployTarget( deploymentId, deployerCoordinator, poolConfig, @@ -143,7 +130,7 @@ abstract contract IntegrationTest is HyperdriveTest { 2, deploymentSalt ); - _factory.deployTarget( + factory.deployTarget( deploymentId, deployerCoordinator, poolConfig, @@ -153,7 +140,7 @@ abstract contract IntegrationTest is HyperdriveTest { 3, deploymentSalt ); - _factory.deployTarget( + factory.deployTarget( deploymentId, deployerCoordinator, poolConfig, @@ -164,22 +151,62 @@ abstract contract IntegrationTest is HyperdriveTest { deploymentSalt ); - config.token.approve(deployerCoordinator, contribution); - hyperdrive = _factory.deployAndInitialize( - deploymentId, - deployerCoordinator, - poolConfig, - new bytes(0), - contribution, - FIXED_RATE, - FIXED_RATE, - IHyperdrive.Options({ - asBase: false, - destination: deployer, - extraData: new bytes(0) - }), - deploymentSalt - ); + config.token.approve(deployerCoordinator, 100_000e18); + // asBase && isBaseETH ? contribution : 0 + + { + hyperdrive = factory.deployAndInitialize{ + value: asBase && isBaseETH ? contribution : 0 + }( + deploymentId, + deployerCoordinator, + poolConfig, + new bytes(0), + contribution, + FIXED_RATE, + FIXED_RATE, + IHyperdrive.Options({ + asBase: asBase, + destination: alice, + extraData: new bytes(0) + }), + deploymentSalt + ); + } + + // if (config.baseToken == IERC20(ETH) && asBase) { + // hyperdrive = _factory.deployAndInitialize{ value: contribution }( + // deploymentId, + // deployerCoordinator, + // poolConfig, + // new bytes(0), + // contribution, + // FIXED_RATE, + // FIXED_RATE, + // IHyperdrive.Options({ + // asBase: false, + // destination: deployer, + // extraData: new bytes(0) + // }), + // deploymentSalt + // ); + // } else { + // hyperdrive = _factory.deployAndInitialize( + // deploymentId, + // deployerCoordinator, + // poolConfig, + // new bytes(0), + // contribution, + // FIXED_RATE, + // FIXED_RATE, + // IHyperdrive.Options({ + // asBase: asBase, + // destination: deployer, + // extraData: new bytes(0) + // }), + // deploymentSalt + // ); + // } } function deployFactory() internal { @@ -220,60 +247,121 @@ abstract contract IntegrationTest is HyperdriveTest { linkerCodeHash: forwarderFactory.ERC20LINK_HASH() }) ); + + poolConfig = IHyperdrive.PoolDeployConfig({ + baseToken: config.baseToken, + linkerFactory: factory.linkerFactory(), + linkerCodeHash: factory.linkerCodeHash(), + minimumShareReserves: 1e15, + minimumTransactionAmount: config.minTransactionAmount, + positionDuration: POSITION_DURATION, + checkpointDuration: CHECKPOINT_DURATION, + timeStretch: 0, + governance: factory.hyperdriveGovernance(), + feeCollector: factory.feeCollector(), + sweepCollector: factory.sweepCollector(), + fees: IHyperdrive.Fees({ + curve: 0, + flat: 0, + governanceLP: 0, + governanceZombie: 0 + }) + }); } - function getProtocolSharePrice() internal virtual returns (uint256); + function getProtocolSharePrice() + internal + virtual + returns (uint256, uint256, uint256); function deployCoordinator() internal virtual returns (address); - function test__deployAndInitialize__asShares() external { - IHyperdrive.PoolDeployConfig memory poolConfig = IHyperdrive - .PoolDeployConfig({ - baseToken: config.baseToken, - linkerFactory: factory.linkerFactory(), - linkerCodeHash: factory.linkerCodeHash(), - minimumShareReserves: 1e15, - minimumTransactionAmount: 1e16, - positionDuration: POSITION_DURATION, - checkpointDuration: CHECKPOINT_DURATION, - timeStretch: 0, - governance: factory.hyperdriveGovernance(), - feeCollector: factory.feeCollector(), - sweepCollector: factory.sweepCollector(), - fees: IHyperdrive.Fees({ - curve: 0, - flat: 0, - governanceLP: 0, - governanceZombie: 0 - }) - }); - - uint256 bobBalanceBefore = address(bob).balance; + function test__deployAndInitialize__asBase() external virtual { + uint256 aliceBalanceBefore = address(alice).balance; uint256 contribution = 5_000e18; - uint256 contributionShares = contribution.divDown( - getProtocolSharePrice() + (uint256 totalBase, uint256 totalShare, ) = getProtocolSharePrice(); + uint256 contributionShares = contribution.mulDivDown( + totalShare, + totalBase + ); + + deployTargets( + bytes32(uint256(0xbeefbabe)), + bytes32(uint256(0xdeadfade)), + contribution, + true + // poolConfig + ); + assertEq(address(alice).balance, aliceBalanceBefore - contribution); + + // Ensure that the decimals are set correctly. + assertEq(hyperdrive.decimals(), 18); + + // Ensure that alice received the correct amount of LP tokens. He should + // receive LP shares totaling the amount of shares that he contributed + // minus the shares set aside for the minimum share reserves and the + // zero address's initial LP contribution. + assertApproxEqAbs( + hyperdrive.balanceOf(AssetId._LP_ASSET_ID, alice), + contribution.divDown( + hyperdrive.getPoolConfig().initialVaultSharePrice + ) - 2 * hyperdrive.getPoolConfig().minimumShareReserves, + config.shareTolerance ); + // Ensure that the share reserves and LP total supply are equal and correct. + assertApproxEqAbs( + hyperdrive.getPoolInfo().shareReserves, + contributionShares, + 1 + ); + assertEq( + hyperdrive.getPoolInfo().lpTotalSupply, + hyperdrive.getPoolInfo().shareReserves - + hyperdrive.getPoolConfig().minimumShareReserves + ); + + // Verify that the correct events were emitted. + verifyFactoryEvents( + deployerCoordinator, + hyperdrive, + alice, + contribution, + FIXED_RATE, + true, + hyperdrive.getPoolConfig().minimumShareReserves, + new bytes(0), + // NOTE: Tolerance since stETH uses mulDivDown for share calculations. + config.shareTolerance + ); + } + + function test__deployAndInitialize__asShares() external { + uint256 aliceBalanceBefore = address(alice).balance; + uint256 contribution = 5_000e18; + (, , uint256 sharePrice) = getProtocolSharePrice(); + + uint256 contributionShares = contribution.divDown(sharePrice); + deployTargets( - factory, - bob, + // alice, bytes32(uint256(0xbeefbabe)), bytes32(uint256(0xdeadfade)), contributionShares, - poolConfig + false ); - assertEq(address(bob).balance, bobBalanceBefore); + assertEq(address(alice).balance, aliceBalanceBefore); // Ensure that the decimals are set correctly. assertEq(hyperdrive.decimals(), 18); - // Ensure that Bob received the correct amount of LP tokens. He should + // Ensure that alice received the correct amount of LP tokens. He should // receive LP shares totaling the amount of shares that he contributed // minus the shares set aside for the minimum share reserves and the // zero address's initial LP contribution. assertApproxEqAbs( - hyperdrive.balanceOf(AssetId._LP_ASSET_ID, bob), + hyperdrive.balanceOf(AssetId._LP_ASSET_ID, alice), contribution.divDown( hyperdrive.getPoolConfig().initialVaultSharePrice ) - 2 * hyperdrive.getPoolConfig().minimumShareReserves, @@ -292,7 +380,7 @@ abstract contract IntegrationTest is HyperdriveTest { verifyFactoryEvents( deployerCoordinator, hyperdrive, - bob, + alice, contributionShares, FIXED_RATE, false, From 426abd00a657176d6e96a18a977c1c63d0a4c987 Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Fri, 22 Mar 2024 01:41:12 -0500 Subject: [PATCH 06/21] integration test suite deployAndInit test generalized --- test/utils/IntegrationTest.sol | 43 ++++------------------------------ 1 file changed, 4 insertions(+), 39 deletions(-) diff --git a/test/utils/IntegrationTest.sol b/test/utils/IntegrationTest.sol index c1f590203..a691ff99d 100644 --- a/test/utils/IntegrationTest.sol +++ b/test/utils/IntegrationTest.sol @@ -20,7 +20,6 @@ abstract contract IntegrationTest is HyperdriveTest { using FixedPointMath for uint256; uint256 internal constant FIXED_RATE = 0.05e18; - // bytes32 internal constant DEPLOYMENT_SALT = bytes32(uint256(0xdeadbabe)); address internal ETH_WHALE = 0x00000000219ab540356cBB839Cbe05303d7705Fa; @@ -53,10 +52,10 @@ abstract contract IntegrationTest is HyperdriveTest { // _beforeSetUp(); // Fund Accounts - address[] memory accounts = new address[](3); + address[] memory accounts = new address[](2); accounts[0] = alice; accounts[1] = bob; - accounts[2] = celine; + // accounts[2] = celine; for (uint256 i = 0; i < config.whaleAccounts.length; i++) { fundAccounts( address(hyperdrive), @@ -79,7 +78,7 @@ abstract contract IntegrationTest is HyperdriveTest { // alice, bytes32(uint256(0xdeadbeef)), bytes32(uint256(0xdeadbabe)), - 10_000e18, + 5_000e18, false ); @@ -173,40 +172,6 @@ abstract contract IntegrationTest is HyperdriveTest { deploymentSalt ); } - - // if (config.baseToken == IERC20(ETH) && asBase) { - // hyperdrive = _factory.deployAndInitialize{ value: contribution }( - // deploymentId, - // deployerCoordinator, - // poolConfig, - // new bytes(0), - // contribution, - // FIXED_RATE, - // FIXED_RATE, - // IHyperdrive.Options({ - // asBase: false, - // destination: deployer, - // extraData: new bytes(0) - // }), - // deploymentSalt - // ); - // } else { - // hyperdrive = _factory.deployAndInitialize( - // deploymentId, - // deployerCoordinator, - // poolConfig, - // new bytes(0), - // contribution, - // FIXED_RATE, - // FIXED_RATE, - // IHyperdrive.Options({ - // asBase: asBase, - // destination: deployer, - // extraData: new bytes(0) - // }), - // deploymentSalt - // ); - // } } function deployFactory() internal { @@ -336,7 +301,7 @@ abstract contract IntegrationTest is HyperdriveTest { ); } - function test__deployAndInitialize__asShares() external { + function test__deployAndInitialize__asShares(uint) external { uint256 aliceBalanceBefore = address(alice).balance; uint256 contribution = 5_000e18; (, , uint256 sharePrice) = getProtocolSharePrice(); From a80735cd168ff9b2b8c022a1d4007b13d5ede853 Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Fri, 22 Mar 2024 01:41:30 -0500 Subject: [PATCH 07/21] Implement deployAndInit in instances and code cleanup --- test/instances/lseth/LsETHHyperdrive.t.sol | 376 ++++----------------- test/instances/reth/RETHHyperdrive.t.sol | 67 ++-- test/instances/steth/StETHHyperdrive.t.sol | 46 +-- 3 files changed, 109 insertions(+), 380 deletions(-) diff --git a/test/instances/lseth/LsETHHyperdrive.t.sol b/test/instances/lseth/LsETHHyperdrive.t.sol index 765c1ef3e..77010955c 100644 --- a/test/instances/lseth/LsETHHyperdrive.t.sol +++ b/test/instances/lseth/LsETHHyperdrive.t.sol @@ -20,207 +20,78 @@ import { ETH } from "contracts/src/libraries/Constants.sol"; import { HyperdriveMath } from "contracts/src/libraries/HyperdriveMath.sol"; import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; import { ERC20Mintable } from "contracts/test/ERC20Mintable.sol"; -import { HyperdriveTest } from "test/utils/HyperdriveTest.sol"; +import { IntegrationTest } from "test/utils/IntegrationTest.sol"; import { HyperdriveUtils } from "test/utils/HyperdriveUtils.sol"; import { Lib } from "test/utils/Lib.sol"; -contract LsETHHyperdriveTest is HyperdriveTest { +contract LsETHHyperdriveTest is IntegrationTest { using FixedPointMath for uint256; using Lib for *; using stdStorage for StdStorage; - uint256 internal constant FIXED_RATE = 0.05e18; - - bytes32 - internal constant LAST_CONSENSUS_LAYER_REPORT_VALIDATOR_BALANCE_SLOT = - bytes32(uint256(keccak256("river.state.lastConsensusLayerReport"))); - + // The LsETH token contract. IRiverV1 internal constant RIVER = IRiverV1(0x8c1BEd5b9a0928467c9B1341Da1D7BD5e10b6549); - address internal LSETH_WHALE = 0xF047ab4c75cebf0eB9ed34Ae2c186f3611aEAfa6; - address internal LSETH_WHALE_2 = 0xAe60d8180437b5C34bB956822ac2710972584473; - address internal ETH_WHALE = 0x00000000219ab540356cBB839Cbe05303d7705Fa; - - HyperdriveFactory factory; - address deployerCoordinator; + // Whale accounts. + address internal constant LSETH_WHALE = + 0xF047ab4c75cebf0eB9ed34Ae2c186f3611aEAfa6; + address internal constant LSETH_WHALE_2 = + 0xAe60d8180437b5C34bB956822ac2710972584473; + address internal constant LSETH_WHALE_3 = + 0xa6941E15B15fF30F2B2d42AE922134A82F6b7189; + address[] internal whaleAccounts = [ + LSETH_WHALE, + LSETH_WHALE_2, + LSETH_WHALE_3 + ]; + + // The configuration for the integration testing suite. + IntegrationConfig internal __testConfig = + IntegrationConfig(whaleAccounts, IERC20(RIVER), IERC20(ETH), 0, 1e15); + + constructor() IntegrationTest(__testConfig) {} function setUp() public override __mainnet_fork(19_429_100) { super.setUp(); + } - // Fund the test accounts with LsETH and ETH. - address[] memory accounts = new address[](3); - accounts[0] = alice; - accounts[1] = bob; - accounts[2] = celine; - fundAccounts(address(hyperdrive), IERC20(RIVER), LSETH_WHALE, accounts); - fundAccounts( - address(hyperdrive), - IERC20(RIVER), - LSETH_WHALE_2, - accounts - ); - vm.deal(alice, 20_000e18); - vm.deal(bob, 20_000e18); - vm.deal(celine, 20_000e18); - - // Deploy the hyperdrive factory. - vm.startPrank(deployer); - address[] memory defaults = new address[](1); - defaults[0] = bob; - forwarderFactory = new ERC20ForwarderFactory(); - factory = new HyperdriveFactory( - HyperdriveFactory.FactoryConfig({ - governance: alice, - hyperdriveGovernance: bob, - feeCollector: celine, - sweepCollector: sweepCollector, - defaultPausers: defaults, - checkpointDurationResolution: 1 hours, - minCheckpointDuration: 8 hours, - maxCheckpointDuration: 1 days, - minPositionDuration: 7 days, - maxPositionDuration: 10 * 365 days, - minFixedAPR: 0.001e18, - maxFixedAPR: 0.5e18, - minTimeStretchAPR: 0.005e18, - maxTimeStretchAPR: 0.5e18, - minFees: IHyperdrive.Fees({ - curve: 0, - flat: 0, - governanceLP: 0, - governanceZombie: 0 - }), - maxFees: IHyperdrive.Fees({ - curve: ONE, - flat: ONE, - governanceLP: ONE, - governanceZombie: ONE - }), - linkerFactory: address(forwarderFactory), - linkerCodeHash: forwarderFactory.ERC20LINK_HASH() - }) - ); + /// Overrides /// - // Deploy the hyperdrive deployers and register the deployer coordinator - // in the factory. - vm.stopPrank(); + /// @dev Deploys the LsETH deployer coordinator contract. + function deployCoordinator() internal override returns (address) { vm.startPrank(alice); - deployerCoordinator = address( - new LsETHHyperdriveDeployerCoordinator( - address(new LsETHHyperdriveCoreDeployer(RIVER)), - address(new LsETHTarget0Deployer(RIVER)), - address(new LsETHTarget1Deployer(RIVER)), - address(new LsETHTarget2Deployer(RIVER)), - address(new LsETHTarget3Deployer(RIVER)), - address(new LsETHTarget4Deployer(RIVER)), - RIVER - ) - ); - factory.addDeployerCoordinator(address(deployerCoordinator)); - - // Alice deploys the hyperdrive instance. - IHyperdrive.PoolDeployConfig memory config = IHyperdrive - .PoolDeployConfig({ - baseToken: IERC20(ETH), - linkerFactory: factory.linkerFactory(), - linkerCodeHash: factory.linkerCodeHash(), - minimumShareReserves: 1e15, - minimumTransactionAmount: 1e15, - positionDuration: POSITION_DURATION, - checkpointDuration: CHECKPOINT_DURATION, - timeStretch: 0, - governance: factory.hyperdriveGovernance(), - feeCollector: factory.feeCollector(), - sweepCollector: factory.sweepCollector(), - fees: IHyperdrive.Fees({ - curve: 0, - flat: 0, - governanceLP: 0, - governanceZombie: 0 - }) - }); - uint256 contribution = 5_000e18; - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 0, - bytes32(uint256(0xdeadbabe)) - ); - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 1, - bytes32(uint256(0xdeadbabe)) - ); - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 2, - bytes32(uint256(0xdeadbabe)) - ); - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 3, - bytes32(uint256(0xdeadbabe)) - ); - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 4, - bytes32(uint256(0xdeadbabe)) - ); - RIVER.approve(deployerCoordinator, contribution); - hyperdrive = factory.deployAndInitialize( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - contribution, - FIXED_RATE, - FIXED_RATE, - IHyperdrive.Options({ - asBase: false, - destination: alice, - extraData: new bytes(0) - }), - bytes32(uint256(0xdeadbabe)) - ); + return + address( + new LsETHHyperdriveDeployerCoordinator( + address(new LsETHHyperdriveCoreDeployer(RIVER)), + address(new LsETHTarget0Deployer(RIVER)), + address(new LsETHTarget1Deployer(RIVER)), + address(new LsETHTarget2Deployer(RIVER)), + address(new LsETHTarget3Deployer(RIVER)), + address(new LsETHTarget4Deployer(RIVER)), + RIVER + ) + ); + } - // Ensure that Alice received the correct amount of LP tokens. She should - // receive LP shares totaling the amount of shares that she contributed - // minus the shares set aside for the minimum share reserves and the - // zero address's initial LP contribution. - assertEq( - hyperdrive.balanceOf(AssetId._LP_ASSET_ID, alice), - contribution - 2 * hyperdrive.getPoolConfig().minimumShareReserves + /// @dev Fetches share price information about LsETH. + function getProtocolSharePrice() + internal + view + override + returns (uint256, uint256, uint256) + { + return ( + RIVER.totalUnderlyingSupply(), + RIVER.totalSupply(), + RIVER.underlyingBalanceFromShares(1e18) ); - - // Start recording event logs. - vm.recordLogs(); } + /// @dev Initializing the market with the ETH is not supported. + function test__deployAndInitialize__asBase() external override {} + /// Getters /// function test_getters() external { @@ -230,135 +101,6 @@ contract LsETHHyperdriveTest is HyperdriveTest { ); } - /// Deploy and Initialize /// - - function test__lseth__deployAndInitialize() external { - // Deploy and Initialize the LsETH hyperdrive instance. - vm.stopPrank(); - vm.startPrank(bob); - uint256 bobBalanceBefore = address(bob).balance; - IHyperdrive.PoolDeployConfig memory config = IHyperdrive - .PoolDeployConfig({ - baseToken: IERC20(ETH), - governance: factory.hyperdriveGovernance(), - feeCollector: factory.feeCollector(), - sweepCollector: factory.sweepCollector(), - linkerFactory: factory.linkerFactory(), - linkerCodeHash: factory.linkerCodeHash(), - minimumShareReserves: 1e15, - minimumTransactionAmount: 1e15, - positionDuration: POSITION_DURATION, - checkpointDuration: CHECKPOINT_DURATION, - timeStretch: 0, - fees: IHyperdrive.Fees({ - curve: 0, - flat: 0, - governanceLP: 0, - governanceZombie: 0 - }) - }); - uint256 contribution = 5_000e18; - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 0, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 1, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 2, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 3, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 4, - bytes32(uint256(0xdeadfade)) - ); - RIVER.approve(deployerCoordinator, contribution); - hyperdrive = factory.deployAndInitialize( - bytes32(uint256(0xbeefbabe)), - address(deployerCoordinator), - config, - new bytes(0), - contribution, - FIXED_RATE, - FIXED_RATE, - IHyperdrive.Options({ - asBase: false, - destination: bob, - extraData: new bytes(0) - }), - bytes32(uint256(0xdeadfade)) - ); - assertEq(address(bob).balance, bobBalanceBefore); - - // Ensure that the decimals are set correctly. - assertEq(hyperdrive.decimals(), 18); - - // Ensure that Bob received the correct amount of LP tokens. He should - // receive LP shares totaling the amount of shares that he contributed - // minus the shares set aside for the minimum share reserves and the - // zero address's initial LP contribution. - assertEq( - hyperdrive.balanceOf(AssetId._LP_ASSET_ID, bob), - contribution - 2 * hyperdrive.getPoolConfig().minimumShareReserves - ); - - // Ensure that the share reserves and LP total supply are equal and correct. - assertEq(hyperdrive.getPoolInfo().shareReserves, contribution); - assertEq( - hyperdrive.getPoolInfo().lpTotalSupply, - hyperdrive.getPoolInfo().shareReserves - config.minimumShareReserves - ); - - // Verify that the correct events were emitted. - verifyFactoryEvents( - deployerCoordinator, - hyperdrive, - bob, - contribution, - FIXED_RATE, - false, - config.minimumShareReserves, - new bytes(0), - 0 - ); - } - /// Price Per Share /// function test_pricePerVaultShare(uint256 basePaid) external { @@ -383,7 +125,7 @@ contract LsETHHyperdriveTest is HyperdriveTest { ); } - // /// Long /// + /// Long /// function test_open_long_with_eth(uint256 basePaid) external { // Bob opens a long by depositing ETH. This is not allowed and @@ -853,16 +595,18 @@ contract LsETHHyperdriveTest is HyperdriveTest { uint256 timeDelta, int256 variableRate ) internal override { + // Storage slot for LsETH underlying ether balance. + bytes32 lastConsensusLayerReportSlot = bytes32( + uint256(keccak256("river.state.lastConsensusLayerReport")) + ); + // Advance the time. vm.warp(block.timestamp + timeDelta); // Load the validator balance from the last consensus // layer report slot. uint256 validatorBalance = uint256( - vm.load( - address(RIVER), - LAST_CONSENSUS_LAYER_REPORT_VALIDATOR_BALANCE_SLOT - ) + vm.load(address(RIVER), lastConsensusLayerReportSlot) ); // Increase the balance by the variable rate. @@ -871,7 +615,7 @@ contract LsETHHyperdriveTest is HyperdriveTest { : validatorBalance.mulDown(uint256(1e18 - variableRate)); vm.store( address(RIVER), - LAST_CONSENSUS_LAYER_REPORT_VALIDATOR_BALANCE_SLOT, + lastConsensusLayerReportSlot, bytes32(newValidatorBalance) ); } diff --git a/test/instances/reth/RETHHyperdrive.t.sol b/test/instances/reth/RETHHyperdrive.t.sol index 818ce7e6c..4c127822b 100644 --- a/test/instances/reth/RETHHyperdrive.t.sol +++ b/test/instances/reth/RETHHyperdrive.t.sol @@ -33,21 +33,23 @@ contract RETHHyperdriveTest is IntegrationTest { using Lib for *; using stdStorage for StdStorage; - // uint256 internal constant FIXED_RATE = 0.05e18; + // Rocket Network contracts can be upgraded and addresses changed. + // We can safely assume these addresses are accurate because + // this testing suite is forked from block 19429100. IRocketStorage internal constant ROCKET_STORAGE = IRocketStorage(0x1d8f8f00cfa6758d7bE78336684788Fb0ee0Fa46); - - IRocketTokenRETH rocketTokenRETH; - IRocketNetworkBalances rocketNetworkBalances; - IRocketDepositPool rocketDepositPool; - + IRocketTokenRETH internal constant rocketTokenRETH = + IRocketTokenRETH(0xae78736Cd615f374D3085123A210448E74Fc6393); + IRocketNetworkBalances internal constant rocketNetworkBalances = + IRocketNetworkBalances(0x07FCaBCbe4ff0d80c2b1eb42855C0131b6cba2F4); + IRocketDepositPool internal constant rocketDepositPool = + IRocketDepositPool(0xDD3f50F8A6CafbE9b31a427582963f465E745AF8); + + // Whale accounts. address internal RETH_WHALE = 0xCc9EE9483f662091a1de4795249E24aC0aC2630f; - // address internal ETH_WHALE = 0x00000000219ab540356cBB839Cbe05303d7705Fa; - - // HyperdriveFactory factory; - // address deployerCoordinator; - address[] internal whaleAccounts = [RETH_WHALE]; + + // The configuration for the integration testing suite. IntegrationConfig internal __testConfig = IntegrationConfig( whaleAccounts, @@ -59,8 +61,18 @@ contract RETHHyperdriveTest is IntegrationTest { constructor() IntegrationTest(__testConfig) {} + function setUp() public override __mainnet_fork(19_429_100) { + // Give the rETH contract ETH to mimic adequate withdrawable liquidity. + vm.deal(address(rocketTokenRETH), 50_000e18); + super.setUp(); + } + + /// Overrides /// + + /// @dev Fetches share price information about rETH. function getProtocolSharePrice() internal + view override returns (uint256, uint256, uint256) { @@ -71,8 +83,10 @@ contract RETHHyperdriveTest is IntegrationTest { ); } + /// @dev Initializing the market with the ETH is not supported. function test__deployAndInitialize__asBase() external override {} + /// @dev Deploys the rETH deployer coordinator contract. function deployCoordinator() internal override returns (address) { vm.startPrank(alice); return @@ -89,33 +103,6 @@ contract RETHHyperdriveTest is IntegrationTest { ); } - function setUp() public override __mainnet_fork(19_429_100) { - // Fetching the rETH token contract address from storage. - address rocketTokenRETHAddress = ROCKET_STORAGE.getAddress( - keccak256(abi.encodePacked("contract.address", "rocketTokenRETH")) - ); - rocketTokenRETH = IRocketTokenRETH(rocketTokenRETHAddress); - - // Fetching the Rocket Network Balances contract address from storage. - address rocketNetworkBalancesAddress = ROCKET_STORAGE.getAddress( - keccak256( - abi.encodePacked("contract.address", "rocketNetworkBalances") - ) - ); - rocketNetworkBalances = IRocketNetworkBalances( - rocketNetworkBalancesAddress - ); - - // Fetching the Rocket Deposit Pool contract address from storage. - address rocketDepositPoolAddress = ROCKET_STORAGE.getAddress( - keccak256(abi.encodePacked("contract.address", "rocketDepositPool")) - ); - rocketDepositPool = IRocketDepositPool(rocketDepositPoolAddress); - - vm.deal(address(rocketTokenRETH), 50_000e18); - super.setUp(); - } - /// Getters /// function test_getters() external { @@ -129,8 +116,6 @@ contract RETHHyperdriveTest is IntegrationTest { ); } - /// Deploy and Initialize /// - /// Price Per Share /// function test_pricePerVaultShare(uint256 basePaid) external { @@ -157,7 +142,7 @@ contract RETHHyperdriveTest is IntegrationTest { ); } - // /// Long /// + /// Long /// function test_open_long_with_eth(uint256 basePaid) external { // Bob opens a long by depositing ETH. This is not allowed and diff --git a/test/instances/steth/StETHHyperdrive.t.sol b/test/instances/steth/StETHHyperdrive.t.sol index 8d346dc91..31411071f 100644 --- a/test/instances/steth/StETHHyperdrive.t.sol +++ b/test/instances/steth/StETHHyperdrive.t.sol @@ -29,8 +29,6 @@ contract StETHHyperdriveTest is IntegrationTest { using Lib for *; using stdStorage for StdStorage; - // uint256 internal constant FIXED_RATE = 0.05e18; - // The Lido storage location that tracks buffered ether reserves. We can // simulate the accrual of interest by updating this value. bytes32 internal constant BUFFERED_ETHER_POSITION = @@ -39,34 +37,16 @@ contract StETHHyperdriveTest is IntegrationTest { ILido internal constant LIDO = ILido(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84); + // Whale accounts. address internal STETH_WHALE = 0x1982b2F5814301d4e9a8b0201555376e62F82428; - // address internal ETH_WHALE = 0x00000000219ab540356cBB839Cbe05303d7705Fa; - - // HyperdriveFactory factory; - // address deployerCoordinator; - address[] internal whaleAccounts = [STETH_WHALE]; + + // The configuration for the integration testing suite. IntegrationConfig internal __testConfig = IntegrationConfig(whaleAccounts, IERC20(LIDO), IERC20(ETH), 1e5, 1e15); constructor() IntegrationTest(__testConfig) {} - function deployCoordinator() internal override returns (address) { - vm.startPrank(alice); - return - address( - new StETHHyperdriveDeployerCoordinator( - address(new StETHHyperdriveCoreDeployer(LIDO)), - address(new StETHTarget0Deployer(LIDO)), - address(new StETHTarget1Deployer(LIDO)), - address(new StETHTarget2Deployer(LIDO)), - address(new StETHTarget3Deployer(LIDO)), - address(new StETHTarget4Deployer(LIDO)), - LIDO - ) - ); - } - function setUp() public override __mainnet_fork(17_376_154) { super.setUp(); @@ -74,6 +54,9 @@ contract StETHHyperdriveTest is IntegrationTest { LIDO.approve(address(hyperdrive), 100_000e18); } + /// Overrides /// + + /// @dev Fetches share price information about StETH. function getProtocolSharePrice() internal override @@ -88,6 +71,23 @@ contract StETHHyperdriveTest is IntegrationTest { ); } + /// @dev Deploys the rETH deployer coordinator contract. + function deployCoordinator() internal override returns (address) { + vm.startPrank(alice); + return + address( + new StETHHyperdriveDeployerCoordinator( + address(new StETHHyperdriveCoreDeployer(LIDO)), + address(new StETHTarget0Deployer(LIDO)), + address(new StETHTarget1Deployer(LIDO)), + address(new StETHTarget2Deployer(LIDO)), + address(new StETHTarget3Deployer(LIDO)), + address(new StETHTarget4Deployer(LIDO)), + LIDO + ) + ); + } + /// Getters /// function test_getters() external { From 560d2c22150c3b7142130642e4dac889f43959b7 Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Fri, 22 Mar 2024 01:53:28 -0500 Subject: [PATCH 08/21] Update RETHHyperdrive.t.sol --- test/instances/reth/RETHHyperdrive.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/instances/reth/RETHHyperdrive.t.sol b/test/instances/reth/RETHHyperdrive.t.sol index 4c127822b..fbd53542d 100644 --- a/test/instances/reth/RETHHyperdrive.t.sol +++ b/test/instances/reth/RETHHyperdrive.t.sol @@ -53,7 +53,7 @@ contract RETHHyperdriveTest is IntegrationTest { IntegrationConfig internal __testConfig = IntegrationConfig( whaleAccounts, - IERC20(0xae78736Cd615f374D3085123A210448E74Fc6393), + IERC20(rocketTokenRETH), IERC20(ETH), 0, 1e16 From 3ee5e5cfbaa03d6fd04f0e6ff2089a37a4d56ed1 Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Fri, 22 Mar 2024 02:50:26 -0500 Subject: [PATCH 09/21] wip ezeth instance --- test/instances/lseth/LsETHHyperdrive.t.sol | 9 ++++++++- test/instances/reth/RETHHyperdrive.t.sol | 3 ++- test/instances/steth/StETHHyperdrive.t.sol | 10 +++++++++- test/utils/IntegrationTest.sol | 15 +++++++++++---- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/test/instances/lseth/LsETHHyperdrive.t.sol b/test/instances/lseth/LsETHHyperdrive.t.sol index 77010955c..0688997b4 100644 --- a/test/instances/lseth/LsETHHyperdrive.t.sol +++ b/test/instances/lseth/LsETHHyperdrive.t.sol @@ -48,7 +48,14 @@ contract LsETHHyperdriveTest is IntegrationTest { // The configuration for the integration testing suite. IntegrationConfig internal __testConfig = - IntegrationConfig(whaleAccounts, IERC20(RIVER), IERC20(ETH), 0, 1e15); + IntegrationConfig( + whaleAccounts, + IERC20(RIVER), + IERC20(ETH), + 0, + 1e15, + POSITION_DURATION + ); constructor() IntegrationTest(__testConfig) {} diff --git a/test/instances/reth/RETHHyperdrive.t.sol b/test/instances/reth/RETHHyperdrive.t.sol index fbd53542d..58c0424e5 100644 --- a/test/instances/reth/RETHHyperdrive.t.sol +++ b/test/instances/reth/RETHHyperdrive.t.sol @@ -56,7 +56,8 @@ contract RETHHyperdriveTest is IntegrationTest { IERC20(rocketTokenRETH), IERC20(ETH), 0, - 1e16 + 1e16, + POSITION_DURATION ); constructor() IntegrationTest(__testConfig) {} diff --git a/test/instances/steth/StETHHyperdrive.t.sol b/test/instances/steth/StETHHyperdrive.t.sol index 31411071f..528d6aa00 100644 --- a/test/instances/steth/StETHHyperdrive.t.sol +++ b/test/instances/steth/StETHHyperdrive.t.sol @@ -43,7 +43,14 @@ contract StETHHyperdriveTest is IntegrationTest { // The configuration for the integration testing suite. IntegrationConfig internal __testConfig = - IntegrationConfig(whaleAccounts, IERC20(LIDO), IERC20(ETH), 1e5, 1e15); + IntegrationConfig( + whaleAccounts, + IERC20(LIDO), + IERC20(ETH), + 1e5, + 1e15, + POSITION_DURATION + ); constructor() IntegrationTest(__testConfig) {} @@ -59,6 +66,7 @@ contract StETHHyperdriveTest is IntegrationTest { /// @dev Fetches share price information about StETH. function getProtocolSharePrice() internal + view override returns (uint256, uint256, uint256) { diff --git a/test/utils/IntegrationTest.sol b/test/utils/IntegrationTest.sol index a691ff99d..9fae04a77 100644 --- a/test/utils/IntegrationTest.sol +++ b/test/utils/IntegrationTest.sol @@ -14,6 +14,7 @@ import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; import { ETH } from "contracts/src/libraries/Constants.sol"; import { HyperdriveUtils } from "test/utils/HyperdriveUtils.sol"; +import "forge-std/console.sol"; abstract contract IntegrationTest is HyperdriveTest { using Lib for *; @@ -29,6 +30,7 @@ abstract contract IntegrationTest is HyperdriveTest { IERC20 baseToken; uint256 shareTolerance; uint256 minTransactionAmount; + uint256 positionDuration; } IntegrationConfig internal config; @@ -64,9 +66,11 @@ abstract contract IntegrationTest is HyperdriveTest { accounts ); } - vm.deal(alice, 20_000e18); - vm.deal(bob, 20_000e18); - vm.deal(celine, 20_000e18); + vm.deal(alice, 100_000e18); + vm.deal(bob, 100_000e18); + // vm.deal(celine, 20_000e18); + // console.logString("here1"); + // console.logUint(config.token.balanceOf(alice)); // _afterSetup(); @@ -99,6 +103,9 @@ abstract contract IntegrationTest is HyperdriveTest { ) internal { vm.startPrank(alice); + // console.logString("here2"); + // console.logUint(config.token.balanceOf(alice)); + factory.deployTarget( deploymentId, deployerCoordinator, @@ -219,7 +226,7 @@ abstract contract IntegrationTest is HyperdriveTest { linkerCodeHash: factory.linkerCodeHash(), minimumShareReserves: 1e15, minimumTransactionAmount: config.minTransactionAmount, - positionDuration: POSITION_DURATION, + positionDuration: config.positionDuration, checkpointDuration: CHECKPOINT_DURATION, timeStretch: 0, governance: factory.hyperdriveGovernance(), From fefaa6fb53adb681126a4dc79ab8a74c35114e60 Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Fri, 22 Mar 2024 02:50:38 -0500 Subject: [PATCH 10/21] wip --- test/instances/ezETH/EzETHHyperdrive.t.sol | 726 +++++++++------------ 1 file changed, 309 insertions(+), 417 deletions(-) diff --git a/test/instances/ezETH/EzETHHyperdrive.t.sol b/test/instances/ezETH/EzETHHyperdrive.t.sol index dc7bfc697..2f7ca105e 100644 --- a/test/instances/ezETH/EzETHHyperdrive.t.sol +++ b/test/instances/ezETH/EzETHHyperdrive.t.sol @@ -21,17 +21,16 @@ import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol" import { HyperdriveMath } from "contracts/src/libraries/HyperdriveMath.sol"; import { ERC20ForwarderFactory } from "contracts/src/token/ERC20ForwarderFactory.sol"; import { ERC20Mintable } from "contracts/test/ERC20Mintable.sol"; -import { HyperdriveTest } from "test/utils/HyperdriveTest.sol"; +import { IntegrationTest } from "test/utils/IntegrationTest.sol"; import { HyperdriveUtils } from "test/utils/HyperdriveUtils.sol"; import { Lib } from "test/utils/Lib.sol"; +import "forge-std/console.sol"; -contract EzETHHyperdriveTest is HyperdriveTest { +contract EzETHHyperdriveTest is IntegrationTest { using FixedPointMath for uint256; using Lib for *; using stdStorage for StdStorage; - uint256 internal constant FIXED_RATE = 0.05e18; - // The Renzo main entrypoint contract to stake ETH and receive ezETH. IRestakeManager internal constant RESTAKE_MANAGER = IRestakeManager(0x74a09653A083691711cF8215a6ab074BB4e99ef5); @@ -54,187 +53,80 @@ contract EzETHHyperdriveTest is HyperdriveTest { // mocking. To test with their deployed code we use a shorter position // duration. uint256 internal constant POSITION_DURATION_2_WEEKS = 15 days; - address internal ETH_WHALE = 0x00000000219ab540356cBB839Cbe05303d7705Fa; - address internal EZETH_WHALE = 0x40C0d1fbcB0A43A62ca7A241E7A42ca58EeF96eb; uint256 internal constant STARTING_BLOCK = 19119544; - HyperdriveFactory factory; - address deployerCoordinator; - - function setUp() public override __mainnet_fork(STARTING_BLOCK) { - super.setUp(); + // Whale accounts. + address internal EZETH_WHALE = 0x40C0d1fbcB0A43A62ca7A241E7A42ca58EeF96eb; + address[] internal whaleAccounts = [EZETH_WHALE]; - // Fund the test accounts with ezETH and ETH. - address[] memory accounts = new address[](3); - accounts[0] = alice; - accounts[1] = bob; - accounts[2] = celine; - fundAccounts(address(hyperdrive), IERC20(EZETH), EZETH_WHALE, accounts); - vm.deal(alice, 1_000_000e18); - vm.deal(bob, 1_000_000e18); - vm.deal(celine, 1_000_000e18); - - // Deploy the hyperdrive factory. - vm.startPrank(deployer); - address[] memory defaults = new address[](1); - defaults[0] = bob; - forwarderFactory = new ERC20ForwarderFactory(); - factory = new HyperdriveFactory( - HyperdriveFactory.FactoryConfig({ - governance: alice, - hyperdriveGovernance: bob, - feeCollector: feeCollector, - sweepCollector: sweepCollector, - defaultPausers: defaults, - checkpointDurationResolution: 1 hours, - minCheckpointDuration: 8 hours, - maxCheckpointDuration: 1 days, - minPositionDuration: 7 days, - maxPositionDuration: 10 * 365 days, - minFixedAPR: 0.001e18, - maxFixedAPR: 0.5e18, - minTimeStretchAPR: 0.005e18, - maxTimeStretchAPR: 0.5e18, - minFees: IHyperdrive.Fees({ - curve: 0, - flat: 0, - governanceLP: 0, - governanceZombie: 0 - }), - maxFees: IHyperdrive.Fees({ - curve: ONE, - flat: ONE, - governanceLP: ONE, - governanceZombie: ONE - }), - linkerFactory: address(forwarderFactory), - linkerCodeHash: forwarderFactory.ERC20LINK_HASH() - }) + // The configuration for the integration testing suite. + IntegrationConfig internal __testConfig = + IntegrationConfig( + whaleAccounts, + IERC20(EZETH), + IERC20(ETH), + 1e6, + 1e15, + POSITION_DURATION_2_WEEKS ); - // Deploy the hyperdrive deployers and register the deployer coordinator - // in the factory. - vm.stopPrank(); - vm.startPrank(alice); - deployerCoordinator = address( - new EzETHHyperdriveDeployerCoordinator( - address(new EzETHHyperdriveCoreDeployer(RESTAKE_MANAGER)), - address(new EzETHTarget0Deployer(RESTAKE_MANAGER)), - address(new EzETHTarget1Deployer(RESTAKE_MANAGER)), - address(new EzETHTarget2Deployer(RESTAKE_MANAGER)), - address(new EzETHTarget3Deployer(RESTAKE_MANAGER)), - address(new EzETHTarget4Deployer(RESTAKE_MANAGER)), - RESTAKE_MANAGER - ) - ); - factory.addDeployerCoordinator(address(deployerCoordinator)); - - // Alice deploys the hyperdrive instance. - IHyperdrive.PoolDeployConfig memory config = IHyperdrive - .PoolDeployConfig({ - baseToken: IERC20(ETH), - linkerFactory: factory.linkerFactory(), - linkerCodeHash: factory.linkerCodeHash(), - minimumShareReserves: 1e15, - minimumTransactionAmount: 1e15, - positionDuration: POSITION_DURATION_2_WEEKS, - checkpointDuration: CHECKPOINT_DURATION, - timeStretch: 0, - governance: factory.hyperdriveGovernance(), - feeCollector: factory.feeCollector(), - sweepCollector: factory.sweepCollector(), - fees: IHyperdrive.Fees({ - curve: 0, - flat: 0, - governanceLP: 0, - governanceZombie: 0 - }) - }); - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 0, - bytes32(uint256(0xdeadbabe)) - ); - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 1, - bytes32(uint256(0xdeadbabe)) - ); - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 2, - bytes32(uint256(0xdeadbabe)) - ); - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 3, - bytes32(uint256(0xdeadbabe)) - ); - factory.deployTarget( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 4, - bytes32(uint256(0xdeadbabe)) - ); + constructor() IntegrationTest(__testConfig) {} + function setUp() public override __mainnet_fork(STARTING_BLOCK) { // Depositing with ETH is not allowed for this pool so we need to get // some ezETH for alice first. - uint256 contribution = 10_000e18; - RESTAKE_MANAGER.depositETH{ value: 2 * contribution }(); - EZETH.approve(deployerCoordinator, contribution); - - hyperdrive = factory.deployAndInitialize( - bytes32(uint256(0xdeadbeef)), - deployerCoordinator, - config, - new bytes(0), - contribution, - FIXED_RATE, - FIXED_RATE, - IHyperdrive.Options({ - asBase: false, - destination: alice, - extraData: new bytes(0) - }), - bytes32(uint256(0xdeadbabe)) - ); + vm.startPrank(EZETH_WHALE); - // Ensure that Alice received the correct amount of LP tokens. She should - // receive LP shares totaling the amount of shares that she contributed - // minus the shares set aside for the minimum share reserves and the - // zero address's initial LP contribution. - assertApproxEqAbs( - hyperdrive.balanceOf(AssetId._LP_ASSET_ID, alice), - contribution - 2 * hyperdrive.getPoolConfig().minimumShareReserves, - 1e6 + vm.deal(EZETH_WHALE, 50_000e18); + RESTAKE_MANAGER.depositETH{ value: 40_000e18 }(); + vm.stopPrank(); + + super.setUp(); + } + + /// Overrides /// + + /// @dev Fetches share price information about EzETH. + function getProtocolSharePrice() + internal + view + override + returns (uint256, uint256, uint256) + { + // Get the total TVL priced in ETH from restakeManager. + (, , uint256 totalTVL) = RESTAKE_MANAGER.calculateTVLs(); + + // Get the total supply of the ezETH token. + uint256 totalSupply = EZETH.totalSupply(); + + // Calculate the share price. + uint256 sharePrice = RENZO_ORACLE.calculateRedeemAmount( + ONE, + totalSupply, + totalTVL ); - // Start recording event logs. - vm.recordLogs(); + return (totalTVL, totalSupply, sharePrice); + } + + /// @dev Initializing the market with the ETH is not supported. + function test__deployAndInitialize__asBase() external override {} + + /// @dev Deploys the EzETH deployer coordinator contract. + function deployCoordinator() internal override returns (address) { + vm.startPrank(alice); + return + address( + new EzETHHyperdriveDeployerCoordinator( + address(new EzETHHyperdriveCoreDeployer(RESTAKE_MANAGER)), + address(new EzETHTarget0Deployer(RESTAKE_MANAGER)), + address(new EzETHTarget1Deployer(RESTAKE_MANAGER)), + address(new EzETHTarget2Deployer(RESTAKE_MANAGER)), + address(new EzETHTarget3Deployer(RESTAKE_MANAGER)), + address(new EzETHTarget4Deployer(RESTAKE_MANAGER)), + RESTAKE_MANAGER + ) + ); } /// Getters /// @@ -256,249 +148,249 @@ contract EzETHHyperdriveTest is HyperdriveTest { /// Deploy and Initialize /// - function test__eth_deployAndInitialize() external { - // Deploy and Initialize the ezETH hyperdrive instance. - vm.stopPrank(); - vm.startPrank(bob); - - // Make sure bob has enough funds. - uint256 contribution = 5_000e18; - RESTAKE_MANAGER.depositETH{ value: 2 * contribution }(); - EZETH.approve(deployerCoordinator, contribution); - - IHyperdrive.PoolDeployConfig memory config = IHyperdrive - .PoolDeployConfig({ - baseToken: IERC20(ETH), - governance: factory.hyperdriveGovernance(), - feeCollector: factory.feeCollector(), - sweepCollector: factory.sweepCollector(), - linkerFactory: factory.linkerFactory(), - linkerCodeHash: factory.linkerCodeHash(), - minimumShareReserves: 1e15, - minimumTransactionAmount: 1e15, - positionDuration: POSITION_DURATION_2_WEEKS, - checkpointDuration: CHECKPOINT_DURATION, - timeStretch: 0, - fees: IHyperdrive.Fees({ - curve: 0, - flat: 0, - governanceLP: 0, - governanceZombie: 0 - }) - }); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 0, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 1, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 2, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 3, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 4, - bytes32(uint256(0xdeadfade)) - ); - - // Ensure that using base to deploy and initialize is not allowed. - vm.expectRevert(IHyperdrive.NotPayable.selector); - hyperdrive = factory.deployAndInitialize{ value: contribution + 1e18 }( - bytes32(uint256(0xbeefbabe)), - address(deployerCoordinator), - config, - new bytes(0), - contribution, - FIXED_RATE, - FIXED_RATE, - IHyperdrive.Options({ - asBase: true, - destination: bob, - extraData: new bytes(0) - }), - bytes32(uint256(0xdeadfade)) - ); - } - - function test__ezeth_deployAndInitialize() external { - // Deploy and Initialize the ezETH hyperdrive instance. - vm.stopPrank(); - vm.startPrank(bob); - - // Make sure bob has enough funds. - uint256 contribution = 5_000e18; - RESTAKE_MANAGER.depositETH{ value: 2 * contribution }(); - EZETH.approve(deployerCoordinator, contribution); - - // Get balance information. - uint256 bobBalanceBefore = address(bob).balance; - uint256 bobEzETHBalanceBefore = EZETH.balanceOf(address(bob)); - - IHyperdrive.PoolDeployConfig memory config = IHyperdrive - .PoolDeployConfig({ - baseToken: IERC20(ETH), - governance: factory.hyperdriveGovernance(), - feeCollector: factory.feeCollector(), - sweepCollector: factory.sweepCollector(), - linkerFactory: factory.linkerFactory(), - linkerCodeHash: factory.linkerCodeHash(), - minimumShareReserves: 1e15, - minimumTransactionAmount: 1e15, - positionDuration: POSITION_DURATION_2_WEEKS, - checkpointDuration: CHECKPOINT_DURATION, - timeStretch: 0, - fees: IHyperdrive.Fees({ - curve: 0, - flat: 0, - governanceLP: 0, - governanceZombie: 0 - }) - }); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 0, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 1, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 2, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 3, - bytes32(uint256(0xdeadfade)) - ); - factory.deployTarget( - bytes32(uint256(0xbeefbabe)), - deployerCoordinator, - config, - new bytes(0), - FIXED_RATE, - FIXED_RATE, - 4, - bytes32(uint256(0xdeadfade)) - ); - - // Deploy the pool. - hyperdrive = factory.deployAndInitialize( - bytes32(uint256(0xbeefbabe)), - address(deployerCoordinator), - config, - new bytes(0), - contribution, - FIXED_RATE, - FIXED_RATE, - IHyperdrive.Options({ - asBase: false, - destination: bob, - extraData: new bytes(0) - }), - bytes32(uint256(0xdeadfade)) - ); - - // Ensure eth and ezEth balances are correct. - assertEq(address(bob).balance, bobBalanceBefore); - assertEq( - EZETH.balanceOf(address(bob)), - bobEzETHBalanceBefore - contribution - ); - - // Ensure that the decimals are set correctly. - assertEq(hyperdrive.decimals(), 18); - - // Ensure that Bob received the correct amount of LP tokens. He should - // receive LP shares totaling the amount of shares that he contributed - // minus the shares set aside for the minimum share reserves and the - // zero address's initial LP contribution. - assertApproxEqAbs( - hyperdrive.balanceOf(AssetId._LP_ASSET_ID, bob), - contribution - 2 * hyperdrive.getPoolConfig().minimumShareReserves, - 1e5 - ); - - // Ensure that the share reserves and LP total supply are equal and correct. - assertEq(hyperdrive.getPoolInfo().shareReserves, contribution); - assertEq( - hyperdrive.getPoolInfo().lpTotalSupply, - hyperdrive.getPoolInfo().shareReserves - config.minimumShareReserves - ); - - // Verify that the correct events were emitted. - verifyFactoryEvents( - deployerCoordinator, - hyperdrive, - bob, - contribution, - FIXED_RATE, - false, - config.minimumShareReserves, - new bytes(0), - // NOTE: Tolerance since ezETH uses mulDivDown for share calculations. - 1e5 - ); - } + // function test__eth_deployAndInitialize() external { + // // Deploy and Initialize the ezETH hyperdrive instance. + // vm.stopPrank(); + // vm.startPrank(bob); + + // // Make sure bob has enough funds. + // uint256 contribution = 5_000e18; + // RESTAKE_MANAGER.depositETH{ value: 2 * contribution }(); + // EZETH.approve(deployerCoordinator, contribution); + + // IHyperdrive.PoolDeployConfig memory config = IHyperdrive + // .PoolDeployConfig({ + // baseToken: IERC20(ETH), + // governance: factory.hyperdriveGovernance(), + // feeCollector: factory.feeCollector(), + // sweepCollector: factory.sweepCollector(), + // linkerFactory: factory.linkerFactory(), + // linkerCodeHash: factory.linkerCodeHash(), + // minimumShareReserves: 1e15, + // minimumTransactionAmount: 1e15, + // positionDuration: POSITION_DURATION_2_WEEKS, + // checkpointDuration: CHECKPOINT_DURATION, + // timeStretch: 0, + // fees: IHyperdrive.Fees({ + // curve: 0, + // flat: 0, + // governanceLP: 0, + // governanceZombie: 0 + // }) + // }); + // factory.deployTarget( + // bytes32(uint256(0xbeefbabe)), + // deployerCoordinator, + // config, + // new bytes(0), + // FIXED_RATE, + // FIXED_RATE, + // 0, + // bytes32(uint256(0xdeadfade)) + // ); + // factory.deployTarget( + // bytes32(uint256(0xbeefbabe)), + // deployerCoordinator, + // config, + // new bytes(0), + // FIXED_RATE, + // FIXED_RATE, + // 1, + // bytes32(uint256(0xdeadfade)) + // ); + // factory.deployTarget( + // bytes32(uint256(0xbeefbabe)), + // deployerCoordinator, + // config, + // new bytes(0), + // FIXED_RATE, + // FIXED_RATE, + // 2, + // bytes32(uint256(0xdeadfade)) + // ); + // factory.deployTarget( + // bytes32(uint256(0xbeefbabe)), + // deployerCoordinator, + // config, + // new bytes(0), + // FIXED_RATE, + // FIXED_RATE, + // 3, + // bytes32(uint256(0xdeadfade)) + // ); + // factory.deployTarget( + // bytes32(uint256(0xbeefbabe)), + // deployerCoordinator, + // config, + // new bytes(0), + // FIXED_RATE, + // FIXED_RATE, + // 4, + // bytes32(uint256(0xdeadfade)) + // ); + + // // Ensure that using base to deploy and initialize is not allowed. + // vm.expectRevert(IHyperdrive.NotPayable.selector); + // hyperdrive = factory.deployAndInitialize{ value: contribution + 1e18 }( + // bytes32(uint256(0xbeefbabe)), + // address(deployerCoordinator), + // config, + // new bytes(0), + // contribution, + // FIXED_RATE, + // FIXED_RATE, + // IHyperdrive.Options({ + // asBase: true, + // destination: bob, + // extraData: new bytes(0) + // }), + // bytes32(uint256(0xdeadfade)) + // ); + // } + + // function test__ezeth_deployAndInitialize() external { + // // Deploy and Initialize the ezETH hyperdrive instance. + // vm.stopPrank(); + // vm.startPrank(bob); + + // // Make sure bob has enough funds. + // uint256 contribution = 5_000e18; + // RESTAKE_MANAGER.depositETH{ value: 2 * contribution }(); + // EZETH.approve(deployerCoordinator, contribution); + + // // Get balance information. + // uint256 bobBalanceBefore = address(bob).balance; + // uint256 bobEzETHBalanceBefore = EZETH.balanceOf(address(bob)); + + // IHyperdrive.PoolDeployConfig memory config = IHyperdrive + // .PoolDeployConfig({ + // baseToken: IERC20(ETH), + // governance: factory.hyperdriveGovernance(), + // feeCollector: factory.feeCollector(), + // sweepCollector: factory.sweepCollector(), + // linkerFactory: factory.linkerFactory(), + // linkerCodeHash: factory.linkerCodeHash(), + // minimumShareReserves: 1e15, + // minimumTransactionAmount: 1e15, + // positionDuration: POSITION_DURATION_2_WEEKS, + // checkpointDuration: CHECKPOINT_DURATION, + // timeStretch: 0, + // fees: IHyperdrive.Fees({ + // curve: 0, + // flat: 0, + // governanceLP: 0, + // governanceZombie: 0 + // }) + // }); + // factory.deployTarget( + // bytes32(uint256(0xbeefbabe)), + // deployerCoordinator, + // config, + // new bytes(0), + // FIXED_RATE, + // FIXED_RATE, + // 0, + // bytes32(uint256(0xdeadfade)) + // ); + // factory.deployTarget( + // bytes32(uint256(0xbeefbabe)), + // deployerCoordinator, + // config, + // new bytes(0), + // FIXED_RATE, + // FIXED_RATE, + // 1, + // bytes32(uint256(0xdeadfade)) + // ); + // factory.deployTarget( + // bytes32(uint256(0xbeefbabe)), + // deployerCoordinator, + // config, + // new bytes(0), + // FIXED_RATE, + // FIXED_RATE, + // 2, + // bytes32(uint256(0xdeadfade)) + // ); + // factory.deployTarget( + // bytes32(uint256(0xbeefbabe)), + // deployerCoordinator, + // config, + // new bytes(0), + // FIXED_RATE, + // FIXED_RATE, + // 3, + // bytes32(uint256(0xdeadfade)) + // ); + // factory.deployTarget( + // bytes32(uint256(0xbeefbabe)), + // deployerCoordinator, + // config, + // new bytes(0), + // FIXED_RATE, + // FIXED_RATE, + // 4, + // bytes32(uint256(0xdeadfade)) + // ); + + // // Deploy the pool. + // hyperdrive = factory.deployAndInitialize( + // bytes32(uint256(0xbeefbabe)), + // address(deployerCoordinator), + // config, + // new bytes(0), + // contribution, + // FIXED_RATE, + // FIXED_RATE, + // IHyperdrive.Options({ + // asBase: false, + // destination: bob, + // extraData: new bytes(0) + // }), + // bytes32(uint256(0xdeadfade)) + // ); + + // // Ensure eth and ezEth balances are correct. + // assertEq(address(bob).balance, bobBalanceBefore); + // assertEq( + // EZETH.balanceOf(address(bob)), + // bobEzETHBalanceBefore - contribution + // ); + + // // Ensure that the decimals are set correctly. + // assertEq(hyperdrive.decimals(), 18); + + // // Ensure that Bob received the correct amount of LP tokens. He should + // // receive LP shares totaling the amount of shares that he contributed + // // minus the shares set aside for the minimum share reserves and the + // // zero address's initial LP contribution. + // assertApproxEqAbs( + // hyperdrive.balanceOf(AssetId._LP_ASSET_ID, bob), + // contribution - 2 * hyperdrive.getPoolConfig().minimumShareReserves, + // 1e5 + // ); + + // // Ensure that the share reserves and LP total supply are equal and correct. + // assertEq(hyperdrive.getPoolInfo().shareReserves, contribution); + // assertEq( + // hyperdrive.getPoolInfo().lpTotalSupply, + // hyperdrive.getPoolInfo().shareReserves - config.minimumShareReserves + // ); + + // // Verify that the correct events were emitted. + // verifyFactoryEvents( + // deployerCoordinator, + // hyperdrive, + // bob, + // contribution, + // FIXED_RATE, + // false, + // config.minimumShareReserves, + // new bytes(0), + // // NOTE: Tolerance since ezETH uses mulDivDown for share calculations. + // 1e5 + // ); + // } function test__ezeth_interest_and_advance_time() external { // hand calculated value sanity check From cfc42a68653ea936e4626c422620c7ffe1c04552 Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Fri, 22 Mar 2024 13:37:54 -0500 Subject: [PATCH 11/21] useful make command --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile b/Makefile index 4063cef3a..f604ab5b4 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,9 @@ SOLIDITY_ZOMBIE_TESTS = ZombieInterestTest test: make test-sol && make test-rust +test-instances: + forge test -vv --match-path test/instances/*.t.sol + test-sol-core: forge test -vv --no-match-contract "$(SOLIDITY_LP_WITHDRAWAL_TESTS)|$(SOLIDITY_NETTING_TESTS)|$(SOLIDITY_ZOMBIE_TESTS)" @@ -37,6 +40,8 @@ test-sol-netting: test-sol-zombie: forge test -vv --match-contract "$(SOLIDITY_ZOMBIE_TESTS)" + + test-rust: cargo test --workspace --exclude hyperdrive-math && \ cargo test --package hyperdrive-math -- --test-threads=1 From dc139e98cc9936ce4b7bd05816a286e05514a8d0 Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Fri, 22 Mar 2024 13:38:17 -0500 Subject: [PATCH 12/21] ezeth - remove comment blocks up and error --- test/instances/ezETH/EzETHHyperdrive.t.sol | 248 +-------------------- 1 file changed, 1 insertion(+), 247 deletions(-) diff --git a/test/instances/ezETH/EzETHHyperdrive.t.sol b/test/instances/ezETH/EzETHHyperdrive.t.sol index 2f7ca105e..60757c0be 100644 --- a/test/instances/ezETH/EzETHHyperdrive.t.sol +++ b/test/instances/ezETH/EzETHHyperdrive.t.sol @@ -146,252 +146,6 @@ contract EzETHHyperdriveTest is IntegrationTest { ); } - /// Deploy and Initialize /// - - // function test__eth_deployAndInitialize() external { - // // Deploy and Initialize the ezETH hyperdrive instance. - // vm.stopPrank(); - // vm.startPrank(bob); - - // // Make sure bob has enough funds. - // uint256 contribution = 5_000e18; - // RESTAKE_MANAGER.depositETH{ value: 2 * contribution }(); - // EZETH.approve(deployerCoordinator, contribution); - - // IHyperdrive.PoolDeployConfig memory config = IHyperdrive - // .PoolDeployConfig({ - // baseToken: IERC20(ETH), - // governance: factory.hyperdriveGovernance(), - // feeCollector: factory.feeCollector(), - // sweepCollector: factory.sweepCollector(), - // linkerFactory: factory.linkerFactory(), - // linkerCodeHash: factory.linkerCodeHash(), - // minimumShareReserves: 1e15, - // minimumTransactionAmount: 1e15, - // positionDuration: POSITION_DURATION_2_WEEKS, - // checkpointDuration: CHECKPOINT_DURATION, - // timeStretch: 0, - // fees: IHyperdrive.Fees({ - // curve: 0, - // flat: 0, - // governanceLP: 0, - // governanceZombie: 0 - // }) - // }); - // factory.deployTarget( - // bytes32(uint256(0xbeefbabe)), - // deployerCoordinator, - // config, - // new bytes(0), - // FIXED_RATE, - // FIXED_RATE, - // 0, - // bytes32(uint256(0xdeadfade)) - // ); - // factory.deployTarget( - // bytes32(uint256(0xbeefbabe)), - // deployerCoordinator, - // config, - // new bytes(0), - // FIXED_RATE, - // FIXED_RATE, - // 1, - // bytes32(uint256(0xdeadfade)) - // ); - // factory.deployTarget( - // bytes32(uint256(0xbeefbabe)), - // deployerCoordinator, - // config, - // new bytes(0), - // FIXED_RATE, - // FIXED_RATE, - // 2, - // bytes32(uint256(0xdeadfade)) - // ); - // factory.deployTarget( - // bytes32(uint256(0xbeefbabe)), - // deployerCoordinator, - // config, - // new bytes(0), - // FIXED_RATE, - // FIXED_RATE, - // 3, - // bytes32(uint256(0xdeadfade)) - // ); - // factory.deployTarget( - // bytes32(uint256(0xbeefbabe)), - // deployerCoordinator, - // config, - // new bytes(0), - // FIXED_RATE, - // FIXED_RATE, - // 4, - // bytes32(uint256(0xdeadfade)) - // ); - - // // Ensure that using base to deploy and initialize is not allowed. - // vm.expectRevert(IHyperdrive.NotPayable.selector); - // hyperdrive = factory.deployAndInitialize{ value: contribution + 1e18 }( - // bytes32(uint256(0xbeefbabe)), - // address(deployerCoordinator), - // config, - // new bytes(0), - // contribution, - // FIXED_RATE, - // FIXED_RATE, - // IHyperdrive.Options({ - // asBase: true, - // destination: bob, - // extraData: new bytes(0) - // }), - // bytes32(uint256(0xdeadfade)) - // ); - // } - - // function test__ezeth_deployAndInitialize() external { - // // Deploy and Initialize the ezETH hyperdrive instance. - // vm.stopPrank(); - // vm.startPrank(bob); - - // // Make sure bob has enough funds. - // uint256 contribution = 5_000e18; - // RESTAKE_MANAGER.depositETH{ value: 2 * contribution }(); - // EZETH.approve(deployerCoordinator, contribution); - - // // Get balance information. - // uint256 bobBalanceBefore = address(bob).balance; - // uint256 bobEzETHBalanceBefore = EZETH.balanceOf(address(bob)); - - // IHyperdrive.PoolDeployConfig memory config = IHyperdrive - // .PoolDeployConfig({ - // baseToken: IERC20(ETH), - // governance: factory.hyperdriveGovernance(), - // feeCollector: factory.feeCollector(), - // sweepCollector: factory.sweepCollector(), - // linkerFactory: factory.linkerFactory(), - // linkerCodeHash: factory.linkerCodeHash(), - // minimumShareReserves: 1e15, - // minimumTransactionAmount: 1e15, - // positionDuration: POSITION_DURATION_2_WEEKS, - // checkpointDuration: CHECKPOINT_DURATION, - // timeStretch: 0, - // fees: IHyperdrive.Fees({ - // curve: 0, - // flat: 0, - // governanceLP: 0, - // governanceZombie: 0 - // }) - // }); - // factory.deployTarget( - // bytes32(uint256(0xbeefbabe)), - // deployerCoordinator, - // config, - // new bytes(0), - // FIXED_RATE, - // FIXED_RATE, - // 0, - // bytes32(uint256(0xdeadfade)) - // ); - // factory.deployTarget( - // bytes32(uint256(0xbeefbabe)), - // deployerCoordinator, - // config, - // new bytes(0), - // FIXED_RATE, - // FIXED_RATE, - // 1, - // bytes32(uint256(0xdeadfade)) - // ); - // factory.deployTarget( - // bytes32(uint256(0xbeefbabe)), - // deployerCoordinator, - // config, - // new bytes(0), - // FIXED_RATE, - // FIXED_RATE, - // 2, - // bytes32(uint256(0xdeadfade)) - // ); - // factory.deployTarget( - // bytes32(uint256(0xbeefbabe)), - // deployerCoordinator, - // config, - // new bytes(0), - // FIXED_RATE, - // FIXED_RATE, - // 3, - // bytes32(uint256(0xdeadfade)) - // ); - // factory.deployTarget( - // bytes32(uint256(0xbeefbabe)), - // deployerCoordinator, - // config, - // new bytes(0), - // FIXED_RATE, - // FIXED_RATE, - // 4, - // bytes32(uint256(0xdeadfade)) - // ); - - // // Deploy the pool. - // hyperdrive = factory.deployAndInitialize( - // bytes32(uint256(0xbeefbabe)), - // address(deployerCoordinator), - // config, - // new bytes(0), - // contribution, - // FIXED_RATE, - // FIXED_RATE, - // IHyperdrive.Options({ - // asBase: false, - // destination: bob, - // extraData: new bytes(0) - // }), - // bytes32(uint256(0xdeadfade)) - // ); - - // // Ensure eth and ezEth balances are correct. - // assertEq(address(bob).balance, bobBalanceBefore); - // assertEq( - // EZETH.balanceOf(address(bob)), - // bobEzETHBalanceBefore - contribution - // ); - - // // Ensure that the decimals are set correctly. - // assertEq(hyperdrive.decimals(), 18); - - // // Ensure that Bob received the correct amount of LP tokens. He should - // // receive LP shares totaling the amount of shares that he contributed - // // minus the shares set aside for the minimum share reserves and the - // // zero address's initial LP contribution. - // assertApproxEqAbs( - // hyperdrive.balanceOf(AssetId._LP_ASSET_ID, bob), - // contribution - 2 * hyperdrive.getPoolConfig().minimumShareReserves, - // 1e5 - // ); - - // // Ensure that the share reserves and LP total supply are equal and correct. - // assertEq(hyperdrive.getPoolInfo().shareReserves, contribution); - // assertEq( - // hyperdrive.getPoolInfo().lpTotalSupply, - // hyperdrive.getPoolInfo().shareReserves - config.minimumShareReserves - // ); - - // // Verify that the correct events were emitted. - // verifyFactoryEvents( - // deployerCoordinator, - // hyperdrive, - // bob, - // contribution, - // FIXED_RATE, - // false, - // config.minimumShareReserves, - // new bytes(0), - // // NOTE: Tolerance since ezETH uses mulDivDown for share calculations. - // 1e5 - // ); - // } - function test__ezeth_interest_and_advance_time() external { // hand calculated value sanity check uint256 positionAdjustedInterestRate = uint256(0.05e18).mulDivDown( @@ -852,7 +606,7 @@ contract EzETHHyperdriveTest is IntegrationTest { totalShares ); assertLe(baseProceeds, expectedBaseProceeds + 1e4); - assertApproxEqAbs(baseProceeds, expectedBaseProceeds, 1e5); + assertApproxEqAbs(baseProceeds, expectedBaseProceeds, 1e6); // Ensure that Lido's aggregates and the token balances were updated // correctly during the trade. From 83e8ace4c574c6a0f8e6d3e55fd0de591695fbed Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Fri, 22 Mar 2024 14:49:42 -0500 Subject: [PATCH 13/21] Added flag for disabled base deposits and natspec for IntegrationTest --- Makefile | 2 - test/instances/ezETH/EzETHHyperdrive.t.sol | 7 +- test/instances/lseth/LsETHHyperdrive.t.sol | 6 +- test/instances/reth/RETHHyperdrive.t.sol | 6 +- test/instances/steth/StETHHyperdrive.t.sol | 3 +- test/utils/IntegrationTest.sol | 271 ++++++++++++--------- 6 files changed, 170 insertions(+), 125 deletions(-) diff --git a/Makefile b/Makefile index f604ab5b4..07f8a7017 100644 --- a/Makefile +++ b/Makefile @@ -40,8 +40,6 @@ test-sol-netting: test-sol-zombie: forge test -vv --match-contract "$(SOLIDITY_ZOMBIE_TESTS)" - - test-rust: cargo test --workspace --exclude hyperdrive-math && \ cargo test --package hyperdrive-math -- --test-threads=1 diff --git a/test/instances/ezETH/EzETHHyperdrive.t.sol b/test/instances/ezETH/EzETHHyperdrive.t.sol index 60757c0be..f65da2b0b 100644 --- a/test/instances/ezETH/EzETHHyperdrive.t.sol +++ b/test/instances/ezETH/EzETHHyperdrive.t.sol @@ -24,7 +24,6 @@ import { ERC20Mintable } from "contracts/test/ERC20Mintable.sol"; import { IntegrationTest } from "test/utils/IntegrationTest.sol"; import { HyperdriveUtils } from "test/utils/HyperdriveUtils.sol"; import { Lib } from "test/utils/Lib.sol"; -import "forge-std/console.sol"; contract EzETHHyperdriveTest is IntegrationTest { using FixedPointMath for uint256; @@ -67,7 +66,8 @@ contract EzETHHyperdriveTest is IntegrationTest { IERC20(ETH), 1e6, 1e15, - POSITION_DURATION_2_WEEKS + POSITION_DURATION_2_WEEKS, + false ); constructor() IntegrationTest(__testConfig) {} @@ -109,9 +109,6 @@ contract EzETHHyperdriveTest is IntegrationTest { return (totalTVL, totalSupply, sharePrice); } - /// @dev Initializing the market with the ETH is not supported. - function test__deployAndInitialize__asBase() external override {} - /// @dev Deploys the EzETH deployer coordinator contract. function deployCoordinator() internal override returns (address) { vm.startPrank(alice); diff --git a/test/instances/lseth/LsETHHyperdrive.t.sol b/test/instances/lseth/LsETHHyperdrive.t.sol index 0688997b4..3e5d9c868 100644 --- a/test/instances/lseth/LsETHHyperdrive.t.sol +++ b/test/instances/lseth/LsETHHyperdrive.t.sol @@ -54,7 +54,8 @@ contract LsETHHyperdriveTest is IntegrationTest { IERC20(ETH), 0, 1e15, - POSITION_DURATION + POSITION_DURATION, + false ); constructor() IntegrationTest(__testConfig) {} @@ -96,9 +97,6 @@ contract LsETHHyperdriveTest is IntegrationTest { ); } - /// @dev Initializing the market with the ETH is not supported. - function test__deployAndInitialize__asBase() external override {} - /// Getters /// function test_getters() external { diff --git a/test/instances/reth/RETHHyperdrive.t.sol b/test/instances/reth/RETHHyperdrive.t.sol index 58c0424e5..9b2593967 100644 --- a/test/instances/reth/RETHHyperdrive.t.sol +++ b/test/instances/reth/RETHHyperdrive.t.sol @@ -57,7 +57,8 @@ contract RETHHyperdriveTest is IntegrationTest { IERC20(ETH), 0, 1e16, - POSITION_DURATION + POSITION_DURATION, + false ); constructor() IntegrationTest(__testConfig) {} @@ -84,9 +85,6 @@ contract RETHHyperdriveTest is IntegrationTest { ); } - /// @dev Initializing the market with the ETH is not supported. - function test__deployAndInitialize__asBase() external override {} - /// @dev Deploys the rETH deployer coordinator contract. function deployCoordinator() internal override returns (address) { vm.startPrank(alice); diff --git a/test/instances/steth/StETHHyperdrive.t.sol b/test/instances/steth/StETHHyperdrive.t.sol index 528d6aa00..c112470a1 100644 --- a/test/instances/steth/StETHHyperdrive.t.sol +++ b/test/instances/steth/StETHHyperdrive.t.sol @@ -49,7 +49,8 @@ contract StETHHyperdriveTest is IntegrationTest { IERC20(ETH), 1e5, 1e15, - POSITION_DURATION + POSITION_DURATION, + true ); constructor() IntegrationTest(__testConfig) {} diff --git a/test/utils/IntegrationTest.sol b/test/utils/IntegrationTest.sol index 9fae04a77..a98fd1928 100644 --- a/test/utils/IntegrationTest.sol +++ b/test/utils/IntegrationTest.sol @@ -3,27 +3,34 @@ pragma solidity 0.8.20; import { ERC20ForwarderFactory } from "contracts/src/token/ERC20ForwarderFactory.sol"; import { HyperdriveFactory } from "contracts/src/factory/HyperdriveFactory.sol"; -import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; - -import { AssetId } from "contracts/src/libraries/AssetId.sol"; -import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; - -import { Lib } from "test/utils/Lib.sol"; -import { HyperdriveTest } from "test/utils/HyperdriveTest.sol"; import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; +import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; +import { AssetId } from "contracts/src/libraries/AssetId.sol"; import { ETH } from "contracts/src/libraries/Constants.sol"; - +import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; +import { HyperdriveTest } from "test/utils/HyperdriveTest.sol"; import { HyperdriveUtils } from "test/utils/HyperdriveUtils.sol"; -import "forge-std/console.sol"; +import { Lib } from "test/utils/Lib.sol"; +/// @author DELV +/// @title IntegrationTest +/// @notice The base contract for the integration testing suite. +/// @dev A testing suite that provides a foundation to setup, deploy, and +/// test common cases for Hyperdrive instances. +/// @custom:disclaimer The language used in this code is for coding convenience +/// only, and is not intended to, and does not, have any +/// particular legal or regulatory significance. abstract contract IntegrationTest is HyperdriveTest { using Lib for *; using FixedPointMath for uint256; + // Fixed rate used to configure market. uint256 internal constant FIXED_RATE = 0.05e18; + // ETH whale account. address internal ETH_WHALE = 0x00000000219ab540356cBB839Cbe05303d7705Fa; + /// @dev Configuration for the Integration testing suite. struct IntegrationConfig { address[] whaleAccounts; IERC20 token; @@ -31,33 +38,34 @@ abstract contract IntegrationTest is HyperdriveTest { uint256 shareTolerance; uint256 minTransactionAmount; uint256 positionDuration; + bool enableBaseDeposits; } IntegrationConfig internal config; - + IHyperdrive.PoolDeployConfig internal poolConfig; HyperdriveFactory factory; address deployerCoordinator; - - IHyperdrive.PoolDeployConfig internal poolConfig; - bool internal immutable isBaseETH; + /// @dev Constructor for the Integration testing suite. + /// @param _config The Integration configuration. constructor(IntegrationConfig storage _config) { config = _config; - isBaseETH = config.baseToken == IERC20(ETH); } + /// @notice Forge setup function. + /// @dev Inherits from HyperdriveTest and deploys the + /// Hyperdrive factory, deployer coordinator, and targets. function setUp() public virtual override { super.setUp(); - // _beforeSetUp(); - - // Fund Accounts + // Fund accounts with ETH and token from whales. + vm.deal(alice, 100_000e18); + vm.deal(bob, 100_000e18); address[] memory accounts = new address[](2); accounts[0] = alice; accounts[1] = bob; - // accounts[2] = celine; for (uint256 i = 0; i < config.whaleAccounts.length; i++) { fundAccounts( address(hyperdrive), @@ -66,46 +74,42 @@ abstract contract IntegrationTest is HyperdriveTest { accounts ); } - vm.deal(alice, 100_000e18); - vm.deal(bob, 100_000e18); - // vm.deal(celine, 20_000e18); - // console.logString("here1"); - // console.logUint(config.token.balanceOf(alice)); - - // _afterSetup(); + // Deploy the Hyperdrive Factory contract. deployFactory(); + + // Set the deployer coordinator address and add to the factory. deployerCoordinator = deployCoordinator(); factory.addDeployerCoordinator(deployerCoordinator); + // Deploy all Hyperdrive targets using deployer coordinator contract. deployTargets( - // alice, - bytes32(uint256(0xdeadbeef)), - bytes32(uint256(0xdeadbabe)), - 5_000e18, - false + bytes32(uint256(0xdeadbeef)), // Deployment Id + bytes32(uint256(0xdeadbabe)), // Deployment Salt + 5_000e18, // Contribution + false // asBase ); // Start recording event logs. vm.recordLogs(); } - // function isBaseETH() internal returns (bool) { - // return asBase && config.baseToken; - // } - + /// @dev Deploys all Hyperdrive contracts using the + /// deployer coordinator contract. + /// @param deploymentId The deployment id. + /// @param deploymentSalt The deployment salt for create2. + /// @param contribution The amount to initialize the market. + /// @param asBase Initialize the market with base token. function deployTargets( - // address deployer, bytes32 deploymentId, bytes32 deploymentSalt, uint256 contribution, bool asBase ) internal { + // Alice is the default deployer. vm.startPrank(alice); - // console.logString("here2"); - // console.logUint(config.token.balanceOf(alice)); - + // Deploy Hyperdrive target contracts. factory.deployTarget( deploymentId, deployerCoordinator, @@ -157,30 +161,45 @@ abstract contract IntegrationTest is HyperdriveTest { deploymentSalt ); + // Alice gives approval to the deployer coordinator + // to fund the market. config.token.approve(deployerCoordinator, 100_000e18); - // asBase && isBaseETH ? contribution : 0 - { - hyperdrive = factory.deployAndInitialize{ - value: asBase && isBaseETH ? contribution : 0 - }( - deploymentId, - deployerCoordinator, - poolConfig, - new bytes(0), - contribution, - FIXED_RATE, - FIXED_RATE, - IHyperdrive.Options({ - asBase: asBase, - destination: alice, - extraData: new bytes(0) - }), - deploymentSalt + // We expect the deployAndInitialize to fail with an + // UnSupported token error if depositing as base is not supported. + // If the base token is ETH we expect a NotPayable error. + if (!config.enableBaseDeposits && asBase) { + vm.expectRevert( + isBaseETH + ? IHyperdrive.NotPayable.selector + : IHyperdrive.UnsupportedToken.selector ); } + + // Deploy and initialize the market. + // If the base token is ETH we pass the + // contribution through the call. + hyperdrive = factory.deployAndInitialize{ + value: asBase && isBaseETH ? contribution : 0 + }( + deploymentId, + deployerCoordinator, + poolConfig, + new bytes(0), + contribution, + FIXED_RATE, + FIXED_RATE, + IHyperdrive.Options({ + asBase: asBase, + destination: alice, + extraData: new bytes(0) + }), + deploymentSalt + ); } + /// @dev Deploys the Hyperdrive Factory contract and + /// sets the default pool configuration. function deployFactory() internal { // Deploy the hyperdrive factory. vm.startPrank(deployer); @@ -241,94 +260,128 @@ abstract contract IntegrationTest is HyperdriveTest { }); } + /// @dev A virtual function that exposes important state + /// about the underlying protocol and token. Not all values + /// will be used depending on the instance. + /// @param baseSupply Amount of base tokens in circulation. + /// @param shareSupply Amount of share tokens in circulation. + /// @param sharePrice Price of of one share in terms of base. function getProtocolSharePrice() internal virtual - returns (uint256, uint256, uint256); + returns (uint256 baseSupply, uint256 shareSupply, uint256 sharePrice); + /// @dev A virtual function that defines the deployer coordinator + /// contract that will be used to deploy all the instance targets. function deployCoordinator() internal virtual returns (address); + /// @dev Test to verify a market can be deployed and initialized funded by the + /// base token. Is expected to revert when base deposits are not supported. function test__deployAndInitialize__asBase() external virtual { uint256 aliceBalanceBefore = address(alice).balance; + + // Contribution in terms of base. uint256 contribution = 5_000e18; + + // Get protocol state information used for calculating correct LP shares. (uint256 totalBase, uint256 totalShare, ) = getProtocolSharePrice(); + + // Contribution in terms of shares. uint256 contributionShares = contribution.mulDivDown( totalShare, totalBase ); + // Deploy all Hyperdrive targets using deployer coordinator contract. + // This function reverts if base deposits are disabled. deployTargets( - bytes32(uint256(0xbeefbabe)), - bytes32(uint256(0xdeadfade)), - contribution, - true - // poolConfig + bytes32(uint256(0xbeefbabe)), // Deployment Id + bytes32(uint256(0xdeadfade)), // Deployment Salt + contribution, // Contribution + true // asBase ); - assertEq(address(alice).balance, aliceBalanceBefore - contribution); - - // Ensure that the decimals are set correctly. - assertEq(hyperdrive.decimals(), 18); - // Ensure that alice received the correct amount of LP tokens. He should - // receive LP shares totaling the amount of shares that he contributed - // minus the shares set aside for the minimum share reserves and the - // zero address's initial LP contribution. - assertApproxEqAbs( - hyperdrive.balanceOf(AssetId._LP_ASSET_ID, alice), - contribution.divDown( - hyperdrive.getPoolConfig().initialVaultSharePrice - ) - 2 * hyperdrive.getPoolConfig().minimumShareReserves, - config.shareTolerance - ); + // If base deposits are enabled we verify some assertions. + if (config.enableBaseDeposits && isBaseETH) { + // If the base token is ETH we assert the ETH balance is correct. + if (isBaseETH) { + assertEq( + address(alice).balance, + aliceBalanceBefore - contribution + ); + } + + // Ensure that the decimals are set correctly. + assertEq(hyperdrive.decimals(), 18); + + // Ensure that Alice received the correct amount of LP tokens. She should + // receive LP shares totaling the amount of shares that he contributed + // minus the shares set aside for the minimum share reserves and the + // zero address's initial LP contribution. + assertApproxEqAbs( + hyperdrive.balanceOf(AssetId._LP_ASSET_ID, alice), + contribution.divDown( + hyperdrive.getPoolConfig().initialVaultSharePrice + ) - 2 * hyperdrive.getPoolConfig().minimumShareReserves, + config.shareTolerance // Custom share tolerance per integration. + ); - // Ensure that the share reserves and LP total supply are equal and correct. - assertApproxEqAbs( - hyperdrive.getPoolInfo().shareReserves, - contributionShares, - 1 - ); - assertEq( - hyperdrive.getPoolInfo().lpTotalSupply, - hyperdrive.getPoolInfo().shareReserves - - hyperdrive.getPoolConfig().minimumShareReserves - ); + // Ensure that the share reserves and LP total supply are equal and correct. + assertApproxEqAbs( + hyperdrive.getPoolInfo().shareReserves, + contributionShares, + 1 + ); + assertEq( + hyperdrive.getPoolInfo().lpTotalSupply, + hyperdrive.getPoolInfo().shareReserves - + hyperdrive.getPoolConfig().minimumShareReserves + ); - // Verify that the correct events were emitted. - verifyFactoryEvents( - deployerCoordinator, - hyperdrive, - alice, - contribution, - FIXED_RATE, - true, - hyperdrive.getPoolConfig().minimumShareReserves, - new bytes(0), - // NOTE: Tolerance since stETH uses mulDivDown for share calculations. - config.shareTolerance - ); + // Verify that the correct events were emitted. + verifyFactoryEvents( + deployerCoordinator, + hyperdrive, + alice, + contribution, + FIXED_RATE, + true, + hyperdrive.getPoolConfig().minimumShareReserves, + new bytes(0), + config.shareTolerance + ); + } } - function test__deployAndInitialize__asShares(uint) external { + /// @dev Test to verify a market can be deployed and initialized funded + /// by the share token. + function test__deployAndInitialize__asShares() external { uint256 aliceBalanceBefore = address(alice).balance; + + // Contribution in terms of base. uint256 contribution = 5_000e18; + + // Get protocol state information used for calculating correct LP shares. (, , uint256 sharePrice) = getProtocolSharePrice(); + // Contribution in terms of shares. uint256 contributionShares = contribution.divDown(sharePrice); + // Deploy all Hyperdrive targets using deployer coordinator contract. deployTargets( - // alice, - bytes32(uint256(0xbeefbabe)), - bytes32(uint256(0xdeadfade)), - contributionShares, - false + bytes32(uint256(0xbeefbabe)), // Deployment Id + bytes32(uint256(0xdeadfade)), // Deployment Salt + contributionShares, // Contribution + false // asBase ); + // Ensure Alice's ETH balance remains the same. assertEq(address(alice).balance, aliceBalanceBefore); // Ensure that the decimals are set correctly. assertEq(hyperdrive.decimals(), 18); - // Ensure that alice received the correct amount of LP tokens. He should + // Ensure that Alice received the correct amount of LP tokens. She should // receive LP shares totaling the amount of shares that he contributed // minus the shares set aside for the minimum share reserves and the // zero address's initial LP contribution. @@ -337,7 +390,7 @@ abstract contract IntegrationTest is HyperdriveTest { contribution.divDown( hyperdrive.getPoolConfig().initialVaultSharePrice ) - 2 * hyperdrive.getPoolConfig().minimumShareReserves, - config.shareTolerance + config.shareTolerance // Custom share tolerance per integration. ); // Ensure that the share reserves and LP total supply are equal and correct. From 7d3d8c8d2b29ef8fa9aa9aa1c5d21af24e20e8e6 Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Fri, 22 Mar 2024 16:09:33 -0500 Subject: [PATCH 14/21] comment formatting --- test/utils/IntegrationTest.sol | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/utils/IntegrationTest.sol b/test/utils/IntegrationTest.sol index a98fd1928..dcc55e471 100644 --- a/test/utils/IntegrationTest.sol +++ b/test/utils/IntegrationTest.sol @@ -161,8 +161,7 @@ abstract contract IntegrationTest is HyperdriveTest { deploymentSalt ); - // Alice gives approval to the deployer coordinator - // to fund the market. + // Alice gives approval to the deployer coordinator to fund the market. config.token.approve(deployerCoordinator, 100_000e18); // We expect the deployAndInitialize to fail with an @@ -176,8 +175,7 @@ abstract contract IntegrationTest is HyperdriveTest { ); } - // Deploy and initialize the market. - // If the base token is ETH we pass the + // Deploy and initialize the market. If the base token is ETH we pass the // contribution through the call. hyperdrive = factory.deployAndInitialize{ value: asBase && isBaseETH ? contribution : 0 From f9cd5f6747d9f330644ffc0785ba14469157a90b Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Mon, 25 Mar 2024 13:30:35 -0500 Subject: [PATCH 15/21] Rename IntegrationTest -> InstanceTest --- test/instances/ezETH/EzETHHyperdrive.t.sol | 12 +++++----- test/instances/lseth/LsETHHyperdrive.t.sol | 12 +++++----- test/instances/reth/RETHHyperdrive.t.sol | 12 +++++----- test/instances/steth/StETHHyperdrive.t.sol | 12 +++++----- .../{IntegrationTest.sol => InstanceTest.sol} | 22 +++++++++---------- 5 files changed, 35 insertions(+), 35 deletions(-) rename test/utils/{IntegrationTest.sol => InstanceTest.sol} (96%) diff --git a/test/instances/ezETH/EzETHHyperdrive.t.sol b/test/instances/ezETH/EzETHHyperdrive.t.sol index f65da2b0b..746c3bf56 100644 --- a/test/instances/ezETH/EzETHHyperdrive.t.sol +++ b/test/instances/ezETH/EzETHHyperdrive.t.sol @@ -21,11 +21,11 @@ import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol" import { HyperdriveMath } from "contracts/src/libraries/HyperdriveMath.sol"; import { ERC20ForwarderFactory } from "contracts/src/token/ERC20ForwarderFactory.sol"; import { ERC20Mintable } from "contracts/test/ERC20Mintable.sol"; -import { IntegrationTest } from "test/utils/IntegrationTest.sol"; +import { InstanceTest } from "test/utils/InstanceTest.sol"; import { HyperdriveUtils } from "test/utils/HyperdriveUtils.sol"; import { Lib } from "test/utils/Lib.sol"; -contract EzETHHyperdriveTest is IntegrationTest { +contract EzETHHyperdriveTest is InstanceTest { using FixedPointMath for uint256; using Lib for *; using stdStorage for StdStorage; @@ -58,9 +58,9 @@ contract EzETHHyperdriveTest is IntegrationTest { address internal EZETH_WHALE = 0x40C0d1fbcB0A43A62ca7A241E7A42ca58EeF96eb; address[] internal whaleAccounts = [EZETH_WHALE]; - // The configuration for the integration testing suite. - IntegrationConfig internal __testConfig = - IntegrationConfig( + // The configuration for the Instance testing suite. + InstanceTestConfig internal __testConfig = + InstanceTestConfig( whaleAccounts, IERC20(EZETH), IERC20(ETH), @@ -70,7 +70,7 @@ contract EzETHHyperdriveTest is IntegrationTest { false ); - constructor() IntegrationTest(__testConfig) {} + constructor() InstanceTest(__testConfig) {} function setUp() public override __mainnet_fork(STARTING_BLOCK) { // Depositing with ETH is not allowed for this pool so we need to get diff --git a/test/instances/lseth/LsETHHyperdrive.t.sol b/test/instances/lseth/LsETHHyperdrive.t.sol index 3e5d9c868..2d36962d6 100644 --- a/test/instances/lseth/LsETHHyperdrive.t.sol +++ b/test/instances/lseth/LsETHHyperdrive.t.sol @@ -20,11 +20,11 @@ import { ETH } from "contracts/src/libraries/Constants.sol"; import { HyperdriveMath } from "contracts/src/libraries/HyperdriveMath.sol"; import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; import { ERC20Mintable } from "contracts/test/ERC20Mintable.sol"; -import { IntegrationTest } from "test/utils/IntegrationTest.sol"; +import { InstanceTest } from "test/utils/InstanceTest.sol"; import { HyperdriveUtils } from "test/utils/HyperdriveUtils.sol"; import { Lib } from "test/utils/Lib.sol"; -contract LsETHHyperdriveTest is IntegrationTest { +contract LsETHHyperdriveTest is InstanceTest { using FixedPointMath for uint256; using Lib for *; using stdStorage for StdStorage; @@ -46,9 +46,9 @@ contract LsETHHyperdriveTest is IntegrationTest { LSETH_WHALE_3 ]; - // The configuration for the integration testing suite. - IntegrationConfig internal __testConfig = - IntegrationConfig( + // The configuration for the Instance testing suite. + InstanceTestConfig internal __testConfig = + InstanceTestConfig( whaleAccounts, IERC20(RIVER), IERC20(ETH), @@ -58,7 +58,7 @@ contract LsETHHyperdriveTest is IntegrationTest { false ); - constructor() IntegrationTest(__testConfig) {} + constructor() InstanceTest(__testConfig) {} function setUp() public override __mainnet_fork(19_429_100) { super.setUp(); diff --git a/test/instances/reth/RETHHyperdrive.t.sol b/test/instances/reth/RETHHyperdrive.t.sol index 9b2593967..9c23c18f4 100644 --- a/test/instances/reth/RETHHyperdrive.t.sol +++ b/test/instances/reth/RETHHyperdrive.t.sol @@ -8,7 +8,7 @@ import { ETH } from "contracts/src/libraries/Constants.sol"; import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol"; import { HyperdriveFactory } from "contracts/src/factory/HyperdriveFactory.sol"; import { HyperdriveMath } from "contracts/src/libraries/HyperdriveMath.sol"; -import { IntegrationTest } from "test/utils/IntegrationTest.sol"; +import { InstanceTest } from "test/utils/InstanceTest.sol"; import { HyperdriveUtils } from "test/utils/HyperdriveUtils.sol"; import { IERC20 } from "contracts/src/interfaces/IERC20.sol"; import { IHyperdrive } from "contracts/src/interfaces/IHyperdrive.sol"; @@ -28,7 +28,7 @@ import { RETHTarget3Deployer } from "contracts/src/deployers/reth/RETHTarget3Dep import { RETHTarget4Deployer } from "contracts/src/deployers/reth/RETHTarget4Deployer.sol"; import { stdStorage, StdStorage } from "forge-std/Test.sol"; -contract RETHHyperdriveTest is IntegrationTest { +contract RETHHyperdriveTest is InstanceTest { using FixedPointMath for uint256; using Lib for *; using stdStorage for StdStorage; @@ -49,9 +49,9 @@ contract RETHHyperdriveTest is IntegrationTest { address internal RETH_WHALE = 0xCc9EE9483f662091a1de4795249E24aC0aC2630f; address[] internal whaleAccounts = [RETH_WHALE]; - // The configuration for the integration testing suite. - IntegrationConfig internal __testConfig = - IntegrationConfig( + // The configuration for the Instance testing suite. + InstanceTestConfig internal __testConfig = + InstanceTestConfig( whaleAccounts, IERC20(rocketTokenRETH), IERC20(ETH), @@ -61,7 +61,7 @@ contract RETHHyperdriveTest is IntegrationTest { false ); - constructor() IntegrationTest(__testConfig) {} + constructor() InstanceTest(__testConfig) {} function setUp() public override __mainnet_fork(19_429_100) { // Give the rETH contract ETH to mimic adequate withdrawable liquidity. diff --git a/test/instances/steth/StETHHyperdrive.t.sol b/test/instances/steth/StETHHyperdrive.t.sol index c112470a1..ee2012c67 100644 --- a/test/instances/steth/StETHHyperdrive.t.sol +++ b/test/instances/steth/StETHHyperdrive.t.sol @@ -20,11 +20,11 @@ import { FixedPointMath, ONE } from "contracts/src/libraries/FixedPointMath.sol" import { HyperdriveMath } from "contracts/src/libraries/HyperdriveMath.sol"; import { ERC20ForwarderFactory } from "contracts/src/token/ERC20ForwarderFactory.sol"; import { ERC20Mintable } from "contracts/test/ERC20Mintable.sol"; -import { IntegrationTest } from "test/utils/IntegrationTest.sol"; +import { InstanceTest } from "test/utils/InstanceTest.sol"; import { HyperdriveUtils } from "test/utils/HyperdriveUtils.sol"; import { Lib } from "test/utils/Lib.sol"; -contract StETHHyperdriveTest is IntegrationTest { +contract StETHHyperdriveTest is InstanceTest { using FixedPointMath for uint256; using Lib for *; using stdStorage for StdStorage; @@ -41,9 +41,9 @@ contract StETHHyperdriveTest is IntegrationTest { address internal STETH_WHALE = 0x1982b2F5814301d4e9a8b0201555376e62F82428; address[] internal whaleAccounts = [STETH_WHALE]; - // The configuration for the integration testing suite. - IntegrationConfig internal __testConfig = - IntegrationConfig( + // The configuration for the Instance testing suite. + InstanceTestConfig internal __testConfig = + InstanceTestConfig( whaleAccounts, IERC20(LIDO), IERC20(ETH), @@ -53,7 +53,7 @@ contract StETHHyperdriveTest is IntegrationTest { true ); - constructor() IntegrationTest(__testConfig) {} + constructor() InstanceTest(__testConfig) {} function setUp() public override __mainnet_fork(17_376_154) { super.setUp(); diff --git a/test/utils/IntegrationTest.sol b/test/utils/InstanceTest.sol similarity index 96% rename from test/utils/IntegrationTest.sol rename to test/utils/InstanceTest.sol index dcc55e471..46677890c 100644 --- a/test/utils/IntegrationTest.sol +++ b/test/utils/InstanceTest.sol @@ -13,14 +13,14 @@ import { HyperdriveUtils } from "test/utils/HyperdriveUtils.sol"; import { Lib } from "test/utils/Lib.sol"; /// @author DELV -/// @title IntegrationTest -/// @notice The base contract for the integration testing suite. +/// @title InstanceTest +/// @notice The base contract for the instance testing suite. /// @dev A testing suite that provides a foundation to setup, deploy, and /// test common cases for Hyperdrive instances. /// @custom:disclaimer The language used in this code is for coding convenience /// only, and is not intended to, and does not, have any /// particular legal or regulatory significance. -abstract contract IntegrationTest is HyperdriveTest { +abstract contract InstanceTest is HyperdriveTest { using Lib for *; using FixedPointMath for uint256; @@ -30,8 +30,8 @@ abstract contract IntegrationTest is HyperdriveTest { // ETH whale account. address internal ETH_WHALE = 0x00000000219ab540356cBB839Cbe05303d7705Fa; - /// @dev Configuration for the Integration testing suite. - struct IntegrationConfig { + /// @dev Configuration for the Instance testing suite. + struct InstanceTestConfig { address[] whaleAccounts; IERC20 token; IERC20 baseToken; @@ -41,15 +41,15 @@ abstract contract IntegrationTest is HyperdriveTest { bool enableBaseDeposits; } - IntegrationConfig internal config; + InstanceTestConfig internal config; IHyperdrive.PoolDeployConfig internal poolConfig; HyperdriveFactory factory; address deployerCoordinator; bool internal immutable isBaseETH; - /// @dev Constructor for the Integration testing suite. - /// @param _config The Integration configuration. - constructor(IntegrationConfig storage _config) { + /// @dev Constructor for the Instance testing suite. + /// @param _config The Instance configuration. + constructor(InstanceTestConfig storage _config) { config = _config; isBaseETH = config.baseToken == IERC20(ETH); } @@ -321,7 +321,7 @@ abstract contract IntegrationTest is HyperdriveTest { contribution.divDown( hyperdrive.getPoolConfig().initialVaultSharePrice ) - 2 * hyperdrive.getPoolConfig().minimumShareReserves, - config.shareTolerance // Custom share tolerance per integration. + config.shareTolerance // Custom share tolerance per instance. ); // Ensure that the share reserves and LP total supply are equal and correct. @@ -388,7 +388,7 @@ abstract contract IntegrationTest is HyperdriveTest { contribution.divDown( hyperdrive.getPoolConfig().initialVaultSharePrice ) - 2 * hyperdrive.getPoolConfig().minimumShareReserves, - config.shareTolerance // Custom share tolerance per integration. + config.shareTolerance // Custom share tolerance per instance. ); // Ensure that the share reserves and LP total supply are equal and correct. From 909da0c5c1827299f4cdbe52c10067319d9f7300 Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Mon, 25 Mar 2024 13:46:41 -0500 Subject: [PATCH 16/21] Add comments for local contract variables and update function sig to be private --- test/utils/InstanceTest.sol | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/test/utils/InstanceTest.sol b/test/utils/InstanceTest.sol index 46677890c..5d927bbef 100644 --- a/test/utils/InstanceTest.sol +++ b/test/utils/InstanceTest.sol @@ -24,12 +24,6 @@ abstract contract InstanceTest is HyperdriveTest { using Lib for *; using FixedPointMath for uint256; - // Fixed rate used to configure market. - uint256 internal constant FIXED_RATE = 0.05e18; - - // ETH whale account. - address internal ETH_WHALE = 0x00000000219ab540356cBB839Cbe05303d7705Fa; - /// @dev Configuration for the Instance testing suite. struct InstanceTestConfig { address[] whaleAccounts; @@ -41,11 +35,23 @@ abstract contract InstanceTest is HyperdriveTest { bool enableBaseDeposits; } - InstanceTestConfig internal config; - IHyperdrive.PoolDeployConfig internal poolConfig; - HyperdriveFactory factory; - address deployerCoordinator; - bool internal immutable isBaseETH; + // Fixed rate used to configure market. + uint256 internal constant FIXED_RATE = 0.05e18; + + // The configuration for the Instance testing suite. + InstanceTestConfig private config; + + // The configuration for the pool. + IHyperdrive.PoolDeployConfig private poolConfig; + + // The address of the deployer coordinator contract. + address private deployerCoordinator; + + // The factory contract used for deployment in this testing suite. + HyperdriveFactory private factory; + + // Flag for denoting if the base token is ETH. + bool private immutable isBaseETH; /// @dev Constructor for the Instance testing suite. /// @param _config The Instance configuration. @@ -105,7 +111,7 @@ abstract contract InstanceTest is HyperdriveTest { bytes32 deploymentSalt, uint256 contribution, bool asBase - ) internal { + ) private { // Alice is the default deployer. vm.startPrank(alice); @@ -198,7 +204,7 @@ abstract contract InstanceTest is HyperdriveTest { /// @dev Deploys the Hyperdrive Factory contract and /// sets the default pool configuration. - function deployFactory() internal { + function deployFactory() private { // Deploy the hyperdrive factory. vm.startPrank(deployer); address[] memory defaults = new address[](1); From 6975cb5fe0de54a88beaaee494a453272e22dff5 Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Mon, 25 Mar 2024 14:39:20 -0500 Subject: [PATCH 17/21] EzETH rename position duration constant --- test/instances/ezETH/EzETHHyperdrive.t.sol | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/test/instances/ezETH/EzETHHyperdrive.t.sol b/test/instances/ezETH/EzETHHyperdrive.t.sol index 746c3bf56..81fba1649 100644 --- a/test/instances/ezETH/EzETHHyperdrive.t.sol +++ b/test/instances/ezETH/EzETHHyperdrive.t.sol @@ -51,7 +51,7 @@ contract EzETHHyperdriveTest is InstanceTest { // oracles makes it difficult to test on a mainnet fork without heavy // mocking. To test with their deployed code we use a shorter position // duration. - uint256 internal constant POSITION_DURATION_2_WEEKS = 15 days; + uint256 internal constant POSITION_DURATION_15_DAYS = 15 days; uint256 internal constant STARTING_BLOCK = 19119544; // Whale accounts. @@ -66,7 +66,7 @@ contract EzETHHyperdriveTest is InstanceTest { IERC20(ETH), 1e6, 1e15, - POSITION_DURATION_2_WEEKS, + POSITION_DURATION_15_DAYS, false ); @@ -146,13 +146,13 @@ contract EzETHHyperdriveTest is InstanceTest { function test__ezeth_interest_and_advance_time() external { // hand calculated value sanity check uint256 positionAdjustedInterestRate = uint256(0.05e18).mulDivDown( - POSITION_DURATION_2_WEEKS, + POSITION_DURATION_15_DAYS, 365 days ); // Ensure that advancing time accrues interest like we expect. (uint256 sharePriceBefore, , ) = getSharePrice(); - advanceTime(POSITION_DURATION_2_WEEKS, 0.05e18); + advanceTime(POSITION_DURATION_15_DAYS, 0.05e18); (uint256 sharePriceAfter, , ) = getSharePrice(); assertEq(positionAdjustedInterestRate, 0.002054794520547945e18); assertEq( @@ -312,7 +312,7 @@ contract EzETHHyperdriveTest is InstanceTest { ) external { // Accrue interest for a term to ensure that the share price is greater // than one. - advanceTime(POSITION_DURATION_2_WEEKS, 0.05e18); + advanceTime(POSITION_DURATION_15_DAYS, 0.05e18); vm.startPrank(bob); // Calculate the maximum amount of basePaid we can test. @@ -336,7 +336,7 @@ contract EzETHHyperdriveTest is InstanceTest { // The term passes and some interest accrues. variableRate = variableRate.normalizeToRange(0, 2.5e18); - advanceTime(POSITION_DURATION_2_WEEKS, variableRate); + advanceTime(POSITION_DURATION_15_DAYS, variableRate); // Get some balance information before the withdrawal. ( @@ -446,7 +446,7 @@ contract EzETHHyperdriveTest is InstanceTest { assertGt(basePaid, 0); assertGe( realizedRate, - FIXED_RATE.mulDown(POSITION_DURATION_2_WEEKS.divDown(365 days)) + FIXED_RATE.mulDown(POSITION_DURATION_15_DAYS.divDown(365 days)) ); // Ensure that Renzo's aggregates and the token balances were updated @@ -526,7 +526,7 @@ contract EzETHHyperdriveTest is InstanceTest { // // The term passes and interest accrues. variableRate = variableRate.normalizeToRange(0.01e18, 2.5e18); - advanceTime(POSITION_DURATION_2_WEEKS, variableRate); + advanceTime(POSITION_DURATION_15_DAYS, variableRate); // Bob attempts to close his short with ETH as the target asset. This // fails since ETH isn't supported as a withdrawal asset. @@ -551,7 +551,7 @@ contract EzETHHyperdriveTest is InstanceTest { ) external { // Accrue interest for a term to ensure that the share price is greater // than one. - advanceTime(POSITION_DURATION_2_WEEKS, 0.05e18); + advanceTime(POSITION_DURATION_15_DAYS, 0.05e18); // Calculate the maximum amount we can short. shortAmount = shortAmount.normalizeToRange( @@ -572,7 +572,7 @@ contract EzETHHyperdriveTest is InstanceTest { .getPoolInfo() .vaultSharePrice; variableRate = variableRate.normalizeToRange(0, 2.5e18); - advanceTime(POSITION_DURATION_2_WEEKS, variableRate); + advanceTime(POSITION_DURATION_15_DAYS, variableRate); // Get some balance information before closing the short. ( @@ -802,7 +802,7 @@ contract EzETHHyperdriveTest is InstanceTest { // accrual of interest by adding to the balance of the DepositQueue contract. // RestakeManager adds the balance of the DepositQueue to totalTVL in calculateTVLs() uint256 adjustedVariableRate = uint256(variableRate).mulDivDown( - POSITION_DURATION_2_WEEKS, + POSITION_DURATION_15_DAYS, 365 days ); uint256 ethToAdd = totalTVLBefore.mulDown(adjustedVariableRate); From 70a4a2be3162222f16e2b0c00646397fc2e7b250 Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Mon, 25 Mar 2024 14:51:45 -0500 Subject: [PATCH 18/21] instance test comments pt1 --- test/utils/InstanceTest.sol | 134 +++++++++++++++++++++--------------- 1 file changed, 77 insertions(+), 57 deletions(-) diff --git a/test/utils/InstanceTest.sol b/test/utils/InstanceTest.sol index 5d927bbef..44ef97f6c 100644 --- a/test/utils/InstanceTest.sol +++ b/test/utils/InstanceTest.sol @@ -38,6 +38,12 @@ abstract contract InstanceTest is HyperdriveTest { // Fixed rate used to configure market. uint256 internal constant FIXED_RATE = 0.05e18; + // Default deployment constants. + bytes32 private constant DEFAULT_DEPLOYMENT_ID = + bytes32(uint256(0xdeadbeef)); + bytes32 private constant DEFAULT_DEPLOYMENT_SALT = + bytes32(uint256(0xdeadbabe)); + // The configuration for the Instance testing suite. InstanceTestConfig private config; @@ -66,6 +72,9 @@ abstract contract InstanceTest is HyperdriveTest { function setUp() public virtual override { super.setUp(); + // Initial contribution. + uint256 contribution = 5_000e18; + // Fund accounts with ETH and token from whales. vm.deal(alice, 100_000e18); vm.deal(bob, 100_000e18); @@ -88,14 +97,24 @@ abstract contract InstanceTest is HyperdriveTest { deployerCoordinator = deployCoordinator(); factory.addDeployerCoordinator(deployerCoordinator); - // Deploy all Hyperdrive targets using deployer coordinator contract. - deployTargets( - bytes32(uint256(0xdeadbeef)), // Deployment Id - bytes32(uint256(0xdeadbabe)), // Deployment Salt - 5_000e18, // Contribution + // Deploy all Hyperdrive contracts using deployer coordinator contract. + deployHyperdrive( + DEFAULT_DEPLOYMENT_ID, // Deployment Id + DEFAULT_DEPLOYMENT_SALT, // Deployment Salt + contribution, // Contribution false // asBase ); + // Ensure that Alice received the correct amount of LP tokens. She should + // receive LP shares totaling the amount of shares that she contributed + // minus the shares set aside for the minimum share reserves and the + // zero address's initial LP contribution. + assertApproxEqAbs( + hyperdrive.balanceOf(AssetId._LP_ASSET_ID, alice), + contribution - 2 * hyperdrive.getPoolConfig().minimumShareReserves, + config.shareTolerance + ); + // Start recording event logs. vm.recordLogs(); } @@ -106,7 +125,7 @@ abstract contract InstanceTest is HyperdriveTest { /// @param deploymentSalt The deployment salt for create2. /// @param contribution The amount to initialize the market. /// @param asBase Initialize the market with base token. - function deployTargets( + function deployHyperdrive( bytes32 deploymentId, bytes32 deploymentSalt, uint256 contribution, @@ -171,7 +190,7 @@ abstract contract InstanceTest is HyperdriveTest { config.token.approve(deployerCoordinator, 100_000e18); // We expect the deployAndInitialize to fail with an - // UnSupported token error if depositing as base is not supported. + // Unsupported token error if depositing as base is not supported. // If the base token is ETH we expect a NotPayable error. if (!config.enableBaseDeposits && asBase) { vm.expectRevert( @@ -243,6 +262,7 @@ abstract contract InstanceTest is HyperdriveTest { }) ); + // Set the pool configuration that will be used for instance deployments. poolConfig = IHyperdrive.PoolDeployConfig({ baseToken: config.baseToken, linkerFactory: factory.linkerFactory(), @@ -296,65 +316,65 @@ abstract contract InstanceTest is HyperdriveTest { totalBase ); - // Deploy all Hyperdrive targets using deployer coordinator contract. + // Deploy all Hyperdrive contract using deployer coordinator contract. // This function reverts if base deposits are disabled. - deployTargets( + deployHyperdrive( bytes32(uint256(0xbeefbabe)), // Deployment Id bytes32(uint256(0xdeadfade)), // Deployment Salt contribution, // Contribution true // asBase ); + // Early termination if base deposits are not supported. + if (!config.enableBaseDeposits) { + return; + } + // If base deposits are enabled we verify some assertions. - if (config.enableBaseDeposits && isBaseETH) { + if (isBaseETH) { // If the base token is ETH we assert the ETH balance is correct. - if (isBaseETH) { - assertEq( - address(alice).balance, - aliceBalanceBefore - contribution - ); - } - - // Ensure that the decimals are set correctly. - assertEq(hyperdrive.decimals(), 18); - - // Ensure that Alice received the correct amount of LP tokens. She should - // receive LP shares totaling the amount of shares that he contributed - // minus the shares set aside for the minimum share reserves and the - // zero address's initial LP contribution. - assertApproxEqAbs( - hyperdrive.balanceOf(AssetId._LP_ASSET_ID, alice), - contribution.divDown( - hyperdrive.getPoolConfig().initialVaultSharePrice - ) - 2 * hyperdrive.getPoolConfig().minimumShareReserves, - config.shareTolerance // Custom share tolerance per instance. - ); + assertEq(address(alice).balance, aliceBalanceBefore - contribution); + } - // Ensure that the share reserves and LP total supply are equal and correct. - assertApproxEqAbs( - hyperdrive.getPoolInfo().shareReserves, - contributionShares, - 1 - ); - assertEq( - hyperdrive.getPoolInfo().lpTotalSupply, - hyperdrive.getPoolInfo().shareReserves - - hyperdrive.getPoolConfig().minimumShareReserves - ); + // Ensure that the decimals are set correctly. + assertEq(hyperdrive.decimals(), 18); - // Verify that the correct events were emitted. - verifyFactoryEvents( - deployerCoordinator, - hyperdrive, - alice, - contribution, - FIXED_RATE, - true, - hyperdrive.getPoolConfig().minimumShareReserves, - new bytes(0), - config.shareTolerance - ); - } + // Ensure that Alice received the correct amount of LP tokens. She should + // receive LP shares totaling the amount of shares that he contributed + // minus the shares set aside for the minimum share reserves and the + // zero address's initial LP contribution. + assertApproxEqAbs( + hyperdrive.balanceOf(AssetId._LP_ASSET_ID, alice), + contribution.divDown( + hyperdrive.getPoolConfig().initialVaultSharePrice + ) - 2 * hyperdrive.getPoolConfig().minimumShareReserves, + config.shareTolerance // Custom share tolerance per instance. + ); + + // Ensure that the share reserves and LP total supply are equal and correct. + assertApproxEqAbs( + hyperdrive.getPoolInfo().shareReserves, + contributionShares, + 1 + ); + assertEq( + hyperdrive.getPoolInfo().lpTotalSupply, + hyperdrive.getPoolInfo().shareReserves - + hyperdrive.getPoolConfig().minimumShareReserves + ); + + // Verify that the correct events were emitted. + verifyFactoryEvents( + deployerCoordinator, + hyperdrive, + alice, + contribution, + FIXED_RATE, + true, + hyperdrive.getPoolConfig().minimumShareReserves, + new bytes(0), + config.shareTolerance + ); } /// @dev Test to verify a market can be deployed and initialized funded @@ -371,8 +391,8 @@ abstract contract InstanceTest is HyperdriveTest { // Contribution in terms of shares. uint256 contributionShares = contribution.divDown(sharePrice); - // Deploy all Hyperdrive targets using deployer coordinator contract. - deployTargets( + // Deploy all Hyperdrive contracts using deployer coordinator contract. + deployHyperdrive( bytes32(uint256(0xbeefbabe)), // Deployment Id bytes32(uint256(0xdeadfade)), // Deployment Salt contributionShares, // Contribution From 68342ed44c278a6a516b4ceb1033a5b19a5a5d6d Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Mon, 25 Mar 2024 16:07:13 -0500 Subject: [PATCH 19/21] new converToShares function replaces getProtocolSharePrice calcs --- test/instances/ezETH/EzETHHyperdrive.t.sol | 40 ++++++---------- test/instances/lseth/LsETHHyperdrive.t.sol | 27 +++++------ test/instances/reth/RETHHyperdrive.t.sol | 27 +++++------ test/instances/steth/StETHHyperdrive.t.sol | 25 ++++------ test/utils/InstanceTest.sol | 56 +++++++++++++--------- 5 files changed, 83 insertions(+), 92 deletions(-) diff --git a/test/instances/ezETH/EzETHHyperdrive.t.sol b/test/instances/ezETH/EzETHHyperdrive.t.sol index 81fba1649..326136c56 100644 --- a/test/instances/ezETH/EzETHHyperdrive.t.sol +++ b/test/instances/ezETH/EzETHHyperdrive.t.sol @@ -67,46 +67,34 @@ contract EzETHHyperdriveTest is InstanceTest { 1e6, 1e15, POSITION_DURATION_15_DAYS, - false + false, + true ); + /// @dev Instantiates the Instance testing suite with the configuration. constructor() InstanceTest(__testConfig) {} + /// @dev Forge function that is invoked to setup the testing environment. function setUp() public override __mainnet_fork(STARTING_BLOCK) { - // Depositing with ETH is not allowed for this pool so we need to get - // some ezETH for alice first. + // Giving the EzETH whale account more EzETH before the instance setup. vm.startPrank(EZETH_WHALE); - vm.deal(EZETH_WHALE, 50_000e18); - RESTAKE_MANAGER.depositETH{ value: 40_000e18 }(); + RESTAKE_MANAGER.depositETH{ value: 50_000e18 }(); vm.stopPrank(); + // Invoke the Instance testing suite setup. super.setUp(); } /// Overrides /// - /// @dev Fetches share price information about EzETH. - function getProtocolSharePrice() - internal - view - override - returns (uint256, uint256, uint256) - { - // Get the total TVL priced in ETH from restakeManager. - (, , uint256 totalTVL) = RESTAKE_MANAGER.calculateTVLs(); - - // Get the total supply of the ezETH token. - uint256 totalSupply = EZETH.totalSupply(); - - // Calculate the share price. - uint256 sharePrice = RENZO_ORACLE.calculateRedeemAmount( - ONE, - totalSupply, - totalTVL - ); - - return (totalTVL, totalSupply, sharePrice); + /// @dev Converts base amount to the equivalent about in EzETH. + function convertToShares( + uint256 baseAmount + ) internal override returns (uint256 shareAmount) { + // Get protocol state information used for calculating shares. + (uint256 sharePrice, , ) = getSharePrice(); + return baseAmount.divDown(sharePrice); } /// @dev Deploys the EzETH deployer coordinator contract. diff --git a/test/instances/lseth/LsETHHyperdrive.t.sol b/test/instances/lseth/LsETHHyperdrive.t.sol index 2d36962d6..d0476e572 100644 --- a/test/instances/lseth/LsETHHyperdrive.t.sol +++ b/test/instances/lseth/LsETHHyperdrive.t.sol @@ -52,15 +52,20 @@ contract LsETHHyperdriveTest is InstanceTest { whaleAccounts, IERC20(RIVER), IERC20(ETH), - 0, + 1e5, 1e15, POSITION_DURATION, - false + false, + true ); + /// @dev Instantiates the Instance testing suite with the configuration. constructor() InstanceTest(__testConfig) {} + /// @dev Forge function that is invoked to setup the testing environment. + function setUp() public override __mainnet_fork(19_429_100) { + // Invoke the Instance testing suite setup. super.setUp(); } @@ -83,18 +88,12 @@ contract LsETHHyperdriveTest is InstanceTest { ); } - /// @dev Fetches share price information about LsETH. - function getProtocolSharePrice() - internal - view - override - returns (uint256, uint256, uint256) - { - return ( - RIVER.totalUnderlyingSupply(), - RIVER.totalSupply(), - RIVER.underlyingBalanceFromShares(1e18) - ); + /// @dev Converts base amount to the equivalent amount in LsETH. + function convertToShares( + uint256 baseAmount + ) internal override returns (uint256 shareAmount) { + // River has a built-in function for computing price in terms of shares. + return RIVER.sharesFromUnderlyingBalance(baseAmount); } /// Getters /// diff --git a/test/instances/reth/RETHHyperdrive.t.sol b/test/instances/reth/RETHHyperdrive.t.sol index 9c23c18f4..899994870 100644 --- a/test/instances/reth/RETHHyperdrive.t.sol +++ b/test/instances/reth/RETHHyperdrive.t.sol @@ -55,34 +55,33 @@ contract RETHHyperdriveTest is InstanceTest { whaleAccounts, IERC20(rocketTokenRETH), IERC20(ETH), - 0, + 1e5, 1e16, POSITION_DURATION, - false + false, + true ); + /// @dev Instantiates the Instance testing suite with the configuration. constructor() InstanceTest(__testConfig) {} + /// @dev Forge function that is invoked to setup the testing environment. function setUp() public override __mainnet_fork(19_429_100) { // Give the rETH contract ETH to mimic adequate withdrawable liquidity. vm.deal(address(rocketTokenRETH), 50_000e18); + + // Invoke the Instance testing suite setup. super.setUp(); } /// Overrides /// - /// @dev Fetches share price information about rETH. - function getProtocolSharePrice() - internal - view - override - returns (uint256, uint256, uint256) - { - return ( - rocketTokenRETH.getExchangeRate(), - rocketTokenRETH.getExchangeRate(), - rocketTokenRETH.getExchangeRate() - ); + /// @dev Converts base amount to the equivalent amount in rETH. + function convertToShares( + uint256 baseAmount + ) internal override returns (uint256 shareAmount) { + // Rocket Pool has a built-in function for computing price in terms of shares. + return rocketTokenRETH.getRethValue(baseAmount); } /// @dev Deploys the rETH deployer coordinator contract. diff --git a/test/instances/steth/StETHHyperdrive.t.sol b/test/instances/steth/StETHHyperdrive.t.sol index ee2012c67..95d2bc7c0 100644 --- a/test/instances/steth/StETHHyperdrive.t.sol +++ b/test/instances/steth/StETHHyperdrive.t.sol @@ -50,34 +50,29 @@ contract StETHHyperdriveTest is InstanceTest { 1e5, 1e15, POSITION_DURATION, + true, true ); + /// @dev Instantiates the Instance testing suite with the configuration. constructor() InstanceTest(__testConfig) {} + /// @dev Forge function that is invoked to setup the testing environment. function setUp() public override __mainnet_fork(17_376_154) { + // Invoke the Instance testing suite setup. super.setUp(); - - vm.startPrank(bob); - LIDO.approve(address(hyperdrive), 100_000e18); } /// Overrides /// - /// @dev Fetches share price information about StETH. - function getProtocolSharePrice() - internal - view - override - returns (uint256, uint256, uint256) - { + /// @dev Converts base amount to the equivalent about in stETH. + function convertToShares( + uint256 baseAmount + ) internal override returns (uint256 shareAmount) { + // Get protocol state information used for calculating shares. uint256 totalPooledEther = LIDO.getTotalPooledEther(); uint256 totalShares = LIDO.getTotalShares(); - return ( - totalPooledEther, - totalShares, - totalPooledEther.divDown(totalShares) - ); + return baseAmount.mulDivDown(totalShares, totalPooledEther); } /// @dev Deploys the rETH deployer coordinator contract. diff --git a/test/utils/InstanceTest.sol b/test/utils/InstanceTest.sol index 44ef97f6c..d4ff384df 100644 --- a/test/utils/InstanceTest.sol +++ b/test/utils/InstanceTest.sol @@ -16,7 +16,7 @@ import { Lib } from "test/utils/Lib.sol"; /// @title InstanceTest /// @notice The base contract for the instance testing suite. /// @dev A testing suite that provides a foundation to setup, deploy, and -/// test common cases for Hyperdrive instances. +/// test common cases for Hyperdrive instances. /// @custom:disclaimer The language used in this code is for coding convenience /// only, and is not intended to, and does not, have any /// particular legal or regulatory significance. @@ -33,6 +33,7 @@ abstract contract InstanceTest is HyperdriveTest { uint256 minTransactionAmount; uint256 positionDuration; bool enableBaseDeposits; + bool enableShareDeposits; } // Fixed rate used to configure market. @@ -66,6 +67,8 @@ abstract contract InstanceTest is HyperdriveTest { isBaseETH = config.baseToken == IERC20(ETH); } + /// Deployments /// + /// @notice Forge setup function. /// @dev Inherits from HyperdriveTest and deploys the /// Hyperdrive factory, deployer coordinator, and targets. @@ -105,6 +108,10 @@ abstract contract InstanceTest is HyperdriveTest { false // asBase ); + config.token.approve(address(hyperdrive), 100_000e18); + vm.startPrank(bob); + config.token.approve(address(hyperdrive), 100_000e18); + // Ensure that Alice received the correct amount of LP tokens. She should // receive LP shares totaling the amount of shares that she contributed // minus the shares set aside for the minimum share reserves and the @@ -190,7 +197,7 @@ abstract contract InstanceTest is HyperdriveTest { config.token.approve(deployerCoordinator, 100_000e18); // We expect the deployAndInitialize to fail with an - // Unsupported token error if depositing as base is not supported. + // Unsupported token error if depositing with base is not supported. // If the base token is ETH we expect a NotPayable error. if (!config.enableBaseDeposits && asBase) { vm.expectRevert( @@ -200,6 +207,12 @@ abstract contract InstanceTest is HyperdriveTest { ); } + // We expect the deployAndInitialize to fail with an + // Unsupported token error if depositing with shares is not supported. + if (!config.enableShareDeposits && !asBase) { + vm.expectRevert(IHyperdrive.UnsupportedToken.selector); + } + // Deploy and initialize the market. If the base token is ETH we pass the // contribution through the call. hyperdrive = factory.deployAndInitialize{ @@ -284,21 +297,22 @@ abstract contract InstanceTest is HyperdriveTest { }); } - /// @dev A virtual function that exposes important state - /// about the underlying protocol and token. Not all values - /// will be used depending on the instance. - /// @param baseSupply Amount of base tokens in circulation. - /// @param shareSupply Amount of share tokens in circulation. - /// @param sharePrice Price of of one share in terms of base. - function getProtocolSharePrice() - internal - virtual - returns (uint256 baseSupply, uint256 shareSupply, uint256 sharePrice); + /// Overrides /// /// @dev A virtual function that defines the deployer coordinator /// contract that will be used to deploy all the instance targets. function deployCoordinator() internal virtual returns (address); + /// @dev A virtual function that converts an amount in terms of the base token + /// to equivalent amount in shares. + /// @param baseAmount Amount in terms of the base. + /// @return shareAmount Amount in terms of shares. + function convertToShares( + uint256 baseAmount + ) internal virtual returns (uint256 shareAmount); + + /// Tests /// + /// @dev Test to verify a market can be deployed and initialized funded by the /// base token. Is expected to revert when base deposits are not supported. function test__deployAndInitialize__asBase() external virtual { @@ -307,14 +321,8 @@ abstract contract InstanceTest is HyperdriveTest { // Contribution in terms of base. uint256 contribution = 5_000e18; - // Get protocol state information used for calculating correct LP shares. - (uint256 totalBase, uint256 totalShare, ) = getProtocolSharePrice(); - // Contribution in terms of shares. - uint256 contributionShares = contribution.mulDivDown( - totalShare, - totalBase - ); + uint256 contributionShares = convertToShares(contribution); // Deploy all Hyperdrive contract using deployer coordinator contract. // This function reverts if base deposits are disabled. @@ -385,11 +393,8 @@ abstract contract InstanceTest is HyperdriveTest { // Contribution in terms of base. uint256 contribution = 5_000e18; - // Get protocol state information used for calculating correct LP shares. - (, , uint256 sharePrice) = getProtocolSharePrice(); - // Contribution in terms of shares. - uint256 contributionShares = contribution.divDown(sharePrice); + uint256 contributionShares = convertToShares(contribution); // Deploy all Hyperdrive contracts using deployer coordinator contract. deployHyperdrive( @@ -399,6 +404,11 @@ abstract contract InstanceTest is HyperdriveTest { false // asBase ); + // Early termination if share deposits are not supported. + if (!config.enableShareDeposits) { + return; + } + // Ensure Alice's ETH balance remains the same. assertEq(address(alice).balance, aliceBalanceBefore); From 64e3c1a94de7c3f987550efcd12608cd5e85722d Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Mon, 25 Mar 2024 16:11:48 -0500 Subject: [PATCH 20/21] fix lint errors --- test/instances/ezETH/EzETHHyperdrive.t.sol | 2 +- test/instances/lseth/LsETHHyperdrive.t.sol | 2 +- test/instances/reth/RETHHyperdrive.t.sol | 2 +- test/instances/steth/StETHHyperdrive.t.sol | 2 +- test/utils/InstanceTest.sol | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/instances/ezETH/EzETHHyperdrive.t.sol b/test/instances/ezETH/EzETHHyperdrive.t.sol index 326136c56..9a72da9f0 100644 --- a/test/instances/ezETH/EzETHHyperdrive.t.sol +++ b/test/instances/ezETH/EzETHHyperdrive.t.sol @@ -91,7 +91,7 @@ contract EzETHHyperdriveTest is InstanceTest { /// @dev Converts base amount to the equivalent about in EzETH. function convertToShares( uint256 baseAmount - ) internal override returns (uint256 shareAmount) { + ) internal view override returns (uint256 shareAmount) { // Get protocol state information used for calculating shares. (uint256 sharePrice, , ) = getSharePrice(); return baseAmount.divDown(sharePrice); diff --git a/test/instances/lseth/LsETHHyperdrive.t.sol b/test/instances/lseth/LsETHHyperdrive.t.sol index d0476e572..5d5e0a13e 100644 --- a/test/instances/lseth/LsETHHyperdrive.t.sol +++ b/test/instances/lseth/LsETHHyperdrive.t.sol @@ -91,7 +91,7 @@ contract LsETHHyperdriveTest is InstanceTest { /// @dev Converts base amount to the equivalent amount in LsETH. function convertToShares( uint256 baseAmount - ) internal override returns (uint256 shareAmount) { + ) internal view override returns (uint256 shareAmount) { // River has a built-in function for computing price in terms of shares. return RIVER.sharesFromUnderlyingBalance(baseAmount); } diff --git a/test/instances/reth/RETHHyperdrive.t.sol b/test/instances/reth/RETHHyperdrive.t.sol index 899994870..a46b58f63 100644 --- a/test/instances/reth/RETHHyperdrive.t.sol +++ b/test/instances/reth/RETHHyperdrive.t.sol @@ -79,7 +79,7 @@ contract RETHHyperdriveTest is InstanceTest { /// @dev Converts base amount to the equivalent amount in rETH. function convertToShares( uint256 baseAmount - ) internal override returns (uint256 shareAmount) { + ) internal view override returns (uint256 shareAmount) { // Rocket Pool has a built-in function for computing price in terms of shares. return rocketTokenRETH.getRethValue(baseAmount); } diff --git a/test/instances/steth/StETHHyperdrive.t.sol b/test/instances/steth/StETHHyperdrive.t.sol index 95d2bc7c0..62b6b1b4d 100644 --- a/test/instances/steth/StETHHyperdrive.t.sol +++ b/test/instances/steth/StETHHyperdrive.t.sol @@ -68,7 +68,7 @@ contract StETHHyperdriveTest is InstanceTest { /// @dev Converts base amount to the equivalent about in stETH. function convertToShares( uint256 baseAmount - ) internal override returns (uint256 shareAmount) { + ) internal view override returns (uint256 shareAmount) { // Get protocol state information used for calculating shares. uint256 totalPooledEther = LIDO.getTotalPooledEther(); uint256 totalShares = LIDO.getTotalShares(); diff --git a/test/utils/InstanceTest.sol b/test/utils/InstanceTest.sol index d4ff384df..f92c036a8 100644 --- a/test/utils/InstanceTest.sol +++ b/test/utils/InstanceTest.sol @@ -309,7 +309,7 @@ abstract contract InstanceTest is HyperdriveTest { /// @return shareAmount Amount in terms of shares. function convertToShares( uint256 baseAmount - ) internal virtual returns (uint256 shareAmount); + ) internal view virtual returns (uint256 shareAmount); /// Tests /// From 80518ad402552afa2824a4fd5b50e3a567fcc317 Mon Sep 17 00:00:00 2001 From: Cash Baller Date: Tue, 26 Mar 2024 14:36:46 -0500 Subject: [PATCH 21/21] add check for deployment refunds --- test/utils/InstanceTest.sol | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/utils/InstanceTest.sol b/test/utils/InstanceTest.sol index f92c036a8..05f46ada1 100644 --- a/test/utils/InstanceTest.sol +++ b/test/utils/InstanceTest.sol @@ -213,6 +213,9 @@ abstract contract InstanceTest is HyperdriveTest { vm.expectRevert(IHyperdrive.UnsupportedToken.selector); } + // Record Alice's ETH balance before the deployment call. + uint256 aliceBalanceBefore = address(alice).balance; + // Deploy and initialize the market. If the base token is ETH we pass the // contribution through the call. hyperdrive = factory.deployAndInitialize{ @@ -232,6 +235,13 @@ abstract contract InstanceTest is HyperdriveTest { }), deploymentSalt ); + + // Ensure that refunds are handled properly. + if (config.enableBaseDeposits && asBase && isBaseETH) { + assertEq(aliceBalanceBefore - contribution, address(alice).balance); + } else { + assertEq(aliceBalanceBefore, address(alice).balance); + } } /// @dev Deploys the Hyperdrive Factory contract and