Skip to content

Commit

Permalink
portfolio and 4626 fixes/tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mcclurejt committed Sep 7, 2024
1 parent 6cee98d commit 7f2543d
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 18 deletions.
39 changes: 29 additions & 10 deletions contracts/Everlong.sol
Original file line number Diff line number Diff line change
Expand Up @@ -216,14 +216,27 @@ contract Everlong is IEverlong {
);
}

/// @dev Rebalance after a deposit if needed.
function _afterDeposit(uint256, uint256) internal virtual override {
if (canRebalance()) {
rebalance();
}
}

/// @dev Frees sufficient assets for a withdrawal by closing positions.
/// @param _assets Amount of assets owed to the withdrawer.
function _beforeWithdraw(
uint256 _assets,
uint256
) internal virtual override {
// Close more positions until sufficient idle to process withdrawal.
_closePositions(_assets - _asset.balanceOf(address(this)));
// Obtain everlong's idle balance.
uint256 balance = _asset.balanceOf(address(this));

// Close positions until sufficient idle is present to process the
// withdrawal.
if (balance < _assets) {
_closePositions(_assets - _asset.balanceOf(address(this)));
}
}

// ╭─────────────────────────────────────────────────────────╮
Expand All @@ -248,6 +261,14 @@ contract Everlong is IEverlong {
_portfolio.handleOpenPosition(maturityTime, bondAmount);
}

// FIXME: Consider idle liquidity + maybe maxLong?
//
/// @notice Returns whether the portfolio needs rebalancing.
/// @return True if the portfolio needs rebalancing, false otherwise.
function canRebalance() public view returns (bool) {
return true;
}

// ╭─────────────────────────────────────────────────────────╮
// │ Hyperdrive │
// ╰─────────────────────────────────────────────────────────╯
Expand Down Expand Up @@ -308,6 +329,12 @@ contract Everlong is IEverlong {
return _decimals;
}

/// @dev The decimal offset used for virtual shares.
/// @return The decimal offset used for virtual shares.
function _decimalsOffset() internal view virtual override returns (uint8) {
return decimalsOffset;
}

/// @notice The address of the underlying Hyperdrive Instance.
/// @return The address of the underlying Hyperdrive Instance.
function hyperdrive() external view override returns (address) {
Expand All @@ -331,14 +358,6 @@ contract Everlong is IEverlong {
return _admin;
}

// FIXME: Consider idle liquidity + maybe maxLong?
//
/// @notice Returns whether the portfolio needs rebalancing.
/// @return True if the portfolio needs rebalancing, false otherwise.
function canRebalance() external view returns (bool) {
return _hyperdrive.isMature(_portfolio.head());
}

/// @notice Returns whether the portfolio has matured positions.
/// @return True if the portfolio has matured positions, false otherwise.
function hasMaturedPositions() external view returns (bool) {
Expand Down
1 change: 0 additions & 1 deletion test/integration/CloseImmatureLongs.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ contract PricingTest is EverlongTest {
ERC20Mintable(everlong.asset()).mint(basePaid);
ERC20Mintable(everlong.asset()).approve(address(everlong), basePaid);
uint256 shares = everlong.deposit(basePaid, bob);
everlong.rebalance();

// half term passes
advanceTimeWithCheckpoints(POSITION_DURATION / 2, variableInterest);
Expand Down
42 changes: 40 additions & 2 deletions test/units/EverlongERC4626.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ contract TestEverlongERC4626 is EverlongTest {

/// @dev Tests that previewRedeem does not overestimate proceeds for a
/// single shareholder immediately redeeming part of their shares.
function test_previewRedeem_single_partial() external {
function test_previewRedeem_single_instant_partial() external {
// Deploy the everlong instance.
deployEverlong();

Expand All @@ -52,6 +52,44 @@ contract TestEverlongERC4626 is EverlongTest {

// Ensure that previewRedeem output is at most equal to actual output
// and within margins.
assertRedemption(shares - 1, alice);
assertRedemption(shares / 2, alice);
}

/// @dev Tests that previewRedeem does not overestimate proceeds for a
/// single shareholder waiting half the position duration and
/// redeeming all their shares.
function test_previewRedeem_single_unmatured_full() external {
// Deploy the everlong instance.
deployEverlong();

// Deposit into everlong.
uint256 amount = 250e18;
uint256 shares = depositEverlong(amount, alice);

// Fast forward to halfway through maturity.
advanceTime(POSITION_DURATION / 2, VARIABLE_RATE);

// Ensure that previewRedeem output is at most equal to actual output
// and within margins.
assertRedemption(shares, alice);
}

/// @dev Tests that previewRedeem does not overestimate proceeds for a
/// single shareholder waiting half the position duration and
/// redeeming some of their shares.
function test_previewRedeem_single_unmatured_partial() external {
// Deploy the everlong instance.
deployEverlong();

// Deposit into everlong.
uint256 amount = 250e18;
uint256 shares = depositEverlong(amount, alice);

// Fast forward to halfway through maturity.
advanceTime(POSITION_DURATION / 2, VARIABLE_RATE);

// Ensure that previewRedeem output is at most equal to actual output
// and within margins.
assertRedemption(shares / 3, alice);
}
}
8 changes: 3 additions & 5 deletions test/units/EverlongPortfolio.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,7 @@ contract TestEverlongPositions is EverlongTest {
);

// Record an opened position.
// Check that:
// - `PositionOpened` event is emitted
// - Position count is increased
vm.expectEmit(true, true, true, true);
// Check that position count is increased
portfolio.handleOpenPosition(1, 1);
assertEq(
portfolio.positionCount(),
Expand Down Expand Up @@ -113,11 +110,12 @@ contract TestEverlongPositions is EverlongTest {
// Record opening and fully closing a long.
// Check that `PositionClosed` event is emitted.
portfolio.handleOpenPosition(1, 1);
console.log("hello");
portfolio.handleClosePosition();

// Check position count is 0.
assertEq(
everlong.positionCount(),
portfolio.positionCount(),
0,
"position count should be 0 after opening and closing a long for the full bond amount"
);
Expand Down

0 comments on commit 7f2543d

Please sign in to comment.