Skip to content

Commit

Permalink
Adds a unit test to test the fix
Browse files Browse the repository at this point in the history
  • Loading branch information
jalextowle committed Aug 19, 2023
1 parent a920da4 commit 1008653
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 18 deletions.
61 changes: 43 additions & 18 deletions contracts/src/HyperdriveShort.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,28 +58,28 @@ abstract contract HyperdriveShort is HyperdriveLP {
// backdate the bonds sold to the beginning of the checkpoint.
maturityTime = latestCheckpoint + _positionDuration;
uint256 timeRemaining = _calculateTimeRemaining(maturityTime);
(
uint256 shareReservesDelta,
uint256 totalGovernanceFee
) = _calculateOpenShort(_bondAmount, sharePrice, timeRemaining);
uint256 shareReservesDelta;
{
uint256 totalGovernanceFee;
(
traderDeposit,
shareReservesDelta,
totalGovernanceFee
) = _calculateOpenShort(
_bondAmount,
sharePrice,
openSharePrice,
timeRemaining
);

// Attribute the governance fees.
_governanceFeesAccrued += totalGovernanceFee;
// Attribute the governance fees.
_governanceFeesAccrued += totalGovernanceFee;
}

// Take custody of the trader's deposit and ensure that the trader
// doesn't pay more than their max deposit. The trader's deposit is
// equal to the proceeds that they would receive if they closed
// immediately (without fees).
traderDeposit = HyperdriveMath
.calculateShortProceeds(
_bondAmount,
shareReservesDelta - totalGovernanceFee, // FIXME: Explain this.
openSharePrice,
sharePrice,
sharePrice,
_flatFee
)
.mulDown(sharePrice);
if (_maxDeposit < traderDeposit) revert IHyperdrive.OutputLimit();
_deposit(traderDeposit, _asUnderlying);

Expand Down Expand Up @@ -415,16 +415,23 @@ abstract contract HyperdriveShort is HyperdriveLP {
/// opening a short. This calculation includes trading fees.
/// @param _bondAmount The amount of bonds being sold to open the short.
/// @param _sharePrice The current share price.
/// @param _openSharePrice The share price at the beginning of the checkpoint.
/// @param _timeRemaining The time remaining in the position.
/// @return traderDeposit The deposit required to open the short.
/// @return shareReservesDelta The change in the share reserves.
/// @return totalGovernanceFee The governance fee in shares.
function _calculateOpenShort(
uint256 _bondAmount,
uint256 _sharePrice,
uint256 _openSharePrice,
uint256 _timeRemaining
)
internal
returns (uint256 shareReservesDelta, uint256 totalGovernanceFee)
returns (
uint256 traderDeposit,
uint256 shareReservesDelta,
uint256 totalGovernanceFee
)
{
// Calculate the effect that opening the short should have on the pool's
// reserves as well as the amount of shares the trader receives from
Expand Down Expand Up @@ -479,7 +486,25 @@ abstract contract HyperdriveShort is HyperdriveLP {

// shares -= shares - shares
shareReservesDelta -= totalCurveFee - totalGovernanceFee;
return (shareReservesDelta, totalGovernanceFee);

// The trader will need to deposit capital to pay for the fixed rate,
// the curve fee, the flat fee, and any back-paid interest that will be
// received back upon closing the trade.
traderDeposit = HyperdriveMath
.calculateShortProceeds(
_bondAmount,
// NOTE: We add the governance fee back to the share reserves
// delta here because the trader will need to provide this in
// their deposit.
shareReservesDelta - totalGovernanceFee,
_openSharePrice,
_sharePrice,
_sharePrice,
_flatFee
)
.mulDown(_sharePrice);

return (traderDeposit, shareReservesDelta, totalGovernanceFee);
}

/// @dev Calculate the pool reserve and trader deltas that result from
Expand Down
35 changes: 35 additions & 0 deletions test/units/hyperdrive/OpenShortTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,41 @@ contract OpenShortTest is HyperdriveTest {
assertGe(maxCurveFeeState.shareReserves, maxFeeState.shareReserves);
}

// TODO: This test addresses a specific failure case in calculating the
// trader deposit. We should refactor the short calculation logic and fully
// unit test this, which would remove the need for this test.
function test_short_deposit_with_governance_fee() external {
uint256 fixedRate = 0.05e18;
uint256 contribution = 500_000_000e18;

// Alice initializes the pool. The pool has a curve fee of 100% and
// governance fees of 0%.
IHyperdrive.PoolConfig memory config = testConfig(fixedRate);
config.fees.curve = 1e18;
config.fees.governance = 0;
deploy(address(deployer), config);
initialize(alice, fixedRate, contribution);

// Bob opens a short position.
uint256 shortAmount = 100_000e18;
(, uint256 basePaid) = openShort(bob, shortAmount);

// Alice initializes the pool. The pool has a curve fee of 100% and
// governance fees of 100%.
config = testConfig(fixedRate);
config.fees.curve = 1e18;
config.fees.governance = 1e18;
deploy(address(deployer), config);
initialize(alice, fixedRate, contribution);

// Bob opens a short position.
(, uint256 basePaid2) = openShort(bob, shortAmount);

// The governance fee shouldn't effect the short's deposit, so the base
// paid should be the same in both cases.
assertEq(basePaid, basePaid2);
}

function verifyOpenShort(
IHyperdrive.PoolInfo memory poolInfoBefore,
uint256 contribution,
Expand Down

0 comments on commit 1008653

Please sign in to comment.