diff --git a/contracts/lib/ConsiderationInternal.sol b/contracts/lib/ConsiderationInternal.sol index 8e4a63ba9..923d206d5 100644 --- a/contracts/lib/ConsiderationInternal.sol +++ b/contracts/lib/ConsiderationInternal.sol @@ -83,7 +83,9 @@ contract ConsiderationInternal is ConsiderationInternalView { // Ensure current timestamp falls between order start time and end time. _verifyTime(parameters.startTime, parameters.endTime, true); - // Ensure calldata offsets were produced by default encoding. + // Verify that calldata offsets for all dynamic types were produced by default encoding. + // This ensures that the constants we use for calldata pointers to dynamic types + // are the same as those calculated by Solidity using their offsets. _assertValidBasicOrderParameterOffsets(); // Ensure supplied consideration array length is not less than original. @@ -119,9 +121,14 @@ contract ConsiderationInternal is ConsiderationInternalView { // Load consideration item typehash from runtime and place on stack. bytes32 typeHash = _CONSIDERATION_ITEM_TYPEHASH; - // Utilize assembly to enable reuse of memory regions when possible. + // Utilize assembly to enable reuse of memory regions and use constant + // pointers when possible. assembly { - // 1. Write first ReceivedItem hash to the consideration array. + /* + * 1. Calculate the EIP712 ConsiderationItem hash for the primary consideration + * item of the basic order. + */ + // Write ConsiderationItem type hash and item type to memory. mstore(BasicOrder_considerationItem_typeHash_ptr, typeHash) mstore( @@ -129,21 +136,23 @@ contract ConsiderationInternal is ConsiderationInternalView { receivedItemType ) - // Copy calldata region with token, identifier, and startAmount. + // Copy calldata region with (token, identifier, amount) from BasicOrderParameters to ConsiderationItem. + // considerationAmount is written to startAmount and endAmount as basic orders do not have dynamic amounts. calldatacopy( BasicOrder_considerationItem_token_ptr, BasicOrder_considerationToken_cdPtr, ThreeWords ) - // Copy calldata region with endAmount (reused) and recipient. + // Copy calldata region with considerationAmount and offerer from BasicOrderParameters to endAmount + // and recipient in ConsiderationItem. calldatacopy( BasicOrder_considerationItem_endAmount_ptr, BasicOrder_considerationAmount_cdPtr, TwoWords ) - // Set keccak256(abi.encode(receivedItem)) as first item hash. + // Calculate EIP712 ConsiderationItem hash and store it in the array of EIP712 consideration hashes. mstore( BasicOrder_considerationHashesArray_ptr, keccak256( @@ -152,48 +161,64 @@ contract ConsiderationInternal is ConsiderationInternalView { ) ) - // 2. Write first ReceivedItem to OrderFulfilled data. + /* + * 2. Write a ReceivedItem struct for the primary consideration item to the consideration array + * in OrderFulfilled. + */ + // Get the length of the additional recipients array. let len := calldataload( BasicOrder_additionalRecipients_length_cdPtr ) - // END_ARR + 0x120 = 0x2a0 + len*0x20 - let eventArrPtr := add( + // Calculate pointer to length of OrderFulfilled consideration array. + let eventConsiderationArrPtr := add( OrderFulfilled_consideration_length_baseOffset, mul(0x20, len) ) + + // Set the length of the consideration array to the number of additional recipients, plus one + // for the primary consideration item. mstore( - eventArrPtr, + eventConsiderationArrPtr, add( calldataload( BasicOrder_additionalRecipients_length_cdPtr ), 1 ) - ) // length + ) - // Set pointer to data portion of the initial ReceivedItem. - eventArrPtr := add(eventArrPtr, 0x20) + // Overwrite the consideration array pointer so it points to the body of the first element + eventConsiderationArrPtr := add(eventConsiderationArrPtr, 0x20) - // Set item type at start of the ReceivedItem memory region. - mstore(eventArrPtr, receivedItemType) + // Set itemType at start of the ReceivedItem memory region. + mstore(eventConsiderationArrPtr, receivedItemType) - // Copy calldata region (token, identifier, amount & recipient). + // Copy calldata region (token, identifier, amount & recipient) from + // BasicOrderParameters to ReceivedItem memory. calldatacopy( - add(eventArrPtr, 0x20), + add(eventConsiderationArrPtr, Common_token_offset), BasicOrder_considerationToken_cdPtr, 0x80 ) - // 3. Handle additional recipients. - // Set pointer to current location in receivedItemHashes. + /* + * 3. Calculate EIP712 ConsiderationItem hashes for original additional recipients and add + * a ReceivedItem for each to the consideration array in the OrderFulfilled event. + * The original additional recipients are all the considerations signed by the offerer aside + * from the primary consideration of the order. + * Uses memory region from 0x80-0x160 as a buffer for calculating EIP712 ConsiderationItem hashes. + */ + + // Put pointer to consideration hashes array on the stack. + // This will be updated as each additional recipient is hashed let considerationHashesPtr := BasicOrder_considerationHashesArray_ptr - // Write item type, token, & identifier for additional recipient - // to memory; these values will be reused for each recipient. + // Write item type, token, & identifier for additional recipient to memory region for + // hashing EIP712 ConsiderationItem; these values will be reused for each recipient. mstore( BasicOrder_considerationItem_itemType_ptr, additionalRecipientsItemType @@ -204,7 +229,7 @@ contract ConsiderationInternal is ConsiderationInternalView { ) mstore(BasicOrder_considerationItem_identifier_ptr, 0) - // Read length of the additionalRecipients array and iterate. + // Read length of the additionalRecipients array from calldata and iterate. len := calldataload( BasicOrder_totalOriginalAdditionalRecipients_cdPtr ) @@ -213,21 +238,24 @@ contract ConsiderationInternal is ConsiderationInternalView { for {} lt(i, len) { i := add(i, 1) } { - // Retrieve pointer for additional recipient in question. + /* + * Calculate EIP712 ConsiderationItem hash for recipient. + */ + + // Retrieve calldata pointer for additional recipient in question. let additionalRecipientCdPtr := add( BasicOrder_additionalRecipients_data_cdPtr, mul(AdditionalRecipients_size, i) ) - // a. Write ConsiderationItem hash to consideration array. - // Copy startAmount from calldata. + // Copy startAmount from calldata to the ConsiderationItem struct. calldatacopy( BasicOrder_considerationItem_startAmount_ptr, additionalRecipientCdPtr, 0x20 ) - // Copy endAmount and recipient from calldata. + // Copy endAmount and recipient from calldata to the ConsiderationItem struct. calldatacopy( BasicOrder_considerationItem_endAmount_ptr, additionalRecipientCdPtr, @@ -238,7 +266,7 @@ contract ConsiderationInternal is ConsiderationInternalView { // operations needed to get local offset into the array. considerationHashesPtr := add(considerationHashesPtr, 0x20) - // Set keccak256(abi.encode(receivedItem)) as next hash. + // Calculate EIP712 ConsiderationItem hash and store it in the array of consideration hashes. mstore( considerationHashesPtr, keccak256( @@ -247,30 +275,37 @@ contract ConsiderationInternal is ConsiderationInternalView { ) ) - // b. Write ReceivedItem to OrderFulfilled data. - // At this point, eventArrPtr points to the beginning of the + /* + * Write ReceivedItem to OrderFulfilled data. + */ + + // At this point, eventConsiderationArrPtr points to the beginning of the // ReceivedItem struct of the previous element in the array. - eventArrPtr := add(eventArrPtr, ReceivedItem_size) + // Increase it by the size of the struct to arrive at the pointer for the + // current element. + eventConsiderationArrPtr := add(eventConsiderationArrPtr, ReceivedItem_size) - // Set item type at start of the ReceivedItem memory region. - mstore(eventArrPtr, additionalRecipientsItemType) + // Write itemType to the ReceivedItem struct. + mstore(eventConsiderationArrPtr, additionalRecipientsItemType) - // Set token at next word in the ReceivedItem memory region. - mstore(add(eventArrPtr, 0x20), additionalRecipientsToken) + // Write token to the ReceivedItem struct. + mstore(add(eventConsiderationArrPtr, 0x20), additionalRecipientsToken) - // Copy endAmount and recipient to remaining memory region. + // Copy endAmount and recipient to the ReceivedItem struct. calldatacopy( - add(eventArrPtr, ReceivedItem_amount_offset), + add(eventConsiderationArrPtr, ReceivedItem_amount_offset), additionalRecipientCdPtr, 0x40 ) } - // 4. Hash packed array of ConsiderationItem EIP712 hashes: - // `keccak256(abi.encodePacked(receivedItemHashes))` - // Note that it is set at 0x60 — all other memory begins at - // 0x80. 0x60 is the "zero slot" and will be restored at the end - // of the assembly section and before required by the compiler. + /* + * 4. Hash packed array of ConsiderationItem EIP712 hashes: + * `keccak256(abi.encodePacked(receivedItemHashes))` + * Note that it is set at 0x60 — all other memory begins at + * 0x80. 0x60 is the "zero slot" and will be restored at the end + * of the assembly section and before required by the compiler. + */ mstore( receivedItemsHash_ptr, keccak256( @@ -279,7 +314,13 @@ contract ConsiderationInternal is ConsiderationInternalView { ) ) - // 5. Write tips to event data. + /* + * 5. Add a ReceivedItem for each tip to the consideration array in the OrderFulfilled event. + * The tips are all the considerations that were not signed by the offerer and were provided by + * the fulfiller. + */ + + // Overwrite length to the length of the additionalRecipients array len := calldataload( BasicOrder_additionalRecipients_length_cdPtr ) @@ -287,26 +328,27 @@ contract ConsiderationInternal is ConsiderationInternalView { for {} lt(i, len) { i := add(i, 1) } { - // Retrieve pointer for additional recipient in question. + // Retrieve calldata pointer for additional recipient in question. let additionalRecipientCdPtr := add( BasicOrder_additionalRecipients_data_cdPtr, mul(AdditionalRecipients_size, i) ) - // b. Write ReceivedItem to OrderFulfilled data - // At this point, eventArrPtr points to the beginning of the + // At this point, eventConsiderationArrPtr points to the beginning of the // ReceivedItem struct of the previous element in the array. - eventArrPtr := add(eventArrPtr, ReceivedItem_size) + // Increase it by the size of the struct to arrive at the pointer for the + // current element. + eventConsiderationArrPtr := add(eventConsiderationArrPtr, ReceivedItem_size) - // Set item type at start of the ReceivedItem memory region. - mstore(eventArrPtr, additionalRecipientsItemType) + // Write itemType to the ReceivedItem struct. + mstore(eventConsiderationArrPtr, additionalRecipientsItemType) - // Set token at next word in the ReceivedItem memory region. - mstore(add(eventArrPtr, 0x20), additionalRecipientsToken) + // Write token to the ReceivedItem struct. + mstore(add(eventConsiderationArrPtr, 0x20), additionalRecipientsToken) - // Copy endAmount and recipient to remaining memory region. + // Copy endAmount and recipient to the ReceivedItem struct. calldatacopy( - add(eventArrPtr, ReceivedItem_amount_offset), + add(eventConsiderationArrPtr, ReceivedItem_amount_offset), additionalRecipientCdPtr, 0x40 ) @@ -326,31 +368,37 @@ contract ConsiderationInternal is ConsiderationInternalView { * - 0x120: endAmount */ - // Load offer item typehash from runtime code and place on stack. + // Place offer item typehash on the stack. bytes32 typeHash = _OFFER_ITEM_TYPEHASH; // Utilize assembly to enable reuse of memory regions when possible. assembly { - // 1. Calculate OfferItem EIP712 hash - // Write OfferItem type hash and item type to memory. + /* + * 1. Calculate OfferItem EIP712 hash + */ + + // Write OfferItem typeHash and itemType to memory. mstore(BasicOrder_offerItem_typeHash_ptr, typeHash) // _OFFERED_ITEM_TYPEHASH mstore(BasicOrder_offerItem_itemType_ptr, offeredItemType) // itemType - // Copy calldata region with token, identifier, and startAmount. + // Copy calldata region with (offerToken, offerIdentifier, offerAmount) from + // OrderParameters to (token, identifier, startAmount) in OfferItem struct. + // offerAmount is written to startAmount and endAmount as basic orders do not + // have dynamic amounts. calldatacopy( BasicOrder_offerItem_token_ptr, BasicOrder_offerToken_cdPtr, 0x60 ) - // Copy endAmount from calldata; reuses last word of prior copy. + // Copy offerAmount from calldata to endAmount in OfferItem struct. calldatacopy( BasicOrder_offerItem_endAmount_ptr, BasicOrder_offerAmount_cdPtr, 0x20 ) - // Compute offer item hash and write result to scratch space: + // Compute EIP712 OfferItem hash and write result to scratch space: // `keccak256(abi.encode(offeredItem))` mstore( 0x00, @@ -360,15 +408,17 @@ contract ConsiderationInternal is ConsiderationInternalView { ) ) - // 2. Calculate hash of array of EIP712 hashes and write the - // result to the corresponding offer struct memory region: - // `keccak256(abi.encodePacked(offeredItemHashes))` + /* + * 2. Calculate hash of array of EIP712 hashes and write the + * result to the corresponding OfferItem struct: + * `keccak256(abi.encodePacked(offerItemHashes))` + */ mstore(BasicOrder_order_offerHashes_ptr, keccak256(0x00, 0x20)) - // 3. Write SpentItem array to event data. - // 0x180 + len*32 = event data pointer, where the offer array - // length is stored at 0x80 into the event data. - let eventArrPtr := add( + /* + * 3. Write SpentItem to offer array in OrderFulfilled event. + */ + let eventConsiderationArrPtr := add( OrderFulfilled_offer_length_baseOffset, mul( 0x20, @@ -379,14 +429,15 @@ contract ConsiderationInternal is ConsiderationInternalView { ) // Set a length of 1 for the offer array. - mstore(eventArrPtr, 1) + mstore(eventConsiderationArrPtr, 1) - // Set offer item type at start of the SpentItem memory region. - mstore(add(eventArrPtr, 0x20), offeredItemType) + // Write itemType to the SpentItem struct. + mstore(add(eventConsiderationArrPtr, 0x20), offeredItemType) - // Copy token, identifier, and startAmount to SpentItem region. + // Copy calldata region with (offerToken, offerIdentifier, offerAmount) from + // OrderParameters to (token, identifier, amount) in SpentItem struct. calldatacopy( - add(eventArrPtr, AdditionalRecipients_size), + add(eventConsiderationArrPtr, AdditionalRecipients_size), BasicOrder_offerToken_cdPtr, ThreeWords ) @@ -425,36 +476,37 @@ contract ConsiderationInternal is ConsiderationInternalView { bytes32 typeHash = _ORDER_TYPEHASH; assembly { - // Set the offer typehash in memory. + // Set the OrderItem typeHash in memory. mstore(BasicOrder_order_typeHash_ptr, typeHash) - // Copy offerer and zone from calldata and set them in memory. + // Copy offerer and zone from OrderParameters in calldata to the Order struct. calldatacopy( BasicOrder_order_offerer_ptr, BasicOrder_offerer_cdPtr, TwoWords ) - // Copy receivedItemsHash from zero slot to the required region. + // Copy receivedItemsHash from zero slot to the Order struct. mstore( BasicOrder_order_considerationHashes_ptr, mload(receivedItemsHash_ptr) ) - // Set the supplied order type in memory. + // Write the supplied orderType to the Order struct. mstore(BasicOrder_order_orderType_ptr, orderType) - // Copy startTime, endTime, zoneHash, salt & conduit to memory. + // Copy startTime, endTime, zoneHash, salt & conduit from calldata to + // the Order struct. calldatacopy( BasicOrder_order_startTime_ptr, BasicOrder_startTime_cdPtr, 0xa0 ) - // Take offerer's nonce retrieved from storage & set in memory. + // Take offerer's nonce retrieved from storage & write to struct. mstore(BasicOrder_order_nonce_ptr, nonce) - // Compute the order hash. + // Compute the EIP712 Order hash. orderHash := keccak256( BasicOrder_order_typeHash_ptr, EIP712_Order_size @@ -492,7 +544,7 @@ contract ConsiderationInternal is ConsiderationInternalView { * - 0x140: recipient 0 */ - // Derive pointer from calldata via length of additional recipients. + // Derive pointer to start of OrderFulfilled event data let eventDataPtr := add( OrderFulfilled_baseOffset, mul( @@ -505,7 +557,7 @@ contract ConsiderationInternal is ConsiderationInternalView { mstore(eventDataPtr, orderHash) // Write the fulfiller (i.e. the caller) next. - mstore(add(eventDataPtr, 0x20), caller()) + mstore(add(eventDataPtr, OrderFulfilled_fulfiller_offset), caller()) // Write the SpentItem and ReceivedItem array offsets (constants). mstore( @@ -520,6 +572,8 @@ contract ConsiderationInternal is ConsiderationInternalView { ) // 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. let dataSize := add( OrderFulfilled_baseSize, mul( @@ -536,10 +590,10 @@ contract ConsiderationInternal is ConsiderationInternalView { // Supply the size of event data in memory. dataSize, // Supply the OrderFulfilled event signature. - 0x9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f31, + OrderFulfilled_selector, // Supply the first topic (the offerer). calldataload(BasicOrder_offerer_cdPtr), - // Supply the first topic (the zone). + // Supply the second topic (the zone). calldataload(BasicOrder_zone_cdPtr) ) diff --git a/contracts/lib/ConsiderationInternalView.sol b/contracts/lib/ConsiderationInternalView.sol index 2681d2074..56d7d7bc2 100644 --- a/contracts/lib/ConsiderationInternalView.sol +++ b/contracts/lib/ConsiderationInternalView.sol @@ -814,7 +814,9 @@ contract ConsiderationInternalView is ConsiderationPure { ) ) // Load offer array pointer - let offerArrPtr := mload(add(orderPtr, Order_offer_head_offset)) + let offerArrPtr := mload( + add(orderPtr, OrderParameters_offer_head_offset) + ) invalidFulfillment := or( iszero(lt(itemIndex, mload(offerArrPtr))), invalidFulfillment @@ -832,15 +834,15 @@ contract ConsiderationInternalView is ConsiderationPure { mstore(receivedItemPtr, mload(offerItemPtr)) // token mstore( - add(receivedItemPtr, CommonTokenOffset), - mload(add(offerItemPtr, CommonTokenOffset)) + add(receivedItemPtr, Common_token_offset), + mload(add(offerItemPtr, Common_token_offset)) ) // identifier mstore( add(receivedItemPtr, 0x40), - mload(add(offerItemPtr, CommonIdentifierOffset)) + mload(add(offerItemPtr, Common_identifier_offset)) ) - let amountPtr := add(offerItemPtr, CommonAmountOffset) + let amountPtr := add(offerItemPtr, Common_amount_offset) amount := mload(amountPtr) // recipient mstore( @@ -853,7 +855,7 @@ contract ConsiderationInternalView is ConsiderationPure { // conduit mstore( add(execution, Execution_conduit_offset), - mload(add(orderPtr, Order_conduit_offset)) + mload(add(orderPtr, OrderParameters_conduit_offset)) ) } @@ -887,7 +889,7 @@ contract ConsiderationInternalView is ConsiderationPure { orderPtr := mload(orderPtr) // Load offer array pointer let offerArrPtr := mload( - add(orderPtr, Order_offer_head_offset) + add(orderPtr, OrderParameters_offer_head_offset) ) invalidFulfillment := iszero( lt(itemIndex, mload(offerArrPtr)) @@ -906,7 +908,7 @@ contract ConsiderationInternalView is ConsiderationPure { ) ) - let amountPtr := add(offerItemPtr, CommonAmountOffset) + let amountPtr := add(offerItemPtr, Common_amount_offset) amount := add(amount, mload(amountPtr)) mstore(amountPtr, 0) @@ -915,10 +917,10 @@ contract ConsiderationInternalView is ConsiderationPure { // identifier eq( mload( - add(offerItemPtr, CommonIdentifierOffset) + add(offerItemPtr, Common_identifier_offset) ), mload( - add(receivedItemPtr, CommonIdentifierOffset) + add(receivedItemPtr, Common_identifier_offset) ) ), and( @@ -926,12 +928,12 @@ contract ConsiderationInternalView is ConsiderationPure { // offerer eq( mload(orderPtr), - mload(add(execution, CommonTokenOffset)) + mload(add(execution, Common_token_offset)) ), // conduit eq( mload( - add(orderPtr, Order_conduit_offset) + add(orderPtr, OrderParameters_conduit_offset) ), mload( add( @@ -950,12 +952,12 @@ contract ConsiderationInternalView is ConsiderationPure { // token eq( mload( - add(offerItemPtr, CommonTokenOffset) + add(offerItemPtr, Common_token_offset) ), mload( add( receivedItemPtr, - CommonTokenOffset + Common_token_offset ) ) ) @@ -965,7 +967,7 @@ contract ConsiderationInternalView is ConsiderationPure { ) } } - mstore(add(receivedItemPtr, CommonAmountOffset), amount) + mstore(add(receivedItemPtr, Common_amount_offset), amount) } if (invalidFulfillment) { diff --git a/contracts/lib/ConsiderationPointers.sol b/contracts/lib/ConsiderationPointers.sol index 19326dc86..cb6b236a6 100644 --- a/contracts/lib/ConsiderationPointers.sol +++ b/contracts/lib/ConsiderationPointers.sol @@ -1,22 +1,59 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.13; +/* + * -------------------------- Disambiguation & Other Notes -------------------------- + * - The term "head" is used as it is in the documentation for ABI encoding, + * but only in reference to dynamic types, i.e. it always refers to the offset + * or pointer to the body of a dynamic type. In calldata, the head is always + * an offset (relative to the parent object), while in memory, the head is always + * the pointer to the body + * + * - https://docs.soliditylang.org/en/v0.8.13/abi-spec.html#argument-encoding + * - Note that the length of an array is separate from and precedes the head of + * the array. + * + * - The term "body" is used in place of the term "head" used in the ABI documentation. + * It refers to the start of the data for a dynamic type, e.g. the first word of a + * struct or the first word of the first element in an array. + * + * - "pointer" is used to describe the absolute position of a value and never an offset + * relative to another value. + * + * - The suffix "_ptr" refers to a memory pointer. + * - The suffix "_cdPtr" refers to a calldata pointer. + * + * - "offset" is used to describe the position of a value relative to some parent value. + * For example, OrderParameters_conduit_offset is the offset to the "conduit" value in the + * OrderParameters struct relative to the start of the body. + * + * - Note: Offsets are used to derive pointers. + * + * - Some structs have pointers defined for all of their fields in this file. + * Lines which are commented out are fields that are not used in the codebase but + * have been left in for readability. + */ + // Common Offsets -// Offsets to fields within -Item structs +// Offsets for identically positioned fields shared by: +// OfferItem, ConsiderationItem, SpentItem, ReceivedItem -// uint256 constant CommonItemTypeOffset = 0x0; -uint256 constant CommonTokenOffset = 0x20; -uint256 constant CommonIdentifierOffset = 0x40; -uint256 constant CommonAmountOffset = 0x60; +uint256 constant Common_token_offset = 0x20; +uint256 constant Common_identifier_offset = 0x40; +uint256 constant Common_amount_offset = 0x60; +uint256 constant ReceivedItem_size = 0xa0; +uint256 constant ReceivedItem_amount_offset = 0x60; uint256 constant ReceivedItem_recipient_offset = 0x80; + uint256 constant ConsiderationItem_recipient_offset = 0xa0; + uint256 constant Execution_offerer_offset = 0x20; uint256 constant Execution_conduit_offset = 0x40; -uint256 constant Order_offer_head_offset = 0x40; -uint256 constant Order_consideration_head_offset = 0x60; -uint256 constant Order_conduit_offset = 0x120; +uint256 constant OrderParameters_offer_head_offset = 0x40; +uint256 constant OrderParameters_consideration_head_offset = 0x60; +uint256 constant OrderParameters_conduit_offset = 0x120; uint256 constant Fulfillment_itemIndex_offset = 0x20; @@ -38,12 +75,9 @@ uint256 constant EIP712_Order_size = 0x180; uint256 constant EIP712_OfferItem_size = 0xc0; uint256 constant EIP712_ConsiderationItem_size = 0xe0; uint256 constant AdditionalRecipients_size = 0x40; -uint256 constant ReceivedItem_size = 0xa0; uint256 constant receivedItemsHash_ptr = 0x60; -uint256 constant ReceivedItem_amount_offset = 0x60; - /* * Memory layout in _prepareBasicFulfillmentFromCalldata of * data for OrderFulfilled @@ -76,14 +110,20 @@ uint256 constant ReceivedItem_amount_offset = 0x60; * - 0x1c0: considerationRecipient * - ... */ + +// Minimum length of the OrderFulfilled event data. +// Must be added to the size of the ReceivedItem array for additionalRecipients +// (0xa0 * additionalRecipients.length) to calculate the full size of the buffer. uint256 constant OrderFulfilled_baseSize = 0x1e0; -// Offset in memory to OrderFulfilled before adding the size -// of the received items for additionalRecipients +uint256 constant OrderFulfilled_selector = 0x9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f31; +// Minimum offset in memory to OrderFulfilled event data. +// Must be added to the size of the EIP712 hash array for additionalRecipients +// (32 * additionalRecipients.length) to calculate the pointer to the event data. uint256 constant OrderFulfilled_baseOffset = 0x180; uint256 constant OrderFulfilled_consideration_length_baseOffset = 0x2a0; uint256 constant OrderFulfilled_offer_length_baseOffset = 0x200; -uint256 constant OrderFulfilled_orderHash_offset = 0x00; +// uint256 constant OrderFulfilled_orderHash_offset = 0x00; uint256 constant OrderFulfilled_fulfiller_offset = 0x20; uint256 constant OrderFulfilled_offer_head_offset = 0x40; uint256 constant OrderFulfilled_offer_body_offset = 0x80; @@ -92,23 +132,23 @@ uint256 constant OrderFulfilled_consideration_body_offset = 0x120; // BasicOrderParameters uint256 constant BasicOrder_considerationToken_cdPtr = 0x24; -uint256 constant BasicOrder_considerationIdentifier_cdPtr = 0x44; +// uint256 constant BasicOrder_considerationIdentifier_cdPtr = 0x44; uint256 constant BasicOrder_considerationAmount_cdPtr = 0x64; uint256 constant BasicOrder_offerer_cdPtr = 0x84; uint256 constant BasicOrder_zone_cdPtr = 0xa4; uint256 constant BasicOrder_offerToken_cdPtr = 0xc4; -uint256 constant BasicOrder_offerIdentifier_cdPtr = 0xe4; +// uint256 constant BasicOrder_offerIdentifier_cdPtr = 0xe4; uint256 constant BasicOrder_offerAmount_cdPtr = 0x104; -uint256 constant BasicOrder_basicOrderType_cdPtr = 0x124; +// uint256 constant BasicOrder_basicOrderType_cdPtr = 0x124; uint256 constant BasicOrder_startTime_cdPtr = 0x144; -uint256 constant BasicOrder_endTime_cdPtr = 0x164; -uint256 constant BasicOrder_zoneHash_cdPtr = 0x184; -uint256 constant BasicOrder_salt_cdPtr = 0x1a4; -uint256 constant BasicOrder_offererConduit_cdPtr = 0x1c4; -uint256 constant BasicOrder_fulfillerConduit_cdPtr = 0x1e4; +// uint256 constant BasicOrder_endTime_cdPtr = 0x164; +// uint256 constant BasicOrder_zoneHash_cdPtr = 0x184; +// uint256 constant BasicOrder_salt_cdPtr = 0x1a4; +// uint256 constant BasicOrder_offererConduit_cdPtr = 0x1c4; +// uint256 constant BasicOrder_fulfillerConduit_cdPtr = 0x1e4; uint256 constant BasicOrder_totalOriginalAdditionalRecipients_cdPtr = 0x204; -uint256 constant BasicOrder_additionalRecipients_cdPtr = 0x224; -uint256 constant BasicOrder_signature_cdPtr = 0x244; +// uint256 constant BasicOrder_additionalRecipients_head_cdPtr = 0x224; +// uint256 constant BasicOrder_signature_cdPtr = 0x244; uint256 constant BasicOrder_additionalRecipients_length_cdPtr = 0x264; uint256 constant BasicOrder_additionalRecipients_data_cdPtr = 0x284; @@ -129,7 +169,7 @@ uint256 constant BasicOrder_considerationItem_token_ptr = 0xc0; uint256 constant BasicOrder_considerationItem_identifier_ptr = 0xe0; uint256 constant BasicOrder_considerationItem_startAmount_ptr = 0x100; uint256 constant BasicOrder_considerationItem_endAmount_ptr = 0x120; -uint256 constant BasicOrder_considerationItem_recipient_ptr = 0x140; +// uint256 constant BasicOrder_considerationItem_recipient_ptr = 0x140; /* * Memory layout in _prepareBasicFulfillmentFromCalldata of @@ -144,8 +184,8 @@ uint256 constant BasicOrder_considerationItem_recipient_ptr = 0x140; uint256 constant BasicOrder_offerItem_typeHash_ptr = DefaultFreeMemoryPointer; uint256 constant BasicOrder_offerItem_itemType_ptr = 0xa0; uint256 constant BasicOrder_offerItem_token_ptr = 0xc0; -uint256 constant BasicOrder_offerItem_identifier_ptr = 0xe0; -uint256 constant BasicOrder_offerItem_startAmount_ptr = 0x100; +// uint256 constant BasicOrder_offerItem_identifier_ptr = 0xe0; +// uint256 constant BasicOrder_offerItem_startAmount_ptr = 0x100; uint256 constant BasicOrder_offerItem_endAmount_ptr = 0x120; /* @@ -166,15 +206,15 @@ uint256 constant BasicOrder_offerItem_endAmount_ptr = 0x120; */ uint256 constant BasicOrder_order_typeHash_ptr = 0x80; uint256 constant BasicOrder_order_offerer_ptr = 0xa0; -uint256 constant BasicOrder_order_zone_ptr = 0xc0; +// uint256 constant BasicOrder_order_zone_ptr = 0xc0; uint256 constant BasicOrder_order_offerHashes_ptr = 0xe0; uint256 constant BasicOrder_order_considerationHashes_ptr = 0x100; uint256 constant BasicOrder_order_orderType_ptr = 0x120; uint256 constant BasicOrder_order_startTime_ptr = 0x140; -uint256 constant BasicOrder_order_endTime_ptr = 0x160; -uint256 constant BasicOrder_order_zoneHash_ptr = 0x180; -uint256 constant BasicOrder_order_salt_ptr = 0x1a0; -uint256 constant BasicOrder_order_conduit_ptr = 0x1c0; +// uint256 constant BasicOrder_order_endTime_ptr = 0x160; +// uint256 constant BasicOrder_order_zoneHash_ptr = 0x180; +// uint256 constant BasicOrder_order_salt_ptr = 0x1a0; +// uint256 constant BasicOrder_order_conduit_ptr = 0x1c0; uint256 constant BasicOrder_order_nonce_ptr = 0x1e0; // Signature-related diff --git a/contracts/lib/ConsiderationPure.sol b/contracts/lib/ConsiderationPure.sol index 8a1fcc25c..61dc2d4b8 100644 --- a/contracts/lib/ConsiderationPure.sol +++ b/contracts/lib/ConsiderationPure.sol @@ -629,33 +629,29 @@ contract ConsiderationPure is ConsiderationBase { uint256 startIndex ) internal pure returns (ReceivedItem memory receivedItem) { bool invalidFulfillment; - assembly { let ordersLen := mload(advancedOrders) let i := startIndex - // let fulfillmentLen := mload(considerationComponents) let fulfillmentPtr := mload( add(add(considerationComponents, 0x20), mul(i, 0x20)) ) + let orderIndex := mload(fulfillmentPtr) let itemIndex := mload(add(fulfillmentPtr, 0x20)) invalidFulfillment := iszero(lt(orderIndex, ordersLen)) if iszero(invalidFulfillment) { - // Get pointer to AdvancedOrder element then get pointer to OrderParameters + // Calculate pointer to AdvancedOrder element at advancedOrders[orderIndex] // OrderParameters pointer is first word of AdvancedOrder struct, so we mload twice let orderPtr := mload( + // Read the pointer to advancedOrders[orderIndex] from its head in the array mload( - add( - // Calculate pointer to beginning of advancedOrders head - add(advancedOrders, 0x20), - // Calculate offset to pointer for desired order - mul(orderIndex, 0x20) - ) + // Calculate the position of the head for advancedOrders[orderIndex] + add(add(advancedOrders, 0x20), mul(orderIndex, 0x20)) ) ) // Load consideration array pointer let considerationArrPtr := mload( - add(orderPtr, Order_consideration_head_offset) + add(orderPtr, OrderParameters_consideration_head_offset) ) // Check if itemIndex is within the range of the array invalidFulfillment := iszero( @@ -675,21 +671,23 @@ contract ConsiderationPure is ConsiderationBase { mstore(receivedItem, mload(considerationItemPtr)) // token mstore( - add(receivedItem, CommonTokenOffset), - mload(add(considerationItemPtr, CommonTokenOffset)) + add(receivedItem, Common_token_offset), + mload(add(considerationItemPtr, Common_token_offset)) ) // identifier mstore( - add(receivedItem, CommonIdentifierOffset), - mload(add(considerationItemPtr, CommonIdentifierOffset)) + add(receivedItem, Common_identifier_offset), + mload( + add(considerationItemPtr, Common_identifier_offset) + ) ) let amountPtr := add( considerationItemPtr, - CommonAmountOffset + Common_amount_offset ) // amount mstore( - add(receivedItem, CommonAmountOffset), + add(receivedItem, Common_amount_offset), mload(amountPtr) ) mstore(amountPtr, 0) @@ -737,7 +735,7 @@ contract ConsiderationPure is ConsiderationBase { orderPtr := mload(orderPtr) // Load consideration array pointer considerationArrPtr := mload( - add(orderPtr, Order_consideration_head_offset) + add(orderPtr, OrderParameters_consideration_head_offset) ) // Check if itemIndex is within the range of the array invalidFulfillment := iszero( @@ -756,14 +754,14 @@ contract ConsiderationPure is ConsiderationBase { ) amountPtr := add( considerationItemPtr, - CommonAmountOffset + Common_amount_offset ) mstore( - add(receivedItem, CommonAmountOffset), + add(receivedItem, Common_amount_offset), add( mload( - add(receivedItem, CommonAmountOffset) + add(receivedItem, Common_amount_offset) ), mload(amountPtr) ) @@ -799,13 +797,13 @@ contract ConsiderationPure is ConsiderationBase { mload( add( considerationItemPtr, - CommonTokenOffset + Common_token_offset ) ), mload( add( receivedItem, - CommonTokenOffset + Common_token_offset ) ) ), @@ -814,13 +812,13 @@ contract ConsiderationPure is ConsiderationBase { mload( add( considerationItemPtr, - CommonIdentifierOffset + Common_identifier_offset ) ), mload( add( receivedItem, - CommonIdentifierOffset + Common_identifier_offset ) ) )