Skip to content

Commit

Permalink
Merge pull request #16 from ProjectOpenSea/1.6-pt2
Browse files Browse the repository at this point in the history
second round of 1.6 changes
  • Loading branch information
0age authored Mar 6, 2024
2 parents 2a2217e + 9688a62 commit 81232cf
Show file tree
Hide file tree
Showing 6 changed files with 362 additions and 418 deletions.
25 changes: 14 additions & 11 deletions src/lib/BasicOrderFulfiller.sol
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ import {
OrderFulfilled_offer_body_offset,
OrderFulfilled_offer_head_offset,
OrderFulfilled_offer_length_baseOffset,
OrderFulfilled_offer_length_baseOffset_relativeTo_OrderFulfilled_baseOffset,
OrderFulfilled_offer_itemType_baseOffset_relativeTo_OrderFulfilled_baseOffset,
OrderFulfilled_offer_token_baseOffset_relativeTo_OrderFulfilled_baseOffset,
OrderFulfilled_offer_length_offset_relativeTo_baseOffset,
OrderFulfilled_offer_itemType_offset_relativeTo_baseOffset,
OrderFulfilled_offer_token_offset_relativeTo_baseOffset,
OrderFulfilled_post_memory_region_reservedBytes,
OrderFulfilled_selector,
ReceivedItem_amount_offset,
Expand Down Expand Up @@ -1012,7 +1012,7 @@ contract BasicOrderFulfiller is OrderValidator {
mstore(
add(
eventDataPtr,
OrderFulfilled_offer_length_baseOffset_relativeTo_OrderFulfilled_baseOffset
OrderFulfilled_offer_length_offset_relativeTo_baseOffset
),
1
)
Expand All @@ -1021,7 +1021,7 @@ contract BasicOrderFulfiller is OrderValidator {
mstore(
add(
eventDataPtr,
OrderFulfilled_offer_itemType_baseOffset_relativeTo_OrderFulfilled_baseOffset
OrderFulfilled_offer_itemType_offset_relativeTo_baseOffset
),
offeredItemType
)
Expand All @@ -1032,7 +1032,7 @@ contract BasicOrderFulfiller is OrderValidator {
calldatacopy(
add(
eventDataPtr,
OrderFulfilled_offer_token_baseOffset_relativeTo_OrderFulfilled_baseOffset
OrderFulfilled_offer_token_offset_relativeTo_baseOffset
),
BasicOrder_offerToken_cdPtr,
ThreeWords
Expand Down Expand Up @@ -1074,11 +1074,14 @@ contract BasicOrderFulfiller is OrderValidator {
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)
// 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
)
)
)
}
Expand Down
9 changes: 5 additions & 4 deletions src/lib/ConsiderationDecoder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -890,8 +890,8 @@ contract ConsiderationDecoder {
// 1. offerOffset
// 2. considerationOffset
// 3. offerLength & considerationLength might occupy just one word
// if offerOffset & considerationOffset would point to the same offset
// and the arrays have length 0.
// if offerOffset & considerationOffset would point to the same
// offset and the arrays have length 0.
invalidEncoding := lt(returndatasize(), ThreeWords)

let offsetOffer
Expand All @@ -907,7 +907,8 @@ contract ConsiderationDecoder {
offsetOffer := mload(0)
offsetConsideration := mload(OneWord)

// If valid length, check that offsets word boundaries are within returndata.
// If valid length, check that offsets word boundaries are
// within returndata.
let invalidOfferOffset :=
gt(
add(offsetOffer, OneWord),
Expand All @@ -932,7 +933,7 @@ contract ConsiderationDecoder {
considerationLength := mload(OneWord)

{
// Calculate end offsets of offer & consideration arrays.
// Derive end offsets for offer & consideration arrays.
let offerEndOffset :=
add(
add(offsetOffer, OneWord),
Expand Down
12 changes: 7 additions & 5 deletions src/lib/ConsiderationEncoder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -555,11 +555,13 @@ contract ConsiderationEncoder {

/**
* @dev Takes an order hash and BasicOrderParameters struct (from calldata)
* 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.
* 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. Note that
* the memory region before the spent and received items on the
* `OrderFulfilled` event are overwritten, which implies that this
* function will need to be modified should the layout of that event
* data change in the future.
*
* @param orderHash The order hash.
*
Expand Down
94 changes: 52 additions & 42 deletions src/lib/FulfillmentApplier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -112,28 +112,27 @@ contract FulfillmentApplier is FulfillmentApplicationErrors {

// Validate & aggregate consideration items to new Execution object.
_aggregateValidFulfillmentConsiderationItems(
advancedOrders, considerationComponents, considerationExecution
advancedOrders,
considerationComponents,
considerationExecution,
address(0),
bytes32(0)
);

// Retrieve the consideration item from the execution struct.
ReceivedItem memory considerationItem = considerationExecution.item;

// Skip aggregating offer items if no consideration items are available.
if (considerationItem.amount == 0) {
// Set the offerer and recipient to null address and the item type
// to a non-native item type if the execution amount is zero. This
// will cause the execution item to be skipped.
considerationExecution.offerer = address(0);
considerationExecution.item.recipient = payable(0);
considerationExecution.item.itemType = ItemType.ERC20;
return considerationExecution;
}

// Recipient does not need to be specified because it will always be set
// to that of the consideration.
// Validate & aggregate offer items to Execution object.
_aggregateValidFulfillmentOfferItems(
advancedOrders, offerComponents, execution
advancedOrders,
offerComponents,
execution,
considerationItem.recipient
);

ReceivedItem memory executionItem = execution.item;
Expand Down Expand Up @@ -215,11 +214,8 @@ contract FulfillmentApplier is FulfillmentApplicationErrors {
executionItem.amount = considerationItem.amount;
}

// Reuse consideration recipient.
executionItem.recipient = considerationItem.recipient;

// Return the final execution that will be triggered for relevant items.
return execution; // Execution(considerationItem, offerer, conduitKey);
return execution; // Execution(executionItem, offerer, conduitKey);
}

/**
Expand Down Expand Up @@ -262,35 +258,24 @@ contract FulfillmentApplier is FulfillmentApplicationErrors {

// If the fulfillment components are offer components...
if (side == Side.OFFER) {
// Set the supplied recipient on the execution item.
item.recipient = payable(recipient);

// Return execution for aggregated items provided by offerer.
_aggregateValidFulfillmentOfferItems(
advancedOrders, fulfillmentComponents, execution
advancedOrders,
fulfillmentComponents,
execution,
payable(recipient)
);
} else {
// Otherwise, fulfillment components are consideration
// components. Return execution for aggregated items provided by
// the fulfiller.
_aggregateValidFulfillmentConsiderationItems(
advancedOrders, fulfillmentComponents, execution
advancedOrders,
fulfillmentComponents,
execution,
msg.sender,
fulfillerConduitKey
);

// Set the caller as the offerer on the execution.
execution.offerer = msg.sender;

// Set fulfiller conduit key as the conduit key on execution.
execution.conduitKey = fulfillerConduitKey;
}

// Set the offerer and recipient to null address and the item type
// to a non-native item type if the execution amount is zero. This
// will cause the execution item to be skipped.
if (item.amount == 0) {
execution.offerer = address(0);
item.recipient = payable(0);
item.itemType = ItemType.ERC20;
}
}
}
Expand All @@ -305,11 +290,13 @@ contract FulfillmentApplier is FulfillmentApplicationErrors {
* indicating the order index and item index of each
* candidate offer item for aggregation.
* @param execution The execution to apply the aggregation to.
* @param recipient The intended recipient for the received item.
*/
function _aggregateValidFulfillmentOfferItems(
AdvancedOrder[] memory advancedOrders,
FulfillmentComponent[] memory offerComponents,
Execution memory execution
Execution memory execution,
address payable recipient
) internal pure {
assembly {
// Declare a variable for the final aggregated item amount.
Expand All @@ -335,11 +322,10 @@ contract FulfillmentApplier is FulfillmentApplicationErrors {
// Increment position in considerationComponents head.
fulfillmentHeadPtr := add(fulfillmentHeadPtr, OneWord)

// Retrieve the order index using the fulfillment pointer.
let orderIndex := mload(mload(fulfillmentHeadPtr))

// Ensure that the order index is not out of range.
if iszero(lt(orderIndex, mload(advancedOrders))) {
if iszero(
lt(mload(mload(fulfillmentHeadPtr)), mload(advancedOrders))
) {
throwInvalidFulfillmentComponentData()
}

Expand All @@ -349,7 +335,7 @@ contract FulfillmentApplier is FulfillmentApplicationErrors {
// Calculate head position of advancedOrders[orderIndex]
add(
add(advancedOrders, OneWord),
shl(OneWordShift, orderIndex)
shl(OneWordShift, mload(mload(fulfillmentHeadPtr)))
)
)

Expand Down Expand Up @@ -442,6 +428,12 @@ contract FulfillmentApplier is FulfillmentApplicationErrors {
mload(add(offerItemPtr, Common_identifier_offset))
)

// Set the recipient on the received item.
mstore(
add(receivedItem, ReceivedItem_recipient_offset),
recipient
)

// Set offerer on returned execution using order pointer.
mstore(
add(execution, Execution_offerer_offset),
Expand Down Expand Up @@ -554,7 +546,7 @@ contract FulfillmentApplier is FulfillmentApplicationErrors {
* using supplied directives on which component items are candidates
* for aggregation, skipping items on orders that are not available.
* Note that this function depends on memory layout affected by an
* earlier call to _validateOrdersAndPrepareToFulfill. The memory for
* earlier call to _validateOrdersAndPrepareToFulfill. The memory for
* the consideration arrays needs to be updated before calling
* _aggregateValidFulfillmentConsiderationItems.
* _validateOrdersAndPrepareToFulfill is called in _matchAdvancedOrders
Expand All @@ -567,11 +559,17 @@ contract FulfillmentApplier is FulfillmentApplicationErrors {
* of each candidate consideration item for
* aggregation.
* @param execution The execution to apply the aggregation to.
* @param offerer The address of the offerer to set on the
* execution.
* @param conduitKey A bytes32 value indicating the conduit key
* to set on the execution.
*/
function _aggregateValidFulfillmentConsiderationItems(
AdvancedOrder[] memory advancedOrders,
FulfillmentComponent[] memory considerationComponents,
Execution memory execution
Execution memory execution,
address offerer,
bytes32 conduitKey
) internal pure {
// Utilize assembly in order to efficiently aggregate the items.
assembly {
Expand Down Expand Up @@ -724,6 +722,18 @@ contract FulfillmentApplier is FulfillmentApplicationErrors {
)
)

// Set provided offerer on the execution.
mstore(
add(execution, Execution_offerer_offset),
offerer
)

// Set provided conduitKey on the execution.
mstore(
add(execution, Execution_conduit_offset),
conduitKey
)

// Calculate the hash of (itemType, token, identifier,
// recipient). This is run after amount is set to zero, so
// there will be one blank word after identifier included in
Expand Down
Loading

0 comments on commit 81232cf

Please sign in to comment.