Skip to content

Commit

Permalink
Allow traders to specify the counterparty and fee recipient of their …
Browse files Browse the repository at this point in the history
…trades
  • Loading branch information
jalextowle committed Dec 16, 2024
1 parent 397b382 commit 9b3ec1c
Show file tree
Hide file tree
Showing 4 changed files with 309 additions and 3 deletions.
15 changes: 15 additions & 0 deletions contracts/src/interfaces/IHyperdriveMatchingEngine.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,18 @@ interface IHyperdriveMatchingEngine is IMorphoFlashLoanCallback {
/// @notice Thrown when an order is already expired.
error AlreadyExpired();

/// @notice Thrown when the counterparty doesn't match the counterparty
/// signed into the order.
error InvalidCounterparty();

/// @notice Thrown when the destination for the add or remove liquidity
/// options isn't configured to this contract.
error InvalidDestination();

/// @notice Thrown when the fee recipient doesn't match the fee recipient
/// signed into the order.
error InvalidFeeRecipient();

/// @notice Thrown when orders that don't cross are matched.
error InvalidMatch();

Expand Down Expand Up @@ -66,6 +74,13 @@ interface IHyperdriveMatchingEngine is IMorphoFlashLoanCallback {
struct OrderIntent {
/// @dev The trader address that will be charged when orders are matched.
address trader;
/// @dev The counterparty of the trade. If left as zero, the validation
/// is skipped.
address counterparty;
/// @dev The fee recipient of the trade. This is the address that will
/// receive any excess trading fees on the match. If left as zero,
/// the validation is skipped.
address feeRecipient;
/// @dev The Hyperdrive address where the trade will be executed.
IHyperdrive hyperdrive;
/// @dev The amount to be used in the trade. In the case of `OpenLong`,
Expand Down
31 changes: 28 additions & 3 deletions contracts/src/matching/HyperdriveMatchingEngine.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ contract HyperdriveMatchingEngine is
/// struct.
bytes32 public constant ORDER_INTENT_TYPEHASH =
keccak256(
"OrderIntent(address trader,address hyperdrive,uint256 amount,uint256 slippageGuard,uint256 minVaultSharePrice,Options options,uint8 orderType,uint256 expiry,bytes32 salt)"
"OrderIntent(address trader,address counterparty,address feeRecipient,address hyperdrive,uint256 amount,uint256 slippageGuard,uint256 minVaultSharePrice,Options options,uint8 orderType,uint256 expiry,bytes32 salt)"
);

/// @notice The EIP712 typehash of the `IHyperdrive.Options` struct.
Expand Down Expand Up @@ -130,7 +130,8 @@ contract HyperdriveMatchingEngine is
_longOrder,
_shortOrder,
_addLiquidityOptions,
_removeLiquidityOptions
_removeLiquidityOptions,
_feeRecipient
);

// Cancel the orders so that they can't be used again.
Expand Down Expand Up @@ -256,6 +257,8 @@ contract HyperdriveMatchingEngine is
abi.encode(
ORDER_INTENT_TYPEHASH,
_order.trader,
_order.counterparty,
_order.feeRecipient,
_order.hyperdrive,
_order.amount,
_order.slippageGuard,
Expand Down Expand Up @@ -389,13 +392,15 @@ contract HyperdriveMatchingEngine is
/// @param _shortOrder The order intent to open a short.
/// @param _addLiquidityOptions The options used when adding liquidity.
/// @param _removeLiquidityOptions The options used when removing liquidity.
/// @param _feeRecipient The fee recipient of the match.
/// @return longOrderHash The hash of the long order.
/// @return shortOrderHash The hash of the short order.
function _validateOrders(
OrderIntent calldata _longOrder,
OrderIntent calldata _shortOrder,
IHyperdrive.Options calldata _addLiquidityOptions,
IHyperdrive.Options calldata _removeLiquidityOptions
IHyperdrive.Options calldata _removeLiquidityOptions,
address _feeRecipient
) internal view returns (bytes32 longOrderHash, bytes32 shortOrderHash) {
// Ensure that the long and short orders are the correct type.
if (
Expand All @@ -405,6 +410,26 @@ contract HyperdriveMatchingEngine is
revert InvalidOrderType();
}

// Ensure that the counterparties are compatible.
if (
(_longOrder.counterparty != address(0) &&
_longOrder.counterparty != _shortOrder.trader) ||
(_shortOrder.counterparty != address(0) &&
_shortOrder.counterparty != _longOrder.trader)
) {
revert InvalidCounterparty();
}

// Ensure that the fee recipients are compatible.
if (
(_longOrder.feeRecipient != address(0) &&
_longOrder.feeRecipient != _feeRecipient) ||
(_shortOrder.feeRecipient != address(0) &&
_shortOrder.feeRecipient != _feeRecipient)
) {
revert InvalidFeeRecipient();
}

// Ensure that neither order has expired.
if (
_longOrder.expiry <= block.timestamp ||
Expand Down
8 changes: 8 additions & 0 deletions test/integrations/matching/DirectMatchTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ contract DirectMatchTest is HyperdriveTest {
IHyperdriveMatchingEngine.OrderIntent
memory longOrder = IHyperdriveMatchingEngine.OrderIntent({
trader: LP,
counterparty: HEDGER,
feeRecipient: LP,
hyperdrive: hyperdrive,
amount: 2_440_000e6,
slippageGuard: 2_499_999e6,
Expand All @@ -255,6 +257,8 @@ contract DirectMatchTest is HyperdriveTest {
IHyperdriveMatchingEngine.OrderIntent
memory shortOrder = IHyperdriveMatchingEngine.OrderIntent({
trader: HEDGER,
counterparty: LP,
feeRecipient: LP,
hyperdrive: hyperdrive,
amount: 2_500_000e6,
slippageGuard: 65_000e6,
Expand Down Expand Up @@ -315,6 +319,8 @@ contract DirectMatchTest is HyperdriveTest {
// Create two more orders and sign them.
longOrder = IHyperdriveMatchingEngine.OrderIntent({
trader: LP,
counterparty: HEDGER,
feeRecipient: LP,
hyperdrive: hyperdrive,
amount: 2_440_000e6,
slippageGuard: 2_499_999e6,
Expand All @@ -333,6 +339,8 @@ contract DirectMatchTest is HyperdriveTest {
});
shortOrder = IHyperdriveMatchingEngine.OrderIntent({
trader: HEDGER,
counterparty: LP,
feeRecipient: LP,
hyperdrive: hyperdrive,
amount: 2_500_000e6,
slippageGuard: 65_000e6,
Expand Down
Loading

0 comments on commit 9b3ec1c

Please sign in to comment.