Skip to content

Commit

Permalink
Merge pull request #45 from ProjectOpenSea/wip-basic-order-memory-opt…
Browse files Browse the repository at this point in the history
…imization

Update basic order flow to avoid allocating unnecessary memory
  • Loading branch information
0age authored Mar 1, 2024
2 parents 4d49626 + f675e23 commit d9d3e59
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 40 deletions.
73 changes: 35 additions & 38 deletions src/core/lib/BasicOrderFulfiller.sol
Original file line number Diff line number Diff line change
Expand Up @@ -561,17 +561,27 @@ contract BasicOrderFulfiller is OrderValidator {
* item to the consideration array in OrderFulfilled.
*/

// Get the length of the additional recipients array.
// Get the additional recipients array length from calldata.
// This variable will later be repurposed to track the total
// original additional recipients instead of the total supplied.
let totalAdditionalRecipients :=
calldataload(BasicOrder_additionalRecipients_length_cdPtr)

// Calculate pointer to length of OrderFulfilled consideration
// array.
let eventConsiderationArrPtr :=
add(
OrderFulfilled_consideration_length_baseOffset,
shl(OneWordShift, totalAdditionalRecipients)
// array. Note that this is based on total original additional
// recipients and not the supplied additional recipients, since
// the pointer only needs to be offset based on the size of the
// EIP-712 hashes used to derive the order hash (and the order
// hash does not take tips into account as part of derivation).
let eventConsiderationArrPtr := add(
OrderFulfilled_consideration_length_baseOffset,
shl(
OneWordShift,
calldataload(
BasicOrder_totalOriginalAdditionalRecipients_cdPtr
)
)
)

// Set the length of the consideration array to the number of
// additional recipients, plus one for the primary consideration
Expand Down Expand Up @@ -628,8 +638,9 @@ contract BasicOrderFulfiller is OrderValidator {
// be combined to guard against providing dirty upper bits.
let combinedAdditionalRecipients

// Read length of the additionalRecipients array from calldata
// and iterate.
// Only iterate over the total original additional recipients
// (not the total supplied additional recipients) when deriving
// the order hash.
totalAdditionalRecipients := calldataload(
BasicOrder_totalOriginalAdditionalRecipients_cdPtr
)
Expand Down Expand Up @@ -863,35 +874,6 @@ contract BasicOrderFulfiller is OrderValidator {
* `keccak256(abi.encodePacked(offerItemHashes))`
*/
mstore(BasicOrder_order_offerHashes_ptr, keccak256(0, OneWord))

/*
* 3. Write SpentItem to offer array in OrderFulfilled event.
*/
let eventConsiderationArrPtr :=
add(
OrderFulfilled_offer_length_baseOffset,
shl(
OneWordShift,
calldataload(
BasicOrder_additionalRecipients_length_cdPtr
)
)
)

// Set a length of 1 for the offer array.
mstore(eventConsiderationArrPtr, 1)

// Write itemType to the SpentItem struct.
mstore(add(eventConsiderationArrPtr, OneWord), offeredItemType)

// Copy calldata region with (offerToken, offerIdentifier,
// offerAmount) from OrderParameters to (token, identifier,
// amount) in SpentItem struct.
calldatacopy(
add(eventConsiderationArrPtr, AdditionalRecipient_size),
BasicOrder_offerToken_cdPtr,
ThreeWords
)
}
}

Expand Down Expand Up @@ -1001,7 +983,7 @@ contract BasicOrderFulfiller is OrderValidator {
shl(
OneWordShift,
calldataload(
BasicOrder_additionalRecipients_length_cdPtr
BasicOrder_totalOriginalAdditionalRecipients_cdPtr
)
)
)
Expand All @@ -1024,6 +1006,21 @@ contract BasicOrderFulfiller is OrderValidator {
OrderFulfilled_consideration_body_offset
)

// Set a length of 1 for the offer array.
mstore(add(eventDataPtr, 0x80), 1)

// Write itemType to the SpentItem struct.
mstore(add(eventDataPtr, 0xa0), offeredItemType)

// Copy calldata region with (offerToken, offerIdentifier,
// offerAmount) from OrderParameters to (token, identifier,
// amount) in SpentItem struct.
calldatacopy(
add(eventDataPtr, 0xc0),
BasicOrder_offerToken_cdPtr,
ThreeWords
)

// Derive total data size including SpentItem and ReceivedItem data.
// SpentItem portion is already included in the baseSize constant,
// as there can only be one element in the array.
Expand Down
10 changes: 8 additions & 2 deletions src/core/lib/ConsiderationEncoder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
BasicOrder_offerer_cdPtr,
BasicOrder_startTime_cdPtr,
BasicOrder_startTimeThroughZoneHash_size,
BasicOrder_totalOriginalAdditionalRecipients_cdPtr,
Common_amount_offset,
Common_identifier_offset,
Common_token_offset,
Expand Down Expand Up @@ -613,14 +614,19 @@ contract ConsiderationEncoder {
tailOffset + BasicOrder_consideration_offset_from_offer
);

// Retrieve the offset to the length of additional recipients.
// Retrieve the length of additional recipients.
uint256 additionalRecipientsLength = CalldataPointer.wrap(
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
+ (additionalRecipientsLength << OneWordShift);
+ (totalOriginalAdditionalRecipientsLength << OneWordShift);

// Derive size of offer and consideration data.
// 2 words (lengths) + 4 (offer data) + 5 (consideration 1) + 5 * ar
Expand Down

0 comments on commit d9d3e59

Please sign in to comment.