// orderType > 1,则交易需要在严格模式下执行。 // 严格模式下,如果交易发起者不是 zone 或者 offerer,则需要在 zone 合约中完成基于 EIP 1271 的授权的校验 if ( uint256(orderType) > 1 && msg.sender != zone && msg.sender != offerer ) { // If no extraData or criteria resolvers are supplied... if ( advancedOrder.extraData.length == 0 && criteriaResolvers.length == 0 ) { // Perform minimal staticcall to the zone. _callIsValidOrder(zone, orderHash, offerer, zoneHash); } else { // Otherwise, extra data or criteria resolvers were supplied; in // that event, perform a more verbose staticcall to the zone. // bool success = _staticcall( zone, abi.encodeWithSelector( ZoneInterface.isValidOrderIncludingExtraData.selector, orderHash, msg.sender, advancedOrder, priorOrderHashes, criteriaResolvers ) );
// Ensure call was successful and returned correct magic value. _assertIsValidOrderStaticcallSuccess(success, orderHash); } }
function_verifySignature( address offerer, bytes32 orderHash, bytes memory signature ) internal view { // Skip signature verification if the offerer is the caller. if (offerer == msg.sender) { return; }
// Derive EIP-712 digest using the domain separator and the order hash. bytes32 digest = _deriveEIP712Digest(_domainSeparator(), orderHash);
// Ensure that the signature for the digest is valid for the offerer. _assertValidSignature(offerer, digest, signature); }
function_deriveEIP712Digest(bytes32 domainSeparator, bytes32 orderHash) internal pure returns (bytes32 value) { // Leverage scratch space to perform an efficient hash. assembly { // Place the EIP-712 prefix at the start of scratch space. mstore(0, EIP_712_PREFIX)
// Place the domain separator in the next region of scratch space. mstore(EIP712_DomainSeparator_offset, domainSeparator)
// Place the order hash in scratch space, spilling into the first // two bytes of the free memory pointer — this should never be set // as memory cannot be expanded to that size, and will be zeroed out // after the hash is performed. mstore(EIP712_OrderHash_offset, orderHash)
// Hash the relevant region (65 bytes). value := keccak256(0, EIP712_DigestPayload_size)
// Clear out the dirtied bits in the memory pointer. mstore(EIP712_OrderHash_offset, 0) } }
// CriteriaResolution.sol function_applyCriteriaResolvers( AdvancedOrder[] memory advancedOrders, CriteriaResolver[] memory criteriaResolvers ) internal pure { // Skip overflow checks as all for loops are indexed starting at zero. unchecked { // Retrieve length of criteria resolvers array and place on stack. uint256 totalCriteriaResolvers = criteriaResolvers.length;
// Retrieve length of orders array and place on stack. uint256 totalAdvancedOrders = advancedOrders.length;
// Iterate over each criteria resolver. // 遍历 resolvers for (uint256 i = 0; i < totalCriteriaResolvers; ++i) { // 从 resolvers 中取出 resolver CriteriaResolver memory criteriaResolver = ( criteriaResolvers[i] );
// 找到 resolver 所要处理的 order 所对应的 index uint256 orderIndex = criteriaResolver.orderIndex; // 最基本的,需要确保 resolver 所对应的 order 应在 orders 中 if (orderIndex >= totalAdvancedOrders) { revert OrderCriteriaResolverOutOfRange(); }
// Skip criteria resolution for order if not fulfilled. // 如果其所对应的分子为 0,则不需要再做判断。 // 所以,分子和 criteria resolver 之间存在什么关系呢?? maybe 答案不在这里... if (advancedOrders[orderIndex].numerator == 0) { continue; }
// Retrieve the parameters for the order. OrderParameters memory orderParameters = ( advancedOrders[orderIndex].parameters );
// 具体是对应这 offer 中的那个 item 的索引 index uint256 componentIndex = criteriaResolver.index; // Declare values for item's type and criteria. ItemType itemType; uint256 identifierOrCriteria;
// 所对应的 orderItem 来自于 offer if (criteriaResolver.side == Side.OFFER) { // 取出 order 中的 offer OfferItem[] memory offer = orderParameters.offer; // 至少应确保 resolver 所对应的 offer item index 应在 offer 中 if (componentIndex >= offer.length) { revert OfferCriteriaResolverOutOfRange(); }
// Ensure that the component index is in range. if (componentIndex >= consideration.length) { revert ConsiderationCriteriaResolverOutOfRange(); }
// Retrieve relevant item using order and component index. ConsiderationItem memory considerationItem = ( consideration[componentIndex] );
// Read item type and criteria from memory & place on stack. itemType = considerationItem.itemType; identifierOrCriteria = ( considerationItem.identifierOrCriteria );
// Optimistically update item type to remove criteria usage. // Use assembly to operate on ItemType enum as a number. ItemType newItemType; assembly { // Item type 4 becomes 2 and item type 5 becomes 3. newItemType := sub(3, eq(itemType, 4)) } considerationItem.itemType = newItemType;
// 遍历一遍 orders,所有 order 这时都不再是 criteria 的 for (uint256 i = 0; i < totalAdvancedOrders; ++i) { // Retrieve the advanced order. AdvancedOrder memory advancedOrder = advancedOrders[i];
// Skip criteria resolution for order if not fulfilled. if (advancedOrder.numerator == 0) { continue; }
// Retrieve the parameters for the order. 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 UnresolvedConsiderationCriteria(); } }
// 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 UnresolvedOfferCriteria(); } } } } }
// https://github.com/ProjectOpenSea/seaport/blob/171f2cd7faf13b2bf0455851499f1981274977f7/contracts/lib/Executor.sol#L49 function_transfer( ReceivedItem memory item, address from, bytes32 conduitKey, bytes memory accumulator ) internal { // If the item type indicates Ether or a native token... if (item.itemType == ItemType.NATIVE) { // Ensure neither the token nor the identifier parameters are set. if ((uint160(item.token) | item.identifier) != 0) { revert UnusedItemParameters(); }
// transfer the native tokens to the recipient. _transferEth(item.recipient, item.amount); } elseif (item.itemType == ItemType.ERC20) { // Ensure that no identifier is supplied. if (item.identifier != 0) { revert UnusedItemParameters(); }
// Transfer ERC20 tokens from the source to the recipient. _transferERC20( item.token, from, item.recipient, item.amount, conduitKey, accumulator ); } elseif (item.itemType == ItemType.ERC721) { // Transfer ERC721 token from the source to the recipient. _transferERC721( item.token, from, item.recipient, item.identifier, item.amount, conduitKey, accumulator ); } else { // Transfer ERC1155 token from the source to the recipient. _transferERC1155( item.token, from, item.recipient, item.identifier, item.amount, conduitKey, accumulator ); } }