Skip to content

Commit

Permalink
Merge pull request #14 from ProjectOpenSea/authorize-order-call
Browse files Browse the repository at this point in the history
encode + call authorizeOrder, reuse encoding for validateOrder
  • Loading branch information
0age authored Feb 10, 2024
2 parents bcdfddf + 33a9915 commit 01e3d0d
Show file tree
Hide file tree
Showing 9 changed files with 335 additions and 110 deletions.
79 changes: 43 additions & 36 deletions src/core/lib/BasicOrderFulfiller.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
OrderType
} from "seaport-types/src/lib/ConsiderationEnums.sol";

import { BasicOrderParameters } from
import { BasicOrderParameters, OrderStatus } from
"seaport-types/src/lib/ConsiderationStructs.sol";

import { OrderValidator } from "./OrderValidator.sol";
Expand Down Expand Up @@ -57,6 +57,7 @@ import {
BasicOrder_order_startTime_ptr,
BasicOrder_order_typeHash_ptr,
BasicOrder_receivedItemByteMap,
BasicOrder_signature_cdPtr,
BasicOrder_startTime_cdPtr,
BasicOrder_totalOriginalAdditionalRecipients_cdPtr,
BasicOrder_zone_cdPtr,
Expand Down Expand Up @@ -114,6 +115,10 @@ import {
UnusedItemParameters_error_selector
} from "seaport-types/src/lib/ConsiderationErrorConstants.sol";

import {
CalldataPointer
} from "seaport-types/src/helpers/PointerLibraries.sol";

/**
* @title BasicOrderFulfiller
* @author 0age
Expand Down Expand Up @@ -147,19 +152,9 @@ contract BasicOrderFulfiller is OrderValidator {
* Refer to the documentation for a more comprehensive summary of how
* to utilize this method and what orders are compatible with it.
*
* @param parameters Additional information on the fulfilled order. Note
* that the offerer and the fulfiller must first approve
* this contract (or their chosen conduit if indicated)
* before any tokens can be transferred. Also note that
* contract recipients of ERC1155 consideration items must
* implement `onERC1155Received` in order to receive those
* items.
*
* @return A boolean indicating whether the order has been fulfilled.
*/
function _validateAndFulfillBasicOrder(
BasicOrderParameters calldata parameters
) internal returns (bool) {
function _validateAndFulfillBasicOrder() internal returns (bool) {
// Declare enums for order type & route to extract from basicOrderType.
BasicOrderRouteType route;
OrderType orderType;
Expand Down Expand Up @@ -207,6 +202,7 @@ contract BasicOrderFulfiller is OrderValidator {
address additionalRecipientsToken;
ItemType offeredItemType;
bool offerTypeIsAdditionalRecipientsType;
uint256 callDataPointer;

// Declare scope for received item type to manage stack pressure.
{
Expand Down Expand Up @@ -240,8 +236,7 @@ contract BasicOrderFulfiller is OrderValidator {
}

// Derive & validate order using parameters and update order status.
orderHash = _prepareBasicFulfillmentFromCalldata(
parameters,
(orderHash, callDataPointer) = _prepareBasicFulfillmentFromCalldata(
orderType,
receivedItemType,
additionalRecipientsItemType,
Expand Down Expand Up @@ -303,33 +298,33 @@ contract BasicOrderFulfiller is OrderValidator {
if (route == BasicOrderRouteType.ERC20_TO_ERC721) {
// Transfer ERC721 to caller using offerer's conduit preference.
_transferERC721(
parameters.offerToken,
parameters.offerer,
CalldataPointer.wrap(BasicOrder_offerToken_cdPtr).readAddress(),
CalldataPointer.wrap(BasicOrder_offerer_cdPtr).readAddress(),
msg.sender,
parameters.offerIdentifier,
parameters.offerAmount,
CalldataPointer.wrap(BasicOrder_offerIdentifier_cdPtr).readUint256(),
CalldataPointer.wrap(BasicOrder_offerAmount_cdPtr).readUint256(),
conduitKey,
accumulator
);
} else if (route == BasicOrderRouteType.ERC20_TO_ERC1155) {
// Transfer ERC1155 to caller with offerer's conduit preference.
_transferERC1155(
parameters.offerToken,
parameters.offerer,
CalldataPointer.wrap(BasicOrder_offerToken_cdPtr).readAddress(),
CalldataPointer.wrap(BasicOrder_offerer_cdPtr).readAddress(),
msg.sender,
parameters.offerIdentifier,
parameters.offerAmount,
CalldataPointer.wrap(BasicOrder_offerIdentifier_cdPtr).readUint256(),
CalldataPointer.wrap(BasicOrder_offerAmount_cdPtr).readUint256(),
conduitKey,
accumulator
);
} else if (route == BasicOrderRouteType.ERC721_TO_ERC20) {
// Transfer ERC721 to offerer using caller's conduit preference.
_transferERC721(
parameters.considerationToken,
CalldataPointer.wrap(BasicOrder_considerationToken_cdPtr).readAddress(),
msg.sender,
parameters.offerer,
parameters.considerationIdentifier,
parameters.considerationAmount,
CalldataPointer.wrap(BasicOrder_offerer_cdPtr).readAddress(),
CalldataPointer.wrap(BasicOrder_considerationIdentifier_cdPtr).readUint256(),
CalldataPointer.wrap(BasicOrder_considerationAmount_cdPtr).readUint256(),
conduitKey,
accumulator
);
Expand All @@ -338,11 +333,11 @@ contract BasicOrderFulfiller is OrderValidator {

// Transfer ERC1155 to offerer with caller's conduit preference.
_transferERC1155(
parameters.considerationToken,
CalldataPointer.wrap(BasicOrder_considerationToken_cdPtr).readAddress(),
msg.sender,
parameters.offerer,
parameters.considerationIdentifier,
parameters.considerationAmount,
CalldataPointer.wrap(BasicOrder_offerer_cdPtr).readAddress(),
CalldataPointer.wrap(BasicOrder_considerationIdentifier_cdPtr).readUint256(),
CalldataPointer.wrap(BasicOrder_considerationAmount_cdPtr).readUint256(),
conduitKey,
accumulator
);
Expand All @@ -358,7 +353,7 @@ contract BasicOrderFulfiller is OrderValidator {
}

// Determine whether order is restricted and, if so, that it is valid.
_assertRestrictedBasicOrderValidity(orderHash, orderType, parameters);
_assertRestrictedBasicOrderValidity(orderHash, orderType, callDataPointer);

// Clear the reentrancy guard.
_clearReentrancyGuard();
Expand All @@ -379,7 +374,6 @@ contract BasicOrderFulfiller is OrderValidator {
* same data as the order hash is derived from. Also note that this
* function accesses memory directly.
*
* @param parameters The parameters of the basic order.
* @param orderType The order type.
* @param receivedItemType The item type of the initial
* consideration item on the order.
Expand All @@ -393,13 +387,12 @@ contract BasicOrderFulfiller is OrderValidator {
* @return orderHash The calculated order hash.
*/
function _prepareBasicFulfillmentFromCalldata(
BasicOrderParameters calldata parameters,
OrderType orderType,
ItemType receivedItemType,
ItemType additionalRecipientsItemType,
address additionalRecipientsToken,
ItemType offeredItemType
) internal returns (bytes32 orderHash) {
) internal returns (bytes32 orderHash, uint256 callDataPointer) {
// Ensure this function cannot be triggered during a reentrant call.
_setReentrancyGuard(false); // Native tokens rejected during execution.

Expand Down Expand Up @@ -1026,10 +1019,24 @@ contract BasicOrderFulfiller is OrderValidator {
}

// Verify and update the status of the derived order.
_validateBasicOrderAndUpdateStatus(orderHash, parameters.signature);
OrderStatus storage orderStatus = _validateBasicOrder(
orderHash,
_toBytesReturnType(_decodeBytes)(
CalldataPointer.wrap(
CalldataPointer.wrap(BasicOrder_signature_cdPtr)
.readMaskedUint256() + 0x24
)
)
);

// Determine whether order is restricted and, if so, that it is valid.
callDataPointer = _assertRestrictedBasicOrderAuthorization(orderHash, orderType);

// Update the status of the order and mark as fully filled.
_updateBasicOrderStatus(orderStatus);

// Return the derived order hash.
return orderHash;
return (orderHash, callDataPointer);
}

/**
Expand Down
20 changes: 14 additions & 6 deletions src/core/lib/Consideration.sol
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ contract Consideration is ConsiderationInterface, OrderCombiner {
* to the documentation for a more comprehensive summary of how to
* utilize this method and what orders are compatible with it.
*
* @param parameters Additional information on the fulfilled order. Note
* @custom:param parameters Additional information on the fulfilled order. Note
* that the offerer and the fulfiller must first approve
* this contract (or their chosen conduit if indicated)
* before any tokens can be transferred. Also note that
Expand All @@ -97,14 +97,19 @@ contract Consideration is ConsiderationInterface, OrderCombiner {
* @return fulfilled A boolean indicating whether the order has been
* successfully fulfilled.
*/
function fulfillBasicOrder(BasicOrderParameters calldata parameters)
function fulfillBasicOrder(
/**
* @custom:name parameters
*/
BasicOrderParameters calldata
)
external
payable
override
returns (bool fulfilled)
{
// Validate and fulfill the basic order.
fulfilled = _validateAndFulfillBasicOrder(parameters);
fulfilled = _validateAndFulfillBasicOrder();
}

/**
Expand All @@ -125,7 +130,7 @@ contract Consideration is ConsiderationInterface, OrderCombiner {
* the zero bytes in the function selector (0x00000000) which also
* results in earlier function dispatch.
*
* @param parameters Additional information on the fulfilled order. Note
* @custom:param parameters Additional information on the fulfilled order. Note
* that the offerer and the fulfiller must first approve
* this contract (or their chosen conduit if indicated)
* before any tokens can be transferred. Also note that
Expand All @@ -136,10 +141,13 @@ contract Consideration is ConsiderationInterface, OrderCombiner {
* successfully fulfilled.
*/
function fulfillBasicOrder_efficient_6GL6yc(
BasicOrderParameters calldata parameters
/**
* @custom:name parameters
*/
BasicOrderParameters calldata
) external payable override returns (bool fulfilled) {
// Validate and fulfill the basic order.
fulfilled = _validateAndFulfillBasicOrder(parameters);
fulfilled = _validateAndFulfillBasicOrder();
}

/**
Expand Down
26 changes: 26 additions & 0 deletions src/core/lib/ConsiderationDecoder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1131,6 +1131,32 @@ contract ConsiderationDecoder {
}
}

/**
* @dev Converts a function taking a calldata pointer and returning a memory
* pointer into a function taking that calldata pointer and returning
* a bytes type.
*
* @param inFn The input function, taking an arbitrary calldata pointer and
* returning an arbitrary memory pointer.
*
* @return outFn The output function, taking an arbitrary calldata pointer
* and returning a bytes type.
*/
function _toBytesReturnType(
function(CalldataPointer) internal pure returns (MemoryPointer) inFn
)
internal
pure
returns (
function(CalldataPointer) internal pure returns (bytes memory)
outFn
)
{
assembly {
outFn := inFn
}
}

/**
* @dev Converts a function taking a calldata pointer and returning a memory
* pointer into a function taking that calldata pointer and returning
Expand Down
Loading

0 comments on commit 01e3d0d

Please sign in to comment.