diff --git a/src/core/lib/BasicOrderFulfiller.sol b/src/core/lib/BasicOrderFulfiller.sol index ac4b92e..1623043 100644 --- a/src/core/lib/BasicOrderFulfiller.sol +++ b/src/core/lib/BasicOrderFulfiller.sol @@ -93,6 +93,7 @@ import { OrderFulfilled_offer_body_offset, OrderFulfilled_offer_head_offset, OrderFulfilled_offer_length_baseOffset, + OrderFulfilled_post_memory_region_reservedBytes, OrderFulfilled_selector, ReceivedItem_amount_offset, ReceivedItem_size, @@ -1054,7 +1055,16 @@ contract BasicOrderFulfiller is OrderValidator { mstore(ZeroSlot, 0) // Update the free memory pointer so that event data is persisted. - mstore(FreeMemoryPointerSlot, add(eventDataPtr, dataSize)) + mstore(FreeMemoryPointerSlot, + add( + eventDataPtr, + // reserve extra 3 words to be used by `authorizeOrder` and + // `validatateOrder` if pre-post exection hook to the zone is + // required. These 3 memory slots will be used for the extra data/context + // and order hashes of the calldata. + add(dataSize, OrderFulfilled_post_memory_region_reservedBytes) + ) + ) } // Verify the status of the derived order. diff --git a/src/core/lib/ConsiderationEncoder.sol b/src/core/lib/ConsiderationEncoder.sol index 5ca1293..811a86b 100644 --- a/src/core/lib/ConsiderationEncoder.sol +++ b/src/core/lib/ConsiderationEncoder.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.24; import { + authorizeOrder_calldata_baseOffset, authorizeOrder_head_offset, authorizeOrder_selector_offset, authorizeOrder_selector, @@ -554,9 +555,11 @@ contract ConsiderationEncoder { /** * @dev Takes an order hash and BasicOrderParameters struct (from calldata) - * and encodes it as `authorizeOrder` calldata. Note that data is - * copied from event data, so this function will need to be modified if - * the layout of that event data changes. + * and encodes it as `authorizeOrder` calldata. Note that memory data is reused + * from `OrderFulfilled` event data, and the rest of the calldata is prefixed and + * postfixed to this memory region. Importantly the memory region before the + * `OrderFulfilled`'s spent and received items are overwritten to. So this + * function will need to be modified if the layout of that event data changes. * * @param orderHash The order hash. * @@ -571,8 +574,19 @@ contract ConsiderationEncoder { uint256 size, uint256 memoryLocationForOrderHashes ) { - // Get free memory pointer to write calldata to. - ptr = getFreeMemoryPointer(); + unchecked { + // Derive offset to pre `OrderFulfilled`'s spent item event data + // using base offset & total original recipients. + ptr = MemoryPointer.wrap( + authorizeOrder_calldata_baseOffset + + ( + CalldataPointer.wrap( + BasicOrder_totalOriginalAdditionalRecipients_cdPtr + ).readUint256() << + OneWordShift + ) + ); + } MemoryPointer dst = ptr; @@ -619,25 +633,11 @@ contract ConsiderationEncoder { BasicOrder_additionalRecipients_length_cdPtr ).readUint256(); - // Retrieve the length of additional recipients. - uint256 totalOriginalAdditionalRecipientsLength = CalldataPointer.wrap( - BasicOrder_totalOriginalAdditionalRecipients_cdPtr - ).readUint256(); - - // Derive offset to event data using base offset & total recipients. - uint256 offerDataOffset = OrderFulfilled_offer_length_baseOffset - + (totalOriginalAdditionalRecipientsLength << OneWordShift); - // Derive size of offer and consideration data. // 2 words (lengths) + 4 (offer data) + 5 (consideration 1) + 5 * ar uint256 offerAndConsiderationSize = OrderFulfilled_baseDataSize + (additionalRecipientsLength * ReceivedItem_size); - // Copy offer and consideration data from event data to calldata. - MemoryPointer.wrap(offerDataOffset).copy( - dstHead.offset(tailOffset), offerAndConsiderationSize - ); - // Increment tail offset, now used to populate extraData array. tailOffset += offerAndConsiderationSize; } @@ -669,9 +669,6 @@ contract ConsiderationEncoder { // Final size: selector, ZoneParameters pointer, orderHashes & tail. size = ZoneParameters_basicOrderFixedElements_length + tailOffset; - - // Update the free memory pointer. - setFreeMemoryPointer(dst.offset(size + OneWord)); } } diff --git a/src/types/lib/ConsiderationConstants.sol b/src/types/lib/ConsiderationConstants.sol index 0e0fce3..7cc70f3 100644 --- a/src/types/lib/ConsiderationConstants.sol +++ b/src/types/lib/ConsiderationConstants.sol @@ -300,6 +300,40 @@ uint256 constant OrderFulfilled_offer_body_offset = 0x80; uint256 constant OrderFulfilled_consideration_head_offset = 0x60; uint256 constant OrderFulfilled_consideration_body_offset = 0x120; +/* + * 3 memory slots/words for `authorizeOrder` and `validateOrder` calldata + * to be used for the extra data/context data and order hashes + */ +uint256 constant OrderFulfilled_post_memory_region_reservedBytes = 0x60; + +/* + * OrderFulfilled_offer_length_baseOffset - 12 * 0x20 + * we back up 12 words from where the `OrderFulfilled`'s data + * for spent items start to be rewritten for `authorizeOrder` + * and `validateOrder`. Let the reference pointer be `ptr` + * pointing to the `OrderFulfilled`'s spent item array's length memory + * position then we would have: + * + * ptr - 0x0180 : padded calldata selector + * ptr - 0x0160 : ZoneParameter's struct head (0x20) + * ptr - 0x0140 : order hash + * ptr - 0x0120 : fulfiller / msg.sender + * ptr - 0x0100 : offerer + * ptr - 0x00e0 : spent items' head + * ptr - 0x00c0 : received items' head + * ptr - 0x00a0 : extra data / context head + * ptr - 0x0080 : order hashes head + * ptr - 0x0060 : start time + * ptr - 0x0040 : end time + * ptr - 0x0020 : zone hash + * ptr - 0x0000: offer.length (1) + * ... + * + * Note that the padded calldata selector will be at minimum at the + * 0x80 memory slot if no total original additional recipients were provided + */ +uint256 constant authorizeOrder_calldata_baseOffset = 0x80; // 0x200 - 0x180 + // BasicOrderParameters uint256 constant BasicOrder_parameters_cdPtr = 0x04; uint256 constant BasicOrder_considerationToken_cdPtr = 0x24;