Skip to content

Commit

Permalink
Tests for the SUSDe Integration (#1111)
Browse files Browse the repository at this point in the history
* Started adding tests for Ethena

* Fixed the base tests

* Fixed all but one remaining test

* Fixed the remaining tolerance issue for the SUSDe integration

* Addressed review feedback from @jrhea

* Converted the Morpho round trip tests into fuzz tests
  • Loading branch information
jalextowle authored Jul 24, 2024
1 parent 8b00b7b commit 4ca3f48
Show file tree
Hide file tree
Showing 9 changed files with 872 additions and 66 deletions.
2 changes: 1 addition & 1 deletion contracts/src/instances/morpho-blue/MorphoBlueBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ abstract contract MorphoBlueBase is HyperdriveBase {
irm: _irm,
lltv: _lltv
}),
_convertToBase(_shareAmount),
0,
_shareAmount,
address(this),
_destination
);
Expand Down
13 changes: 7 additions & 6 deletions test/instances/aave/AaveHyperdrive.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ contract AaveHyperdriveTest is InstanceTest {
address[] internal baseTokenWhaleAccounts = [WETH_WHALE];
address[] internal vaultSharesTokenWhaleAccounts = [AWETH_WHALE];

// The configuration for the Instance testing suite.
// The configuration for the instance testing suite.
InstanceTestConfig internal __testConfig =
InstanceTestConfig({
name: "Hyperdrive",
Expand All @@ -63,15 +63,16 @@ contract AaveHyperdriveTest is InstanceTest {
enableBaseDeposits: true,
enableShareDeposits: true,
enableBaseWithdraws: true,
enableShareWithdraws: true
enableShareWithdraws: true,
baseWithdrawError: new bytes(0)
});

/// @dev Instantiates the Instance testing suite with the configuration.
/// @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(20_276_503) {
// Invoke the Instance testing suite setup.
// Invoke the instance testing suite setup.
super.setUp();
}

Expand Down Expand Up @@ -263,8 +264,8 @@ contract AaveHyperdriveTest is InstanceTest {
assertEq(bob.balance, traderBalancesBefore.ETHBalance);

// Ensure that the base balances Hyperdrive base balance doesn't
// change and that the trader's base balance decreased by the amount
// paid.
// change and that the trader's base balance increased by the base
// proceeds.
assertApproxEqAbs(
WETH.balanceOf(address(hyperdrive)),
hyperdriveBalancesBefore.baseBalance,
Expand Down
9 changes: 5 additions & 4 deletions test/instances/ezETH/EzETHHyperdrive.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ contract EzETHHyperdriveTest is InstanceTest {
address internal EZETH_WHALE = 0x40C0d1fbcB0A43A62ca7A241E7A42ca58EeF96eb;
address[] internal whaleAccounts = [EZETH_WHALE];

// The configuration for the Instance testing suite.
// The configuration for the instance testing suite.
InstanceTestConfig internal __testConfig =
InstanceTestConfig(
"Hyperdrive",
Expand All @@ -73,10 +73,11 @@ contract EzETHHyperdriveTest is InstanceTest {
false,
true,
false,
true
true,
abi.encodeWithSelector(IHyperdrive.UnsupportedToken.selector)
);

/// @dev Instantiates the Instance testing suite with the configuration.
/// @dev Instantiates the instance testing suite with the configuration.
constructor() InstanceTest(__testConfig) {}

/// @dev Forge function that is invoked to setup the testing environment.
Expand All @@ -87,7 +88,7 @@ contract EzETHHyperdriveTest is InstanceTest {
RESTAKE_MANAGER.depositETH{ value: 50_000e18 }();
vm.stopPrank();

// Invoke the Instance testing suite setup.
// Invoke the instance testing suite setup.
super.setUp();
}

Expand Down
9 changes: 5 additions & 4 deletions test/instances/lseth/LsETHHyperdrive.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ contract LsETHHyperdriveTest is InstanceTest {
LSETH_WHALE_3
];

// The configuration for the Instance testing suite.
// The configuration for the instance testing suite.
InstanceTestConfig internal __testConfig =
InstanceTestConfig(
"Hyperdrive",
Expand All @@ -60,16 +60,17 @@ contract LsETHHyperdriveTest is InstanceTest {
false,
true,
false,
true
true,
abi.encodeWithSelector(IHyperdrive.UnsupportedToken.selector)
);

/// @dev Instantiates the Instance testing suite with the configuration.
/// @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.
// Invoke the instance testing suite setup.
super.setUp();
}

Expand Down
117 changes: 77 additions & 40 deletions test/instances/morpho-blue/MorphoBlueHyperdrive.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ contract MorphoBlueHyperdriveTest is InstanceTest {
address(0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb);
address[] internal baseTokenWhaleAccounts = [LOAN_TOKEN_WHALE];

// The configuration for the Instance testing suite.
// The configuration for the instance testing suite.
InstanceTestConfig internal __testConfig =
InstanceTestConfig({
name: "Hyperdrive",
Expand All @@ -90,15 +90,18 @@ contract MorphoBlueHyperdriveTest is InstanceTest {
enableBaseDeposits: true,
enableShareDeposits: false,
enableBaseWithdraws: true,
enableShareWithdraws: false
enableShareWithdraws: false,
baseWithdrawError: abi.encodeWithSelector(
IHyperdrive.UnsupportedToken.selector
)
});

/// @dev Instantiates the Instance testing suite with the configuration.
/// @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(20_276_503) {
// Invoke the Instance testing suite setup.
// Invoke the instance testing suite setup.
super.setUp();
}

Expand Down Expand Up @@ -384,14 +387,14 @@ contract MorphoBlueHyperdriveTest is InstanceTest {

/// LP ///

function test_round_trip_lp_instantaneous() external {
function test_round_trip_lp_instantaneous(uint256 _contribution) external {
// Bob adds liquidity with base.
uint256 contribution = 2_500e18;
_contribution = _contribution.normalizeToRange(100e18, 100_000e18);
IERC20(hyperdrive.baseToken()).approve(
address(hyperdrive),
contribution
_contribution
);
uint256 lpShares = addLiquidity(bob, contribution);
uint256 lpShares = addLiquidity(bob, _contribution);

// Get some balance information before the withdrawal.
(
Expand All @@ -412,7 +415,7 @@ contract MorphoBlueHyperdriveTest is InstanceTest {

// Bob should receive approximately as much base as he contributed since
// no time as passed and the fees are zero.
assertApproxEqAbs(baseProceeds, contribution, 1e10);
assertApproxEqAbs(baseProceeds, _contribution, 1e12);

// Ensure that the withdrawal was processed as expected.
verifyWithdrawal(
Expand All @@ -426,14 +429,17 @@ contract MorphoBlueHyperdriveTest is InstanceTest {
);
}

function test_round_trip_lp_withdrawal_shares() external {
function test_round_trip_lp_withdrawal_shares(
uint256 _contribution,
uint256 _variableRate
) external {
// Bob adds liquidity with base.
uint256 contribution = 2_500e18;
_contribution = _contribution.normalizeToRange(100e18, 100_000e18);
IERC20(hyperdrive.baseToken()).approve(
address(hyperdrive),
contribution
_contribution
);
uint256 lpShares = addLiquidity(bob, contribution);
uint256 lpShares = addLiquidity(bob, _contribution);

// Alice opens a large short.
vm.stopPrank();
Expand All @@ -450,11 +456,11 @@ contract MorphoBlueHyperdriveTest is InstanceTest {
bob,
lpShares
);
assertEq(baseProceeds, 0);
assertGt(withdrawalShares, 0);

// The term passes and interest accrues.
advanceTime(POSITION_DURATION, 1.421e18);
_variableRate = _variableRate.normalizeToRange(0, 2.5e18);
advanceTime(POSITION_DURATION, int256(_variableRate));

// Bob should be able to redeem all of his withdrawal shares for
// approximately the LP share price.
Expand All @@ -471,7 +477,7 @@ contract MorphoBlueHyperdriveTest is InstanceTest {
assertApproxEqAbs(
baseProceeds,
withdrawalShares.mulDown(lpSharePrice),
1e9
1e11
);
}

Expand Down Expand Up @@ -507,11 +513,14 @@ contract MorphoBlueHyperdriveTest is InstanceTest {
);
}

function test_round_trip_long_instantaneous() external {
function test_round_trip_long_instantaneous(uint256 _basePaid) external {
// Bob opens a long with base.
uint256 basePaid = hyperdrive.calculateMaxLong();
IERC20(hyperdrive.baseToken()).approve(address(hyperdrive), basePaid);
(uint256 maturityTime, uint256 longAmount) = openLong(bob, basePaid);
_basePaid = _basePaid.normalizeToRange(
2 * hyperdrive.getPoolConfig().minimumTransactionAmount,
hyperdrive.calculateMaxLong()
);
IERC20(hyperdrive.baseToken()).approve(address(hyperdrive), _basePaid);
(uint256 maturityTime, uint256 longAmount) = openLong(bob, _basePaid);

// Get some balance information before the withdrawal.
(
Expand All @@ -528,7 +537,7 @@ contract MorphoBlueHyperdriveTest is InstanceTest {

// Bob should receive approximately as much base as he paid since no
// time as passed and the fees are zero.
assertApproxEqAbs(baseProceeds, basePaid, 1e9);
assertApproxEqAbs(baseProceeds, _basePaid, 1e9);

// Ensure that the withdrawal was processed as expected.
verifyWithdrawal(
Expand All @@ -542,14 +551,21 @@ contract MorphoBlueHyperdriveTest is InstanceTest {
);
}

function test_round_trip_long_maturity() external {
function test_round_trip_long_maturity(
uint256 _basePaid,
uint256 _variableRate
) external {
// Bob opens a long with base.
uint256 basePaid = hyperdrive.calculateMaxLong();
IERC20(hyperdrive.baseToken()).approve(address(hyperdrive), basePaid);
(uint256 maturityTime, uint256 longAmount) = openLong(bob, basePaid);
_basePaid = _basePaid.normalizeToRange(
2 * hyperdrive.getPoolConfig().minimumTransactionAmount,
hyperdrive.calculateMaxLong()
);
IERC20(hyperdrive.baseToken()).approve(address(hyperdrive), _basePaid);
(uint256 maturityTime, uint256 longAmount) = openLong(bob, _basePaid);

// Advance the time and accrue a large amount of interest.
advanceTime(POSITION_DURATION, 137.123423e18);
_variableRate = _variableRate.normalizeToRange(0, 1000e18);
advanceTime(POSITION_DURATION, int256(_variableRate));

// Get some balance information before the withdrawal.
(
Expand All @@ -565,6 +581,7 @@ contract MorphoBlueHyperdriveTest is InstanceTest {
uint256 baseProceeds = closeLong(bob, maturityTime, longAmount);

// Bob should receive almost exactly his bond amount.
assertLe(baseProceeds, longAmount);
assertApproxEqAbs(baseProceeds, longAmount, 2);

// Ensure that the withdrawal was processed as expected.
Expand Down Expand Up @@ -612,14 +629,19 @@ contract MorphoBlueHyperdriveTest is InstanceTest {
);
}

function test_round_trip_short_instantaneous() external {
function test_round_trip_short_instantaneous(
uint256 _shortAmount
) external {
// Bob opens a short with base.
uint256 shortAmount = hyperdrive.calculateMaxShort();
_shortAmount = _shortAmount.normalizeToRange(
2 * hyperdrive.getPoolConfig().minimumTransactionAmount,
hyperdrive.calculateMaxShort()
);
IERC20(hyperdrive.baseToken()).approve(
address(hyperdrive),
shortAmount
_shortAmount
);
(uint256 maturityTime, uint256 basePaid) = openShort(bob, shortAmount);
(uint256 maturityTime, uint256 basePaid) = openShort(bob, _shortAmount);

// Get some balance information before the withdrawal.
(
Expand All @@ -632,7 +654,7 @@ contract MorphoBlueHyperdriveTest is InstanceTest {
);

// Bob closes his long with base as the target asset.
uint256 baseProceeds = closeShort(bob, maturityTime, shortAmount);
uint256 baseProceeds = closeShort(bob, maturityTime, _shortAmount);

// Bob should receive approximately as much base as he paid since no
// time as passed and the fees are zero.
Expand All @@ -650,18 +672,24 @@ contract MorphoBlueHyperdriveTest is InstanceTest {
);
}

function test_round_trip_short_maturity() external {
function test_round_trip_short_maturity(
uint256 _shortAmount,
uint256 _variableRate
) external {
// Bob opens a short with base.
uint256 shortAmount = hyperdrive.calculateMaxShort();
_shortAmount = _shortAmount.normalizeToRange(
2 * hyperdrive.getPoolConfig().minimumTransactionAmount,
hyperdrive.calculateMaxShort()
);
IERC20(hyperdrive.baseToken()).approve(
address(hyperdrive),
shortAmount
_shortAmount
);
(uint256 maturityTime, ) = openShort(bob, shortAmount);
(uint256 maturityTime, ) = openShort(bob, _shortAmount);

// The term passes and some interest accrues.
int256 variableAPR = 0.57e18;
advanceTime(POSITION_DURATION, variableAPR);
_variableRate = _variableRate.normalizeToRange(0, 2.5e18);
advanceTime(POSITION_DURATION, int256(_variableRate));

// Get some balance information before the withdrawal.
(
Expand All @@ -674,14 +702,14 @@ contract MorphoBlueHyperdriveTest is InstanceTest {
);

// Bob closes his long with base as the target asset.
uint256 baseProceeds = closeShort(bob, maturityTime, shortAmount);
uint256 baseProceeds = closeShort(bob, maturityTime, _shortAmount);

// Bob should receive almost exactly the interest that accrued on the
// bonds that were shorted.
assertApproxEqAbs(
baseProceeds,
shortAmount.mulDown(uint256(variableAPR)),
1e9
_shortAmount.mulDown(_variableRate),
1e10
);

// Ensure that the withdrawal was processed as expected.
Expand Down Expand Up @@ -735,5 +763,14 @@ contract MorphoBlueHyperdriveTest is InstanceTest {
bytes32(uint256(marketLocation) + 2),
bytes32((uint256(market.fee) << 128) | uint256(block.timestamp))
);

// In order to prevent transfers from failing, we also need to increase
// the DAI balance of the Morpho vault to match the total assets.
bytes32 balanceLocation = keccak256(abi.encode(address(MORPHO), 2));
vm.store(
address(LOAN_TOKEN),
balanceLocation,
bytes32(totalSupplyAssets)
);
}
}
7 changes: 4 additions & 3 deletions test/instances/reth/RETHHyperdrive.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,19 @@ contract RETHHyperdriveTest is InstanceTest {
false,
true,
true,
true
true,
new bytes(0)
);

/// @dev Instantiates the Instance testing suite with the configuration.
/// @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.
// Invoke the instance testing suite setup.
super.setUp();
}

Expand Down
Loading

0 comments on commit 4ca3f48

Please sign in to comment.