From ec2fe58438101535686aba4f1199b5d1e9904dc3 Mon Sep 17 00:00:00 2001 From: d1ll0n Date: Sun, 18 Feb 2024 19:23:01 -0800 Subject: [PATCH 1/4] Rename child pptr function to pptrOffset so it can be referenced directly --- src/core/lib/Consideration.sol | 18 +++++++-------- src/core/lib/ConsiderationDecoder.sol | 32 +++++++++++++------------- src/core/lib/CriteriaResolution.sol | 2 +- src/types/helpers/PointerLibraries.sol | 7 +++--- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/core/lib/Consideration.sol b/src/core/lib/Consideration.sol index e116844..61a9b38 100644 --- a/src/core/lib/Consideration.sol +++ b/src/core/lib/Consideration.sol @@ -251,7 +251,7 @@ contract Consideration is ConsiderationInterface, OrderCombiner { CalldataStart.pptr() ), _toCriteriaResolversReturnType(_decodeCriteriaResolvers)( - CalldataStart.pptr( + CalldataStart.pptrOffset( Offset_fulfillAdvancedOrder_criteriaResolvers ) ), @@ -346,14 +346,14 @@ contract Consideration is ConsiderationInterface, OrderCombiner { _toNestedFulfillmentComponentsReturnType( _decodeNestedFulfillmentComponents )( - CalldataStart.pptr( + CalldataStart.pptrOffset( Offset_fulfillAvailableOrders_offerFulfillments ) ), _toNestedFulfillmentComponentsReturnType( _decodeNestedFulfillmentComponents )( - CalldataStart.pptr( + CalldataStart.pptrOffset( Offset_fulfillAvailableOrders_considerationFulfillments ) ), @@ -476,21 +476,21 @@ contract Consideration is ConsiderationInterface, OrderCombiner { CalldataStart.pptr() ), _toCriteriaResolversReturnType(_decodeCriteriaResolvers)( - CalldataStart.pptr( + CalldataStart.pptrOffset( Offset_fulfillAvailableAdvancedOrders_criteriaResolvers ) ), _toNestedFulfillmentComponentsReturnType( _decodeNestedFulfillmentComponents )( - CalldataStart.pptr( + CalldataStart.pptrOffset( Offset_fulfillAvailableAdvancedOrders_offerFulfillments ) ), _toNestedFulfillmentComponentsReturnType( _decodeNestedFulfillmentComponents )( - CalldataStart.pptr( + CalldataStart.pptrOffset( Offset_fulfillAvailableAdvancedOrders_cnsdrationFlflmnts ) ), @@ -551,7 +551,7 @@ contract Consideration is ConsiderationInterface, OrderCombiner { ), new CriteriaResolver[](0), // No criteria resolvers supplied. _toFulfillmentsReturnType(_decodeFulfillments)( - CalldataStart.pptr(Offset_matchOrders_fulfillments) + CalldataStart.pptrOffset(Offset_matchOrders_fulfillments) ), msg.sender ); @@ -635,10 +635,10 @@ contract Consideration is ConsiderationInterface, OrderCombiner { CalldataStart.pptr() ), _toCriteriaResolversReturnType(_decodeCriteriaResolvers)( - CalldataStart.pptr(Offset_matchAdvancedOrders_criteriaResolvers) + CalldataStart.pptrOffset(Offset_matchAdvancedOrders_criteriaResolvers) ), _toFulfillmentsReturnType(_decodeFulfillments)( - CalldataStart.pptr(Offset_matchAdvancedOrders_fulfillments) + CalldataStart.pptrOffset(Offset_matchAdvancedOrders_fulfillments) ), _substituteCallerForEmptyRecipient(recipient) ); diff --git a/src/core/lib/ConsiderationDecoder.sol b/src/core/lib/ConsiderationDecoder.sol index 172859d..dd463bb 100644 --- a/src/core/lib/ConsiderationDecoder.sol +++ b/src/core/lib/ConsiderationDecoder.sol @@ -254,14 +254,14 @@ contract ConsiderationDecoder { // Resolve the offer calldata offset, use that to decode and copy offer // from calldata, and write resultant memory offset to head in memory. mPtr.offset(OrderParameters_offer_head_offset).write( - _decodeOffer(cdPtr.pptr(OrderParameters_offer_head_offset)) + _decodeOffer(cdPtr.pptrOffset(OrderParameters_offer_head_offset)) ); // Resolve consideration calldata offset, use that to copy consideration // from calldata, and write resultant memory offset to head in memory. mPtr.offset(OrderParameters_consideration_head_offset).write( _decodeConsideration( - cdPtr.pptr(OrderParameters_consideration_head_offset) + cdPtr.pptrOffset(OrderParameters_consideration_head_offset) ) ); } @@ -311,7 +311,7 @@ contract ConsiderationDecoder { // Resolve signature calldata offset, use that to decode and copy from // calldata, and write resultant memory offset to head in memory. mPtr.offset(Order_signature_offset).write( - _decodeBytes(cdPtr.pptr(Order_signature_offset)) + _decodeBytes(cdPtr.pptrOffset(Order_signature_offset)) ); } @@ -350,13 +350,13 @@ contract ConsiderationDecoder { // Resolve signature calldata offset, use that to decode and copy from // calldata, and write resultant memory offset to head in memory. mPtr.offset(AdvancedOrder_signature_offset).write( - _decodeBytes(cdPtr.pptr(AdvancedOrder_signature_offset)) + _decodeBytes(cdPtr.pptrOffset(AdvancedOrder_signature_offset)) ); // Resolve extraData calldata offset, use that to decode and copy from // calldata, and write resultant memory offset to head in memory. mPtr.offset(AdvancedOrder_extraData_offset).write( - _decodeBytes(cdPtr.pptr(AdvancedOrder_extraData_offset)) + _decodeBytes(cdPtr.pptrOffset(AdvancedOrder_extraData_offset)) ); } @@ -407,7 +407,7 @@ contract ConsiderationDecoder { // Resolve signature calldata offset, use that to decode and copy from // calldata, and write resultant memory offset to head in memory. mPtr.offset(AdvancedOrder_signature_offset).write( - _decodeBytes(cdPtr.pptr(Order_signature_offset)) + _decodeBytes(cdPtr.pptrOffset(Order_signature_offset)) ); // Resolve extraData calldata offset, use that to decode and copy from @@ -454,7 +454,7 @@ contract ConsiderationDecoder { // Resolve Order calldata offset, use it to decode and copy from // calldata, and write resultant AdvancedOrder offset to memory. mPtrHead.offset(offset).write( - _decodeOrderAsAdvancedOrder(cdPtrHead.pptr(offset)) + _decodeOrderAsAdvancedOrder(cdPtrHead.pptrOffset(offset)) ); } } @@ -515,7 +515,7 @@ contract ConsiderationDecoder { // from calldata, and write resultant memory offset to head in memory. mPtr.offset(CriteriaResolver_criteriaProof_offset).write( _decodeCriteriaProof( - cdPtr.pptr(CriteriaResolver_criteriaProof_offset) + cdPtr.pptrOffset(CriteriaResolver_criteriaProof_offset) ) ); } @@ -559,7 +559,7 @@ contract ConsiderationDecoder { // Resolve CriteriaResolver calldata offset, use it to decode // and copy from calldata, and write resultant memory offset. mPtrHead.offset(offset).write( - _decodeCriteriaResolver(cdPtrHead.pptr(offset)) + _decodeCriteriaResolver(cdPtrHead.pptrOffset(offset)) ); } } @@ -601,7 +601,7 @@ contract ConsiderationDecoder { // Resolve Order calldata offset, use it to decode and copy // from calldata, and write resultant memory offset. mPtrHead.offset(offset).write( - _decodeOrder(cdPtrHead.pptr(offset)) + _decodeOrder(cdPtrHead.pptrOffset(offset)) ); } } @@ -691,7 +691,7 @@ contract ConsiderationDecoder { // Resolve FulfillmentComponents array calldata offset, use it // to decode and copy from calldata, and write memory offset. mPtrHead.offset(offset).write( - _decodeFulfillmentComponents(cdPtrHead.pptr(offset)) + _decodeFulfillmentComponents(cdPtrHead.pptrOffset(offset)) ); } } @@ -736,7 +736,7 @@ contract ConsiderationDecoder { // Resolve AdvancedOrder calldata offset, use it to decode and // copy from calldata, and write resultant memory offset. mPtrHead.offset(offset).write( - _decodeAdvancedOrder(cdPtrHead.pptr(offset)) + _decodeAdvancedOrder(cdPtrHead.pptrOffset(offset)) ); } } @@ -767,7 +767,7 @@ contract ConsiderationDecoder { // copy from calldata, and write resultant memory offset to memory head. mPtr.offset(Fulfillment_considerationComponents_offset).write( _decodeFulfillmentComponents( - cdPtr.pptr(Fulfillment_considerationComponents_offset) + cdPtr.pptrOffset(Fulfillment_considerationComponents_offset) ) ); } @@ -811,7 +811,7 @@ contract ConsiderationDecoder { // Resolve Fulfillment calldata offset, use it to decode and // copy from calldata, and write resultant memory offset. mPtrHead.offset(offset).write( - _decodeFulfillment(cdPtrHead.pptr(offset)) + _decodeFulfillment(cdPtrHead.pptrOffset(offset)) ); } } @@ -841,13 +841,13 @@ contract ConsiderationDecoder { // Resolve the offer calldata offset, use that to decode and copy offer // from calldata, and write resultant memory offset to head in memory. mPtr.offset(OrderParameters_offer_head_offset).write( - _decodeOffer(cdPtr.pptr(OrderParameters_offer_head_offset)) + _decodeOffer(cdPtr.pptrOffset(OrderParameters_offer_head_offset)) ); // Resolve consideration calldata offset, use that to copy consideration // from calldata, and write resultant memory offset to head in memory. MemoryPointer consideration = _decodeConsideration( - cdPtr.pptr(OrderParameters_consideration_head_offset) + cdPtr.pptrOffset(OrderParameters_consideration_head_offset) ); mPtr.offset(OrderParameters_consideration_head_offset).write( consideration diff --git a/src/core/lib/CriteriaResolution.sol b/src/core/lib/CriteriaResolution.sol index 1edb08a..fa984ed 100644 --- a/src/core/lib/CriteriaResolution.sol +++ b/src/core/lib/CriteriaResolution.sol @@ -125,7 +125,7 @@ contract CriteriaResolution is CriteriaResolutionErrors { // Using the array directly has a significant impact on // the optimized compiler output. MemoryPointer considerationPtr = orderParameters - .toMemoryPointer().pptr( + .toMemoryPointer().pptrOffset( OrderParameters_consideration_head_offset ); diff --git a/src/types/helpers/PointerLibraries.sol b/src/types/helpers/PointerLibraries.sol index 4623307..6bfafad 100644 --- a/src/types/helpers/PointerLibraries.sol +++ b/src/types/helpers/PointerLibraries.sol @@ -18,6 +18,7 @@ using MemoryWriters for MemoryPointer global; CalldataPointer constant CalldataStart = CalldataPointer.wrap(0x04); MemoryPointer constant FreeMemoryPPtr = MemoryPointer.wrap(0x40); +MemoryPointer constant ZeroSlotPtr = MemoryPointer.wrap(0x60); uint256 constant IdentityPrecompileAddress = 0x4; uint256 constant OffsetOrLengthMask = 0xffffffff; uint256 constant _OneWord = 0x20; @@ -86,7 +87,7 @@ library CalldataPointerLib { /// @dev Resolves an offset stored at `cdPtr + headOffset` to a calldata. /// pointer `cdPtr` must point to some parent object with a dynamic /// type's head stored at `cdPtr + headOffset`. - function pptr(CalldataPointer cdPtr, uint256 headOffset) + function pptrOffset(CalldataPointer cdPtr, uint256 headOffset) internal pure returns (CalldataPointer cdPtrChild) @@ -181,7 +182,7 @@ library ReturndataPointerLib { /// @dev Resolves an offset stored at `rdPtr + headOffset` to a returndata /// pointer. `rdPtr` must point to some parent object with a dynamic /// type's head stored at `rdPtr + headOffset`. - function pptr(ReturndataPointer rdPtr, uint256 headOffset) + function pptrOffset(ReturndataPointer rdPtr, uint256 headOffset) internal pure returns (ReturndataPointer rdPtrChild) @@ -319,7 +320,7 @@ library MemoryPointerLib { /// @dev Resolves a pointer at `mPtr + headOffset` to a memory /// pointer. `mPtr` must point to some parent object with a dynamic /// type's pointer stored at `mPtr + headOffset`. - function pptr(MemoryPointer mPtr, uint256 headOffset) + function pptrOffset(MemoryPointer mPtr, uint256 headOffset) internal pure returns (MemoryPointer mPtrChild) From ab2256a5487f2fcb5f457ba6266c772f93a54769 Mon Sep 17 00:00:00 2001 From: d1ll0n Date: Sun, 18 Feb 2024 19:29:27 -0800 Subject: [PATCH 2/4] Use runtime constants to bypass function specialization for large functions with constant inputs. Add a cast function for pptrOffset to read advanced orders by offset. --- src/core/lib/LowLevelHelpers.sol | 54 ++++++++++++++++++++++++++++++++ src/core/lib/OrderCombiner.sol | 49 +++++++++++++++++------------ src/core/lib/OrderFulfiller.sol | 11 ++++--- src/core/lib/OrderValidator.sol | 4 +-- 4 files changed, 91 insertions(+), 27 deletions(-) diff --git a/src/core/lib/LowLevelHelpers.sol b/src/core/lib/LowLevelHelpers.sol index 9851d0b..834d792 100644 --- a/src/core/lib/LowLevelHelpers.sol +++ b/src/core/lib/LowLevelHelpers.sol @@ -11,6 +11,10 @@ import { ThirtyOneBytes } from "seaport-types/src/lib/ConsiderationConstants.sol"; +import { MemoryPointer, MemoryPointerLib } from "seaport-types/src/helpers/PointerLibraries.sol"; + +import { AdvancedOrder } from "seaport-types/src/lib/ConsiderationStructs.sol"; + /** * @title LowLevelHelpers * @author 0age @@ -107,4 +111,54 @@ contract LowLevelHelpers { u := b } } + + /** + * @dev Internal pure function to cast the `pptrOffset` function from + * `MemoryPointerLib` to a function that takes a memory array of + * `AdvancedOrder` and an offset in memory and returns the + * `AdvancedOrder` whose pointer is stored at that offset from the + * array length. + */ + function _getReadAdvancedOrderByOffset( + // function (MemoryPointer, uint256) internal pure returns (MemoryPointer) fn1 + ) internal pure returns ( + function (AdvancedOrder[] memory, uint256) internal pure returns (AdvancedOrder memory) fn2 + ) { + function (MemoryPointer, uint256) internal pure returns (MemoryPointer) fn1 = MemoryPointerLib.pptrOffset; + assembly { + fn2 := fn1 + } + } + + /** + * @dev Internal pure function to return a `true` value that solc + * will not recognize as a compile time constant. + * + * This function is used to bypass function specialization for + * functions which take a constant boolean as an input parameter. + * + * This should only be used in cases where specialization has a + * negligible impact on the gas cost of the function. + * + * Note: assumes the calldatasize is non-zero. + */ + function _runTimeConstantTrue() internal pure returns (bool) { + return msg.data.length > 0; + } + + /** + * @dev Internal pure function to return a `false` value that solc + * will not recognize as a compile time constant. + * + * This function is used to bypass function specialization for + * functions which take a constant boolean as an input parameter. + * + * This should only be used in cases where specialization has a + * negligible impact on the gas cost of the function. + * + * Note: assumes the calldatasize is non-zero. + */ + function _runTimeConstantFalse() internal pure returns (bool) { + return msg.data.length == 0; + } } diff --git a/src/core/lib/OrderCombiner.sol b/src/core/lib/OrderCombiner.sol index c4f83d7..4ab4166 100644 --- a/src/core/lib/OrderCombiner.sol +++ b/src/core/lib/OrderCombiner.sol @@ -44,6 +44,8 @@ import { TwoWords } from "seaport-types/src/lib/ConsiderationConstants.sol"; +import { MemoryPointer, MemoryPointerLib, ZeroSlotPtr } from "seaport-types/src/helpers/PointerLibraries.sol"; + /** * @title OrderCombiner * @author 0age @@ -140,12 +142,16 @@ contract OrderCombiner is OrderFulfiller, FulfillmentApplier { Execution[] memory /* executions */ ) { + // Create a `false` boolean variable to indicate that invalid orders + // should NOT revert. Does not use a constant to avoid function + // specialization in solc that would increase contract size. + bool revertOnInvalid = _runTimeConstantFalse(); // Validate orders, apply amounts, & determine if they use conduits. (bytes32[] memory orderHashes, bool containsNonOpen) = _validateOrdersAndPrepareToFulfill( advancedOrders, criteriaResolvers, - false, // Signifies that invalid orders should NOT revert. + revertOnInvalid, maximumFulfilled, recipient ); @@ -228,7 +234,6 @@ contract OrderCombiner is OrderFulfiller, FulfillmentApplier { } // Declare variables for later use. - AdvancedOrder memory advancedOrder; uint256 terminalMemoryOffset; unchecked { @@ -244,16 +249,13 @@ contract OrderCombiner is OrderFulfiller, FulfillmentApplier { // Skip overflow checks as all for loops are indexed starting at zero. unchecked { - // Declare inner variables. - OfferItem[] memory offer; - ConsiderationItem[] memory consideration; - // Iterate over each order. for (uint256 i = OneWord; i < terminalMemoryOffset; i += OneWord) { - // Retrieve order using assembly to bypass out-of-range check. - assembly { - advancedOrder := mload(add(advancedOrders, i)) - } + // Retrieve order using pointer libraries to bypass out-of-range + // check and a cast function to avoid additional memory allocation. + AdvancedOrder memory advancedOrder = _getReadAdvancedOrderByOffset( + // MemoryPointerLib.pptrOffset + )(advancedOrders, i); // Validate it, update status, and determine fraction to fill. (bytes32 orderHash, uint256 numerator, uint256 denominator) = @@ -280,12 +282,6 @@ contract OrderCombiner is OrderFulfiller, FulfillmentApplier { // Place the end time for the order on the stack. uint256 endTime = advancedOrder.parameters.endTime; - // Retrieve array of offer items for the order in question. - offer = advancedOrder.parameters.offer; - - // Read length of offer array and place on the stack. - uint256 totalOfferItems = offer.length; - { // Determine the order type, used to check for eligibility // for native token offer items as well as for the presence @@ -309,6 +305,12 @@ contract OrderCombiner is OrderFulfiller, FulfillmentApplier { } } + // Retrieve array of offer items for the order in question. + OfferItem[] memory offer = advancedOrder.parameters.offer; + + // Read length of offer array and place on the stack. + uint256 totalOfferItems = offer.length; + // Iterate over each offer item on the order. for (uint256 j = 0; j < totalOfferItems; ++j) { // Retrieve the offer item. @@ -347,7 +349,7 @@ contract OrderCombiner is OrderFulfiller, FulfillmentApplier { endAmount, startTime, endTime, - false // round down + _runTimeConstantFalse() // round down ); // Update amounts in memory to match the current amount. @@ -357,7 +359,7 @@ contract OrderCombiner is OrderFulfiller, FulfillmentApplier { } // Retrieve array of consideration items for order in question. - consideration = (advancedOrder.parameters.consideration); + ConsiderationItem[] memory consideration = (advancedOrder.parameters.consideration); // Read length of consideration array and place on the stack. uint256 totalConsiderationItems = consideration.length; @@ -396,7 +398,7 @@ contract OrderCombiner is OrderFulfiller, FulfillmentApplier { endAmount, startTime, endTime, - true // round up + _runTimeConstantTrue() // round up ) ); @@ -458,6 +460,9 @@ contract OrderCombiner is OrderFulfiller, FulfillmentApplier { // Iterate over each order. for (uint256 i = OneWord; i < terminalMemoryOffset; i += OneWord) { + AdvancedOrder memory advancedOrder = _getReadAdvancedOrderByOffset( + // MemoryPointerLib.pptrOffset + )(advancedOrders, i); assembly { orderHash := mload(add(orderHashes, i)) } @@ -1024,12 +1029,16 @@ contract OrderCombiner is OrderFulfiller, FulfillmentApplier { Fulfillment[] memory fulfillments, address recipient ) internal returns (Execution[] memory /* executions */ ) { + // Create a `true` boolean variable to indicate that invalid orders + // should revert. Does not use a constant to avoid function + // specialization in solc that would increase contract size. + bool revertOnInvalid = _runTimeConstantTrue(); // Validate orders, update order status, and determine item amounts. (bytes32[] memory orderHashes, bool containsNonOpen) = _validateOrdersAndPrepareToFulfill( advancedOrders, criteriaResolvers, - true, // Signifies that invalid orders should revert. + revertOnInvalid, advancedOrders.length, recipient ); diff --git a/src/core/lib/OrderFulfiller.sol b/src/core/lib/OrderFulfiller.sol index a981155..c6933fc 100644 --- a/src/core/lib/OrderFulfiller.sol +++ b/src/core/lib/OrderFulfiller.sol @@ -101,7 +101,7 @@ contract OrderFulfiller is // Validate order, update status, and determine fraction to fill. (bytes32 orderHash, uint256 fillNumerator, uint256 fillDenominator) = - _validateOrder(advancedOrder, true); + _validateOrder(advancedOrder, _runTimeConstantTrue()); // Create an array with length 1 containing the order. AdvancedOrder[] memory advancedOrders = new AdvancedOrder[](1); @@ -123,17 +123,18 @@ contract OrderFulfiller is // Declare empty bytes32 array and populate with the order hash. bytes32[] memory orderHashes = new bytes32[](1); + bool _true = _runTimeConstantTrue(); if (orderType != OrderType.CONTRACT) { _assertRestrictedAdvancedOrderAuthorization( advancedOrder, orderHashes, orderHash, 0 ); - _updateStatus(orderHash, fillNumerator, fillDenominator, true); + _updateStatus(orderHash, fillNumerator, fillDenominator, _true); } else { // Return the generated order based on the order params and the // provided extra data. orderHash = _getGeneratedOrder( - orderParameters, advancedOrder.extraData, true + orderParameters, advancedOrder.extraData, _true ); } @@ -226,7 +227,7 @@ contract OrderFulfiller is denominator, startTime, endTime, - false + _runTimeConstantFalse() ); // Utilize assembly to set overloaded offerItem arguments. @@ -302,7 +303,7 @@ contract OrderFulfiller is denominator, startTime, endTime, - true + _runTimeConstantTrue() ); // Use assembly to set overloaded considerationItem arguments. diff --git a/src/core/lib/OrderValidator.sol b/src/core/lib/OrderValidator.sol index c99d15e..70f4eff 100644 --- a/src/core/lib/OrderValidator.sol +++ b/src/core/lib/OrderValidator.sol @@ -104,7 +104,7 @@ contract OrderValidator is Executor, ZoneInteraction { orderHash, orderStatus, true, // Only allow unused orders when fulfilling basic orders. - true // Signifies to revert if the order is invalid. + _runTimeConstantTrue() // Signifies to revert if the order is invalid. ); // If the order is not already validated, verify the supplied signature. @@ -803,7 +803,7 @@ contract OrderValidator is Executor, ZoneInteraction { orderHash, orderStatus, false, // Signifies that partially filled orders are valid. - true // Signifies to revert if the order is invalid. + _runTimeConstantTrue() // Signifies to revert if the order is invalid. ); // If the order has not already been validated... From 255bcef7e475bd0f78dc062811a3afa57808fbbb Mon Sep 17 00:00:00 2001 From: d1ll0n Date: Sun, 18 Feb 2024 19:30:51 -0800 Subject: [PATCH 3/4] Cache error selector in memory prior to calling _callAndCheckStatus rather than passing it as an input. --- src/core/lib/ZoneInteraction.sol | 61 +++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/src/core/lib/ZoneInteraction.sol b/src/core/lib/ZoneInteraction.sol index f49c2ad..145569d 100644 --- a/src/core/lib/ZoneInteraction.sol +++ b/src/core/lib/ZoneInteraction.sol @@ -16,7 +16,7 @@ import { LowLevelHelpers } from "./LowLevelHelpers.sol"; import { ConsiderationEncoder } from "./ConsiderationEncoder.sol"; -import { CalldataPointer, MemoryPointer, OffsetOrLengthMask } from "seaport-types/src/helpers/PointerLibraries.sol"; +import { CalldataPointer, MemoryPointer, OffsetOrLengthMask, ZeroSlotPtr } from "seaport-types/src/helpers/PointerLibraries.sol"; import { authorizeOrder_selector_offset, @@ -70,15 +70,21 @@ contract ZoneInteraction is (MemoryPointer callData, uint256 size, uint256 memoryLocationForOrderHashes) = _encodeAuthorizeBasicOrder(orderHash); + // Write the error selector to memory at the zero slot where it can be used + // to revert with a specific error message. + ZeroSlotPtr.write(InvalidRestrictedOrder_error_selector); + // Perform `authorizeOrder` call and ensure magic value was returned. _callAndCheckStatus( CalldataPointer.wrap(BasicOrder_zone_cdPtr).readAddress(), orderHash, callData.offset(authorizeOrder_selector_offset), - size, - InvalidRestrictedOrder_error_selector + size ); + // Restore the zero slot. + ZeroSlotPtr.write(0); + callDataPointer = MemoryPointer.unwrap(callData); unchecked { @@ -120,14 +126,20 @@ contract ZoneInteraction is callData = callData.offset(validateOrder_selector_offset); + // Write the error selector to memory at the zero slot where it can be used + // to revert with a specific error message. + ZeroSlotPtr.write(InvalidRestrictedOrder_error_selector); + // Perform `validateOrder` call and ensure magic value was returned. _callAndCheckStatus( CalldataPointer.wrap(BasicOrder_zone_cdPtr).readAddress(), orderHash, callData, - size, - InvalidRestrictedOrder_error_selector + size ); + + // Restore the zero slot. + ZeroSlotPtr.write(0); } } @@ -182,9 +194,16 @@ contract ZoneInteraction is orderHashes, orderIndex ); + + // Write the error selector to memory at the zero slot where it can be used + // to revert with a specific error message. + ZeroSlotPtr.write(InvalidRestrictedOrder_error_selector); // Perform call and ensure a corresponding magic value was returned. - _callAndCheckStatus(parameters.zone, orderHash, callData, size, InvalidRestrictedOrder_error_selector); + _callAndCheckStatus(parameters.zone, orderHash, callData, size); + + // Restore the zero slot. + ZeroSlotPtr.write(0); } } @@ -258,9 +277,16 @@ contract ZoneInteraction is } else { return; } + + // Write the error selector to memory at the zero slot where it can be used + // to revert with a specific error message. + ZeroSlotPtr.write(errorSelector); // Perform call and ensure a corresponding magic value was returned. - _callAndCheckStatus(target, orderHash, callData, size, errorSelector); + _callAndCheckStatus(target, orderHash, callData, size); + + // Restore the zero slot. + ZeroSlotPtr.write(0); } /** @@ -296,19 +322,20 @@ contract ZoneInteraction is * otherwise reverting calls will throw a generic error based on the * supplied error handler. * + * Note: The custom error selector must already be in memory at the zero + * slot when this function is called. + * * @param target The address of the contract to call. * @param orderHash The hash of the order associated with the call. * @param callData The data to pass to the contract call. * @param size The size of calldata. - * @param errorSelector The error handling function to call if the call - * fails or the magic value does not match. */ function _callAndCheckStatus( address target, bytes32 orderHash, MemoryPointer callData, - uint256 size, - uint256 errorSelector + uint256 size/* , + uint256 errorSelector */ ) internal { bool success; bool magicMatch; @@ -333,14 +360,14 @@ contract ZoneInteraction is // If no reason was returned, revert with supplied error selector. assembly { - mstore(0, errorSelector) - mstore(InvalidRestrictedOrder_error_orderHash_ptr, orderHash) + // The error selector is already in memory at the zero slot. + mstore(0x80, orderHash) // revert(abi.encodeWithSelector( // "InvalidRestrictedOrder(bytes32)", // orderHash // )) revert( - Error_selector_offset, InvalidRestrictedOrder_error_length + 0x7c, InvalidRestrictedOrder_error_length ) } } @@ -349,15 +376,15 @@ contract ZoneInteraction is if (!magicMatch) { // Revert with a generic error message. assembly { - mstore(0, errorSelector) - mstore(InvalidRestrictedOrder_error_orderHash_ptr, orderHash) + // The error selector is already in memory at the zero slot. + mstore(0x80, orderHash) // revert(abi.encodeWithSelector( // "InvalidRestrictedOrder(bytes32)", // orderHash // )) revert( - Error_selector_offset, InvalidRestrictedOrder_error_length + 0x7c, InvalidRestrictedOrder_error_length ) } } From 6cec64941977bddf90fe037dfd108d2c1892ba60 Mon Sep 17 00:00:00 2001 From: d1ll0n Date: Sun, 18 Feb 2024 19:32:29 -0800 Subject: [PATCH 4/4] pptr -> pptrOffset --- test/foundry/new/helpers/event-utils/ForgeEventsLib.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/foundry/new/helpers/event-utils/ForgeEventsLib.sol b/test/foundry/new/helpers/event-utils/ForgeEventsLib.sol index 0398057..28f53d3 100644 --- a/test/foundry/new/helpers/event-utils/ForgeEventsLib.sol +++ b/test/foundry/new/helpers/event-utils/ForgeEventsLib.sol @@ -78,7 +78,7 @@ library ForgeEventsLib { uint256 topicsCount = topics.readUint256(); (bytes32 topic0,, bytes32 topic1,, bytes32 topic2,, bytes32 topic3,) = getTopics(log); - MemoryPointer data = toMemoryPointer(log).pptr(32); + MemoryPointer data = toMemoryPointer(log).pptrOffset(32); assembly { switch topicsCount case 4 { log4(data, mload(data), topic0, topic1, topic2, topic3) }