diff --git a/contracts/src/interfaces/IHyperdriveMatchingEngineV2.sol b/contracts/src/interfaces/IHyperdriveMatchingEngineV2.sol index 5ffeb7f50..b0f2a47b2 100644 --- a/contracts/src/interfaces/IHyperdriveMatchingEngineV2.sol +++ b/contracts/src/interfaces/IHyperdriveMatchingEngineV2.sol @@ -35,7 +35,7 @@ interface IHyperdriveMatchingEngineV2 { /// @notice Thrown when the long and short orders don't refer to the same /// Hyperdrive instance. error MismatchedHyperdrive(); - + /// @notice Thrown when the amount overflows. error AmountOverflow(); @@ -105,14 +105,14 @@ interface IHyperdriveMatchingEngineV2 { 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` or - /// `OpenShort`, this is the amount of funds to deposit; and in the - /// case of `CloseLong` or `CloseShort`, this is the min amount of + /// @dev The amount to be used in the trade. In the case of `OpenLong` or + /// `OpenShort`, this is the amount of funds to deposit; and in the + /// case of `CloseLong` or `CloseShort`, this is the min amount of /// funds to receive. uint256 fundAmount; /// @dev The minimum output amount expected from the trade. In the case of - /// `OpenLong` or `OpenShort`, this is the min amount of bonds to - /// receive; and in the case of `CloseLong` or `CloseShort`, this is + /// `OpenLong` or `OpenShort`, this is the min amount of bonds to + /// receive; and in the case of `CloseLong` or `CloseShort`, this is /// the amount of bonds to close. uint256 bondAmount; /// @dev The minimum vault share price. This protects traders against @@ -181,7 +181,9 @@ interface IHyperdriveMatchingEngineV2 { /// @param orderHash The hash of the order. /// @return bondAmount The bond amount used for the order. /// @return fundAmount The fund amount used for the order. - function orderAmountsUsed(bytes32 orderHash) external view returns (uint128 bondAmount, uint128 fundAmount); + function orderAmountsUsed( + bytes32 orderHash + ) external view returns (uint128 bondAmount, uint128 fundAmount); /// @notice Get the EIP712 typehash for the /// `IHyperdriveMatchingEngine.OrderIntent` struct. diff --git a/contracts/src/matching/HyperdriveMatchingEngineV2.sol b/contracts/src/matching/HyperdriveMatchingEngineV2.sol index a99b7b694..0a910d9ec 100644 --- a/contracts/src/matching/HyperdriveMatchingEngineV2.sol +++ b/contracts/src/matching/HyperdriveMatchingEngineV2.sol @@ -16,14 +16,14 @@ import { IHyperdriveMatchingEngineV2 } from "../interfaces/IHyperdriveMatchingEn /// @author DELV /// @title HyperdriveMatchingEngine -/// @notice A matching engine that processes order intents and settles trades on +/// @notice A matching engine that processes order intents and settles trades on /// the Hyperdrive AMM. -/// @dev This version uses direct Hyperdrive mint/burn functions instead of flash +/// @dev This version uses direct Hyperdrive mint/burn functions instead of flash /// loans. /// @custom:disclaimer The language used in this code is for coding convenience /// only, and is not intended to, and does not, have any /// particular legal or regulatory significance. -contract HyperdriveMatchingEngineV2 is +contract HyperdriveMatchingEngineV2 is IHyperdriveMatchingEngineV2, ReentrancyGuard, EIP712 @@ -69,7 +69,7 @@ contract HyperdriveMatchingEngineV2 is /// @notice Matches two orders. /// @param _order1 The first order to match. /// @param _order2 The second order to match. - /// @param _surplusRecipient The address that receives the surplus funds + /// @param _surplusRecipient The address that receives the surplus funds /// from matching the trades. function matchOrders( OrderIntent calldata _order1, @@ -78,7 +78,7 @@ contract HyperdriveMatchingEngineV2 is ) external nonReentrant { // Validate orders. (bytes32 order1Hash, bytes32 order2Hash) = _validateOrdersNoTaker( - _order1, + _order1, _order2 ); @@ -86,19 +86,25 @@ contract HyperdriveMatchingEngineV2 is // Handle different order type combinations. // Case 1: Long + Short creation using mint(). - if (_order1.orderType == OrderType.OpenLong && - _order2.orderType == OrderType.OpenShort) { + if ( + _order1.orderType == OrderType.OpenLong && + _order2.orderType == OrderType.OpenShort + ) { // Get necessary pool parameters. IHyperdrive.PoolConfig memory config = hyperdrive.getPoolConfig(); - - uint256 latestCheckpoint = _latestCheckpoint(config.checkpointDuration); + + uint256 latestCheckpoint = _latestCheckpoint( + config.checkpointDuration + ); // @dev TODO: there is another way to get the info without calling // getPoolInfo()? uint256 vaultSharePrice = hyperdrive.getPoolInfo().vaultSharePrice; - // Calculate the amount of fund tokens to transfer based on the + // Calculate the amount of fund tokens to transfer based on the // bondMatchAmount. - uint256 openVaultSharePrice = hyperdrive.getCheckpoint(latestCheckpoint).vaultSharePrice; + uint256 openVaultSharePrice = hyperdrive + .getCheckpoint(latestCheckpoint) + .vaultSharePrice; if (openVaultSharePrice == 0) { openVaultSharePrice = vaultSharePrice; } @@ -114,39 +120,54 @@ contract HyperdriveMatchingEngineV2 is // @dev This could have been placed before the control flow for // shorter code, but it's put here to avoid stack-too-deep. uint256 bondMatchAmount = _calculateBondMatchAmount( - order1, - order2, - order1Hash_, + order1, + order2, + order1Hash_, order2Hash_ ); - // Get the sufficient funding amount to mint the bonds. // NOTE: Round the required fund amount up to overestimate the cost. // Round the flat fee calculation up and the governance fee // calculation down to match the rounding used in the other flows. uint256 cost = bondMatchAmount.mulDivUp( - vaultSharePrice.max(openVaultSharePrice), - openVaultSharePrice) + + vaultSharePrice.max(openVaultSharePrice), + openVaultSharePrice + ) + bondMatchAmount.mulUp(config.fees.flat) + - 2 * bondMatchAmount.mulUp(config.fees.flat).mulDown(config.fees.governanceLP); + 2 * + bondMatchAmount.mulUp(config.fees.flat).mulDown( + config.fees.governanceLP + ); - // Calculate the amount of fund tokens to transfer based on the - // bondMatchAmount using dynamic pricing. During a series of partial - // matching, the pricing requirements can go easier as needed for each + // Calculate the amount of fund tokens to transfer based on the + // bondMatchAmount using dynamic pricing. During a series of partial + // matching, the pricing requirements can go easier as needed for each // new match, hence increasing the match likelihood. // NOTE: Round the required fund amount down to prevent overspending // and possible reverting at a later step. - uint256 fundTokenAmountOrder1 = (order1.fundAmount - orderAmountsUsed[order1Hash_].fundAmount).mulDivDown(bondMatchAmount, (order1.bondAmount - orderAmountsUsed[order1Hash_].bondAmount)); - uint256 fundTokenAmountOrder2 = (order2.fundAmount - orderAmountsUsed[order2Hash_].fundAmount).mulDivDown(bondMatchAmount, (order2.bondAmount - orderAmountsUsed[order2Hash_].bondAmount)); + uint256 fundTokenAmountOrder1 = (order1.fundAmount - + orderAmountsUsed[order1Hash_].fundAmount).mulDivDown( + bondMatchAmount, + (order1.bondAmount - + orderAmountsUsed[order1Hash_].bondAmount) + ); + uint256 fundTokenAmountOrder2 = (order2.fundAmount - + orderAmountsUsed[order2Hash_].fundAmount).mulDivDown( + bondMatchAmount, + (order2.bondAmount - + orderAmountsUsed[order2Hash_].bondAmount) + ); // Update order fund amount used. _updateOrderAmount(order1Hash_, fundTokenAmountOrder1, false); _updateOrderAmount(order2Hash_, fundTokenAmountOrder2, false); // Check if the fund amount used is greater than the order amount. - if (orderAmountsUsed[order1Hash_].fundAmount > order1.fundAmount || - orderAmountsUsed[order2Hash_].fundAmount > order2.fundAmount) { + if ( + orderAmountsUsed[order1Hash_].fundAmount > order1.fundAmount || + orderAmountsUsed[order2Hash_].fundAmount > order2.fundAmount + ) { revert InvalidFundAmount(); } @@ -154,8 +175,12 @@ contract HyperdriveMatchingEngineV2 is uint256 maturityTime = latestCheckpoint + config.positionDuration; // Check if the maturity time is within the range. - if (maturityTime < order1.minMaturityTime || maturityTime > order1.maxMaturityTime || - maturityTime < order2.minMaturityTime || maturityTime > order2.maxMaturityTime) { + if ( + maturityTime < order1.minMaturityTime || + maturityTime > order1.maxMaturityTime || + maturityTime < order2.minMaturityTime || + maturityTime > order2.maxMaturityTime + ) { revert InvalidMaturityTime(); } @@ -171,15 +196,16 @@ contract HyperdriveMatchingEngineV2 is // Mint the bonds. uint256 bondAmount = _handleMint( - order1, - order2, - fundTokenAmountOrder1, + order1, + order2, + fundTokenAmountOrder1, fundTokenAmountOrder2, - cost, - bondMatchAmount, - fundToken, - hyperdrive_); - + cost, + bondMatchAmount, + fundToken, + hyperdrive_ + ); + // Update order bond amount used. _updateOrderAmount(order1Hash_, bondAmount, true); _updateOrderAmount(order2Hash_, bondAmount, true); @@ -189,34 +215,42 @@ contract HyperdriveMatchingEngineV2 is // control flow, but it's placed here to avoid stack-too-deep. uint256 remainingBalance = fundToken.balanceOf(address(this)); if (remainingBalance > 0) { - fundToken.safeTransfer( - surplusRecipient, - remainingBalance - ); + fundToken.safeTransfer(surplusRecipient, remainingBalance); } - } - + } // Case 2: Long + Short closing using burn(). - else if (_order1.orderType == OrderType.CloseLong && - _order2.orderType == OrderType.CloseShort) { + else if ( + _order1.orderType == OrderType.CloseLong && + _order2.orderType == OrderType.CloseShort + ) { // Verify both orders have the same maturity time. if (_order1.maxMaturityTime != _order2.maxMaturityTime) { revert InvalidMaturityTime(); } - + // Calculate matching amount. uint256 bondMatchAmount = _calculateBondMatchAmount( - _order1, - _order2, - order1Hash, + _order1, + _order2, + order1Hash, order2Hash ); // Get the min fund output according to the bondMatchAmount. // NOTE: Round the required fund amount up to respect the order specified // min fund output. - uint256 minFundAmountOrder1 = (_order1.fundAmount - orderAmountsUsed[order1Hash].fundAmount).mulDivUp(bondMatchAmount, (_order1.bondAmount - orderAmountsUsed[order1Hash].bondAmount)); - uint256 minFundAmountOrder2 = (_order2.fundAmount - orderAmountsUsed[order2Hash].fundAmount).mulDivUp(bondMatchAmount, (_order2.bondAmount - orderAmountsUsed[order2Hash].bondAmount)); + uint256 minFundAmountOrder1 = (_order1.fundAmount - + orderAmountsUsed[order1Hash].fundAmount).mulDivUp( + bondMatchAmount, + (_order1.bondAmount - + orderAmountsUsed[order1Hash].bondAmount) + ); + uint256 minFundAmountOrder2 = (_order2.fundAmount - + orderAmountsUsed[order2Hash].fundAmount).mulDivUp( + bondMatchAmount, + (_order2.bondAmount - + orderAmountsUsed[order2Hash].bondAmount) + ); // Update order bond amount used. // @dev After the update, there is no need to check if the bond @@ -243,7 +277,7 @@ contract HyperdriveMatchingEngineV2 is fundToken, hyperdrive ); - + // Update order fund amount used. _updateOrderAmount(order1Hash, minFundAmountOrder1, false); _updateOrderAmount(order2Hash, minFundAmountOrder2, false); @@ -253,45 +287,55 @@ contract HyperdriveMatchingEngineV2 is // control flow, but it's placed here to avoid stack-too-deep. uint256 remainingBalance = fundToken.balanceOf(address(this)); if (remainingBalance > 0) { - fundToken.safeTransfer( - _surplusRecipient, - remainingBalance - ); + fundToken.safeTransfer(_surplusRecipient, remainingBalance); } } - // Case 3: Transfer positions between traders. - else if ((_order1.orderType == OrderType.OpenLong && - _order2.orderType == OrderType.CloseLong) || - (_order1.orderType == OrderType.OpenShort && - _order2.orderType == OrderType.CloseShort)) { - // Verify that the maturity time of the close order matches the + else if ( + (_order1.orderType == OrderType.OpenLong && + _order2.orderType == OrderType.CloseLong) || + (_order1.orderType == OrderType.OpenShort && + _order2.orderType == OrderType.CloseShort) + ) { + // Verify that the maturity time of the close order matches the // open order's requirements. - if (_order2.maxMaturityTime > _order1.maxMaturityTime || - _order2.maxMaturityTime < _order1.minMaturityTime) { + if ( + _order2.maxMaturityTime > _order1.maxMaturityTime || + _order2.maxMaturityTime < _order1.minMaturityTime + ) { revert InvalidMaturityTime(); } // Calculate matching amount. uint256 bondMatchAmount = _calculateBondMatchAmount( - _order1, - _order2, - order1Hash, + _order1, + _order2, + order1Hash, order2Hash ); - // Calculate the amount of fund tokens to transfer based on the - // bondMatchAmount using dynamic pricing. During a series of partial - // matching, the pricing requirements can go easier as needed for each + // Calculate the amount of fund tokens to transfer based on the + // bondMatchAmount using dynamic pricing. During a series of partial + // matching, the pricing requirements can go easier as needed for each // new match, hence increasing the match likelihood. // NOTE: Round the required fund amount down to prevent overspending // and possible reverting at a later step. - uint256 fundTokenAmountOrder1 = (_order1.fundAmount - orderAmountsUsed[order1Hash].fundAmount).mulDivDown(bondMatchAmount, (_order1.bondAmount - orderAmountsUsed[order1Hash].bondAmount)); - + uint256 fundTokenAmountOrder1 = (_order1.fundAmount - + orderAmountsUsed[order1Hash].fundAmount).mulDivDown( + bondMatchAmount, + (_order1.bondAmount - + orderAmountsUsed[order1Hash].bondAmount) + ); + // Get the min fund output according to the bondMatchAmount. // NOTE: Round the required fund amount up to respect the order specified // min fund output. - uint256 minFundAmountOrder2 = (_order2.fundAmount - orderAmountsUsed[order2Hash].fundAmount).mulDivUp(bondMatchAmount, (_order2.bondAmount - orderAmountsUsed[order2Hash].bondAmount)); + uint256 minFundAmountOrder2 = (_order2.fundAmount - + orderAmountsUsed[order2Hash].fundAmount).mulDivUp( + bondMatchAmount, + (_order2.bondAmount - + orderAmountsUsed[order2Hash].bondAmount) + ); // Get the fund token. ERC20 fundToken; @@ -303,7 +347,10 @@ contract HyperdriveMatchingEngineV2 is // Check if trader 1 has enough fund to transfer to trader 2. // @dev Also considering any donations to help match the orders. - if (fundTokenAmountOrder1 + fundToken.balanceOf(address(this)) < minFundAmountOrder2) { + if ( + fundTokenAmountOrder1 + fundToken.balanceOf(address(this)) < + minFundAmountOrder2 + ) { revert InsufficientFunding(); } @@ -333,13 +380,9 @@ contract HyperdriveMatchingEngineV2 is // control flow, but it's placed here to avoid stack-too-deep. uint256 remainingBalance = fundToken.balanceOf(address(this)); if (remainingBalance > 0) { - fundToken.safeTransfer( - _surplusRecipient, - remainingBalance - ); + fundToken.safeTransfer(_surplusRecipient, remainingBalance); } } - // All other cases are invalid. else { revert InvalidOrderCombination(); @@ -360,9 +403,11 @@ contract HyperdriveMatchingEngineV2 is /// @notice Allows traders to cancel their orders. /// @param _orders Array of orders to cancel. - function cancelOrders(OrderIntent[] calldata _orders) external nonReentrant { + function cancelOrders( + OrderIntent[] calldata _orders + ) external nonReentrant { bytes32[] memory orderHashes = new bytes32[](_orders.length); - + for (uint256 i = 0; i < _orders.length; i++) { // Ensure sender is the trader. if (msg.sender != _orders[i].trader) { @@ -389,33 +434,33 @@ contract HyperdriveMatchingEngineV2 is function hashOrderIntent( OrderIntent calldata _order ) public view returns (bytes32) { - - return _hashTypedDataV4( - keccak256( - abi.encode( - ORDER_INTENT_TYPEHASH, - _order.trader, - _order.counterparty, - _order.feeRecipient, - address(_order.hyperdrive), - _order.fundAmount, - _order.bondAmount, - _order.minVaultSharePrice, - keccak256( - abi.encode( - OPTIONS_TYPEHASH, - _order.options.destination, - _order.options.asBase - ) - ), - uint8(_order.orderType), - _order.minMaturityTime, - _order.maxMaturityTime, - _order.expiry, - _order.salt + return + _hashTypedDataV4( + keccak256( + abi.encode( + ORDER_INTENT_TYPEHASH, + _order.trader, + _order.counterparty, + _order.feeRecipient, + address(_order.hyperdrive), + _order.fundAmount, + _order.bondAmount, + _order.minVaultSharePrice, + keccak256( + abi.encode( + OPTIONS_TYPEHASH, + _order.options.destination, + _order.options.asBase + ) + ), + uint8(_order.orderType), + _order.minMaturityTime, + _order.maxMaturityTime, + _order.expiry, + _order.salt + ) ) - ) - ); + ); } /// @notice Verifies a signature for a given signer. @@ -479,36 +524,41 @@ contract HyperdriveMatchingEngineV2 is // @dev TODO: only supporting both true or both false for now. // Supporting mixed asBase values needs code changes on the Hyperdrive // instances. - if ( - _order1.options.asBase != _order2.options.asBase - ) { + if (_order1.options.asBase != _order2.options.asBase) { revert InvalidSettlementAsset(); } // Verify valid maturity time. - if (_order1.minMaturityTime > _order1.maxMaturityTime || - _order2.minMaturityTime > _order2.maxMaturityTime - ) { + if ( + _order1.minMaturityTime > _order1.maxMaturityTime || + _order2.minMaturityTime > _order2.maxMaturityTime + ) { revert InvalidMaturityTime(); } // For close orders, minMaturityTime must equal maxMaturityTime. - if (_order1.orderType == OrderType.CloseLong || - _order1.orderType == OrderType.CloseShort) { + if ( + _order1.orderType == OrderType.CloseLong || + _order1.orderType == OrderType.CloseShort + ) { if (_order1.minMaturityTime != _order1.maxMaturityTime) { revert InvalidMaturityTime(); } } - if (_order2.orderType == OrderType.CloseLong || - _order2.orderType == OrderType.CloseShort) { + if ( + _order2.orderType == OrderType.CloseLong || + _order2.orderType == OrderType.CloseShort + ) { if (_order2.minMaturityTime != _order2.maxMaturityTime) { revert InvalidMaturityTime(); } } // Check that the destination is not the zero address. - if (_order1.options.destination == address(0) || - _order2.options.destination == address(0)) { + if ( + _order1.options.destination == address(0) || + _order2.options.destination == address(0) + ) { revert InvalidDestination(); } @@ -517,12 +567,16 @@ contract HyperdriveMatchingEngineV2 is order2Hash = hashOrderIntent(_order2); // Check if orders are fully executed. - if (orderAmountsUsed[order1Hash].bondAmount >= _order1.bondAmount || - orderAmountsUsed[order1Hash].fundAmount >= _order1.fundAmount) { + if ( + orderAmountsUsed[order1Hash].bondAmount >= _order1.bondAmount || + orderAmountsUsed[order1Hash].fundAmount >= _order1.fundAmount + ) { revert AlreadyFullyExecuted(); } - if (orderAmountsUsed[order2Hash].bondAmount >= _order2.bondAmount || - orderAmountsUsed[order2Hash].fundAmount >= _order2.fundAmount) { + if ( + orderAmountsUsed[order2Hash].bondAmount >= _order2.bondAmount || + orderAmountsUsed[order2Hash].fundAmount >= _order2.fundAmount + ) { revert AlreadyFullyExecuted(); } @@ -533,16 +587,8 @@ contract HyperdriveMatchingEngineV2 is // Verify signatures. if ( - !verifySignature( - order1Hash, - _order1.signature, - _order1.trader - ) || - !verifySignature( - order2Hash, - _order2.signature, - _order2.trader - ) + !verifySignature(order1Hash, _order1.signature, _order1.trader) || + !verifySignature(order2Hash, _order2.signature, _order2.trader) ) { revert InvalidSignature(); } @@ -565,16 +611,16 @@ contract HyperdriveMatchingEngineV2 is uint256 order1BondAmount = _order1.bondAmount - amounts1.bondAmount; uint256 order2BondAmount = _order2.bondAmount - amounts2.bondAmount; - + bondMatchAmount = order1BondAmount.min(order2BondAmount); } /// @dev Handles the minting of matching positions. /// @param _longOrder The order for opening a long position. /// @param _shortOrder The order for opening a short position. - /// @param _fundTokenAmountLongOrder The amount of fund tokens from the long + /// @param _fundTokenAmountLongOrder The amount of fund tokens from the long /// order. - /// @param _fundTokenAmountShortOrder The amount of fund tokens from the short + /// @param _fundTokenAmountShortOrder The amount of fund tokens from the short /// order. /// @param _cost The total cost of the operation. /// @param _bondMatchAmount The amount of bonds to mint. @@ -606,8 +652,8 @@ contract HyperdriveMatchingEngineV2 is ); // Approve Hyperdrive. - // @dev Use balanceOf to get the total amount of fund tokens instead of - // summing up the two amounts, in order to open the door for any + // @dev Use balanceOf to get the total amount of fund tokens instead of + // summing up the two amounts, in order to open the door for any // potential donation to help match orders. uint256 totalFundTokenAmount = _fundToken.balanceOf(address(this)); uint256 fundTokenAmountToUse = _cost + TOKEN_AMOUNT_BUFFER; @@ -629,10 +675,12 @@ contract HyperdriveMatchingEngineV2 is // Calculate minVaultSharePrice. // @dev Take the larger of the two minVaultSharePrice as the min guard // price to prevent slippage, so that it satisfies both orders. - uint256 minVaultSharePrice = _longOrder.minVaultSharePrice.max(_shortOrder.minVaultSharePrice); + uint256 minVaultSharePrice = _longOrder.minVaultSharePrice.max( + _shortOrder.minVaultSharePrice + ); // Mint matching positions. - ( , uint256 bondAmount) = _hyperdrive.mint( + (, uint256 bondAmount) = _hyperdrive.mint( fundTokenAmountToUse, _bondMatchAmount, minVaultSharePrice, @@ -669,7 +717,7 @@ contract HyperdriveMatchingEngineV2 is AssetId.AssetIdPrefix.Short, _shortOrder.maxMaturityTime ); - + // This contract needs to take custody of the bonds before burning. _hyperdrive.transferFrom( longAssetId, @@ -686,9 +734,13 @@ contract HyperdriveMatchingEngineV2 is // Calculate minOutput and consider the potential donation to help match // orders. - uint256 minOutput = (_minFundAmountLongOrder + _minFundAmountShortOrder) > _fundToken.balanceOf(address(this)) ? - _minFundAmountLongOrder + _minFundAmountShortOrder - _fundToken.balanceOf(address(this)) : 0; - + uint256 minOutput = (_minFundAmountLongOrder + + _minFundAmountShortOrder) > _fundToken.balanceOf(address(this)) + ? _minFundAmountLongOrder + + _minFundAmountShortOrder - + _fundToken.balanceOf(address(this)) + : 0; + // Stack cycling to avoid stack-too-deep. OrderIntent calldata longOrder = _longOrder; OrderIntent calldata shortOrder = _shortOrder; @@ -704,10 +756,16 @@ contract HyperdriveMatchingEngineV2 is extraData: "" }) ); - + // Transfer proceeds to traders. - _fundToken.safeTransfer(longOrder.options.destination, _minFundAmountLongOrder); - _fundToken.safeTransfer(shortOrder.options.destination, _minFundAmountShortOrder); + _fundToken.safeTransfer( + longOrder.options.destination, + _minFundAmountLongOrder + ); + _fundToken.safeTransfer( + shortOrder.options.destination, + _minFundAmountShortOrder + ); } /// @dev Handles the transfer of positions between traders. @@ -769,11 +827,9 @@ contract HyperdriveMatchingEngineV2 is /// @dev Gets the most recent checkpoint time. /// @param _checkpointDuration The duration of the checkpoint. /// @return latestCheckpoint The latest checkpoint. - function _latestCheckpoint(uint256 _checkpointDuration) - internal - view - returns (uint256 latestCheckpoint) - { + function _latestCheckpoint( + uint256 _checkpointDuration + ) internal view returns (uint256 latestCheckpoint) { latestCheckpoint = HyperdriveMath.calculateCheckpointTime( block.timestamp, _checkpointDuration @@ -791,7 +847,7 @@ contract HyperdriveMatchingEngineV2 is bool updateBond ) internal { OrderAmounts memory amounts = orderAmountsUsed[orderHash]; - + if (updateBond) { // Check for overflow before casting to uint128 if (amounts.bondAmount + amount > type(uint128).max) { diff --git a/test/units/matching/HyperdriveMatchingEngineV2Test.t.sol b/test/units/matching/HyperdriveMatchingEngineV2Test.t.sol index 1579a0526..9f712abf8 100644 --- a/test/units/matching/HyperdriveMatchingEngineV2Test.t.sol +++ b/test/units/matching/HyperdriveMatchingEngineV2Test.t.sol @@ -18,7 +18,7 @@ contract HyperdriveMatchingEngineV2Test is HyperdriveTest { using SafeERC20 for ERC20; using Lib for *; - /// @dev A salt used to help create orders. + /// @dev A salt used to help create orders. bytes32 internal constant salt = bytes32(uint256(0xdeadbeef)); /// @dev The deployed Hyperdrive matching engine. @@ -33,7 +33,10 @@ contract HyperdriveMatchingEngineV2Test is HyperdriveTest { super.setUp(); // Deploy and initialize a Hyperdrive pool with fees. - IHyperdrive.PoolConfig memory config = testConfig(0.05e18, POSITION_DURATION); + IHyperdrive.PoolConfig memory config = testConfig( + 0.05e18, + POSITION_DURATION + ); config.fees.curve = 0.01e18; config.fees.flat = 0.0005e18; config.fees.governanceLP = 0.15e18; @@ -41,7 +44,9 @@ contract HyperdriveMatchingEngineV2Test is HyperdriveTest { initialize(alice, 0.05e18, 100_000e18); // Deploy matching engine. - matchingEngine = new HyperdriveMatchingEngineV2("Hyperdrive Matching Engine V2"); + matchingEngine = new HyperdriveMatchingEngineV2( + "Hyperdrive Matching Engine V2" + ); // Fund accounts and approve matching engine. address[3] memory accounts = [alice, bob, celine]; @@ -59,23 +64,25 @@ contract HyperdriveMatchingEngineV2Test is HyperdriveTest { /// @dev Tests matching orders with open long and open short orders. function test_matchOrders_openLongAndOpenShort() public { // Create orders. - IHyperdriveMatchingEngineV2.OrderIntent memory longOrder = _createOrderIntent( - alice, - address(0), - address(0), - 100_000e18, // fundAmount. - 95_000e18, // bondAmount. - IHyperdriveMatchingEngineV2.OrderType.OpenLong - ); - - IHyperdriveMatchingEngineV2.OrderIntent memory shortOrder = _createOrderIntent( - bob, - address(0), - address(0), - 101_000e18, // fundAmount. - 95_000e18, // bondAmount. - IHyperdriveMatchingEngineV2.OrderType.OpenShort - ); + IHyperdriveMatchingEngineV2.OrderIntent + memory longOrder = _createOrderIntent( + alice, + address(0), + address(0), + 100_000e18, // fundAmount. + 95_000e18, // bondAmount. + IHyperdriveMatchingEngineV2.OrderType.OpenLong + ); + + IHyperdriveMatchingEngineV2.OrderIntent + memory shortOrder = _createOrderIntent( + bob, + address(0), + address(0), + 101_000e18, // fundAmount. + 95_000e18, // bondAmount. + IHyperdriveMatchingEngineV2.OrderType.OpenShort + ); // Sign orders. longOrder.signature = _signOrderIntent(longOrder, alicePK); @@ -102,40 +109,57 @@ contract HyperdriveMatchingEngineV2Test is HyperdriveTest { // First create and match open orders to create positions. test_matchOrders_openLongAndOpenShort(); - uint256 maturityTime = hyperdrive.latestCheckpoint() + hyperdrive.getPoolConfig().positionDuration; - + uint256 maturityTime = hyperdrive.latestCheckpoint() + + hyperdrive.getPoolConfig().positionDuration; + // Approve Hyperdrive bonds positions to the matching engine. - uint256 longAssetId = AssetId.encodeAssetId(AssetId.AssetIdPrefix.Long, maturityTime); - uint256 shortAssetId = AssetId.encodeAssetId(AssetId.AssetIdPrefix.Short, maturityTime); + uint256 longAssetId = AssetId.encodeAssetId( + AssetId.AssetIdPrefix.Long, + maturityTime + ); + uint256 shortAssetId = AssetId.encodeAssetId( + AssetId.AssetIdPrefix.Short, + maturityTime + ); vm.startPrank(alice); - hyperdrive.setApproval(longAssetId, address(matchingEngine), type(uint256).max); + hyperdrive.setApproval( + longAssetId, + address(matchingEngine), + type(uint256).max + ); vm.stopPrank(); vm.startPrank(bob); - hyperdrive.setApproval(shortAssetId, address(matchingEngine), type(uint256).max); + hyperdrive.setApproval( + shortAssetId, + address(matchingEngine), + type(uint256).max + ); vm.stopPrank(); // Create close orders. - IHyperdriveMatchingEngineV2.OrderIntent memory closeLongOrder = _createOrderIntent( - alice, - address(0), - address(0), - 90_000e18, // min fund amount to receive. - 95_000e18, // bond amount to close. - IHyperdriveMatchingEngineV2.OrderType.CloseLong - ); + IHyperdriveMatchingEngineV2.OrderIntent + memory closeLongOrder = _createOrderIntent( + alice, + address(0), + address(0), + 90_000e18, // min fund amount to receive. + 95_000e18, // bond amount to close. + IHyperdriveMatchingEngineV2.OrderType.CloseLong + ); closeLongOrder.minMaturityTime = maturityTime; closeLongOrder.maxMaturityTime = maturityTime; - IHyperdriveMatchingEngineV2.OrderIntent memory closeShortOrder = _createOrderIntent( - bob, - address(0), - address(0), - 5_001e18, // min fund amount to receive. - 95_000e18, // bond amount to close. - IHyperdriveMatchingEngineV2.OrderType.CloseShort - ); + IHyperdriveMatchingEngineV2.OrderIntent + memory closeShortOrder = _createOrderIntent( + bob, + address(0), + address(0), + 5_001e18, // min fund amount to receive. + 95_000e18, // bond amount to close. + IHyperdriveMatchingEngineV2.OrderType.CloseShort + ); closeShortOrder.minMaturityTime = maturityTime; closeShortOrder.maxMaturityTime = maturityTime; @@ -163,87 +187,98 @@ contract HyperdriveMatchingEngineV2Test is HyperdriveTest { /// different maturity times. function test_matchOrders_revertInvalidMaturityTime() public { // Create close orders with different maturity times. - uint256 maturityTime = hyperdrive.latestCheckpoint() + hyperdrive.getPoolConfig().positionDuration; - - IHyperdriveMatchingEngineV2.OrderIntent memory closeLongOrder = _createOrderIntent( - alice, - address(0), - address(0), - 90_000e18, - 95_000e18, - IHyperdriveMatchingEngineV2.OrderType.CloseLong - ); + uint256 maturityTime = hyperdrive.latestCheckpoint() + + hyperdrive.getPoolConfig().positionDuration; + + IHyperdriveMatchingEngineV2.OrderIntent + memory closeLongOrder = _createOrderIntent( + alice, + address(0), + address(0), + 90_000e18, + 95_000e18, + IHyperdriveMatchingEngineV2.OrderType.CloseLong + ); closeLongOrder.minMaturityTime = maturityTime; closeLongOrder.maxMaturityTime = maturityTime; - IHyperdriveMatchingEngineV2.OrderIntent memory closeShortOrder = _createOrderIntent( - bob, - address(0), - address(0), - 90_000e18, - 95_000e18, - IHyperdriveMatchingEngineV2.OrderType.CloseShort - ); + IHyperdriveMatchingEngineV2.OrderIntent + memory closeShortOrder = _createOrderIntent( + bob, + address(0), + address(0), + 90_000e18, + 95_000e18, + IHyperdriveMatchingEngineV2.OrderType.CloseShort + ); closeShortOrder.minMaturityTime = maturityTime + 1 days; closeShortOrder.maxMaturityTime = maturityTime + 1 days; closeLongOrder.signature = _signOrderIntent(closeLongOrder, alicePK); closeShortOrder.signature = _signOrderIntent(closeShortOrder, bobPK); - vm.expectRevert(IHyperdriveMatchingEngineV2.InvalidMaturityTime.selector); + vm.expectRevert( + IHyperdriveMatchingEngineV2.InvalidMaturityTime.selector + ); matchingEngine.matchOrders(closeLongOrder, closeShortOrder, celine); } /// @dev Tests matching orders with insufficient funding. function test_matchOrders_failure_insufficientFunding() public { // Create orders with insufficient funding. - IHyperdriveMatchingEngineV2.OrderIntent memory longOrder = _createOrderIntent( - alice, - address(0), - address(0), - 1e18, // Very small fundAmount. - 95_000e18, - IHyperdriveMatchingEngineV2.OrderType.OpenLong - ); - - IHyperdriveMatchingEngineV2.OrderIntent memory shortOrder = _createOrderIntent( - bob, - address(0), - address(0), - 1e18, // Very small fundAmount. - 95_000e18, - IHyperdriveMatchingEngineV2.OrderType.OpenShort - ); + IHyperdriveMatchingEngineV2.OrderIntent + memory longOrder = _createOrderIntent( + alice, + address(0), + address(0), + 1e18, // Very small fundAmount. + 95_000e18, + IHyperdriveMatchingEngineV2.OrderType.OpenLong + ); + + IHyperdriveMatchingEngineV2.OrderIntent + memory shortOrder = _createOrderIntent( + bob, + address(0), + address(0), + 1e18, // Very small fundAmount. + 95_000e18, + IHyperdriveMatchingEngineV2.OrderType.OpenShort + ); longOrder.signature = _signOrderIntent(longOrder, alicePK); shortOrder.signature = _signOrderIntent(shortOrder, bobPK); - vm.expectRevert(IHyperdriveMatchingEngineV2.InsufficientFunding.selector); + vm.expectRevert( + IHyperdriveMatchingEngineV2.InsufficientFunding.selector + ); matchingEngine.matchOrders(longOrder, shortOrder, celine); } - /// @dev Tests matching orders with valid but different bond amounts + /// @dev Tests matching orders with valid but different bond amounts /// (partial match). function test_matchOrders_differentBondAmounts() public { // Create orders with different bond amounts - this should succeed with // partial matching. - IHyperdriveMatchingEngineV2.OrderIntent memory longOrder = _createOrderIntent( - alice, - address(0), - address(0), - 100_000e18, - 95_000e18, - IHyperdriveMatchingEngineV2.OrderType.OpenLong - ); - - IHyperdriveMatchingEngineV2.OrderIntent memory shortOrder = _createOrderIntent( - bob, - address(0), - address(0), - 100_000e18, - 90_000e18, // Different but valid bond amount. - IHyperdriveMatchingEngineV2.OrderType.OpenShort - ); + IHyperdriveMatchingEngineV2.OrderIntent + memory longOrder = _createOrderIntent( + alice, + address(0), + address(0), + 100_000e18, + 95_000e18, + IHyperdriveMatchingEngineV2.OrderType.OpenLong + ); + + IHyperdriveMatchingEngineV2.OrderIntent + memory shortOrder = _createOrderIntent( + bob, + address(0), + address(0), + 100_000e18, + 90_000e18, // Different but valid bond amount. + IHyperdriveMatchingEngineV2.OrderType.OpenShort + ); longOrder.signature = _signOrderIntent(longOrder, alicePK); shortOrder.signature = _signOrderIntent(shortOrder, bobPK); @@ -265,41 +300,58 @@ contract HyperdriveMatchingEngineV2Test is HyperdriveTest { function test_matchOrders_failure_invalidBondAmount() public { // First create some positions. test_matchOrders_openLongAndOpenShort(); - - uint256 maturityTime = hyperdrive.latestCheckpoint() + hyperdrive.getPoolConfig().positionDuration; + + uint256 maturityTime = hyperdrive.latestCheckpoint() + + hyperdrive.getPoolConfig().positionDuration; // Approve Hyperdrive bonds positions to the matching engine. - uint256 longAssetId = AssetId.encodeAssetId(AssetId.AssetIdPrefix.Long, maturityTime); - uint256 shortAssetId = AssetId.encodeAssetId(AssetId.AssetIdPrefix.Short, maturityTime); + uint256 longAssetId = AssetId.encodeAssetId( + AssetId.AssetIdPrefix.Long, + maturityTime + ); + uint256 shortAssetId = AssetId.encodeAssetId( + AssetId.AssetIdPrefix.Short, + maturityTime + ); vm.startPrank(alice); - hyperdrive.setApproval(longAssetId, address(matchingEngine), type(uint256).max); + hyperdrive.setApproval( + longAssetId, + address(matchingEngine), + type(uint256).max + ); vm.stopPrank(); vm.startPrank(bob); - hyperdrive.setApproval(shortAssetId, address(matchingEngine), type(uint256).max); + hyperdrive.setApproval( + shortAssetId, + address(matchingEngine), + type(uint256).max + ); vm.stopPrank(); - + // Try to close more bonds than available. - IHyperdriveMatchingEngineV2.OrderIntent memory closeLongOrder = _createOrderIntent( - alice, - address(0), - address(0), - 100_000e18, - 200_000e18, // More than what alice has. - IHyperdriveMatchingEngineV2.OrderType.CloseLong - ); + IHyperdriveMatchingEngineV2.OrderIntent + memory closeLongOrder = _createOrderIntent( + alice, + address(0), + address(0), + 100_000e18, + 200_000e18, // More than what alice has. + IHyperdriveMatchingEngineV2.OrderType.CloseLong + ); closeLongOrder.minMaturityTime = maturityTime; closeLongOrder.maxMaturityTime = maturityTime; - - IHyperdriveMatchingEngineV2.OrderIntent memory closeShortOrder = _createOrderIntent( - bob, - address(0), - address(0), - 100_000e18, - 200_000e18, - IHyperdriveMatchingEngineV2.OrderType.CloseShort - ); + + IHyperdriveMatchingEngineV2.OrderIntent + memory closeShortOrder = _createOrderIntent( + bob, + address(0), + address(0), + 100_000e18, + 200_000e18, + IHyperdriveMatchingEngineV2.OrderType.CloseShort + ); closeShortOrder.minMaturityTime = maturityTime; closeShortOrder.maxMaturityTime = maturityTime; @@ -315,24 +367,26 @@ contract HyperdriveMatchingEngineV2Test is HyperdriveTest { /// @dev Tests matching orders with expired orders. function test_matchOrders_failure_alreadyExpired() public { - IHyperdriveMatchingEngineV2.OrderIntent memory longOrder = _createOrderIntent( - alice, - address(0), - address(0), - 100_000e18, - 95_000e18, - IHyperdriveMatchingEngineV2.OrderType.OpenLong - ); + IHyperdriveMatchingEngineV2.OrderIntent + memory longOrder = _createOrderIntent( + alice, + address(0), + address(0), + 100_000e18, + 95_000e18, + IHyperdriveMatchingEngineV2.OrderType.OpenLong + ); longOrder.expiry = block.timestamp - 1; // Already expired. - - IHyperdriveMatchingEngineV2.OrderIntent memory shortOrder = _createOrderIntent( - bob, - address(0), - address(0), - 100_000e18, - 95_000e18, - IHyperdriveMatchingEngineV2.OrderType.OpenShort - ); + + IHyperdriveMatchingEngineV2.OrderIntent + memory shortOrder = _createOrderIntent( + bob, + address(0), + address(0), + 100_000e18, + 95_000e18, + IHyperdriveMatchingEngineV2.OrderType.OpenShort + ); longOrder.signature = _signOrderIntent(longOrder, alicePK); shortOrder.signature = _signOrderIntent(shortOrder, bobPK); @@ -343,52 +397,58 @@ contract HyperdriveMatchingEngineV2Test is HyperdriveTest { /// @dev Tests matching orders with mismatched Hyperdrive instances. function test_matchOrders_failure_mismatchedHyperdrive() public { - IHyperdriveMatchingEngineV2.OrderIntent memory longOrder = _createOrderIntent( - alice, - address(0), - address(0), - 100_000e18, - 95_000e18, - IHyperdriveMatchingEngineV2.OrderType.OpenLong - ); - - IHyperdriveMatchingEngineV2.OrderIntent memory shortOrder = _createOrderIntent( - bob, - address(0), - address(0), - 100_000e18, - 95_000e18, - IHyperdriveMatchingEngineV2.OrderType.OpenShort - ); + IHyperdriveMatchingEngineV2.OrderIntent + memory longOrder = _createOrderIntent( + alice, + address(0), + address(0), + 100_000e18, + 95_000e18, + IHyperdriveMatchingEngineV2.OrderType.OpenLong + ); + + IHyperdriveMatchingEngineV2.OrderIntent + memory shortOrder = _createOrderIntent( + bob, + address(0), + address(0), + 100_000e18, + 95_000e18, + IHyperdriveMatchingEngineV2.OrderType.OpenShort + ); shortOrder.hyperdrive = IHyperdrive(address(0xdead)); // Different Hyperdrive instance. longOrder.signature = _signOrderIntent(longOrder, alicePK); shortOrder.signature = _signOrderIntent(shortOrder, bobPK); - vm.expectRevert(IHyperdriveMatchingEngineV2.MismatchedHyperdrive.selector); + vm.expectRevert( + IHyperdriveMatchingEngineV2.MismatchedHyperdrive.selector + ); matchingEngine.matchOrders(longOrder, shortOrder, celine); } /// @dev Tests successful partial matching of orders. function test_matchOrders_partialMatch() public { // Create orders where one has larger amount than the other. - IHyperdriveMatchingEngineV2.OrderIntent memory longOrder = _createOrderIntent( - alice, - address(0), - address(0), - 100_000e18, - 95_000e18, - IHyperdriveMatchingEngineV2.OrderType.OpenLong - ); - - IHyperdriveMatchingEngineV2.OrderIntent memory shortOrder = _createOrderIntent( - bob, - address(0), - address(0), - 50_000e18, // Half the amount. - 47_500e18, // Half the bonds. - IHyperdriveMatchingEngineV2.OrderType.OpenShort - ); + IHyperdriveMatchingEngineV2.OrderIntent + memory longOrder = _createOrderIntent( + alice, + address(0), + address(0), + 100_000e18, + 95_000e18, + IHyperdriveMatchingEngineV2.OrderType.OpenLong + ); + + IHyperdriveMatchingEngineV2.OrderIntent + memory shortOrder = _createOrderIntent( + bob, + address(0), + address(0), + 50_000e18, // Half the amount. + 47_500e18, // Half the bonds. + IHyperdriveMatchingEngineV2.OrderType.OpenShort + ); longOrder.signature = _signOrderIntent(longOrder, alicePK); shortOrder.signature = _signOrderIntent(shortOrder, bobPK); @@ -403,7 +463,7 @@ contract HyperdriveMatchingEngineV2Test is HyperdriveTest { // Verify partial fill. assertGe(_getLongBalance(alice) - aliceLongBalanceBefore, 47_500e18); assertGe(_getShortBalance(bob) - bobShortBalanceBefore, 47_500e18); - + // Verify order is not fully cancelled for alice. bytes32 orderHash = matchingEngine.hashOrderIntent(longOrder); assertFalse(matchingEngine.isCancelled(orderHash)); @@ -411,24 +471,26 @@ contract HyperdriveMatchingEngineV2Test is HyperdriveTest { /// @dev Tests matching orders with invalid vault share price. function test_matchOrders_failure_invalidVaultSharePrice() public { - IHyperdriveMatchingEngineV2.OrderIntent memory longOrder = _createOrderIntent( - alice, - address(0), - address(0), - 100_000e18, - 95_000e18, - IHyperdriveMatchingEngineV2.OrderType.OpenLong - ); + IHyperdriveMatchingEngineV2.OrderIntent + memory longOrder = _createOrderIntent( + alice, + address(0), + address(0), + 100_000e18, + 95_000e18, + IHyperdriveMatchingEngineV2.OrderType.OpenLong + ); longOrder.minVaultSharePrice = type(uint256).max; // Unreasonably high min vault share price. - - IHyperdriveMatchingEngineV2.OrderIntent memory shortOrder = _createOrderIntent( - bob, - address(0), - address(0), - 100_000e18, - 95_000e18, - IHyperdriveMatchingEngineV2.OrderType.OpenShort - ); + + IHyperdriveMatchingEngineV2.OrderIntent + memory shortOrder = _createOrderIntent( + bob, + address(0), + address(0), + 100_000e18, + 95_000e18, + IHyperdriveMatchingEngineV2.OrderType.OpenShort + ); shortOrder.minVaultSharePrice = type(uint256).max; // Unreasonably high min vault share price. longOrder.signature = _signOrderIntent(longOrder, alicePK); @@ -440,23 +502,25 @@ contract HyperdriveMatchingEngineV2Test is HyperdriveTest { /// @dev Tests matching orders with invalid signatures. function test_matchOrders_failure_invalidSignature() public { - IHyperdriveMatchingEngineV2.OrderIntent memory longOrder = _createOrderIntent( - alice, - address(0), - address(0), - 100_000e18, - 95_000e18, - IHyperdriveMatchingEngineV2.OrderType.OpenLong - ); - - IHyperdriveMatchingEngineV2.OrderIntent memory shortOrder = _createOrderIntent( - bob, - address(0), - address(0), - 100_000e18, - 95_000e18, - IHyperdriveMatchingEngineV2.OrderType.OpenShort - ); + IHyperdriveMatchingEngineV2.OrderIntent + memory longOrder = _createOrderIntent( + alice, + address(0), + address(0), + 100_000e18, + 95_000e18, + IHyperdriveMatchingEngineV2.OrderType.OpenLong + ); + + IHyperdriveMatchingEngineV2.OrderIntent + memory shortOrder = _createOrderIntent( + bob, + address(0), + address(0), + 100_000e18, + 95_000e18, + IHyperdriveMatchingEngineV2.OrderType.OpenShort + ); // Sign with wrong private keys. longOrder.signature = _signOrderIntent(longOrder, bobPK); // Wrong signer. @@ -484,48 +548,56 @@ contract HyperdriveMatchingEngineV2Test is HyperdriveTest { uint256 bondAmount, IHyperdriveMatchingEngineV2.OrderType orderType ) internal view returns (IHyperdriveMatchingEngineV2.OrderIntent memory) { - return IHyperdriveMatchingEngineV2.OrderIntent({ - trader: trader, - counterparty: counterparty, - feeRecipient: feeRecipient, - hyperdrive: hyperdrive, - fundAmount: fundAmount, - bondAmount: bondAmount, - minVaultSharePrice: 0, - options: IHyperdrive.Options({ - destination: trader, - asBase: true, - extraData: "" - }), - orderType: orderType, - minMaturityTime: 0, - maxMaturityTime: type(uint256).max, - signature: "", - expiry: block.timestamp + 1 days, - salt: salt - }); + return + IHyperdriveMatchingEngineV2.OrderIntent({ + trader: trader, + counterparty: counterparty, + feeRecipient: feeRecipient, + hyperdrive: hyperdrive, + fundAmount: fundAmount, + bondAmount: bondAmount, + minVaultSharePrice: 0, + options: IHyperdrive.Options({ + destination: trader, + asBase: true, + extraData: "" + }), + orderType: orderType, + minMaturityTime: 0, + maxMaturityTime: type(uint256).max, + signature: "", + expiry: block.timestamp + 1 days, + salt: salt + }); } /// @dev Gets the balance of long bonds for an account. /// @param account The address of the account. /// @return The balance of long bonds for the account. function _getLongBalance(address account) internal view returns (uint256) { - uint256 maturityTime = hyperdrive.latestCheckpoint() + hyperdrive.getPoolConfig().positionDuration; - return hyperdrive.balanceOf( - AssetId.encodeAssetId(AssetId.AssetIdPrefix.Long, maturityTime), - account - ); + uint256 maturityTime = hyperdrive.latestCheckpoint() + + hyperdrive.getPoolConfig().positionDuration; + return + hyperdrive.balanceOf( + AssetId.encodeAssetId(AssetId.AssetIdPrefix.Long, maturityTime), + account + ); } /// @dev Gets the balance of short bonds for an account. /// @param account The address of the account. /// @return The balance of short bonds for the account. function _getShortBalance(address account) internal view returns (uint256) { - uint256 maturityTime = hyperdrive.latestCheckpoint() + hyperdrive.getPoolConfig().positionDuration; - return hyperdrive.balanceOf( - AssetId.encodeAssetId(AssetId.AssetIdPrefix.Short, maturityTime), - account - ); + uint256 maturityTime = hyperdrive.latestCheckpoint() + + hyperdrive.getPoolConfig().positionDuration; + return + hyperdrive.balanceOf( + AssetId.encodeAssetId( + AssetId.AssetIdPrefix.Short, + maturityTime + ), + account + ); } /// @dev Signs an order intent. @@ -540,4 +612,4 @@ contract HyperdriveMatchingEngineV2Test is HyperdriveTest { (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); return abi.encodePacked(r, s, v); } -} \ No newline at end of file +}