Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 36 additions & 11 deletions contracts/EverlongStrategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol";
import { BaseStrategy, ERC20 } from "tokenized-strategy/BaseStrategy.sol";
import { IEverlongStrategy } from "./interfaces/IEverlongStrategy.sol";
import { IERC20Wrappable } from "./interfaces/IERC20Wrappable.sol";
import { EVERLONG_STRATEGY_KIND, EVERLONG_VERSION, MAX_BPS, ONE } from "./libraries/Constants.sol";
import { EVERLONG_STRATEGY_KIND, EVERLONG_VERSION, ONE } from "./libraries/Constants.sol";
import { EverlongPortfolioLibrary } from "./libraries/EverlongPortfolio.sol";
import { HyperdriveExecutionLibrary } from "./libraries/HyperdriveExecution.sol";
import { IEverlongEvents } from "./interfaces/IEverlongEvents.sol";

// ,---..-. .-.,---. ,---. ,-. .---. .-. .-. ,--,
// | .-' \ \ / / | .-' | .-.\ | | / .-. ) | \| |.' .'
Expand Down Expand Up @@ -344,8 +345,11 @@ contract EverlongStrategy is BaseStrategy {
tendConfig.extraData
);

// Account for the new position in the portfolio.
_portfolio.handleOpenPosition(maturityTime, bondAmount);
// Only update the portfolio if _openLong was successful (indicated by non-zero bondAmount)
if (bondAmount > 0) {
// Account for the new position in the portfolio.
_portfolio.handleOpenPosition(maturityTime, bondAmount);
}
}
}

Expand Down Expand Up @@ -708,14 +712,35 @@ contract EverlongStrategy is BaseStrategy {
ERC20(asset).forceApprove(address(hyperdrive), _toSpend + 1);
}

// Open the long. Return the maturity time and amount of bonds received.
(maturityTime, bondAmount) = IHyperdrive(hyperdrive).openLong(
asBase,
_toSpend,
_minOutput,
_minVaultSharePrice,
_extraData
);
// Open the long using a try-catch to handle potential failures
// (e.g., deposit caps) gracefully.
try
IHyperdrive(hyperdrive).openLong(
_toSpend,
_minOutput,
_minVaultSharePrice,
IHyperdrive.Options({
destination: address(this),
asBase: asBase,
extraData: _extraData
})
)
returns (uint256 _maturityTime, uint256 _bondAmount) {
maturityTime = _maturityTime;
bondAmount = _bondAmount;

// Emit the position opened event as the library function would
emit IEverlongEvents.PositionOpened(
maturityTime.toUint128(),
bondAmount.toUint128()
);
} catch {
// If the openLong fails (e.g., due to deposit caps), return zeros
// to indicate no position was opened. The calling function (_tend)
// will not update the portfolio in this case.
maturityTime = 0;
bondAmount = 0;
}
}

/// @dev Preview the amount of assets received from closing the specified
Expand Down
38 changes: 34 additions & 4 deletions test/everlong/units/Tend.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,11 @@ contract TestTend is EverlongTest {
// Set minOutput to a very high value.
uint256 minOutput = type(uint256).max;

// Ensure `tend()` reverts.
vm.expectRevert();
// Record the initial position count and portfolio state
uint256 initialPositionCount = IEverlongStrategy(address(strategy)).positionCount();
uint256 initialTotalBonds = IEverlongStrategy(address(strategy)).totalBonds();

// Call tend() with extreme minOutput - should not revert with try/catch in place
keeperContract.tend(
address(strategy),
IEverlongStrategy.TendConfig({
Expand All @@ -239,6 +242,18 @@ contract TestTend is EverlongTest {
})
);

// Verify that no new position was opened (portfolio was not updated)
assertEq(
IEverlongStrategy(address(strategy)).positionCount(),
initialPositionCount,
"Position count should not change with impossible minOutput"
);
assertEq(
IEverlongStrategy(address(strategy)).totalBonds(),
initialTotalBonds,
"Total bonds should not change with impossible minOutput"
);

// Stop the prank.
vm.stopPrank();
}
Expand All @@ -257,8 +272,11 @@ contract TestTend is EverlongTest {
// Set minVaultSharePrice to a very high value.
uint256 minVaultSharePrice = type(uint256).max;

// Ensure `tend()` reverts.
vm.expectRevert();
// Record the initial position count and portfolio state
uint256 initialPositionCount = IEverlongStrategy(address(strategy)).positionCount();
uint256 initialTotalBonds = IEverlongStrategy(address(strategy)).totalBonds();

// Call tend() with extreme minVaultSharePrice - should not revert with try/catch in place
keeperContract.tend(
address(strategy),
IEverlongStrategy.TendConfig({
Expand All @@ -269,6 +287,18 @@ contract TestTend is EverlongTest {
})
);

// Verify that no new position was opened (portfolio was not updated)
assertEq(
IEverlongStrategy(address(strategy)).positionCount(),
initialPositionCount,
"Position count should not change with impossible minVaultSharePrice"
);
assertEq(
IEverlongStrategy(address(strategy)).totalBonds(),
initialTotalBonds,
"Total bonds should not change with impossible minVaultSharePrice"
);

// Stop the prank.
vm.stopPrank();
}
Expand Down
Loading