Skip to content

Commit

Permalink
Merge pull request #25 from ProjectOpenSea/random-codesize-stuff
Browse files Browse the repository at this point in the history
random stuff to reduce codesize and apply small optimizations
  • Loading branch information
0age authored Feb 17, 2024
2 parents 47822ba + a5594be commit d065e19
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 78 deletions.
4 changes: 2 additions & 2 deletions src/core/lib/ConsiderationEncoder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ contract ConsiderationEncoder {
orderHashesLengthLocation.write(orderIndex);

// Modify encoding size to account for the shorter orderHashes array.
size -= (orderHashes.length - orderIndex) * OneWord;
size -= (orderHashes.length - orderIndex) << OneWordShift;
}

/**
Expand Down Expand Up @@ -604,7 +604,7 @@ contract ConsiderationEncoder {

// Derive offset to event data using base offset & total recipients.
uint256 offerDataOffset = OrderFulfilled_offer_length_baseOffset
+ additionalRecipientsLength * OneWord;
+ (additionalRecipientsLength << OneWordShift);

// Derive size of offer and consideration data.
// 2 words (lengths) + 4 (offer data) + 5 (consideration 1) + 5 * ar
Expand Down
137 changes: 95 additions & 42 deletions src/core/lib/CriteriaResolution.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {

import {
AdvancedOrder,
ConsiderationItem,
CriteriaResolver,
MemoryPointer,
OfferItem,
Expand All @@ -18,9 +19,7 @@ import {
import {
_revertCriteriaNotEnabledForItem,
_revertInvalidProof,
_revertOrderCriteriaResolverOutOfRange,
_revertUnresolvedConsiderationCriteria,
_revertUnresolvedOfferCriteria
_revertOrderCriteriaResolverOutOfRange
} from "seaport-types/src/lib/ConsiderationErrors.sol";

import { CriteriaResolutionErrors } from
Expand All @@ -37,7 +36,12 @@ import {
import {
ConsiderationCriteriaResolverOutOfRange_err_selector,
Error_selector_offset,
OfferCriteriaResolverOutOfRange_error_selector
OfferCriteriaResolverOutOfRange_error_selector,
UnresolvedConsiderationCriteria_error_length,
UnresolvedConsiderationCriteria_error_orderIndex_ptr,
UnresolvedConsiderationCriteria_error_considerationIdx_ptr,
UnresolvedConsiderationCriteria_error_selector,
UnresolvedOfferCriteria_error_selector
} from "seaport-types/src/lib/ConsiderationErrorConstants.sol";

/**
Expand Down Expand Up @@ -177,50 +181,99 @@ contract CriteriaResolution is CriteriaResolutionErrors {
OrderParameters memory orderParameters =
(advancedOrder.parameters);

// Read consideration length from memory and place on stack.
uint256 totalItems = orderParameters.consideration.length;

// Iterate over each consideration item on the order.
for (uint256 j = 0; j < totalItems; ++j) {
// Ensure item type no longer indicates criteria usage.
if (
_isItemWithCriteria(
orderParameters.consideration[j].itemType
)
) {
// Revert unless the order is a contract order and
// the identifier is 0.
if (
orderParameters.orderType != OrderType.CONTRACT ||
orderParameters.consideration[j].identifierOrCriteria != 0
) {
_revertUnresolvedConsiderationCriteria(i, j);
}
}
}
OrderType orderType = orderParameters.orderType;

_ensureAllRequiredCriteriaResolved(
i,
orderParameters.consideration,
orderType,
UnresolvedConsiderationCriteria_error_selector
);

_toOfferItemArgumentType(_ensureAllRequiredCriteriaResolved)(
i,
orderParameters.offer,
orderType,
UnresolvedOfferCriteria_error_selector
);
}
}
}

// Read offer length from memory and place on stack.
totalItems = orderParameters.offer.length;

// Iterate over each offer item on the order.
for (uint256 j = 0; j < totalItems; ++j) {
// Ensure item type no longer indicates criteria usage.
if (_isItemWithCriteria(orderParameters.offer[j].itemType))
{
// Revert unless the order is a contract order and
// the identifier is 0.
if (
orderParameters.orderType != OrderType.CONTRACT ||
orderParameters.offer[j].identifierOrCriteria != 0
) {
_revertUnresolvedOfferCriteria(i, j);
}
}
function _ensureAllRequiredCriteriaResolved(
uint256 orderIndex,
ConsiderationItem[] memory items,
OrderType orderType,
uint256 revertSelector
) internal pure {
// Read items array length from memory and place on stack.
uint256 totalItems = items.length;

// Iterate over each item on the order.
for (uint256 i = 0; i < totalItems; ++i) {
ConsiderationItem memory item = items[i];

// Revert if the item is still a criteria item unless the
// order is a contract order and the identifier is 0.
ItemType itemType = item.itemType;
uint256 identifierOrCriteria = item.identifierOrCriteria;

assembly {
if and(
gt(itemType, 3), // Criteria-based item
or(
iszero(eq(orderType, 4)), // not OrderType.CONTRACT
iszero(iszero(identifierOrCriteria)) // not wildcard
)
) {
// Store left-padded selector with push4 (reduces bytecode),
// mem[28:32] = selector
mstore(0, revertSelector)

// Store arguments.
mstore(
UnresolvedConsiderationCriteria_error_orderIndex_ptr,
orderIndex
)
mstore(
UnresolvedConsiderationCriteria_error_considerationIdx_ptr,
i
)

// revert(abi.encodeWithSignature(
// "Unresolved[Offer|Consideration]Criteria(uint256, uint256)",
// orderIndex,
// i
// ))
revert(
Error_selector_offset,
UnresolvedConsiderationCriteria_error_length
)
}
}
}
}

function _toOfferItemArgumentType(
function(
uint256,
ConsiderationItem[] memory,
OrderType,
uint256
) internal pure inFn
) internal pure returns (
function(
uint256,
OfferItem[] memory,
OrderType,
uint256
) internal pure outFn
) {
assembly {
outFn := inFn
}
}

/**
* @dev Internal pure function to update a criteria item.
*
Expand Down
2 changes: 1 addition & 1 deletion src/core/lib/Executor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ contract Executor is Verifiers, TokenTransferrer {
_revertInvalidCallToConduit(conduit);
}

// Ensure result was extracted and matches EIP-1271 magic value.
// Ensure result was extracted and matches magic value.
if (result != ConduitInterface.execute.selector) {
_revertInvalidConduit(conduitKey, conduit);
}
Expand Down
90 changes: 65 additions & 25 deletions src/core/lib/FulfillmentApplier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ import {
} from "seaport-types/src/lib/ConsiderationStructs.sol";

import {
_revertMismatchedFulfillmentOfferAndConsiderationComponents,
_revertMissingFulfillmentComponentOnAggregation,
_revertOfferAndConsiderationRequiredOnFulfillment
_revertMissingFulfillmentComponentOnAggregation
} from "seaport-types/src/lib/ConsiderationErrors.sol";

import { FulfillmentApplicationErrors } from
Expand Down Expand Up @@ -41,8 +39,13 @@ import {
Error_selector_offset,
InvalidFulfillmentComponentData_error_length,
InvalidFulfillmentComponentData_error_selector,
MismatchedOfferAndConsiderationComponents_error_idx_ptr,
MismatchedOfferAndConsiderationComponents_error_length,
MismatchedOfferAndConsiderationComponents_error_selector,
MissingItemAmount_error_length,
MissingItemAmount_error_selector,
OfferAndConsiderationRequiredOnFulfillment_error_length,
OfferAndConsiderationRequiredOnFulfillment_error_selector,
Panic_arithmetic,
Panic_error_code_ptr,
Panic_error_length,
Expand Down Expand Up @@ -82,9 +85,23 @@ contract FulfillmentApplier is FulfillmentApplicationErrors {
uint256 fulfillmentIndex
) internal pure returns (Execution memory execution) {
// Ensure 1+ of both offer and consideration components are supplied.
if (offerComponents.length == 0 || considerationComponents.length == 0)
{
_revertOfferAndConsiderationRequiredOnFulfillment();
assembly {
if or(
iszero(mload(offerComponents)),
iszero(mload(considerationComponents))
) {
// Store left-padded selector with push4 (reduces bytecode),
// mem[28:32] = selector
mstore(0, OfferAndConsiderationRequiredOnFulfillment_error_selector)

// revert(abi.encodeWithSignature(
// "OfferAndConsiderationRequiredOnFulfillment()"
// ))
revert(
Error_selector_offset,
OfferAndConsiderationRequiredOnFulfillment_error_length
)
}
}

// Declare a new Execution struct.
Expand Down Expand Up @@ -116,28 +133,51 @@ contract FulfillmentApplier is FulfillmentApplicationErrors {
advancedOrders, offerComponents, execution
);

ReceivedItem memory executionItem = execution.item;

// Ensure offer & consideration item types, tokens, & identifiers match.
// (a != b || c != d || e != f) == (((a ^ b) | (c ^ d) | (e ^ f)) != 0),
// but the second expression requires less gas to evaluate.
if (
(
(
uint8(execution.item.itemType)
^ uint8(considerationItem.itemType)
assembly {
if or(
or(
xor(
mload(executionItem), // no offset for item type
mload(considerationItem) // no offset for item type
),
xor(
mload(add(executionItem, Common_token_offset)),
mload(add(considerationItem, Common_token_offset))
)
),
xor(
mload(add(executionItem, Common_identifier_offset)),
mload(add(considerationItem, Common_identifier_offset))
)
) {
// Store left-padded selector with push4 (reduces bytecode),
// mem[28:32] = selector
mstore(0, MismatchedOfferAndConsiderationComponents_error_selector)

// Store fulfillment index argument.
mstore(
MismatchedOfferAndConsiderationComponents_error_idx_ptr,
fulfillmentIndex
)
| (
uint160(execution.item.token)
^ uint160(considerationItem.token)
) | (execution.item.identifier ^ considerationItem.identifier)
) != 0
) {
_revertMismatchedFulfillmentOfferAndConsiderationComponents(
fulfillmentIndex
);

// revert(abi.encodeWithSignature(
// "MismatchedFulfillmentOfferAndConsiderationComponents(uint256)",
// fulfillmentIndex
// ))
revert(
Error_selector_offset,
MismatchedOfferAndConsiderationComponents_error_length
)
}
}

// If total consideration amount exceeds the offer amount...
if (considerationItem.amount > execution.item.amount) {
if (considerationItem.amount > executionItem.amount) {
// Retrieve the first consideration component from the fulfillment.
FulfillmentComponent memory targetComponent =
(considerationComponents[0]);
Expand All @@ -149,7 +189,7 @@ contract FulfillmentApplier is FulfillmentApplicationErrors {
advancedOrders[targetComponent.orderIndex]
.parameters
.consideration[targetComponent.itemIndex].startAmount =
(considerationItem.amount - execution.item.amount);
(considerationItem.amount - executionItem.amount);
}
} else {
// Retrieve the first offer component from the fulfillment.
Expand All @@ -161,15 +201,15 @@ contract FulfillmentApplier is FulfillmentApplicationErrors {
// Add excess offer item amount to the original array of orders.
advancedOrders[targetComponent.orderIndex].parameters.offer[targetComponent
.itemIndex].startAmount =
(execution.item.amount - considerationItem.amount);
(executionItem.amount - considerationItem.amount);
}

// Reduce total offer amount to equal the consideration amount.
execution.item.amount = considerationItem.amount;
executionItem.amount = considerationItem.amount;
}

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

// Return the final execution that will be triggered for relevant items.
return execution; // Execution(considerationItem, offerer, conduitKey);
Expand Down
2 changes: 1 addition & 1 deletion src/core/lib/OrderCombiner.sol
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ contract OrderCombiner is OrderFulfiller, FulfillmentApplier {
// Update order status as long as there is some fraction available.
if (advancedOrder.parameters.orderType != OrderType.CONTRACT) {
if (!_checkRestrictedAdvancedOrderAuthorization(
advancedOrder, orderHashes, orderHash, (i / OneWord) - 1, revertOnInvalid
advancedOrder, orderHashes, orderHash, (i >> OneWordShift) - 1, revertOnInvalid
)) {
assembly {
mstore(add(orderHashes, i), 0)
Expand Down
Loading

0 comments on commit d065e19

Please sign in to comment.