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
6 changes: 5 additions & 1 deletion contracts/src/internal/HyperdriveLP.sol
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ abstract contract HyperdriveLP is
// Redeem as many of the withdrawal shares as possible.
uint256 withdrawalSharesRedeemed;
(proceeds, withdrawalSharesRedeemed) = _redeemWithdrawalSharesInternal(
_options.destination,
_lpShares,
vaultSharePrice,
_minOutputPerShare,
Expand Down Expand Up @@ -346,6 +347,7 @@ abstract contract HyperdriveLP is

// Redeem as many of the withdrawal shares as possible.
(proceeds, withdrawalSharesRedeemed) = _redeemWithdrawalSharesInternal(
msg.sender,
_withdrawalShares,
vaultSharePrice,
_minOutputPerShare,
Expand All @@ -372,6 +374,7 @@ abstract contract HyperdriveLP is
/// withdrawal pool's proceeds. This function redeems the maximum
/// amount of the specified withdrawal shares given the amount of
/// withdrawal shares ready to withdraw.
/// @param _source The address that owns the withdrawal shares to redeem.
/// @param _withdrawalShares The withdrawal shares to redeem.
/// @param _sharePrice The share price.
/// @param _minOutputPerShare The minimum amount of base the LP expects to
Expand All @@ -381,6 +384,7 @@ abstract contract HyperdriveLP is
/// @return withdrawalSharesRedeemed The amount of withdrawal shares that
/// were redeemed.
function _redeemWithdrawalSharesInternal(
address _source,
uint256 _withdrawalShares,
uint256 _sharePrice,
uint256 _minOutputPerShare,
Expand All @@ -399,7 +403,7 @@ abstract contract HyperdriveLP is
// We burn the shares from the user.
_burn(
AssetId._WITHDRAWAL_SHARE_ASSET_ID,
msg.sender,
_source,
withdrawalSharesRedeemed
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ contract NegativeInterestLongFeeTest is HyperdriveTest {
basePaid,
DepositOverrides({
asBase: true,
destination: bob,
depositAmount: basePaid,
minSharePrice: 0,
minSlippage: 0, // TODO: This should never go below the base amount. Investigate this.
Expand Down Expand Up @@ -353,6 +354,7 @@ contract NegativeInterestLongFeeTest is HyperdriveTest {
basePaid,
DepositOverrides({
asBase: true,
destination: bob,
depositAmount: basePaid,
minSharePrice: 0,
minSlippage: 0, // TODO: This should never go below the base amount. Investigate this.
Expand Down Expand Up @@ -558,6 +560,7 @@ contract NegativeInterestLongFeeTest is HyperdriveTest {
basePaid,
DepositOverrides({
asBase: true,
destination: bob,
depositAmount: basePaid,
minSharePrice: 0,
minSlippage: 0, // TODO: This should never go below the base amount. Investigate this.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ contract NegativeInterestShortFeeTest is HyperdriveTest {
shortAmount,
DepositOverrides({
asBase: true,
destination: bob,
// NOTE: Roughly double deposit amount needed to cover 100% flat fee
depositAmount: shortAmount * 2,
minSharePrice: 0,
Expand Down Expand Up @@ -557,6 +558,7 @@ contract NegativeInterestShortFeeTest is HyperdriveTest {
shortAmount,
DepositOverrides({
asBase: true,
destination: bob,
// NOTE: Roughly double deposit amount needed to cover 100% flat fee
depositAmount: shortAmount * 2,
minSharePrice: 0,
Expand Down
1 change: 1 addition & 0 deletions test/integrations/hyperdrive/NonstandardDecimals.sol
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ contract NonstandardDecimalsTest is HyperdriveTest {
// checking for reverts.
DepositOverrides memory overrides = DepositOverrides({
asBase: true,
destination: celine,
depositAmount: testParams.contribution,
minSharePrice: 0, // unused
minSlippage: spotAPRBefore - 0.015e18, // min spot rate of .5%
Expand Down
5 changes: 5 additions & 0 deletions test/integrations/hyperdrive/ReentrancyTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ contract ReentrancyTest is HyperdriveTest {
// the ETH receiver will receive a refund.
DepositOverrides({
asBase: true,
destination: _trader,
depositAmount: CONTRIBUTION + 1,
minSharePrice: 0,
minSlippage: 0,
Expand Down Expand Up @@ -326,6 +327,7 @@ contract ReentrancyTest is HyperdriveTest {
// the ETH receiver will receive a refund.
DepositOverrides({
asBase: true,
destination: _trader,
depositAmount: CONTRIBUTION + 1,
minSharePrice: 0,
minSlippage: 0,
Expand Down Expand Up @@ -393,6 +395,7 @@ contract ReentrancyTest is HyperdriveTest {
// the ETH receiver will receive a refund.
DepositOverrides({
asBase: true,
destination: _trader,
depositAmount: BASE_PAID + 1,
minSharePrice: 0,
minSlippage: 0,
Expand Down Expand Up @@ -433,6 +436,7 @@ contract ReentrancyTest is HyperdriveTest {
// ETH receiver will receive a refund.
DepositOverrides({
asBase: true,
destination: _trader,
// NOTE: Roughly double deposit amount needed to cover 100% flat fee
depositAmount: BOND_AMOUNT * 2,
minSharePrice: 0,
Expand All @@ -452,6 +456,7 @@ contract ReentrancyTest is HyperdriveTest {
BOND_AMOUNT,
DepositOverrides({
asBase: true,
destination: _trader,
// NOTE: Roughly double deposit amount needed to cover 100% flat fee
depositAmount: BOND_AMOUNT * 2,
minSharePrice: 0,
Expand Down
29 changes: 29 additions & 0 deletions test/units/hyperdrive/AddLiquidityTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,35 @@ contract AddLiquidityTest is HyperdriveTest {
);
}

function test_add_liquidity_destination() external {
// Initialize the pool with a large amount of capital.
uint256 fixedRate = 0.05e18;
uint256 contribution = 500_000_000e18;
initialize(alice, fixedRate, contribution);

// Bob adds liquidity and sends the LP shares to Celine.
uint256 lpShares = addLiquidity(
bob,
contribution,
DepositOverrides({
asBase: true,
destination: celine,
depositAmount: contribution,
minSharePrice: 0, // min lp share price of 0
minSlippage: 0, // min spot rate of 0
maxSlippage: type(uint256).max, // max spot rate of uint256 max
extraData: new bytes(0) // unused
})
);

// Ensure that the correct event was emitted.
verifyAddLiquidityEvent(celine, lpShares, contribution);

// Ensure that Celine received the LP shares.
assertEq(hyperdrive.balanceOf(AssetId._LP_ASSET_ID, bob), 0);
assertEq(hyperdrive.balanceOf(AssetId._LP_ASSET_ID, celine), lpShares);
}

function verifyAddLiquidity(
address lp,
uint256 contribution
Expand Down
105 changes: 70 additions & 35 deletions test/units/hyperdrive/CloseLongTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,37 @@ contract CloseLongTest is HyperdriveTest {
assertGt(maxFlatFeeState.shareReserves, zeroFeeState.shareReserves);
}

function test_close_long_destination() external {
// Initialize the pool with a large amount of capital.
uint256 fixedRate = 0.05e18;
uint256 contribution = 500_000_000e18;
initialize(alice, fixedRate, contribution);

// Bob opens a long.
uint256 basePaid = 1_000_000e18;
(uint256 maturityTime, uint256 bondAmount) = openLong(bob, basePaid);

// Bob closes his long and sends the proceeds to Celine.
uint256 baseProceeds = closeLong(
bob,
maturityTime,
bondAmount,
WithdrawalOverrides({
asBase: true,
destination: celine,
minSlippage: 0,
extraData: new bytes(0)
})
);

// Ensure that the correct event was emitted.
verifyCloseLongEvent(celine, maturityTime, bondAmount, baseProceeds);

// Ensure that the proceeds were sent to Celine.
assertEq(baseToken.balanceOf(bob), 0);
assertEq(baseToken.balanceOf(celine), baseProceeds);
}

struct TestCase {
IHyperdrive.PoolInfo poolInfoBefore;
uint256 traderBaseBalanceBefore;
Expand All @@ -893,41 +924,12 @@ contract CloseLongTest is HyperdriveTest {
function verifyCloseLong(TestCase memory testCase) internal {
// Ensure that one `CloseLong` event was emitted with the correct
// arguments.
{
VmSafe.Log[] memory logs = vm.getRecordedLogs().filterLogs(
CloseLong.selector
);
assertEq(logs.length, 1);
VmSafe.Log memory log = logs[0];
assertEq(address(uint160(uint256(log.topics[1]))), bob);
assertEq(
uint256(log.topics[2]),
AssetId.encodeAssetId(
AssetId.AssetIdPrefix.Long,
testCase.maturityTime
)
);
(
uint256 eventMaturityTime,
uint256 eventBaseAmount,
uint256 eventVaultShareAmount,
bool eventAsBase,
uint256 eventBondAmount
) = abi.decode(
log.data,
(uint256, uint256, uint256, bool, uint256)
);
assertEq(eventMaturityTime, testCase.maturityTime);
assertEq(eventBaseAmount, testCase.baseProceeds);
assertEq(
eventVaultShareAmount,
testCase.baseProceeds.divDown(
hyperdrive.getPoolInfo().vaultSharePrice
)
);
assertEq(eventAsBase, true);
assertEq(eventBondAmount, testCase.bondAmount);
}
verifyCloseLongEvent(
bob,
testCase.maturityTime,
testCase.bondAmount,
testCase.baseProceeds
);

// Ensure that the correct amount of base was transferred.
assertEq(
Expand Down Expand Up @@ -1044,4 +1046,37 @@ contract CloseLongTest is HyperdriveTest {
);
assertEq(poolInfoAfter.shortAverageMaturityTime, 0);
}

function verifyCloseLongEvent(
address destination,
uint256 maturityTime,
uint256 bondAmount,
uint256 baseProceeds
) internal {
VmSafe.Log[] memory logs = vm.getRecordedLogs().filterLogs(
CloseLong.selector
);
assertEq(logs.length, 1);
VmSafe.Log memory log = logs[0];
assertEq(address(uint160(uint256(log.topics[1]))), destination);
assertEq(
uint256(log.topics[2]),
AssetId.encodeAssetId(AssetId.AssetIdPrefix.Long, maturityTime)
);
(
uint256 eventMaturityTime,
uint256 eventBaseAmount,
uint256 eventVaultShareAmount,
bool eventAsBase,
uint256 eventBondAmount
) = abi.decode(log.data, (uint256, uint256, uint256, bool, uint256));
assertEq(eventMaturityTime, maturityTime);
assertEq(eventBaseAmount, baseProceeds);
assertEq(
eventVaultShareAmount,
baseProceeds.divDown(hyperdrive.getPoolInfo().vaultSharePrice)
);
assertEq(eventAsBase, true);
assertEq(eventBondAmount, bondAmount);
}
}
Loading