From 0034f14ef727ff23e4cb52bb4756bb333b17ba2c Mon Sep 17 00:00:00 2001 From: djviau Date: Tue, 12 Sep 2023 14:35:11 -0400 Subject: [PATCH 1/8] initial navigator import hygiene pass --- .../helpers/navigator/SeaportNavigator.sol | 14 ++- .../helpers/navigator/lib/CriteriaHelper.sol | 4 - .../lib/NavigatorAdvancedOrderLib.sol | 22 ++++- .../navigator/lib/NavigatorContextLib.sol | 22 ++--- .../navigator/lib/NavigatorDetailsLib.sol | 4 + .../navigator/lib/NavigatorExecutionsLib.sol | 13 +-- .../lib/NavigatorRequestValidatorLib.sol | 1 + .../lib/NavigatorSeaportValidatorLib.sol | 3 +- .../lib/NavigatorSuggestedActionLib.sol | 88 ++++++++++++++++--- .../navigator/lib/OrderStructureLib.sol | 47 +++++----- .../navigator/lib/RequestValidator.sol | 5 +- .../lib/SeaportNavigatorInterface.sol | 5 -- .../navigator/lib/SeaportNavigatorTypes.sol | 23 ++--- .../helpers/navigator/lib/ValidatorHelper.sol | 6 -- .../lib/ReadOnlyOrderValidator.sol | 36 ++++---- script/CallNavigator.s.sol | 11 ++- script/NavigatorDeployer.s.sol | 55 +++++++----- test/foundry/new/SeaportNavigator.t.sol | 43 ++++----- test/foundry/new/SeaportNavigatorTest.sol | 39 ++++---- test/foundry/new/SeaportValidatorTest.sol | 10 +-- 20 files changed, 246 insertions(+), 205 deletions(-) diff --git a/contracts/helpers/navigator/SeaportNavigator.sol b/contracts/helpers/navigator/SeaportNavigator.sol index 9997b33a3..c8aae71e9 100644 --- a/contracts/helpers/navigator/SeaportNavigator.sol +++ b/contracts/helpers/navigator/SeaportNavigator.sol @@ -4,10 +4,6 @@ pragma solidity ^0.8.17; import { ConsiderationInterface } from "seaport-types/src/interfaces/ConsiderationInterface.sol"; -import { - AdvancedOrder, - CriteriaResolver -} from "seaport-types/src/lib/ConsiderationStructs.sol"; import { SeaportValidatorInterface @@ -37,16 +33,16 @@ import { HelperInterface } from "./lib/HelperInterface.sol"; * and optionally generate criteria resolvers from provided token IDs. */ contract SeaportNavigator is SeaportNavigatorInterface { - using NavigatorContextLib for NavigatorContext; using CriteriaHelperLib for uint256[]; + using NavigatorContextLib for NavigatorContext; - HelperInterface public immutable requestValidator; HelperInterface public immutable criteriaHelper; - HelperInterface public immutable validatorHelper; - HelperInterface public immutable orderDetailsHelper; + HelperInterface public immutable executionsHelper; HelperInterface public immutable fulfillmentsHelper; + HelperInterface public immutable orderDetailsHelper; + HelperInterface public immutable requestValidator; HelperInterface public immutable suggestedActionHelper; - HelperInterface public immutable executionsHelper; + HelperInterface public immutable validatorHelper; HelperInterface[] public helpers; diff --git a/contracts/helpers/navigator/lib/CriteriaHelper.sol b/contracts/helpers/navigator/lib/CriteriaHelper.sol index d132a6748..8cc64945a 100644 --- a/contracts/helpers/navigator/lib/CriteriaHelper.sol +++ b/contracts/helpers/navigator/lib/CriteriaHelper.sol @@ -1,10 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import { - CriteriaResolver -} from "seaport-types/src/lib/ConsiderationStructs.sol"; - import { NavigatorCriteriaResolverLib } from "./NavigatorCriteriaResolverLib.sol"; diff --git a/contracts/helpers/navigator/lib/NavigatorAdvancedOrderLib.sol b/contracts/helpers/navigator/lib/NavigatorAdvancedOrderLib.sol index 2f99fc17b..0a3b33949 100644 --- a/contracts/helpers/navigator/lib/NavigatorAdvancedOrderLib.sol +++ b/contracts/helpers/navigator/lib/NavigatorAdvancedOrderLib.sol @@ -12,18 +12,20 @@ import { import { Side } from "seaport-types/src/lib/ConsiderationEnums.sol"; import { CriteriaHelperLib } from "./CriteriaHelperLib.sol"; + import { HelperItemLib } from "./HelperItemLib.sol"; + import { NavigatorAdvancedOrder, - NavigatorOrderParameters, + NavigatorConsiderationItem, NavigatorOfferItem, - NavigatorConsiderationItem + NavigatorOrderParameters } from "./SeaportNavigatorTypes.sol"; library NavigatorAdvancedOrderLib { using CriteriaHelperLib for uint256[]; - using HelperItemLib for NavigatorOfferItem; using HelperItemLib for NavigatorConsiderationItem; + using HelperItemLib for NavigatorOfferItem; function fromAdvancedOrders( AdvancedOrder[] memory orders @@ -178,9 +180,16 @@ library NavigatorAdvancedOrderLib { }); } } + + // This just encodes the length of the array that we gradually built up + // above. It's just a way of creating an array of arbitrary length. It's + // initialized to its longest possible length at the top, then populated + // partially or fully in the for loop above. Finally, the length is set + // here surgically. assembly { mstore(criteriaResolvers, criteriaResolverLen) } + return ( AdvancedOrder({ parameters: OrderParameters({ @@ -238,9 +247,16 @@ library NavigatorAdvancedOrderLib { criteriaResolverIndex++; } } + + // This just encodes the length of the array that we gradually built up + // above. It's just a way of creating an array of arbitrary length. It's + // initialized to its longest possible length at the top, then populated + // partially or fully in the for loop above. Finally, the length is set + // here surgically. assembly { mstore(criteriaResolvers, criteriaResolverIndex) } + return (advancedOrders, criteriaResolvers); } } diff --git a/contracts/helpers/navigator/lib/NavigatorContextLib.sol b/contracts/helpers/navigator/lib/NavigatorContextLib.sol index a00ea9f0b..91742d19c 100644 --- a/contracts/helpers/navigator/lib/NavigatorContextLib.sol +++ b/contracts/helpers/navigator/lib/NavigatorContextLib.sol @@ -1,37 +1,27 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import { - ConsiderationInterface -} from "seaport-types/src/interfaces/ConsiderationInterface.sol"; - import { MatchComponent } from "seaport-sol/src/lib/types/MatchComponentType.sol"; + import { OrderDetails } from "seaport-sol/src/fulfillments/lib/Structs.sol"; import { AdvancedOrder, + CriteriaResolver, Execution, Fulfillment, - FulfillmentComponent, - CriteriaResolver + FulfillmentComponent } from "seaport-types/src/lib/ConsiderationStructs.sol"; import { - NavigatorRequest, - NavigatorResponse, NavigatorContext, - NavigatorOfferItem, - NavigatorConsiderationItem, - NavigatorOrderParameters, - NavigatorAdvancedOrder + NavigatorRequest, + NavigatorResponse } from "./SeaportNavigatorTypes.sol"; -import { - SeaportValidatorInterface, - ErrorsAndWarnings -} from "../../order-validator/SeaportValidator.sol"; +import { ErrorsAndWarnings } from "../../order-validator/SeaportValidator.sol"; library NavigatorContextLib { function from( diff --git a/contracts/helpers/navigator/lib/NavigatorDetailsLib.sol b/contracts/helpers/navigator/lib/NavigatorDetailsLib.sol index 3047208c9..9d05155d1 100644 --- a/contracts/helpers/navigator/lib/NavigatorDetailsLib.sol +++ b/contracts/helpers/navigator/lib/NavigatorDetailsLib.sol @@ -2,9 +2,13 @@ pragma solidity ^0.8.17; import { UnavailableReason } from "seaport-sol/src/SpaceEnums.sol"; + import { AdvancedOrder } from "seaport-types/src/lib/ConsiderationStructs.sol"; + import { AdvancedOrderLib } from "seaport-sol/src/lib/AdvancedOrderLib.sol"; + import { NavigatorContext } from "./SeaportNavigatorTypes.sol"; + import { OrderAvailabilityLib } from "./OrderAvailabilityLib.sol"; library NavigatorDetailsLib { diff --git a/contracts/helpers/navigator/lib/NavigatorExecutionsLib.sol b/contracts/helpers/navigator/lib/NavigatorExecutionsLib.sol index 5941f0829..8884b1c9c 100644 --- a/contracts/helpers/navigator/lib/NavigatorExecutionsLib.sol +++ b/contracts/helpers/navigator/lib/NavigatorExecutionsLib.sol @@ -5,14 +5,7 @@ import { ConsiderationInterface } from "seaport-types/src/interfaces/ConsiderationInterface.sol"; -import { - AdvancedOrder, - Execution, - SpentItem, - ReceivedItem -} from "seaport-types/src/lib/ConsiderationStructs.sol"; - -import { ItemType } from "seaport-types/src/lib/ConsiderationEnums.sol"; +import { Execution } from "seaport-types/src/lib/ConsiderationStructs.sol"; import { FulfillmentDetails @@ -22,10 +15,6 @@ import { ExecutionHelper } from "seaport-sol/src/executions/ExecutionHelper.sol"; -import { UnavailableReason } from "seaport-sol/src/SpaceEnums.sol"; - -import { OrderDetails } from "seaport-sol/src/fulfillments/lib/Structs.sol"; - import { NavigatorContext } from "./SeaportNavigatorTypes.sol"; library NavigatorExecutionsLib { diff --git a/contracts/helpers/navigator/lib/NavigatorRequestValidatorLib.sol b/contracts/helpers/navigator/lib/NavigatorRequestValidatorLib.sol index 77922d9e9..60b192029 100644 --- a/contracts/helpers/navigator/lib/NavigatorRequestValidatorLib.sol +++ b/contracts/helpers/navigator/lib/NavigatorRequestValidatorLib.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.17; import { AdvancedOrder } from "seaport-types/src/lib/ConsiderationStructs.sol"; import { Type, OrderStructureLib } from "./OrderStructureLib.sol"; + import { NavigatorContext } from "./SeaportNavigatorTypes.sol"; library NavigatorRequestValidatorLib { diff --git a/contracts/helpers/navigator/lib/NavigatorSeaportValidatorLib.sol b/contracts/helpers/navigator/lib/NavigatorSeaportValidatorLib.sol index 5bbe77795..bb8b47597 100644 --- a/contracts/helpers/navigator/lib/NavigatorSeaportValidatorLib.sol +++ b/contracts/helpers/navigator/lib/NavigatorSeaportValidatorLib.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.17; import { AdvancedOrder } from "seaport-types/src/lib/ConsiderationStructs.sol"; + import { AdvancedOrderLib } from "seaport-sol/src/lib/AdvancedOrderLib.sol"; import { ErrorsAndWarnings } from "../../order-validator/SeaportValidator.sol"; @@ -11,8 +12,6 @@ import { NavigatorContext } from "./SeaportNavigatorTypes.sol"; library NavigatorSeaportValidatorLib { using AdvancedOrderLib for AdvancedOrder; - error ValidatorReverted(); - /** * @dev Validate each order using SeaportValidator and add the results to * the NavigatorResponse. diff --git a/contracts/helpers/navigator/lib/NavigatorSuggestedActionLib.sol b/contracts/helpers/navigator/lib/NavigatorSuggestedActionLib.sol index cd30c3440..4f11b4fc1 100644 --- a/contracts/helpers/navigator/lib/NavigatorSuggestedActionLib.sol +++ b/contracts/helpers/navigator/lib/NavigatorSuggestedActionLib.sol @@ -7,9 +7,8 @@ import { import { AdvancedOrder, - Execution, - SpentItem, - ReceivedItem + ReceivedItem, + SpentItem } from "seaport-types/src/lib/ConsiderationStructs.sol"; import { ItemType } from "seaport-types/src/lib/ConsiderationEnums.sol"; @@ -20,15 +19,15 @@ import { OrderDetails } from "seaport-sol/src/fulfillments/lib/Structs.sol"; import { AdvancedOrderLib } from "seaport-sol/src/lib/AdvancedOrderLib.sol"; -import { Family, Structure, OrderStructureLib } from "./OrderStructureLib.sol"; +import { Family, OrderStructureLib, Structure } from "./OrderStructureLib.sol"; import { NavigatorContext } from "./SeaportNavigatorTypes.sol"; library NavigatorSuggestedActionLib { - using OrderStructureLib for AdvancedOrder; - using OrderStructureLib for AdvancedOrder[]; using AdvancedOrderLib for AdvancedOrder; using AdvancedOrderLib for AdvancedOrder[]; + using OrderStructureLib for AdvancedOrder; + using OrderStructureLib for AdvancedOrder[]; /** * @dev Bad request error: provided orders cannot be fulfilled. @@ -84,16 +83,38 @@ library NavigatorSuggestedActionLib { function suggestedCallData( NavigatorContext memory context ) internal view returns (bytes memory) { + // Get the family of the orders (single or combined). Family family = context.response.orders.getFamily(); + // `mustUseMatch` returns true if the orders require the use of one of + // the match* methods. + // + //TODO: why is this a proxy for an invalid offer + // item? bool invalidOfferItemsLocated = mustUseMatch(context); + // Get the structure of the orders (basic, standard, or advanced). Structure structure = context.response.orders.getStructure( address(context.request.seaport) ); + // TODO: figure out why this is the formula for determining if there are + // unavailable orders. bool hasUnavailable = context.request.maximumFulfilled < context.response.orders.length; + + // The match* methods are only an option if everything is going to find + // a partner (the first half of the if statement below) and if there are + // no unavailable orders (the second half of the if statement below). + bool cannotMatch = (context + .response + .unmetConsiderationComponents + .length != + 0 || + hasUnavailable); + + // Iterate through the orders and check if any of the orders has an + // unavailable reason. for (uint256 i = 0; i < context.response.orderDetails.length; ++i) { if ( context.response.orderDetails[i].unavailableReason != @@ -104,11 +125,16 @@ library NavigatorSuggestedActionLib { } } + // If there are unavailable orders, follow this branch. if (hasUnavailable) { + // If there are unavailable orders and the orders could only be + // fulfilled using match*, it's a no-go. if (invalidOfferItemsLocated) { revert InvalidNativeTokenUnavailableCombination(); } + // If there are unavailable orders and the orders are advanced, use + // fulfillAvailableAdvancedOrders. if (structure == Structure.ADVANCED) { return abi.encodeCall( @@ -124,6 +150,8 @@ library NavigatorSuggestedActionLib { ) ); } else { + // If there are unavailable orders and the orders are not + // advanced, use fulfillAvailableOrders. return abi.encodeCall( ConsiderationInterface.fulfillAvailableOrders, @@ -138,7 +166,13 @@ library NavigatorSuggestedActionLib { } } + // If there are no unavailable orders, follow this branch. + + // If the order family is single (just one being fulfilled) and it + // doesn't require using match*, use the appropriate fulfill* method. if (family == Family.SINGLE && !invalidOfferItemsLocated) { + // If the order structure is basic, use + // fulfillBasicOrder_efficient_6GL6yc for maximum gas efficiency. if (structure == Structure.BASIC) { AdvancedOrder memory order = context.response.orders[0]; return @@ -153,6 +187,7 @@ library NavigatorSuggestedActionLib { ); } + // If the order structure is standard, use fulfillOrder. if (structure == Structure.STANDARD) { return abi.encodeCall( @@ -164,6 +199,7 @@ library NavigatorSuggestedActionLib { ); } + // If the order structure is advanced, use fulfillAdvancedOrder. if (structure == Structure.ADVANCED) { return abi.encodeCall( @@ -178,17 +214,14 @@ library NavigatorSuggestedActionLib { } } - bool cannotMatch = (context - .response - .unmetConsiderationComponents - .length != - 0 || - hasUnavailable); - + // This is like saying "if it's not possible to use match* but it's + // mandatory to use match*, revert." if (cannotMatch && invalidOfferItemsLocated) { revert CannotFulfillProvidedCombinedOrder(); } + // If it's not mandatory to use match* and it's not possible to use + // match*, use fulfillAvailable*. if (cannotMatch) { if (structure == Structure.ADVANCED) { return @@ -218,6 +251,8 @@ library NavigatorSuggestedActionLib { ); } } else if (invalidOfferItemsLocated) { + // Even if match* is an option, if there are invalid offer items and + // the structure is advanced use fulfillAvailable*. if (structure == Structure.ADVANCED) { return abi.encodeCall( @@ -233,6 +268,7 @@ library NavigatorSuggestedActionLib { ) ); } else { + // TODO: document. return abi.encodeCall( ConsiderationInterface.matchOrders, @@ -243,6 +279,11 @@ library NavigatorSuggestedActionLib { ); } } else { + // If match* is an option and there are no invalid offer items, + // follow this branch. + // + // If the structure is advanced, use matchAdvancedOrders or use + // fulfillAvailableAdvancedOrders depending on the caller's request. if (structure == Structure.ADVANCED) { if (context.request.preferMatch) { return @@ -272,6 +313,8 @@ library NavigatorSuggestedActionLib { ); } } else { + // If the structure is not advanced, use matchOrders or + // fulfillAvailableOrders depending on the caller's request. if (context.request.preferMatch) { return abi.encodeCall( @@ -307,6 +350,8 @@ library NavigatorSuggestedActionLib { ) internal pure returns (bool) { OrderDetails[] memory orders = context.response.orderDetails; + // Iterate through the orders and check if any of the non-contract + // orders has a native token in the offer. for (uint256 i = 0; i < orders.length; ++i) { OrderDetails memory order = orders[i]; @@ -314,6 +359,7 @@ library NavigatorSuggestedActionLib { continue; } + // If the order has a native token in the offer, use match. for (uint256 j = 0; j < order.offer.length; ++j) { if (order.offer[j].itemType == ItemType.NATIVE) { return true; @@ -321,30 +367,46 @@ library NavigatorSuggestedActionLib { } } + // If the caller is the recipient, it's never necessary to use match. if (context.request.caller == context.request.recipient) { return false; } + // This basically checks if there's an ERC721 in the offer of one order + // that is also in the consideration of another order. If yes, use + // match. for (uint256 i = 0; i < orders.length; ++i) { + // Get the order. OrderDetails memory order = orders[i]; + // Iterate over the offer items. for (uint256 j = 0; j < order.offer.length; ++j) { + // Get the item. SpentItem memory item = order.offer[j]; + // If the item is not an ERC721, skip it. if (item.itemType != ItemType.ERC721) { continue; } + // Iterate over the orders again. for (uint256 k = 0; k < orders.length; ++k) { + // Get an order to compare against. OrderDetails memory comparisonOrder = orders[k]; + + // Iterate over the consideration items. for ( uint256 l = 0; l < comparisonOrder.consideration.length; ++l ) { + // Get the consideration item. ReceivedItem memory considerationItem = comparisonOrder .consideration[l]; + // If the consideration item is an ERC721, and the ID is + // the same as the offer item, and the token address is + // the same as the offer item, use match. if ( considerationItem.itemType == ItemType.ERC721 && considerationItem.identifier == item.identifier && diff --git a/contracts/helpers/navigator/lib/OrderStructureLib.sol b/contracts/helpers/navigator/lib/OrderStructureLib.sol index 736bcd9db..d176f0060 100644 --- a/contracts/helpers/navigator/lib/OrderStructureLib.sol +++ b/contracts/helpers/navigator/lib/OrderStructureLib.sol @@ -4,8 +4,6 @@ pragma solidity ^0.8.17; import { AdvancedOrderLib, ConsiderationItemLib, - MatchComponent, - MatchComponentType, OfferItemLib, OrderComponentsLib, OrderLib, @@ -14,25 +12,18 @@ import { import { AdvancedOrder, - CriteriaResolver, - Execution, - Order, - OrderComponents, - OrderParameters, ConsiderationItem, OfferItem, - ReceivedItem, - SpentItem, - Fulfillment, - FulfillmentComponent + Order, + OrderComponents, + OrderParameters } from "seaport-types/src/lib/ConsiderationStructs.sol"; import { BasicOrderRouteType, BasicOrderType, ItemType, - OrderType, - Side + OrderType } from "seaport-types/src/lib/ConsiderationEnums.sol"; import { @@ -101,13 +92,13 @@ enum State { * for determining which fulfillment method to use. */ library OrderStructureLib { - using OrderLib for Order; - using OrderComponentsLib for OrderComponents; - using OrderParametersLib for OrderParameters; - using OfferItemLib for OfferItem[]; - using ConsiderationItemLib for ConsiderationItem[]; using AdvancedOrderLib for AdvancedOrder; using AdvancedOrderLib for AdvancedOrder[]; + using ConsiderationItemLib for ConsiderationItem[]; + using OfferItemLib for OfferItem[]; + using OrderComponentsLib for OrderComponents; + using OrderLib for Order; + using OrderParametersLib for OrderParameters; function getQuantity( AdvancedOrder[] memory orders @@ -129,10 +120,15 @@ library OrderStructureLib { AdvancedOrder memory order, ConsiderationInterface seaport ) internal view returns (State) { + // Get the counter for the offerer. uint256 counter = seaport.getCounter(order.parameters.offerer); + + // Use the counter to get the order hash. bytes32 orderHash = seaport.getOrderHash( order.parameters.toOrderComponents(counter) ); + + // Use the order hash to get the order status. ( bool isValidated, bool isCancelled, @@ -140,11 +136,18 @@ library OrderStructureLib { uint256 totalSize ) = seaport.getOrderStatus(orderHash); - if (totalFilled != 0 && totalSize != 0 && totalFilled == totalSize) + if (totalFilled != 0 && totalSize != 0 && totalFilled == totalSize) { return State.FULLY_FILLED; - if (totalFilled != 0 && totalSize != 0) return State.PARTIALLY_FILLED; - if (isCancelled) return State.CANCELLED; - if (isValidated) return State.VALIDATED; + } + if (totalFilled != 0 && totalSize != 0) { + return State.PARTIALLY_FILLED; + } + if (isCancelled) { + return State.CANCELLED; + } + if (isValidated) { + return State.VALIDATED; + } return State.UNUSED; } diff --git a/contracts/helpers/navigator/lib/RequestValidator.sol b/contracts/helpers/navigator/lib/RequestValidator.sol index a72b0bf26..767e9f4a3 100644 --- a/contracts/helpers/navigator/lib/RequestValidator.sol +++ b/contracts/helpers/navigator/lib/RequestValidator.sol @@ -5,10 +5,7 @@ import { NavigatorRequestValidatorLib } from "./NavigatorRequestValidatorLib.sol"; -import { - NavigatorContext, - NavigatorResponse -} from "./SeaportNavigatorTypes.sol"; +import { NavigatorContext } from "./SeaportNavigatorTypes.sol"; import { HelperInterface } from "./HelperInterface.sol"; diff --git a/contracts/helpers/navigator/lib/SeaportNavigatorInterface.sol b/contracts/helpers/navigator/lib/SeaportNavigatorInterface.sol index 013e2d5da..645930e28 100644 --- a/contracts/helpers/navigator/lib/SeaportNavigatorInterface.sol +++ b/contracts/helpers/navigator/lib/SeaportNavigatorInterface.sol @@ -1,11 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import { - AdvancedOrder, - CriteriaResolver -} from "seaport-types/src/lib/ConsiderationStructs.sol"; - import { NavigatorRequest, NavigatorResponse diff --git a/contracts/helpers/navigator/lib/SeaportNavigatorTypes.sol b/contracts/helpers/navigator/lib/SeaportNavigatorTypes.sol index 2314f8e36..fa87d827f 100644 --- a/contracts/helpers/navigator/lib/SeaportNavigatorTypes.sol +++ b/contracts/helpers/navigator/lib/SeaportNavigatorTypes.sol @@ -1,11 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import { - SeaportValidatorInterface, - ErrorsAndWarnings -} from "../../order-validator/SeaportValidator.sol"; - import { ConsiderationInterface } from "seaport-types/src/interfaces/ConsiderationInterface.sol"; @@ -14,20 +9,12 @@ import { AdvancedOrder, CriteriaResolver, Execution, - Order, - OrderComponents, - OrderParameters, - ConsiderationItem, - OfferItem, - ReceivedItem, - SpentItem, Fulfillment, FulfillmentComponent } from "seaport-types/src/lib/ConsiderationStructs.sol"; import { ItemType, - Side, OrderType } from "seaport-types/src/lib/ConsiderationEnums.sol"; @@ -35,15 +22,17 @@ import { MatchComponent } from "seaport-sol/src/lib/types/MatchComponentType.sol"; -import { - FulfillmentDetails, - OrderDetails -} from "seaport-sol/src/fulfillments/lib/Structs.sol"; +import { OrderDetails } from "seaport-sol/src/fulfillments/lib/Structs.sol"; import { FulfillmentStrategy } from "seaport-sol/src/fulfillments/lib/FulfillmentLib.sol"; +import { + SeaportValidatorInterface, + ErrorsAndWarnings +} from "../../order-validator/SeaportValidator.sol"; + struct NavigatorAdvancedOrder { NavigatorOrderParameters parameters; uint120 numerator; diff --git a/contracts/helpers/navigator/lib/ValidatorHelper.sol b/contracts/helpers/navigator/lib/ValidatorHelper.sol index 5a3d813c8..526fb88b2 100644 --- a/contracts/helpers/navigator/lib/ValidatorHelper.sol +++ b/contracts/helpers/navigator/lib/ValidatorHelper.sol @@ -9,12 +9,6 @@ import { NavigatorContext } from "./SeaportNavigatorTypes.sol"; import { HelperInterface } from "./HelperInterface.sol"; -import { Order } from "seaport-types/src/lib/ConsiderationStructs.sol"; - -import { - SeaportValidatorInterface -} from "../../order-validator/SeaportValidator.sol"; - contract ValidatorHelper is HelperInterface { using NavigatorSeaportValidatorLib for NavigatorContext; diff --git a/contracts/helpers/order-validator/lib/ReadOnlyOrderValidator.sol b/contracts/helpers/order-validator/lib/ReadOnlyOrderValidator.sol index c0d231245..2116297ba 100644 --- a/contracts/helpers/order-validator/lib/ReadOnlyOrderValidator.sol +++ b/contracts/helpers/order-validator/lib/ReadOnlyOrderValidator.sol @@ -20,29 +20,14 @@ import { } from "seaport-core/src/lib/SignatureVerification.sol"; import { + _revertOrderAlreadyFilled, _revertOrderIsCancelled, - _revertOrderPartiallyFilled, - _revertOrderAlreadyFilled + _revertOrderPartiallyFilled } from "seaport-types/src/lib/ConsiderationErrors.sol"; import { SeaportInterface } from "seaport-sol/src/SeaportInterface.sol"; import { - EIP_712_PREFIX, - EIP712_DigestPayload_size, - EIP712_DomainSeparator_offset, - EIP712_OrderHash_offset, - BulkOrderProof_keyShift, - BulkOrderProof_keySize, - BulkOrderProof_lengthAdjustmentBeforeMask, - BulkOrderProof_lengthRangeAfterMask, - BulkOrderProof_minSize, - BulkOrderProof_rangeSize, - ECDSA_MaxLength, - OneWordShift, - ThirtyOneBytes, - OneWord, - TwoWords, BulkOrder_Typehash_Height_One, BulkOrder_Typehash_Height_Two, BulkOrder_Typehash_Height_Three, @@ -66,7 +51,22 @@ import { BulkOrder_Typehash_Height_TwentyOne, BulkOrder_Typehash_Height_TwentyTwo, BulkOrder_Typehash_Height_TwentyThree, - BulkOrder_Typehash_Height_TwentyFour + BulkOrder_Typehash_Height_TwentyFour, + BulkOrderProof_keyShift, + BulkOrderProof_keySize, + BulkOrderProof_lengthAdjustmentBeforeMask, + BulkOrderProof_lengthRangeAfterMask, + BulkOrderProof_minSize, + BulkOrderProof_rangeSize, + ECDSA_MaxLength, + EIP_712_PREFIX, + EIP712_DigestPayload_size, + EIP712_DomainSeparator_offset, + EIP712_OrderHash_offset, + OneWord, + OneWordShift, + ThirtyOneBytes, + TwoWords } from "seaport-types/src/lib/ConsiderationConstants.sol"; contract ReadOnlyOrderValidator is SignatureVerification { diff --git a/script/CallNavigator.s.sol b/script/CallNavigator.s.sol index ce634e533..826be66c5 100644 --- a/script/CallNavigator.s.sol +++ b/script/CallNavigator.s.sol @@ -2,26 +2,25 @@ pragma solidity ^0.8.4; import "forge-std/Script.sol"; -import "forge-std/console.sol"; import { - SeaportNavigatorInterface, - NavigatorRequest, ConsiderationInterface, + NavigatorRequest, + SeaportNavigatorInterface, SeaportValidatorInterface } from "../contracts/helpers/navigator/SeaportNavigator.sol"; import { NavigatorAdvancedOrder, - NavigatorOrderParameters, + NavigatorConsiderationItem, NavigatorOfferItem, - NavigatorConsiderationItem + NavigatorOrderParameters } from "../contracts/helpers/navigator/lib/SeaportNavigatorTypes.sol"; import { - FulfillmentStrategy, AggregationStrategy, FulfillAvailableStrategy, + FulfillmentStrategy, MatchStrategy } from "seaport-sol/src/fulfillments/lib/FulfillmentLib.sol"; diff --git a/script/NavigatorDeployer.s.sol b/script/NavigatorDeployer.s.sol index 3246a97b1..b6927d6c1 100644 --- a/script/NavigatorDeployer.s.sol +++ b/script/NavigatorDeployer.s.sol @@ -2,44 +2,54 @@ pragma solidity ^0.8.4; import "forge-std/Script.sol"; + import "forge-std/console.sol"; import { LibString } from "solady/src/utils/LibString.sol"; import { - ReadOnlyOrderValidator -} from "../contracts/helpers/order-validator/lib/ReadOnlyOrderValidator.sol"; + CriteriaHelper +} from "../contracts/helpers/navigator/lib/CriteriaHelper.sol"; + import { - SeaportValidatorHelper -} from "../contracts/helpers/order-validator/lib/SeaportValidatorHelper.sol"; + ExecutionsHelper +} from "../contracts/helpers/navigator/lib/ExecutionsHelper.sol"; + import { - SeaportValidator -} from "../contracts/helpers/order-validator/SeaportValidator.sol"; + FulfillmentsHelper +} from "../contracts/helpers/navigator/lib/FulfillmentsHelper.sol"; + +import { + OrderDetailsHelper +} from "../contracts/helpers/navigator/lib/OrderDetailsHelper.sol"; + +import { + ReadOnlyOrderValidator +} from "../contracts/helpers/order-validator/lib/ReadOnlyOrderValidator.sol"; import { RequestValidator } from "../contracts/helpers/navigator/lib/RequestValidator.sol"; + import { - CriteriaHelper -} from "../contracts/helpers/navigator/lib/CriteriaHelper.sol"; -import { - ValidatorHelper -} from "../contracts/helpers/navigator/lib/ValidatorHelper.sol"; + SeaportNavigator +} from "../contracts/helpers/navigator/SeaportNavigator.sol"; + import { - OrderDetailsHelper -} from "../contracts/helpers/navigator/lib/OrderDetailsHelper.sol"; + SeaportValidator +} from "../contracts/helpers/order-validator/SeaportValidator.sol"; + import { - FulfillmentsHelper -} from "../contracts/helpers/navigator/lib/FulfillmentsHelper.sol"; + SeaportValidatorHelper +} from "../contracts/helpers/order-validator/lib/SeaportValidatorHelper.sol"; + import { SuggestedActionHelper } from "../contracts/helpers/navigator/lib/SuggestedActionHelper.sol"; + import { - ExecutionsHelper -} from "../contracts/helpers/navigator/lib/ExecutionsHelper.sol"; -import { - SeaportNavigator -} from "../contracts/helpers/navigator/SeaportNavigator.sol"; + ValidatorHelper +} from "../contracts/helpers/navigator/lib/ValidatorHelper.sol"; interface ImmutableCreate2Factory { function hasBeenDeployed( @@ -58,11 +68,14 @@ interface ImmutableCreate2Factory { } contract NavigatorDeployer is Script { + // Set up the immutable create2 factory and conduit controller addresses. ImmutableCreate2Factory private constant IMMUTABLE_CREATE2_FACTORY = ImmutableCreate2Factory(0x0000000000FFe8B47B3e2130213B802212439497); address private constant CONDUIT_CONTROLLER = 0x00000000F9490004C11Cef243f5400493c00Ad63; + // Set up the default salt and the salt for the seaport validator and + // navigator. bytes32 private constant DEFAULT_SALT = bytes32(uint256(0x1)); bytes32 private constant SEAPORT_VALIDATOR_SALT = bytes32(uint256(0x459b42ee5b5e5000d96491ce)); @@ -76,6 +89,8 @@ contract NavigatorDeployer is Script { pad("Address", 43), "Initcode hash" ); + + // Deploy the helpers, seaport validator, and navigator. vm.startBroadcast(); address seaportValidatorHelper = deploy( "SeaportValidatorHelper", diff --git a/test/foundry/new/SeaportNavigator.t.sol b/test/foundry/new/SeaportNavigator.t.sol index 1560582b1..39f946cc0 100644 --- a/test/foundry/new/SeaportNavigator.t.sol +++ b/test/foundry/new/SeaportNavigator.t.sol @@ -2,18 +2,14 @@ pragma solidity ^0.8.17; import { + AdvancedOrderLib, + ConsiderationInterface, ConsiderationItemLib, + CriteriaResolver, OfferItemLib, - OrderParametersLib, OrderComponentsLib, OrderLib, - OrderType, - AdvancedOrderLib, - ItemType, - SeaportInterface, - Side, - CriteriaResolver, - ConsiderationInterface + OrderParametersLib } from "seaport-sol/src/SeaportSol.sol"; import { @@ -25,9 +21,14 @@ import { AdvancedOrder } from "seaport-sol/src/SeaportStructs.sol"; +import { ItemType } from "seaport-sol/src/SeaportEnums.sol"; + import { - SeaportValidatorInterface -} from "../../../contracts/helpers/order-validator/SeaportValidator.sol"; + AggregationStrategy, + FulfillAvailableStrategy, + FulfillmentStrategy, + MatchStrategy +} from "seaport-sol/src/fulfillments/lib/FulfillmentLib.sol"; import { NavigatorRequest, @@ -35,12 +36,6 @@ import { SeaportNavigator } from "../../../contracts/helpers/navigator/SeaportNavigator.sol"; -import { - NavigatorOfferItem, - NavigatorConsiderationItem, - NavigatorOrderParameters -} from "../../../contracts/helpers/navigator/lib/SeaportNavigatorTypes.sol"; - import { TokenIdNotFound } from "../../../contracts/helpers/navigator/lib/CriteriaHelperLib.sol"; @@ -49,34 +44,30 @@ import { NavigatorAdvancedOrder, NavigatorAdvancedOrderLib } from "../../../contracts/helpers/navigator/lib/NavigatorAdvancedOrderLib.sol"; + import { OrderStructureLib } from "../../../contracts/helpers/navigator/lib/OrderStructureLib.sol"; import { BaseOrderTest } from "./BaseOrderTest.sol"; + import { SeaportValidatorTest } from "./SeaportValidatorTest.sol"; -import { SeaportNavigatorTest } from "./SeaportNavigatorTest.sol"; -import { - FulfillmentStrategy, - AggregationStrategy, - FulfillAvailableStrategy, - MatchStrategy -} from "seaport-sol/src/fulfillments/lib/FulfillmentLib.sol"; +import { SeaportNavigatorTest } from "./SeaportNavigatorTest.sol"; contract SeaportNavigatorTestSuite is BaseOrderTest, SeaportValidatorTest, SeaportNavigatorTest { + using AdvancedOrderLib for AdvancedOrder; using ConsiderationItemLib for ConsiderationItem; + using NavigatorAdvancedOrderLib for NavigatorAdvancedOrder; using OfferItemLib for OfferItem; - using OrderParametersLib for OrderParameters; using OrderComponentsLib for OrderComponents; using OrderLib for Order; - using AdvancedOrderLib for AdvancedOrder; + using OrderParametersLib for OrderParameters; using OrderStructureLib for AdvancedOrder; - using NavigatorAdvancedOrderLib for NavigatorAdvancedOrder; string constant SINGLE_ERC721_SINGLE_ERC20 = "SINGLE_ERC721_SINGLE_ERC20"; string constant SINGLE_ERC721_WITH_CRITERIA_SINGLE_ERC721_WITH_CRITERIA = diff --git a/test/foundry/new/SeaportNavigatorTest.sol b/test/foundry/new/SeaportNavigatorTest.sol index f13f4d274..bc00f11fa 100644 --- a/test/foundry/new/SeaportNavigatorTest.sol +++ b/test/foundry/new/SeaportNavigatorTest.sol @@ -1,33 +1,41 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import { - SeaportNavigator -} from "../../../contracts/helpers/navigator/SeaportNavigator.sol"; -import { - HelperInterface -} from "../../../contracts/helpers/navigator/lib/HelperInterface.sol"; -import { - RequestValidator -} from "../../../contracts/helpers/navigator/lib/RequestValidator.sol"; import { CriteriaHelper } from "../../../contracts/helpers/navigator/lib/CriteriaHelper.sol"; + import { - ValidatorHelper -} from "../../../contracts/helpers/navigator/lib/ValidatorHelper.sol"; + ExecutionsHelper +} from "../../../contracts/helpers/navigator/lib/ExecutionsHelper.sol"; + +import { + FulfillmentsHelper +} from "../../../contracts/helpers/navigator/lib/FulfillmentsHelper.sol"; + +import { + HelperInterface +} from "../../../contracts/helpers/navigator/lib/HelperInterface.sol"; + import { OrderDetailsHelper } from "../../../contracts/helpers/navigator/lib/OrderDetailsHelper.sol"; + import { - FulfillmentsHelper -} from "../../../contracts/helpers/navigator/lib/FulfillmentsHelper.sol"; + RequestValidator +} from "../../../contracts/helpers/navigator/lib/RequestValidator.sol"; + +import { + SeaportNavigator +} from "../../../contracts/helpers/navigator/SeaportNavigator.sol"; + import { SuggestedActionHelper } from "../../../contracts/helpers/navigator/lib/SuggestedActionHelper.sol"; + import { - ExecutionsHelper -} from "../../../contracts/helpers/navigator/lib/ExecutionsHelper.sol"; + ValidatorHelper +} from "../../../contracts/helpers/navigator/lib/ValidatorHelper.sol"; contract SeaportNavigatorTest { HelperInterface internal requestValidator = new RequestValidator(); @@ -39,6 +47,7 @@ contract SeaportNavigatorTest { new SuggestedActionHelper(); HelperInterface internal executionsHelper = new ExecutionsHelper(); + // Initialize the navigator with all its constituent helpers. SeaportNavigator internal navigator = new SeaportNavigator( address(requestValidator), diff --git a/test/foundry/new/SeaportValidatorTest.sol b/test/foundry/new/SeaportValidatorTest.sol index b65e27d23..77e9762a8 100644 --- a/test/foundry/new/SeaportValidatorTest.sol +++ b/test/foundry/new/SeaportValidatorTest.sol @@ -4,14 +4,9 @@ pragma solidity ^0.8.17; import { BaseSeaportTest } from "./helpers/BaseSeaportTest.sol"; import { - ConduitControllerInterface -} from "seaport-sol/src/ConduitControllerInterface.sol"; - -import { - SeaportValidatorHelper, + ReadOnlyOrderValidator, SeaportValidator, - SeaportValidatorInterface, - ReadOnlyOrderValidator + SeaportValidatorHelper } from "../../../contracts/helpers/order-validator/SeaportValidator.sol"; contract SeaportValidatorTest is BaseSeaportTest { @@ -28,6 +23,7 @@ contract SeaportValidatorTest is BaseSeaportTest { seaportValidatorHelper = new SeaportValidatorHelper(); vm.chainId(chainId); + // Initialize the validator. validator = new SeaportValidator( address(new ReadOnlyOrderValidator()), address(seaportValidatorHelper), From de19a48a5c6bef267a8280c372ff1e362b472639 Mon Sep 17 00:00:00 2001 From: djviau Date: Tue, 12 Sep 2023 19:55:42 -0400 Subject: [PATCH 2/8] fix typo, rename, refactor, document --- .../lib/NavigatorSuggestedActionLib.sol | 114 ++++++++++-------- test/foundry/new/helpers/FuzzEngineLib.sol | 10 +- 2 files changed, 67 insertions(+), 57 deletions(-) diff --git a/contracts/helpers/navigator/lib/NavigatorSuggestedActionLib.sol b/contracts/helpers/navigator/lib/NavigatorSuggestedActionLib.sol index 4f11b4fc1..56d3c6a2b 100644 --- a/contracts/helpers/navigator/lib/NavigatorSuggestedActionLib.sol +++ b/contracts/helpers/navigator/lib/NavigatorSuggestedActionLib.sol @@ -87,31 +87,23 @@ library NavigatorSuggestedActionLib { Family family = context.response.orders.getFamily(); // `mustUseMatch` returns true if the orders require the use of one of - // the match* methods. - // - //TODO: why is this a proxy for an invalid offer - // item? - bool invalidOfferItemsLocated = mustUseMatch(context); + // the match* methods. `mustUseMatch` checks for two things: 1) the + // presence of a native token in the offer of one of the orders, and 2) + // the presence of an ERC721 in the offer of one of the orders that is + // also in the consideration of another order. So, + // `containsOrderThatDemandsMatch` means that there's an offer item that + // can't be part of a standing order. + bool containsOrderThatDemandsMatch = mustUseMatch(context); // Get the structure of the orders (basic, standard, or advanced). Structure structure = context.response.orders.getStructure( address(context.request.seaport) ); - // TODO: figure out why this is the formula for determining if there are - // unavailable orders. - bool hasUnavailable = context.request.maximumFulfilled < - context.response.orders.length; + bool contextHasExcessOrders = context.response.orders.length > + context.request.maximumFulfilled; - // The match* methods are only an option if everything is going to find - // a partner (the first half of the if statement below) and if there are - // no unavailable orders (the second half of the if statement below). - bool cannotMatch = (context - .response - .unmetConsiderationComponents - .length != - 0 || - hasUnavailable); + bool contextHasUnavailableOrders; // Iterate through the orders and check if any of the orders has an // unavailable reason. @@ -120,21 +112,35 @@ library NavigatorSuggestedActionLib { context.response.orderDetails[i].unavailableReason != UnavailableReason.AVAILABLE ) { - hasUnavailable = true; + contextHasUnavailableOrders = true; break; } } - // If there are unavailable orders, follow this branch. - if (hasUnavailable) { - // If there are unavailable orders and the orders could only be - // fulfilled using match*, it's a no-go. - if (invalidOfferItemsLocated) { + // The match* methods are only an option if everything is going to find + // a partner (the first half of the if statement below) and if there are + // no unavailable orders (the second half of the if statement below). + bool cannotMatch = (context + .response + .unmetConsiderationComponents + .length != + 0 || + contextHasExcessOrders); + + bool contextHasExcessOrUnavailableOrders = contextHasExcessOrders || + contextHasUnavailableOrders; + + // If there are excess or unavailable orders, follow this branch. + if (contextHasExcessOrUnavailableOrders) { + // If there are excess or unavailable orders and the orders could + // only be fulfilled using match*, it's a no-go, because every order + // must find a partner in the match* methods. + if (containsOrderThatDemandsMatch) { revert InvalidNativeTokenUnavailableCombination(); } - // If there are unavailable orders and the orders are advanced, use - // fulfillAvailableAdvancedOrders. + // If there are excess or unavailable orders and the orders are + // advanced, use fulfillAvailableAdvancedOrders. if (structure == Structure.ADVANCED) { return abi.encodeCall( @@ -150,8 +156,8 @@ library NavigatorSuggestedActionLib { ) ); } else { - // If there are unavailable orders and the orders are not - // advanced, use fulfillAvailableOrders. + // If there are excess or unavailable orders and the orders are + // not advanced, use fulfillAvailableOrders. return abi.encodeCall( ConsiderationInterface.fulfillAvailableOrders, @@ -166,11 +172,11 @@ library NavigatorSuggestedActionLib { } } - // If there are no unavailable orders, follow this branch. + // If there are no excess or unavailable orders, follow this branch. // If the order family is single (just one being fulfilled) and it // doesn't require using match*, use the appropriate fulfill* method. - if (family == Family.SINGLE && !invalidOfferItemsLocated) { + if (family == Family.SINGLE && !containsOrderThatDemandsMatch) { // If the order structure is basic, use // fulfillBasicOrder_efficient_6GL6yc for maximum gas efficiency. if (structure == Structure.BASIC) { @@ -216,12 +222,11 @@ library NavigatorSuggestedActionLib { // This is like saying "if it's not possible to use match* but it's // mandatory to use match*, revert." - if (cannotMatch && invalidOfferItemsLocated) { + if (cannotMatch && containsOrderThatDemandsMatch) { revert CannotFulfillProvidedCombinedOrder(); } - // If it's not mandatory to use match* and it's not possible to use - // match*, use fulfillAvailable*. + // If it's not possible to use match*, use fulfillAvailable*. if (cannotMatch) { if (structure == Structure.ADVANCED) { return @@ -250,25 +255,22 @@ library NavigatorSuggestedActionLib { ) ); } - } else if (invalidOfferItemsLocated) { - // Even if match* is an option, if there are invalid offer items and - // the structure is advanced use fulfillAvailable*. + } else if (containsOrderThatDemandsMatch) { + // Here, matching is an option and "containsOrderThatDemandsMatch" + // means that match is mandatory, so pick the appropriate match* + // method based on structure. if (structure == Structure.ADVANCED) { return abi.encodeCall( - ConsiderationInterface.fulfillAvailableAdvancedOrders, + ConsiderationInterface.matchAdvancedOrders, ( context.response.orders, context.response.criteriaResolvers, - context.response.offerFulfillments, - context.response.considerationFulfillments, - context.request.fulfillerConduitKey, - context.request.recipient, - context.request.maximumFulfilled + context.response.fulfillments, + context.request.recipient ) ); } else { - // TODO: document. return abi.encodeCall( ConsiderationInterface.matchOrders, @@ -279,11 +281,12 @@ library NavigatorSuggestedActionLib { ); } } else { - // If match* is an option and there are no invalid offer items, - // follow this branch. + // If match* is an option and there are no excess or unavailable + // offer items, follow this branch. // // If the structure is advanced, use matchAdvancedOrders or use - // fulfillAvailableAdvancedOrders depending on the caller's request. + // fulfillAvailableAdvancedOrders depending on the caller's + // preference. if (structure == Structure.ADVANCED) { if (context.request.preferMatch) { return @@ -314,7 +317,7 @@ library NavigatorSuggestedActionLib { } } else { // If the structure is not advanced, use matchOrders or - // fulfillAvailableOrders depending on the caller's request. + // fulfillAvailableOrders depending on the caller's preference. if (context.request.preferMatch) { return abi.encodeCall( @@ -350,16 +353,23 @@ library NavigatorSuggestedActionLib { ) internal pure returns (bool) { OrderDetails[] memory orders = context.response.orderDetails; - // Iterate through the orders and check if any of the non-contract + // Iterate through the orders and check if any of the non-contract // orders has a native token in the offer. for (uint256 i = 0; i < orders.length; ++i) { OrderDetails memory order = orders[i]; + // Skip contract orders. if (order.isContract) { continue; } - // If the order has a native token in the offer, use match. + // If the order has a native token in the offer, must use match. If + // an order is being passed in that has a native token on the offer + // side, then all the fulfill* methods are ruled out, because it's + // not possible to create a standing order that offers ETH (WETH + // would be required). If an order with native tokens is passed in, + // then it necessarily must be coming from a caller who's passing in + // a bookend order. for (uint256 j = 0; j < order.offer.length; ++j) { if (order.offer[j].itemType == ItemType.NATIVE) { return true; @@ -373,7 +383,7 @@ library NavigatorSuggestedActionLib { } // This basically checks if there's an ERC721 in the offer of one order - // that is also in the consideration of another order. If yes, use + // that is also in the consideration of another order. If yes, must use // match. for (uint256 i = 0; i < orders.length; ++i) { // Get the order. @@ -391,7 +401,7 @@ library NavigatorSuggestedActionLib { // Iterate over the orders again. for (uint256 k = 0; k < orders.length; ++k) { - // Get an order to compare against. + // Get an order to compare `orders[i]` against. OrderDetails memory comparisonOrder = orders[k]; // Iterate over the consideration items. @@ -406,7 +416,7 @@ library NavigatorSuggestedActionLib { // If the consideration item is an ERC721, and the ID is // the same as the offer item, and the token address is - // the same as the offer item, use match. + // the same as the offer item, must use match. if ( considerationItem.itemType == ItemType.ERC721 && considerationItem.identifier == item.identifier && diff --git a/test/foundry/new/helpers/FuzzEngineLib.sol b/test/foundry/new/helpers/FuzzEngineLib.sol index 94b5cd8b3..816fb5ed9 100644 --- a/test/foundry/new/helpers/FuzzEngineLib.sol +++ b/test/foundry/new/helpers/FuzzEngineLib.sol @@ -113,7 +113,7 @@ library FuzzEngineLib { ) internal view returns (bytes4[] memory) { Family family = context.executionState.orders.getFamily(); - bool invalidOfferItemsLocated = mustUseMatch(context); + bool containsOrderThatDemandsMatch = mustUseMatch(context); Structure structure = context.executionState.orders.getStructure( address(context.seaport) @@ -136,7 +136,7 @@ library FuzzEngineLib { } if (hasUnavailable) { - if (invalidOfferItemsLocated) { + if (containsOrderThatDemandsMatch) { revert( "FuzzEngineLib: invalid native token + unavailable combination" ); @@ -160,7 +160,7 @@ library FuzzEngineLib { } } - if (family == Family.SINGLE && !invalidOfferItemsLocated) { + if (family == Family.SINGLE && !containsOrderThatDemandsMatch) { if (structure == Structure.BASIC) { bytes4[] memory selectors = new bytes4[](6); selectors[0] = context.seaport.fulfillOrder.selector; @@ -204,7 +204,7 @@ library FuzzEngineLib { bool cannotMatch = (context.executionState.hasRemainders || hasUnavailable); - if (cannotMatch && invalidOfferItemsLocated) { + if (cannotMatch && containsOrderThatDemandsMatch) { revert("FuzzEngineLib: cannot fulfill provided combined order"); } @@ -227,7 +227,7 @@ library FuzzEngineLib { //selectors[3] = context.seaport.validate.selector; return selectors; } - } else if (invalidOfferItemsLocated) { + } else if (containsOrderThatDemandsMatch) { if (structure == Structure.ADVANCED) { bytes4[] memory selectors = new bytes4[](1); selectors[0] = context.seaport.matchAdvancedOrders.selector; From fd7dd10bbf65f5e77ebca79d996411650c8a2901 Mon Sep 17 00:00:00 2001 From: djviau Date: Wed, 13 Sep 2023 16:36:53 -0400 Subject: [PATCH 3/8] add some comments and a logging library --- contracts/helpers/helm.sol | 705 ++++++++++++++++++ .../navigator/lib/CriteriaHelperLib.sol | 36 + .../helpers/navigator/lib/HelperItemLib.sol | 63 +- contracts/helpers/navigator/lib/MerkleLib.sol | 54 +- .../lib/NavigatorAdvancedOrderLib.sol | 38 + .../navigator/lib/NavigatorContextLib.sol | 8 + .../navigator/lib/NavigatorExecutionsLib.sol | 9 + test/foundry/ConsiderationStructLogger.t.sol | 382 ++++++++++ 8 files changed, 1277 insertions(+), 18 deletions(-) create mode 100644 contracts/helpers/helm.sol create mode 100644 test/foundry/ConsiderationStructLogger.t.sol diff --git a/contracts/helpers/helm.sol b/contracts/helpers/helm.sol new file mode 100644 index 000000000..5a45a8201 --- /dev/null +++ b/contracts/helpers/helm.sol @@ -0,0 +1,705 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import "forge-std/console.sol"; + +import { LibString } from "solady/src/utils/LibString.sol"; + +import { + BasicOrderType, + ItemType, + OrderType, + Side +} from "seaport-types/src/lib/ConsiderationEnums.sol"; + +import { + AdditionalRecipient, + AdvancedOrder, + BasicOrderParameters, + ConsiderationItem, + CriteriaResolver, + Execution, + Fulfillment, + FulfillmentComponent, + OfferItem, + Order, + OrderComponents, + OrderParameters, + ReceivedItem, + SpentItem, + ZoneParameters +} from "seaport-types/src/lib/ConsiderationStructs.sol"; + +/** + * @title helm + * @author snotrocket.eth + * @notice helm is an extension of the console.sol library that provides + * additional logging functionality for Seaport structs. + */ +library helm { + function log(OrderComponents memory orderComponents) public view { + logOrderComponents(orderComponents, 0); + } + + function log(OrderComponents[] memory orderComponentsArray) public view { + console.log(gStr(0, "orderComponentsArray: [")); + for (uint256 j = 0; j < orderComponentsArray.length; j++) { + logOrderComponents(orderComponentsArray[j], 1); + } + console.log(gStr(0, "]")); + } + + function logOrderComponents( + OrderComponents memory oc, + uint256 i // indent + ) internal view { + console.log(gStr(i, "OrderComponents: {")); + console.log(gStr(i + 1, "offerer", oc.offerer)); + console.log(gStr(i + 1, "zone", oc.zone)); + logOffer(oc.offer, i + 1); + logConsideration(oc.consideration, i + 1); + console.log(gStr(i + 1, "orderType", _orderTypeStr(oc.orderType))); + console.log(gStr(i + 1, "startTime", oc.startTime)); + console.log(gStr(i + 1, "endTime", oc.endTime)); + console.log(gStr(i + 1, "zoneHash", oc.zoneHash)); + console.log(gStr(i + 1, "salt", oc.salt)); + console.log(gStr(i + 1, "conduitKey", oc.conduitKey)); + console.log(gStr(i + 1, "counter", oc.counter)); + console.log(gStr(i, "}")); + } + + function log(OfferItem memory offerItem) public view { + logOfferItem(offerItem, 0); + } + + function log(OfferItem[] memory offerItemArray) public view { + console.log(gStr(0, "offerItemArray: [")); + for (uint256 j = 0; j < offerItemArray.length; j++) { + logOfferItem(offerItemArray[j], 1); + } + console.log(gStr(0, "]")); + } + + function logOfferItem( + OfferItem memory oi, + uint256 i // indent + ) internal view { + console.log(gStr(i, "OfferItem: {")); + console.log(gStr(i + 1, "itemType", _itemTypeStr(oi.itemType))); + console.log(gStr(i + 1, "token", oi.token)); + console.log( + gStr(i + 1, "identifierOrCriteria", oi.identifierOrCriteria) + ); + console.log(gStr(i + 1, "startAmount", oi.startAmount)); + console.log(gStr(i + 1, "endAmount", oi.endAmount)); + console.log(gStr(i, "}")); + } + + function log(ConsiderationItem memory considerationItem) public view { + logConsiderationItem(considerationItem, 0); + } + + function log( + ConsiderationItem[] memory considerationItemArray + ) public view { + console.log(gStr(0, "considerationItemArray: [")); + for (uint256 j = 0; j < considerationItemArray.length; j++) { + logConsiderationItem(considerationItemArray[j], 1); + } + console.log(gStr(0, "]")); + } + + function logConsiderationItem( + ConsiderationItem memory ci, + uint256 i // indent + ) internal view { + console.log(gStr(i, "ConsiderationItem: {")); + console.log(gStr(i + 1, "itemType", _itemTypeStr(ci.itemType))); + console.log(gStr(i + 1, "token", ci.token)); + console.log( + gStr(i + 1, "identifierOrCriteria", ci.identifierOrCriteria) + ); + console.log(gStr(i + 1, "startAmount", ci.startAmount)); + console.log(gStr(i + 1, "endAmount", ci.endAmount)); + console.log(gStr(i, "}")); + } + + function log(SpentItem memory spentItem) public view { + logSpentItem(spentItem, 0); + } + + function log(SpentItem[] memory spentItemArray) public view { + console.log(gStr(0, "spentItemArray: [")); + for (uint256 j = 0; j < spentItemArray.length; j++) { + logSpentItem(spentItemArray[j], 1); + } + console.log(gStr(0, "]")); + } + + function logSpentItem( + SpentItem memory si, + uint256 i // indent + ) internal view { + console.log(gStr(i, "SpentItem: {")); + console.log(gStr(i + 1, "itemType", _itemTypeStr(si.itemType))); + console.log(gStr(i + 1, "token", si.token)); + console.log(gStr(i + 1, "identifier", si.identifier)); + console.log(gStr(i + 1, "amount", si.amount)); + console.log(gStr(i, "}")); + } + + function log(ReceivedItem memory receivedItem) public view { + logReceivedItem(receivedItem, 0); + } + + function log(ReceivedItem[] memory receivedItemArray) public view { + console.log(gStr(0, "receivedItemArray: [")); + for (uint256 j = 0; j < receivedItemArray.length; j++) { + logReceivedItem(receivedItemArray[j], 1); + } + console.log(gStr(0, "]")); + } + + function logReceivedItem( + ReceivedItem memory ri, + uint256 i // indent + ) internal view { + console.log(gStr(i, "ReceivedItem: {")); + console.log(gStr(i + 1, "itemType", _itemTypeStr(ri.itemType))); + console.log(gStr(i + 1, "token", ri.token)); + console.log(gStr(i + 1, "identifier", ri.identifier)); + console.log(gStr(i + 1, "amount", ri.amount)); + console.log(gStr(i + 1, "recipient", ri.recipient)); + console.log(gStr(i, "}")); + } + + function log(BasicOrderParameters memory basicOrderParameters) public view { + logBasicOrderParameters(basicOrderParameters, 0); + } + + function log( + BasicOrderParameters[] memory basicOrderParametersArray + ) public view { + console.log(gStr(0, "basicOrderParametersArray: [")); + for (uint256 j = 0; j < basicOrderParametersArray.length; j++) { + logBasicOrderParameters(basicOrderParametersArray[j], 1); + } + console.log(gStr(0, "]")); + } + + function logBasicOrderParameters( + BasicOrderParameters memory bop, + uint256 i // indent + ) internal view { + console.log(gStr(i, "BasicOrderParameters: {")); + console.log(gStr(i + 1, "considerationToken", bop.considerationToken)); + console.log( + gStr(i + 1, "considerationIdentifier", bop.considerationIdentifier) + ); + console.log( + gStr(i + 1, "considerationAmount", bop.considerationAmount) + ); + console.log(gStr(i + 1, "offerer", bop.offerer)); + console.log(gStr(i + 1, "zone", bop.zone)); + console.log(gStr(i + 1, "offerToken", bop.offerToken)); + console.log(gStr(i + 1, "offerIdentifier", bop.offerIdentifier)); + console.log(gStr(i + 1, "offerAmount", bop.offerAmount)); + console.log( + gStr( + i + 1, + "basicOrderType", + _basicOrderTypeStr(bop.basicOrderType) + ) + ); + console.log(gStr(i + 1, "startTime", bop.startTime)); + console.log(gStr(i + 1, "endTime", bop.endTime)); + console.log(gStr(i + 1, "zoneHash", bop.zoneHash)); + console.log(gStr(i + 1, "salt", bop.salt)); + console.log(gStr(i + 1, "offererConduitKey", bop.offererConduitKey)); + console.log( + gStr(i + 1, "fulfillerConduitKey", bop.fulfillerConduitKey) + ); + console.log( + gStr( + i + 1, + "totalOriginalAdditionalRecipients", + bop.totalOriginalAdditionalRecipients + ) + ); + console.log(gStr(i + 1, "additionalRecipients: [")); + for (uint256 j = 0; j < bop.additionalRecipients.length; j++) { + logAdditionalRecipient(bop.additionalRecipients[j], i + 1); + } + console.log(gStr(i + 1, "]")); + console.log(gStr(i + 1, "signature", bop.signature)); + console.log(gStr(i, "}")); + } + + function log(AdditionalRecipient memory additionalRecipient) public view { + logAdditionalRecipient(additionalRecipient, 0); + } + + function log( + AdditionalRecipient[] memory additionalRecipientArray + ) public view { + console.log(gStr(0, "additionalRecipientArray: [")); + for (uint256 j = 0; j < additionalRecipientArray.length; j++) { + logAdditionalRecipient(additionalRecipientArray[j], 1); + } + console.log(gStr(0, "]")); + } + + function logAdditionalRecipient( + AdditionalRecipient memory ar, + uint256 i // indent + ) internal view { + console.log(gStr(i, "AdditionalRecipient: {")); + console.log(gStr(i + 1, "recipient", ar.recipient)); + console.log(gStr(i + 1, "amount", ar.amount)); + console.log(gStr(i, "}")); + } + + function log(OrderParameters memory orderParameters) public view { + logOrderParameters(orderParameters, 0); + } + + function log(OrderParameters[] memory orderParametersArray) public view { + console.log(gStr(0, "orderParametersArray: [")); + for (uint256 j = 0; j < orderParametersArray.length; j++) { + logOrderParameters(orderParametersArray[j], 1); + } + console.log(gStr(0, "]")); + } + + function logOrderParameters( + OrderParameters memory op, + uint256 i // indent + ) internal view { + console.log(gStr(i, "OrderParameters: {")); + console.log(gStr(i + 1, "offerer", op.offerer)); + console.log(gStr(i + 1, "zone", op.zone)); + logOffer(op.offer, i + 1); + logConsideration(op.consideration, i + 1); + console.log(gStr(i + 1, "orderType", _orderTypeStr(op.orderType))); + console.log(gStr(i + 1, "startTime", op.startTime)); + console.log(gStr(i + 1, "endTime", op.endTime)); + console.log(gStr(i + 1, "zoneHash", op.zoneHash)); + console.log(gStr(i + 1, "salt", op.salt)); + console.log(gStr(i + 1, "conduitKey", op.conduitKey)); + console.log( + gStr( + i + 1, + "totalOriginalConsiderationItems", + op.totalOriginalConsiderationItems + ) + ); + console.log(gStr(i, "}")); + } + + function log(Order memory order) public view { + logOrder(order, 0); + } + + function log(Order[] memory orderArray) public view { + console.log(gStr(0, "orderArray: [")); + for (uint256 j = 0; j < orderArray.length; j++) { + logOrder(orderArray[j], 1); + } + console.log(gStr(0, "]")); + } + + function logOrder( + Order memory order, + uint256 i /* indent */ + ) internal view { + console.log(gStr(i, "Order: {")); + logOrderParameters(order.parameters, i + 1); + console.log(gStr(i + 1, "signature", order.signature)); + console.log(gStr(i, "}")); + } + + function log(AdvancedOrder memory advancedOrder) public view { + logAdvancedOrder(advancedOrder, 0); + } + + function log(AdvancedOrder[] memory advancedOrderArray) public view { + console.log(gStr(0, "advancedOrderArray: [")); + for (uint256 j = 0; j < advancedOrderArray.length; j++) { + logAdvancedOrder(advancedOrderArray[j], 1); + } + console.log(gStr(0, "]")); + } + + function logAdvancedOrder( + AdvancedOrder memory advancedOrder, + uint256 i // indent + ) internal view { + console.log(gStr(i, "AdvancedOrder: {")); + logOrderParameters(advancedOrder.parameters, i + 1); + console.log(gStr(i + 1, "numerator", advancedOrder.numerator)); + console.log(gStr(i + 1, "denominator", advancedOrder.denominator)); + console.log(gStr(i + 1, "signature", advancedOrder.signature)); + console.log(gStr(i + 1, "extraData", advancedOrder.extraData)); + console.log(gStr(i, "}")); + } + + function log(CriteriaResolver memory criteriaResolver) public view { + logCriteriaResolver(criteriaResolver, 0); + } + + function log(CriteriaResolver[] memory criteriaResolverArray) public view { + console.log(gStr(0, "criteriaResolverArray: [")); + for (uint256 j = 0; j < criteriaResolverArray.length; j++) { + logCriteriaResolver(criteriaResolverArray[j], 1); + } + console.log(gStr(0, "]")); + } + + function logCriteriaResolver( + CriteriaResolver memory cr, + uint256 i // indent + ) internal view { + console.log(gStr(i, "CriteriaResolver: {")); + console.log(gStr(i + 1, "orderIndex", cr.orderIndex)); + console.log(gStr(i + 1, "side", _sideStr(cr.side))); + console.log(gStr(i + 1, "index", cr.index)); + console.log(gStr(i + 1, "identifier", cr.identifier)); + for (uint256 j = 0; j < cr.criteriaProof.length; j++) { + console.log(gStr(i + 2, "criteriaProof", cr.criteriaProof[j])); + } + console.log(gStr(i, "}")); + } + + function log(Fulfillment memory fulfillment) public view { + logFulfillment(fulfillment, 0); + } + + function log(Fulfillment[] memory fulfillmentArray) public view { + console.log(gStr(0, "fulfillmentArray: [")); + for (uint256 j = 0; j < fulfillmentArray.length; j++) { + logFulfillment(fulfillmentArray[j], 1); + } + console.log(gStr(0, "]")); + } + + function logFulfillment( + Fulfillment memory f, + uint256 i // indent + ) internal view { + console.log(gStr(i, "Fulfillment: {")); + console.log(gStr(i + 1, "offerComponents: [")); + for (uint256 j = 0; j < f.offerComponents.length; j++) { + logFulfillmentComponent(f.offerComponents[j], i + 2); + } + console.log(gStr(i + 1, "]")); + console.log(gStr(i + 1, "considerationComponents: [")); + for (uint256 j = 0; j < f.considerationComponents.length; j++) { + logFulfillmentComponent(f.considerationComponents[j], i + 2); + } + console.log(gStr(i + 1, "]")); + console.log(gStr(i, "}")); + } + + function log(FulfillmentComponent memory fulfillmentComponent) public view { + logFulfillmentComponent(fulfillmentComponent, 0); + } + + function log( + FulfillmentComponent[] memory fulfillmentComponentArray + ) public view { + console.log(gStr(0, "fulfillmentComponentArray: [")); + for (uint256 j = 0; j < fulfillmentComponentArray.length; j++) { + logFulfillmentComponent(fulfillmentComponentArray[j], 1); + } + console.log(gStr(0, "]")); + } + + function logFulfillmentComponent( + FulfillmentComponent memory fc, + uint256 i // indent + ) internal view { + console.log(gStr(i, "FulfillmentComponent: {")); + console.log(gStr(i + 1, "orderIndex", fc.orderIndex)); + console.log(gStr(i + 1, "itemIndex", fc.itemIndex)); + console.log(gStr(i, "}")); + } + + function log(Execution memory execution) public view { + logExecution(execution, 0); + } + + function log(Execution[] memory executionArray) public view { + console.log(gStr(0, "executionArray: [")); + for (uint256 j = 0; j < executionArray.length; j++) { + logExecution(executionArray[j], 1); + } + console.log(gStr(0, "]")); + } + + function logExecution( + Execution memory execution, + uint256 i // indent + ) internal view { + console.log(gStr(i, "Execution: {")); + logReceivedItem(execution.item, i + 1); + console.log(gStr(i + 1, "offerer", execution.offerer)); + console.log(gStr(i + 1, "conduitKey", execution.conduitKey)); + console.log(gStr(i, "}")); + } + + function log(ZoneParameters memory zoneParameters) public view { + logZoneParameters(zoneParameters, 0); + } + + function log(ZoneParameters[] memory zoneParametersArray) public view { + console.log(gStr(0, "zoneParametersArray: [")); + for (uint256 j = 0; j < zoneParametersArray.length; j++) { + logZoneParameters(zoneParametersArray[j], 1); + } + console.log(gStr(0, "]")); + } + + function logZoneParameters( + ZoneParameters memory zp, + uint256 i // indent + ) internal view { + console.log(gStr(i, "ZoneParameters: {")); + console.log(gStr(i + 1, "orderHash", zp.orderHash)); + console.log(gStr(i + 1, "fulfiller", zp.fulfiller)); + console.log(gStr(i + 1, "offerer", zp.offerer)); + console.log(gStr(i + 1, "offer: [")); + for (uint256 j = 0; j < zp.offer.length; j++) { + logSpentItem(zp.offer[j], i + 1); + } + console.log(gStr(i + 1, "]")); + console.log(gStr(i + 1, "consideration: [")); + for (uint256 j = 0; j < zp.consideration.length; j++) { + logReceivedItem(zp.consideration[j], i + 1); + } + console.log(gStr(i + 1, "]")); + console.log(gStr(i + 1, "extraData", zp.extraData)); + console.log(gStr(i + 1, "orderHashes: [")); + for (uint256 j = 0; j < zp.orderHashes.length; j++) { + console.log(gStr(i + 2, "", zp.orderHashes[j])); + } + console.log(gStr(i + 1, "]")); + console.log(gStr(i + 1, "startTime", zp.startTime)); + console.log(gStr(i + 1, "endTime", zp.endTime)); + console.log(gStr(i + 1, "zoneHash", zp.zoneHash)); + console.log(gStr(i, "}")); + } + + //////////////////////////////////////////////////////////////////////////// + // Helpers // + //////////////////////////////////////////////////////////////////////////// + + function generateIndentString( + uint256 i // indent + ) public pure returns (string memory) { + string memory indentString = ""; + for (uint256 j = 0; j < i; j++) { + indentString = string.concat(indentString, " "); + } + return indentString; + } + + function gStr( + // generateString + uint256 i, // indent + string memory stringToIndent + ) public pure returns (string memory) { + string memory indentString = generateIndentString(i); + return string.concat(indentString, stringToIndent); + } + + function gStr( + uint256 i, // indent + string memory labelString, + string memory valueString + ) public pure returns (string memory) { + string memory indentString = generateIndentString(i); + return + string.concat( + indentString, + string.concat(labelString, ": ", valueString) + ); + } + + function gStr( + uint256 i, // indent + string memory labelString, + uint256 value + ) public pure returns (string memory) { + string memory indentString = generateIndentString(i); + return + string.concat( + indentString, + string.concat(labelString, ": ", LibString.toString(value)) + ); + } + + function gStr( + uint256 i, // indent + string memory labelString, + address value + ) public pure returns (string memory) { + string memory indentString = generateIndentString(i); + return + string.concat( + indentString, + string.concat(labelString, ": ", LibString.toHexString(value)) + ); + } + + function gStr( + uint256 i, // indent + string memory labelString, + bytes32 value + ) public pure returns (string memory) { + string memory indentString = generateIndentString(i); + return + string.concat( + indentString, + string.concat( + labelString, + ": ", + LibString.toHexString(uint256(value)) + ) + ); + } + + function gStr( + uint256 i, // indent + string memory labelString, + bytes memory value + ) public pure returns (string memory) { + string memory indentString = generateIndentString(i); + return + string.concat( + indentString, + string.concat(labelString, ": ", LibString.toHexString(value)) + ); + } + + //////////////////////////////////////////////////////////////////////////// + // Log Arrays // + //////////////////////////////////////////////////////////////////////////// + + function logOffer( + OfferItem[] memory offer, + uint256 i /* indent */ + ) public view { + console.log(gStr(i, "offer: [")); + for (uint256 j = 0; j < offer.length; j++) { + logOfferItem(offer[j], i + 1); + } + console.log(gStr(i, "]")); + } + + function logConsideration( + ConsiderationItem[] memory consideration, + uint256 i // indent + ) public view { + console.log(gStr(i, "consideration: [")); + for (uint256 j = 0; j < consideration.length; j++) { + logConsiderationItem(consideration[j], i + 1); + } + console.log(gStr(i, "]")); + } + + //////////////////////////////////////////////////////////////////////////// + // Get Enum String Values // + //////////////////////////////////////////////////////////////////////////// + + function _itemTypeStr( + ItemType itemType + ) internal pure returns (string memory) { + if (itemType == ItemType.NATIVE) return "NATIVE"; + if (itemType == ItemType.ERC20) return "ERC20"; + if (itemType == ItemType.ERC721) return "ERC721"; + if (itemType == ItemType.ERC1155) return "ERC1155"; + if (itemType == ItemType.ERC721_WITH_CRITERIA) + return "ERC721_WITH_CRITERIA"; + if (itemType == ItemType.ERC1155_WITH_CRITERIA) + return "ERC1155_WITH_CRITERIA"; + + return "UNKNOWN"; + } + + function _orderTypeStr( + OrderType orderType + ) internal pure returns (string memory) { + if (orderType == OrderType.FULL_OPEN) return "FULL_OPEN"; + if (orderType == OrderType.PARTIAL_OPEN) return "PARTIAL_OPEN"; + if (orderType == OrderType.FULL_RESTRICTED) return "FULL_RESTRICTED"; + if (orderType == OrderType.PARTIAL_RESTRICTED) + return "PARTIAL_RESTRICTED"; + if (orderType == OrderType.CONTRACT) return "CONTRACT"; + + return "UNKNOWN"; + } + + function _basicOrderTypeStr( + BasicOrderType basicOrderType + ) internal pure returns (string memory) { + if (basicOrderType == BasicOrderType.ETH_TO_ERC721_FULL_OPEN) + return "ETH_TO_ERC721_FULL_OPEN"; + if (basicOrderType == BasicOrderType.ETH_TO_ERC721_PARTIAL_OPEN) + return "ETH_TO_ERC721_PARTIAL_OPEN"; + if (basicOrderType == BasicOrderType.ETH_TO_ERC721_FULL_RESTRICTED) + return "ETH_TO_ERC721_FULL_RESTRICTED"; + if (basicOrderType == BasicOrderType.ETH_TO_ERC721_PARTIAL_RESTRICTED) + return "ETH_TO_ERC721_PARTIAL_RESTRICTED"; + if (basicOrderType == BasicOrderType.ETH_TO_ERC1155_FULL_OPEN) + return "ETH_TO_ERC1155_FULL_OPEN"; + if (basicOrderType == BasicOrderType.ETH_TO_ERC1155_PARTIAL_OPEN) + return "ETH_TO_ERC1155_PARTIAL_OPEN"; + if (basicOrderType == BasicOrderType.ETH_TO_ERC1155_FULL_RESTRICTED) + return "ETH_TO_ERC1155_FULL_RESTRICTED"; + if (basicOrderType == BasicOrderType.ETH_TO_ERC1155_PARTIAL_RESTRICTED) + return "ETH_TO_ERC1155_PARTIAL_RESTRICTED"; + if (basicOrderType == BasicOrderType.ERC20_TO_ERC721_FULL_OPEN) + return "ERC20_TO_ERC721_FULL_OPEN"; + if (basicOrderType == BasicOrderType.ERC20_TO_ERC721_PARTIAL_OPEN) + return "ERC20_TO_ERC721_PARTIAL_OPEN"; + if (basicOrderType == BasicOrderType.ERC20_TO_ERC721_FULL_RESTRICTED) + return "ERC20_TO_ERC721_FULL_RESTRICTED"; + if (basicOrderType == BasicOrderType.ERC20_TO_ERC721_PARTIAL_RESTRICTED) + return "ERC20_TO_ERC721_PARTIAL_RESTRICTED"; + if (basicOrderType == BasicOrderType.ERC20_TO_ERC1155_FULL_OPEN) + return "ERC20_TO_ERC1155_FULL_OPEN"; + if (basicOrderType == BasicOrderType.ERC20_TO_ERC1155_PARTIAL_OPEN) + return "ERC20_TO_ERC1155_PARTIAL_OPEN"; + if (basicOrderType == BasicOrderType.ERC20_TO_ERC1155_FULL_RESTRICTED) + return "ERC20_TO_ERC1155_FULL_RESTRICTED"; + if ( + basicOrderType == BasicOrderType.ERC20_TO_ERC1155_PARTIAL_RESTRICTED + ) return "ERC20_TO_ERC1155_PARTIAL_RESTRICTED"; + if (basicOrderType == BasicOrderType.ERC721_TO_ERC20_FULL_OPEN) + return "ERC721_TO_ERC20_FULL_OPEN"; + if (basicOrderType == BasicOrderType.ERC721_TO_ERC20_PARTIAL_OPEN) + return "ERC721_TO_ERC20_PARTIAL_OPEN"; + if (basicOrderType == BasicOrderType.ERC721_TO_ERC20_FULL_RESTRICTED) + return "ERC721_TO_ERC20_FULL_RESTRICTED"; + if (basicOrderType == BasicOrderType.ERC721_TO_ERC20_PARTIAL_RESTRICTED) + return "ERC721_TO_ERC20_PARTIAL_RESTRICTED"; + if (basicOrderType == BasicOrderType.ERC1155_TO_ERC20_FULL_OPEN) + return "ERC1155_TO_ERC20_FULL_OPEN"; + if (basicOrderType == BasicOrderType.ERC1155_TO_ERC20_PARTIAL_OPEN) + return "ERC1155_TO_ERC20_PARTIAL_OPEN"; + if (basicOrderType == BasicOrderType.ERC1155_TO_ERC20_FULL_RESTRICTED) + return "ERC1155_TO_ERC20_FULL_RESTRICTED"; + if ( + basicOrderType == BasicOrderType.ERC1155_TO_ERC20_PARTIAL_RESTRICTED + ) return "ERC1155_TO_ERC20_PARTIAL_RESTRICTED"; + + return "UNKNOWN"; + } + + function _sideStr(Side side) internal pure returns (string memory) { + if (side == Side.OFFER) return "OFFER"; + if (side == Side.CONSIDERATION) return "CONSIDERATION"; + + return "UNKNOWN"; + } +} diff --git a/contracts/helpers/navigator/lib/CriteriaHelperLib.sol b/contracts/helpers/navigator/lib/CriteriaHelperLib.sol index a50a69ac0..6cd661724 100644 --- a/contracts/helpers/navigator/lib/CriteriaHelperLib.sol +++ b/contracts/helpers/navigator/lib/CriteriaHelperLib.sol @@ -72,9 +72,12 @@ library CriteriaHelperLib { function sortByHash( uint256[] memory tokenIds ) internal pure returns (uint256[] memory sortedIds) { + // Instantiate a new array of HashAndIntTuple structs. HashAndIntTuple[] memory toSort = new HashAndIntTuple[]( tokenIds.length ); + + // Populate the array of HashAndIntTuple structs. for (uint256 i = 0; i < tokenIds.length; i++) { toSort[i] = HashAndIntTuple( tokenIds[i], @@ -82,8 +85,10 @@ library CriteriaHelperLib { ); } + // Sort the array of HashAndIntTuple structs. _quickSort(toSort, 0, int256(toSort.length - 1)); + // Populate the sortedIds array with the sorted token ids. sortedIds = new uint256[](tokenIds.length); for (uint256 i = 0; i < tokenIds.length; i++) { sortedIds[i] = toSort[i].num; @@ -97,25 +102,52 @@ library CriteriaHelperLib { function toSortedHashes( uint256[] memory tokenIds ) internal pure returns (bytes32[] memory hashes) { + // Instantiate a new array of hashes. hashes = new bytes32[](tokenIds.length); + + // Sort the token ids by their hashes. uint256[] memory ids = sortByHash(tokenIds); + + // Hash each token id and store it in the hashes array. for (uint256 i; i < ids.length; ++i) { hashes[i] = keccak256(abi.encode(ids[i])); } } + /** + * @dev This function performs the quick sort algorithm to sort an array of + * HashAndIntTuple structs. + * + * @param arr The array of HashAndIntTuple structs to be sorted. + * @param left The starting index of the segment to be sorted. + * @param right The ending index of the segment to be sorted. + */ function _quickSort( HashAndIntTuple[] memory arr, int256 left, int256 right ) internal pure { + // Initialize pointers i and j to the left and right ends of the array + // segment. int256 i = left; int256 j = right; + + // If the segment has one element or none, it's already sorted. if (i == j) return; + + // Pick a 'pivot' element from the middle of the list. bytes32 pivot = arr[uint256(left + (right - left) / 2)].hash; + + // The main loop to rearrange elements around the pivot. while (i <= j) { + // Find an element larger than or equal to the pivot from the left. while (arr[uint256(i)].hash < pivot) i++; + + // Find an element smaller than or equal to the pivot from the + // right. while (pivot < arr[uint256(j)].hash) j--; + + // Swap the elements at i and j if needed. if (i <= j) { (arr[uint256(i)], arr[uint256(j)]) = ( arr[uint256(j)], @@ -125,7 +157,11 @@ library CriteriaHelperLib { j--; } } + + // Recursively sort the segment before 'j'. if (left < j) _quickSort(arr, left, j); + + // Recursively sort the segment after 'i'. if (i < right) _quickSort(arr, i, right); } } diff --git a/contracts/helpers/navigator/lib/HelperItemLib.sol b/contracts/helpers/navigator/lib/HelperItemLib.sol index 824057f8c..c381856aa 100644 --- a/contracts/helpers/navigator/lib/HelperItemLib.sol +++ b/contracts/helpers/navigator/lib/HelperItemLib.sol @@ -17,6 +17,21 @@ library HelperItemLib { */ error UnknownItemType(); + /** + * @dev Normalizes the type of a NavigatorOfferItem based on the presence of + * criteria. This originated in the context of the fuzz tests in + * ./test/foundry/new, where an item might be assigned a pseudorandom + * type and a pseudorandom criteria. In this context, it will just + * correct an incorrect item type. If the item has criteria, ERC721 and + * ERC1155 items will be normalized to ERC721_WITH_CRITERIA and + * ERC1155_WITH_CRITERIA, respectively. Reverts with UnknownItemType if + * the item type is neither ERC721, ERC721_WITH_CRITERIA, ERC1155, nor + * ERC1155_WITH_CRITERIA. + * + * @param item The NavigatorOfferItem to normalize. + * + * @return ItemType The normalized item type. + */ function normalizeType( NavigatorOfferItem memory item ) internal pure returns (ItemType) { @@ -40,6 +55,19 @@ library HelperItemLib { } } + /** + * @dev Normalizes the type of a NavigatorConsiderationItem based on the + * presence of criteria. This originated in the context of the fuzz + * tests in ./test/foundry/new, where an item might be assigned a + * pseudorandom type and a pseudorandom criteriaOrIdentifier. In this + * context, it will just correct an incorrect item type. If the item + * has criteria, ERC721 and ERC1155 items will be normalized to + * ERC721_WITH_CRITERIA and ERC1155_WITH_CRITERIA, respectively. + * + * @param item The NavigatorConsiderationItem to normalize. + * + * @return ItemType The normalized item type. + */ function normalizeType( NavigatorConsiderationItem memory item ) internal pure returns (ItemType) { @@ -66,32 +94,47 @@ library HelperItemLib { function hasCriteria( NavigatorOfferItem memory item ) internal pure returns (bool) { + // Candidate identifiers are passed in by the caller as an array of + // uint256s and converted by Navigator. return item.candidateIdentifiers.length > 0; } function hasCriteria( NavigatorConsiderationItem memory item ) internal pure returns (bool) { + // Candidate identifiers are passed in by the caller as an array of + // uint256s and converted by Navigator. return item.candidateIdentifiers.length > 0; } function validate(NavigatorOfferItem memory item) internal pure { ItemType itemType = item.itemType; + + // If the item has criteria, the item type must be ERC721 or ERC1155. if (itemType == ItemType.ERC20 || itemType == ItemType.NATIVE) { - if (item.candidateIdentifiers.length > 0) { + if (hasCriteria(item)) { revert InvalidItemTypeForCandidateIdentifiers(); } else { return; } } - // If the item has candidate identifiers, the item identifier must be - // zero for wildcard or one of the candidates. + + // If the item has no candidate identifiers, the item identifier must be + // non-zero. + // + // NOTE: This is only called after `item.hasCriteria()` checks + // which ensure that `item.candidateIdentifiers.length > 0` but if it + // were used in other contexts, this would prohibit the use of + // legitimate 0 identifiers. if (item.candidateIdentifiers.length == 0 && item.identifier == 0) { revert InvalidIdentifier( item.identifier, item.candidateIdentifiers ); } + + // If the item has candidate identifiers, the item identifier must be + // zero or wildcard for one of the candidates. if (item.candidateIdentifiers.length > 0) { bool identifierFound; for (uint256 i; i < item.candidateIdentifiers.length; i++) { @@ -111,22 +154,28 @@ library HelperItemLib { function validate(NavigatorConsiderationItem memory item) internal pure { ItemType itemType = item.itemType; + + // If the item has criteria, the item type must be ERC721 or ERC1155. if (itemType == ItemType.ERC20 || itemType == ItemType.NATIVE) { - if (item.candidateIdentifiers.length > 0) { + if (hasCriteria(item)) { revert InvalidItemTypeForCandidateIdentifiers(); } else { return; } } - // If the item has candidate identifiers, the item identifier must be - // zero for wildcard or one of the candidates. + + // If the item has no candidate identifiers, the item identifier must be + // non-zero. if (item.candidateIdentifiers.length == 0 && item.identifier == 0) { revert InvalidIdentifier( item.identifier, item.candidateIdentifiers ); } - if (item.candidateIdentifiers.length > 0) { + + // If the item has candidate identifiers, the item identifier must be + // zero or wildcard for one of the candidates. + if (hasCriteria(item)) { bool identifierFound; for (uint256 i; i < item.candidateIdentifiers.length; i++) { if (item.candidateIdentifiers[i] == item.identifier) { diff --git a/contracts/helpers/navigator/lib/MerkleLib.sol b/contracts/helpers/navigator/lib/MerkleLib.sol index f0be29e0a..26a19edb3 100644 --- a/contracts/helpers/navigator/lib/MerkleLib.sol +++ b/contracts/helpers/navigator/lib/MerkleLib.sol @@ -6,59 +6,91 @@ pragma solidity ^0.8.17; * Murky: https://github.com/dmfxyz/murky */ library MerkleLib { + /** + * @dev Computes the Merkle tree hash of two child nodes. + * + * @param left The hash of the left child node. + * @param right The hash of the right child node. + * + * @return _hash The Merkle tree hash of the two input hashes. + */ function merkleHash( bytes32 left, bytes32 right ) internal pure returns (bytes32 _hash) { assembly { + // Compare the left and right hash to order them lt(left, right) + // returns true if left is less than right switch lt(left, right) + // If left is not less than right, switch the order. case 0 { mstore(0x0, right) mstore(0x20, left) } + // If left is less than right, keep the order. default { mstore(0x0, left) mstore(0x20, right) } - _hash := keccak256(0x0, 0x40) - } - } - function xorkleHash( - bytes32 left, - bytes32 right - ) internal pure returns (bytes32 _hash) { - assembly { - mstore(0x0, xor(left, right)) - _hash := keccak256(0x0, 0x20) + // Compute the keccak256 hash of the 64-byte input (two concatenated + // 32-byte hashes) The result is stored in '_hash' + _hash := keccak256(0x0, 0x40) } } + /** + * @dev Verifies a Merkle proof. + * + * @param root The root of the Merkle tree. + * @param proof An array containing the Merkle proof hashes. + * @param valueToProve The leaf node value to prove membership for. + * @param hashLeafPairs A function to hash pairs of leaf nodes. + * + * @return True if the proof is valid, otherwise false. + */ function verifyProof( bytes32 root, bytes32[] memory proof, bytes32 valueToProve, function(bytes32, bytes32) internal pure returns (bytes32) hashLeafPairs ) internal pure returns (bool) { - // proof length must be less than max array size + // Proof length must be less than max array size. bytes32 rollingHash = valueToProve; uint256 length = proof.length; + + // Loop through each proof element to compute the rolling hash. unchecked { for (uint i = 0; i < length; ++i) { rollingHash = hashLeafPairs(rollingHash, proof[i]); } } + + // The final rolling hash must equal the Merkle root for the proof to be + // valid return root == rollingHash; } + /** + * @dev Computes the Merkle root from an array of leaf node hashes. + * + * @param data An array containing the leaf node hashes. + * @param hashLeafPairs A function to hash pairs of leaf nodes. + * + * @return The Merkle root. + */ function getRoot( bytes32[] memory data, function(bytes32, bytes32) internal pure returns (bytes32) hashLeafPairs ) internal pure returns (bytes32) { require(data.length > 1, "won't generate root for single leaf"); + + // Loop until only the Merkle root remains. while (data.length > 1) { data = hashLevel(data, hashLeafPairs); } + + // Return the computed Merkle root. return data[0]; } diff --git a/contracts/helpers/navigator/lib/NavigatorAdvancedOrderLib.sol b/contracts/helpers/navigator/lib/NavigatorAdvancedOrderLib.sol index 0a3b33949..548a07c84 100644 --- a/contracts/helpers/navigator/lib/NavigatorAdvancedOrderLib.sol +++ b/contracts/helpers/navigator/lib/NavigatorAdvancedOrderLib.sol @@ -27,6 +27,10 @@ library NavigatorAdvancedOrderLib { using HelperItemLib for NavigatorConsiderationItem; using HelperItemLib for NavigatorOfferItem; + /* + * @dev Converts an array of AdvancedOrders to an array of + * NavigatorAdvancedOrders. + */ function fromAdvancedOrders( AdvancedOrder[] memory orders ) internal pure returns (NavigatorAdvancedOrder[] memory) { @@ -38,9 +42,13 @@ library NavigatorAdvancedOrderLib { return helperOrders; } + /* + * @dev Converts an AdvancedOrder to a NavigatorAdvancedOrder. + */ function fromAdvancedOrder( AdvancedOrder memory order ) internal pure returns (NavigatorAdvancedOrder memory) { + // Copy over the offer items. NavigatorOfferItem[] memory offerItems = new NavigatorOfferItem[]( order.parameters.offer.length ); @@ -55,6 +63,8 @@ library NavigatorAdvancedOrderLib { candidateIdentifiers: new uint256[](0) }); } + + // Copy over the consideration items. NavigatorConsiderationItem[] memory considerationItems = new NavigatorConsiderationItem[]( order.parameters.consideration.length @@ -95,15 +105,26 @@ library NavigatorAdvancedOrderLib { }); } + /* + * @dev Converts an array of NavigatorAdvancedOrders to an array of + * AdvancedOrders and an array of CriteriaResolvers. + */ function toAdvancedOrder( NavigatorAdvancedOrder memory order, uint256 orderIndex ) internal pure returns (AdvancedOrder memory, CriteriaResolver[] memory) { + // Create an array of CriteriaResolvers to be populated in the for loop + // below. It might be longer than it needs to be, but it gets trimmed in + // the assembly block below. CriteriaResolver[] memory criteriaResolvers = new CriteriaResolver[]( order.parameters.offer.length + order.parameters.consideration.length ); uint256 criteriaResolverLen; + + // Copy over the offer items, converting candidate identifiers to a + // criteria root if necessary and populating the criteria resolvers + // array. OfferItem[] memory offer = new OfferItem[]( order.parameters.offer.length ); @@ -140,6 +161,10 @@ library NavigatorAdvancedOrderLib { }); } } + + // Copy over the consideration items, converting candidate identifiers + // to a criteria root if necessary and populating the criteria resolvers + // array. ConsiderationItem[] memory consideration = new ConsiderationItem[]( order.parameters.consideration.length ); @@ -216,6 +241,10 @@ library NavigatorAdvancedOrderLib { ); } + /* + * @dev Converts an array of NavigatorAdvancedOrders to an array of + * AdvancedOrders and an array of CriteriaResolvers. + */ function toAdvancedOrders( NavigatorAdvancedOrder[] memory orders ) @@ -223,9 +252,15 @@ library NavigatorAdvancedOrderLib { pure returns (AdvancedOrder[] memory, CriteriaResolver[] memory) { + // Create an array of AdvancedOrders to be populated in the for loop + // below. AdvancedOrder[] memory advancedOrders = new AdvancedOrder[]( orders.length ); + + // Create an array of CriteriaResolvers to be populated in the for loop + // below. It might be longer than it needs to be, but it gets trimmed in + // the assembly block below. uint256 maxCriteriaResolvers; for (uint256 i; i < orders.length; i++) { NavigatorOrderParameters memory parameters = orders[i].parameters; @@ -236,6 +271,9 @@ library NavigatorAdvancedOrderLib { CriteriaResolver[] memory criteriaResolvers = new CriteriaResolver[]( maxCriteriaResolvers ); + + // Copy over the NavigatorAdvancedOrder[] orders to the AdvancedOrder[] + // array, converting and populating the criteria resolvers array. for (uint256 i = 0; i < orders.length; i++) { ( AdvancedOrder memory order, diff --git a/contracts/helpers/navigator/lib/NavigatorContextLib.sol b/contracts/helpers/navigator/lib/NavigatorContextLib.sol index 91742d19c..5b0fd351c 100644 --- a/contracts/helpers/navigator/lib/NavigatorContextLib.sol +++ b/contracts/helpers/navigator/lib/NavigatorContextLib.sol @@ -24,12 +24,20 @@ import { import { ErrorsAndWarnings } from "../../order-validator/SeaportValidator.sol"; library NavigatorContextLib { + /** + * @dev Creates a new NavigatorContext from a NavigatorRequest, which just + * means slotting the request into the context's request field and + * ignoring the response field. + */ function from( NavigatorRequest memory request ) internal pure returns (NavigatorContext memory context) { context.request = request; } + /** + * @dev Adds an empty response to the context. + */ function withEmptyResponse( NavigatorContext memory context ) internal pure returns (NavigatorContext memory) { diff --git a/contracts/helpers/navigator/lib/NavigatorExecutionsLib.sol b/contracts/helpers/navigator/lib/NavigatorExecutionsLib.sol index 8884b1c9c..72b8c0123 100644 --- a/contracts/helpers/navigator/lib/NavigatorExecutionsLib.sol +++ b/contracts/helpers/navigator/lib/NavigatorExecutionsLib.sol @@ -33,8 +33,12 @@ library NavigatorExecutionsLib { function withExecutions( NavigatorContext memory context ) internal pure returns (NavigatorContext memory) { + // Extract the suggested action from the response. bytes memory callData = context.response.suggestedCallData; bytes4 _suggestedAction = bytes4(callData); + + // Create a struct to hold details necessary for fulfillment, populated + // from the context. FulfillmentDetails memory fulfillmentDetails = FulfillmentDetails({ orders: context.response.orderDetails, recipient: payable(context.request.recipient), @@ -44,12 +48,15 @@ library NavigatorExecutionsLib { seaport: address(context.request.seaport) }); + // Initialize the execution arrays. Execution[] memory explicitExecutions; Execution[] memory implicitExecutions; Execution[] memory implicitExecutionsPre; Execution[] memory implicitExecutionsPost; uint256 nativeTokensReturned; + // Call the appropriate method on the FulfillmentDetails struct to get + // the executions. if ( _suggestedAction == ConsiderationInterface.fulfillAvailableOrders.selector || @@ -97,6 +104,8 @@ library NavigatorExecutionsLib { } else { revert UnknownAction(); } + + // Add the executions to the response. context.response.explicitExecutions = explicitExecutions; context.response.implicitExecutions = implicitExecutions; context.response.implicitExecutionsPre = implicitExecutionsPre; diff --git a/test/foundry/ConsiderationStructLogger.t.sol b/test/foundry/ConsiderationStructLogger.t.sol new file mode 100644 index 000000000..c6c263531 --- /dev/null +++ b/test/foundry/ConsiderationStructLogger.t.sol @@ -0,0 +1,382 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import { Test } from "forge-std/Test.sol"; + +import { + AdvancedOrderLib, + ConsiderationItemLib, + FulfillmentComponentLib, + FulfillmentLib, + OfferItemLib, + OrderComponentsLib, + OrderLib, + OrderParametersLib +} from "seaport-sol/src/SeaportSol.sol"; + +import { + AdditionalRecipient, + AdvancedOrder, + BasicOrderParameters, + ConsiderationItem, + CriteriaResolver, + Execution, + Fulfillment, + FulfillmentComponent, + OfferItem, + Order, + OrderComponents, + OrderParameters, + ReceivedItem, + SpentItem, + ZoneParameters +} from "seaport-sol/src/SeaportStructs.sol"; + +import { + BasicOrderType, + ItemType, + OrderType, + Side +} from "seaport-sol/src/SeaportEnums.sol"; + +import { helm } from "../../contracts/helpers/helm.sol"; + +contract helmTest is Test { + using AdvancedOrderLib for AdvancedOrder; + using ConsiderationItemLib for ConsiderationItem; + using ConsiderationItemLib for ConsiderationItem[]; + using FulfillmentComponentLib for FulfillmentComponent; + using FulfillmentComponentLib for FulfillmentComponent[]; + using FulfillmentLib for Fulfillment; + using OfferItemLib for OfferItem; + using OfferItemLib for OfferItem[]; + using OrderComponentsLib for OrderComponents; + using OrderLib for Order; + using OrderParametersLib for OrderParameters; + + using helm for AdvancedOrder; + using helm for BasicOrderParameters; + using helm for CriteriaResolver; + using helm for Execution; + using helm for Fulfillment; + using helm for FulfillmentComponent; + using helm for Order; + using helm for OrderComponents; + using helm for OrderComponents[]; + using helm for OrderParameters; + using helm for ZoneParameters; + + function testLogOrderComponents() public view { + OfferItem[] memory offer = new OfferItem[](2); + offer[0] = OfferItem({ + itemType: ItemType(1), + token: address(0x0), + identifierOrCriteria: 0, + startAmount: 0, + endAmount: 0 + }); + offer[1] = OfferItem({ + itemType: ItemType(2), + token: address(0x01), + identifierOrCriteria: 1, + startAmount: 1, + endAmount: 1 + }); + + ConsiderationItem[] memory consideration = new ConsiderationItem[](2); + consideration[0] = ConsiderationItem({ + itemType: ItemType(1), + token: address(0x0), + identifierOrCriteria: 0, + startAmount: 0, + endAmount: 0, + recipient: payable(0x0) + }); + consideration[1] = ConsiderationItem({ + itemType: ItemType(2), + token: address(0x01), + identifierOrCriteria: 1, + startAmount: 1, + endAmount: 1, + recipient: payable(address(0x01)) + }); + + OrderComponents memory orderComponents = OrderComponents({ + offerer: address(0x0), + zone: address(0x0), + offer: offer, + consideration: consideration, + orderType: OrderType(0), + startTime: 0, + endTime: 0, + zoneHash: bytes32(uint256(0x012345)), + salt: 0, + conduitKey: bytes32(uint256(0x98765)), + counter: 0 + }); + + orderComponents.log(); + helm.log(orderComponents); + + OrderComponents[] memory orderComponentsArray = new OrderComponents[]( + 2 + ); + orderComponentsArray[0] = orderComponents; + orderComponentsArray[1] = orderComponents; + + orderComponentsArray.log(); + } + + function testLogBasicOrderParameters() public view { + AdditionalRecipient[] + memory additionalRecipients = new AdditionalRecipient[](2); + additionalRecipients[0] = AdditionalRecipient({ + recipient: payable(address(0x0)), + amount: 0 + }); + additionalRecipients[1] = AdditionalRecipient({ + recipient: payable(address(0x1)), + amount: 1 + }); + + BasicOrderParameters + memory basicOrderParameters = BasicOrderParameters({ + considerationToken: address(0x0), + considerationIdentifier: 0, + considerationAmount: 0, + offerer: payable(address(0x0)), + zone: address(0x0), + offerToken: address(0x0), + offerIdentifier: 0, + offerAmount: 0, + basicOrderType: BasicOrderType(0), + startTime: 0, + endTime: 0, + zoneHash: bytes32(uint256(0x012345)), + salt: 0, + offererConduitKey: bytes32(uint256(0x98765)), + fulfillerConduitKey: bytes32(uint256(0x5678)), + totalOriginalAdditionalRecipients: 0, + additionalRecipients: new AdditionalRecipient[](0), + signature: bytes( + abi.encodePacked( + type(uint256).max, + (type(uint256).max >> 8) + ) + ) + }); + + basicOrderParameters.log(); + } + + function testLogOrder() public view { + OfferItem[] memory offer = new OfferItem[](2); + offer[0] = OfferItem({ + itemType: ItemType(1), + token: address(0x0), + identifierOrCriteria: 0, + startAmount: 0, + endAmount: 0 + }); + offer[1] = OfferItem({ + itemType: ItemType(2), + token: address(0x01), + identifierOrCriteria: 1, + startAmount: 1, + endAmount: 1 + }); + + ConsiderationItem[] memory consideration = new ConsiderationItem[](2); + consideration[0] = ConsiderationItem({ + itemType: ItemType(1), + token: address(0x0), + identifierOrCriteria: 0, + startAmount: 0, + endAmount: 0, + recipient: payable(0x0) + }); + consideration[1] = ConsiderationItem({ + itemType: ItemType(2), + token: address(0x01), + identifierOrCriteria: 1, + startAmount: 1, + endAmount: 1, + recipient: payable(address(0x01)) + }); + + OrderParameters memory orderParameters = OrderParameters({ + offerer: address(0x0), + zone: address(0x0), + offer: offer, + consideration: consideration, + orderType: OrderType(0), + startTime: 0, + endTime: 0, + zoneHash: bytes32(uint256(0x012345)), + salt: 0, + conduitKey: bytes32(uint256(0x98765)), + totalOriginalConsiderationItems: 0 + }); + + orderParameters.log(); + + Order memory order = Order({ + parameters: orderParameters, + signature: bytes( + abi.encodePacked(type(uint256).max, (type(uint256).max >> 8)) + ) + }); + + order.log(); + + AdvancedOrder memory advancedOrder = AdvancedOrder({ + parameters: orderParameters, + numerator: 0, + denominator: 0, + signature: bytes( + abi.encodePacked(type(uint256).max, (type(uint256).max >> 8)) + ), + extraData: bytes( + abi.encodePacked(type(uint256).max, (type(uint256).max >> 8)) + ) + }); + + advancedOrder.log(); + } + + function testLogCriteriaResolver() public view { + // /** + // * @dev A criteria resolver specifies an order, side (offer vs. consideration), + // * and item index. It then provides a chosen identifier (i.e. tokenId) + // * alongside a merkle proof demonstrating the identifier meets the required + // * criteria. + // */ + // struct CriteriaResolver { + // uint256 orderIndex; + // Side side; + // uint256 index; + // uint256 identifier; + // bytes32[] criteriaProof; + // } + + bytes32[] memory criteriaProof = new bytes32[](2); + criteriaProof[0] = bytes32(uint256(0x012345)); + criteriaProof[1] = bytes32(uint256(0x6789)); + + CriteriaResolver memory criteriaResolver = CriteriaResolver({ + orderIndex: 0, + side: Side(0), + index: 0, + identifier: 0, + criteriaProof: criteriaProof + }); + + criteriaResolver.log(); + } + + function testLogFulfillment() public view { + FulfillmentComponent[] + memory fulfillmentComponents = new FulfillmentComponent[](2); + fulfillmentComponents[0] = FulfillmentComponent({ + orderIndex: 0, + itemIndex: 0 + }); + fulfillmentComponents[1] = FulfillmentComponent({ + orderIndex: 1, + itemIndex: 1 + }); + + fulfillmentComponents[1].log(); + + Fulfillment memory fulfillment = Fulfillment({ + offerComponents: fulfillmentComponents, + considerationComponents: fulfillmentComponents + }); + + fulfillment.log(); + } + + function testLogExecution() public view { + Execution memory execution = Execution({ + item: ReceivedItem({ + itemType: ItemType(1), + token: address(0x0), + identifier: 0, + amount: 0, + recipient: payable(address(0x0)) + }), + offerer: address(0x0), + conduitKey: bytes32(uint256(0x98765)) + }); + + execution.log(); + } + + // /** + // * @dev Restricted orders are validated post-execution by calling validateOrder + // * on the zone. This struct provides context about the order fulfillment + // * and any supplied extraData, as well as all order hashes fulfilled in a + // * call to a match or fulfillAvailable method. + // */ + // struct ZoneParameters { + // bytes32 orderHash; + // address fulfiller; + // address offerer; + // SpentItem[] offer; + // ReceivedItem[] consideration; + // bytes extraData; + // bytes32[] orderHashes; + // uint256 startTime; + // uint256 endTime; + // bytes32 zoneHash; + // } + + function testLogZoneParameters() public view { + SpentItem[] memory offer = new SpentItem[](2); + offer[0] = SpentItem({ + itemType: ItemType(1), + token: address(0x0), + identifier: 0, + amount: 0 + }); + offer[1] = SpentItem({ + itemType: ItemType(2), + token: address(0x01), + identifier: 1, + amount: 1 + }); + + ReceivedItem[] memory consideration = new ReceivedItem[](2); + consideration[0] = ReceivedItem({ + itemType: ItemType(1), + token: address(0x0), + identifier: 0, + amount: 0, + recipient: payable(address(0x0)) + }); + consideration[1] = ReceivedItem({ + itemType: ItemType(2), + token: address(0x01), + identifier: 1, + amount: 1, + recipient: payable(address(0x01)) + }); + + ZoneParameters memory zoneParameters = ZoneParameters({ + orderHash: bytes32(uint256(0x012345)), + fulfiller: address(0x0), + offerer: address(0x0), + offer: offer, + consideration: consideration, + extraData: bytes( + abi.encodePacked(type(uint256).max, (type(uint256).max >> 8)) + ), + orderHashes: new bytes32[](0), + startTime: 0, + endTime: 0, + zoneHash: bytes32(uint256(0x98765)) + }); + + zoneParameters.log(); + } +} From 099f0e7d5f142361b561b9a1681afa77ab329bf9 Mon Sep 17 00:00:00 2001 From: djviau Date: Wed, 13 Sep 2023 16:37:21 -0400 Subject: [PATCH 4/8] remove the "test" file --- test/foundry/ConsiderationStructLogger.t.sol | 382 ------------------- 1 file changed, 382 deletions(-) delete mode 100644 test/foundry/ConsiderationStructLogger.t.sol diff --git a/test/foundry/ConsiderationStructLogger.t.sol b/test/foundry/ConsiderationStructLogger.t.sol deleted file mode 100644 index c6c263531..000000000 --- a/test/foundry/ConsiderationStructLogger.t.sol +++ /dev/null @@ -1,382 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; - -import { Test } from "forge-std/Test.sol"; - -import { - AdvancedOrderLib, - ConsiderationItemLib, - FulfillmentComponentLib, - FulfillmentLib, - OfferItemLib, - OrderComponentsLib, - OrderLib, - OrderParametersLib -} from "seaport-sol/src/SeaportSol.sol"; - -import { - AdditionalRecipient, - AdvancedOrder, - BasicOrderParameters, - ConsiderationItem, - CriteriaResolver, - Execution, - Fulfillment, - FulfillmentComponent, - OfferItem, - Order, - OrderComponents, - OrderParameters, - ReceivedItem, - SpentItem, - ZoneParameters -} from "seaport-sol/src/SeaportStructs.sol"; - -import { - BasicOrderType, - ItemType, - OrderType, - Side -} from "seaport-sol/src/SeaportEnums.sol"; - -import { helm } from "../../contracts/helpers/helm.sol"; - -contract helmTest is Test { - using AdvancedOrderLib for AdvancedOrder; - using ConsiderationItemLib for ConsiderationItem; - using ConsiderationItemLib for ConsiderationItem[]; - using FulfillmentComponentLib for FulfillmentComponent; - using FulfillmentComponentLib for FulfillmentComponent[]; - using FulfillmentLib for Fulfillment; - using OfferItemLib for OfferItem; - using OfferItemLib for OfferItem[]; - using OrderComponentsLib for OrderComponents; - using OrderLib for Order; - using OrderParametersLib for OrderParameters; - - using helm for AdvancedOrder; - using helm for BasicOrderParameters; - using helm for CriteriaResolver; - using helm for Execution; - using helm for Fulfillment; - using helm for FulfillmentComponent; - using helm for Order; - using helm for OrderComponents; - using helm for OrderComponents[]; - using helm for OrderParameters; - using helm for ZoneParameters; - - function testLogOrderComponents() public view { - OfferItem[] memory offer = new OfferItem[](2); - offer[0] = OfferItem({ - itemType: ItemType(1), - token: address(0x0), - identifierOrCriteria: 0, - startAmount: 0, - endAmount: 0 - }); - offer[1] = OfferItem({ - itemType: ItemType(2), - token: address(0x01), - identifierOrCriteria: 1, - startAmount: 1, - endAmount: 1 - }); - - ConsiderationItem[] memory consideration = new ConsiderationItem[](2); - consideration[0] = ConsiderationItem({ - itemType: ItemType(1), - token: address(0x0), - identifierOrCriteria: 0, - startAmount: 0, - endAmount: 0, - recipient: payable(0x0) - }); - consideration[1] = ConsiderationItem({ - itemType: ItemType(2), - token: address(0x01), - identifierOrCriteria: 1, - startAmount: 1, - endAmount: 1, - recipient: payable(address(0x01)) - }); - - OrderComponents memory orderComponents = OrderComponents({ - offerer: address(0x0), - zone: address(0x0), - offer: offer, - consideration: consideration, - orderType: OrderType(0), - startTime: 0, - endTime: 0, - zoneHash: bytes32(uint256(0x012345)), - salt: 0, - conduitKey: bytes32(uint256(0x98765)), - counter: 0 - }); - - orderComponents.log(); - helm.log(orderComponents); - - OrderComponents[] memory orderComponentsArray = new OrderComponents[]( - 2 - ); - orderComponentsArray[0] = orderComponents; - orderComponentsArray[1] = orderComponents; - - orderComponentsArray.log(); - } - - function testLogBasicOrderParameters() public view { - AdditionalRecipient[] - memory additionalRecipients = new AdditionalRecipient[](2); - additionalRecipients[0] = AdditionalRecipient({ - recipient: payable(address(0x0)), - amount: 0 - }); - additionalRecipients[1] = AdditionalRecipient({ - recipient: payable(address(0x1)), - amount: 1 - }); - - BasicOrderParameters - memory basicOrderParameters = BasicOrderParameters({ - considerationToken: address(0x0), - considerationIdentifier: 0, - considerationAmount: 0, - offerer: payable(address(0x0)), - zone: address(0x0), - offerToken: address(0x0), - offerIdentifier: 0, - offerAmount: 0, - basicOrderType: BasicOrderType(0), - startTime: 0, - endTime: 0, - zoneHash: bytes32(uint256(0x012345)), - salt: 0, - offererConduitKey: bytes32(uint256(0x98765)), - fulfillerConduitKey: bytes32(uint256(0x5678)), - totalOriginalAdditionalRecipients: 0, - additionalRecipients: new AdditionalRecipient[](0), - signature: bytes( - abi.encodePacked( - type(uint256).max, - (type(uint256).max >> 8) - ) - ) - }); - - basicOrderParameters.log(); - } - - function testLogOrder() public view { - OfferItem[] memory offer = new OfferItem[](2); - offer[0] = OfferItem({ - itemType: ItemType(1), - token: address(0x0), - identifierOrCriteria: 0, - startAmount: 0, - endAmount: 0 - }); - offer[1] = OfferItem({ - itemType: ItemType(2), - token: address(0x01), - identifierOrCriteria: 1, - startAmount: 1, - endAmount: 1 - }); - - ConsiderationItem[] memory consideration = new ConsiderationItem[](2); - consideration[0] = ConsiderationItem({ - itemType: ItemType(1), - token: address(0x0), - identifierOrCriteria: 0, - startAmount: 0, - endAmount: 0, - recipient: payable(0x0) - }); - consideration[1] = ConsiderationItem({ - itemType: ItemType(2), - token: address(0x01), - identifierOrCriteria: 1, - startAmount: 1, - endAmount: 1, - recipient: payable(address(0x01)) - }); - - OrderParameters memory orderParameters = OrderParameters({ - offerer: address(0x0), - zone: address(0x0), - offer: offer, - consideration: consideration, - orderType: OrderType(0), - startTime: 0, - endTime: 0, - zoneHash: bytes32(uint256(0x012345)), - salt: 0, - conduitKey: bytes32(uint256(0x98765)), - totalOriginalConsiderationItems: 0 - }); - - orderParameters.log(); - - Order memory order = Order({ - parameters: orderParameters, - signature: bytes( - abi.encodePacked(type(uint256).max, (type(uint256).max >> 8)) - ) - }); - - order.log(); - - AdvancedOrder memory advancedOrder = AdvancedOrder({ - parameters: orderParameters, - numerator: 0, - denominator: 0, - signature: bytes( - abi.encodePacked(type(uint256).max, (type(uint256).max >> 8)) - ), - extraData: bytes( - abi.encodePacked(type(uint256).max, (type(uint256).max >> 8)) - ) - }); - - advancedOrder.log(); - } - - function testLogCriteriaResolver() public view { - // /** - // * @dev A criteria resolver specifies an order, side (offer vs. consideration), - // * and item index. It then provides a chosen identifier (i.e. tokenId) - // * alongside a merkle proof demonstrating the identifier meets the required - // * criteria. - // */ - // struct CriteriaResolver { - // uint256 orderIndex; - // Side side; - // uint256 index; - // uint256 identifier; - // bytes32[] criteriaProof; - // } - - bytes32[] memory criteriaProof = new bytes32[](2); - criteriaProof[0] = bytes32(uint256(0x012345)); - criteriaProof[1] = bytes32(uint256(0x6789)); - - CriteriaResolver memory criteriaResolver = CriteriaResolver({ - orderIndex: 0, - side: Side(0), - index: 0, - identifier: 0, - criteriaProof: criteriaProof - }); - - criteriaResolver.log(); - } - - function testLogFulfillment() public view { - FulfillmentComponent[] - memory fulfillmentComponents = new FulfillmentComponent[](2); - fulfillmentComponents[0] = FulfillmentComponent({ - orderIndex: 0, - itemIndex: 0 - }); - fulfillmentComponents[1] = FulfillmentComponent({ - orderIndex: 1, - itemIndex: 1 - }); - - fulfillmentComponents[1].log(); - - Fulfillment memory fulfillment = Fulfillment({ - offerComponents: fulfillmentComponents, - considerationComponents: fulfillmentComponents - }); - - fulfillment.log(); - } - - function testLogExecution() public view { - Execution memory execution = Execution({ - item: ReceivedItem({ - itemType: ItemType(1), - token: address(0x0), - identifier: 0, - amount: 0, - recipient: payable(address(0x0)) - }), - offerer: address(0x0), - conduitKey: bytes32(uint256(0x98765)) - }); - - execution.log(); - } - - // /** - // * @dev Restricted orders are validated post-execution by calling validateOrder - // * on the zone. This struct provides context about the order fulfillment - // * and any supplied extraData, as well as all order hashes fulfilled in a - // * call to a match or fulfillAvailable method. - // */ - // struct ZoneParameters { - // bytes32 orderHash; - // address fulfiller; - // address offerer; - // SpentItem[] offer; - // ReceivedItem[] consideration; - // bytes extraData; - // bytes32[] orderHashes; - // uint256 startTime; - // uint256 endTime; - // bytes32 zoneHash; - // } - - function testLogZoneParameters() public view { - SpentItem[] memory offer = new SpentItem[](2); - offer[0] = SpentItem({ - itemType: ItemType(1), - token: address(0x0), - identifier: 0, - amount: 0 - }); - offer[1] = SpentItem({ - itemType: ItemType(2), - token: address(0x01), - identifier: 1, - amount: 1 - }); - - ReceivedItem[] memory consideration = new ReceivedItem[](2); - consideration[0] = ReceivedItem({ - itemType: ItemType(1), - token: address(0x0), - identifier: 0, - amount: 0, - recipient: payable(address(0x0)) - }); - consideration[1] = ReceivedItem({ - itemType: ItemType(2), - token: address(0x01), - identifier: 1, - amount: 1, - recipient: payable(address(0x01)) - }); - - ZoneParameters memory zoneParameters = ZoneParameters({ - orderHash: bytes32(uint256(0x012345)), - fulfiller: address(0x0), - offerer: address(0x0), - offer: offer, - consideration: consideration, - extraData: bytes( - abi.encodePacked(type(uint256).max, (type(uint256).max >> 8)) - ), - orderHashes: new bytes32[](0), - startTime: 0, - endTime: 0, - zoneHash: bytes32(uint256(0x98765)) - }); - - zoneParameters.log(); - } -} From 1db489605254a57b851f599c63e991b0c779ce33 Mon Sep 17 00:00:00 2001 From: djviau Date: Thu, 14 Sep 2023 10:35:46 -0400 Subject: [PATCH 5/8] add a nav test for returned native tokens --- test/foundry/new/SeaportNavigator.t.sol | 152 ++++++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/test/foundry/new/SeaportNavigator.t.sol b/test/foundry/new/SeaportNavigator.t.sol index 39f946cc0..1a084b6ab 100644 --- a/test/foundry/new/SeaportNavigator.t.sol +++ b/test/foundry/new/SeaportNavigator.t.sol @@ -55,6 +55,8 @@ import { SeaportValidatorTest } from "./SeaportValidatorTest.sol"; import { SeaportNavigatorTest } from "./SeaportNavigatorTest.sol"; +import { TestERC721 } from "../../../contracts/test/TestERC721.sol"; + contract SeaportNavigatorTestSuite is BaseOrderTest, SeaportValidatorTest, @@ -355,6 +357,156 @@ contract SeaportNavigatorTestSuite is ); } + function test_simpleOrderWithNativeReturned() public { + NavigatorAdvancedOrder[] memory orders = new NavigatorAdvancedOrder[]( + 1 + ); + + Order memory order = OrderLib.fromDefault(SINGLE_ERC721).copy(); + AdvancedOrder memory advancedOrder = order.toAdvancedOrder( + 1, + 1, + "dummy" + ); + + address offerer = offerer1.addr; + OfferItem memory item = advancedOrder.parameters.offer[0]; + TestERC721(item.token).mint(offerer, item.identifierOrCriteria); + vm.prank(offerer); + TestERC721(item.token).setApprovalForAll(address(seaport), true); + + ConsiderationItem[] memory consideration = new ConsiderationItem[](1); + consideration[0] = ConsiderationItemLib + .empty() + .withItemType(ItemType.NATIVE) + .withToken(address(0)) + .withAmount(1 ether) + .withRecipient(offerer); + + advancedOrder.parameters = advancedOrder + .parameters + .withTotalConsideration(consideration) + .withOfferer(offerer); + + uint256 counter = getSeaport().getCounter(offerer1.addr); + bytes32 orderHash = getSeaport().getOrderHash( + advancedOrder.parameters.toOrderComponents(counter) + ); + advancedOrder = advancedOrder.withSignature( + signOrder(getSeaport(), offerer1.key, orderHash) + ); + + orders[0] = NavigatorAdvancedOrderLib.fromAdvancedOrder(advancedOrder); + + FulfillmentStrategy memory fulfillmentStrategy = FulfillmentStrategy({ + aggregationStrategy: AggregationStrategy.MAXIMUM, + fulfillAvailableStrategy: FulfillAvailableStrategy.KEEP_ALL, + matchStrategy: MatchStrategy.MAX_INCLUSION + }); + + NavigatorResponse memory res = navigator.prepare( + NavigatorRequest({ + seaport: seaport, + validator: validator, + orders: orders, + caller: address(this), + nativeTokensSupplied: 2 ether, + fulfillerConduitKey: bytes32(0), + recipient: address(this), + maximumFulfilled: 1, + seed: 0, + fulfillmentStrategy: fulfillmentStrategy, + criteriaResolvers: new CriteriaResolver[](0), + preferMatch: false + }) + ); + + assertEq( + res.suggestedActionName, + "fulfillAdvancedOrder", + "unexpected actionName selected" + ); + assertEq( + res.suggestedCallData, + abi.encodeCall( + ConsiderationInterface.fulfillAdvancedOrder, + ( + advancedOrder, + new CriteriaResolver[](0), + bytes32(0), + address(this) + ) + ), + "unexpected suggested calldata" + ); + assertEq( + res.validationErrors.length, + 1, + "unexpected validationErrors length" + ); + assertEq( + res.validationErrors[0].errors.length, + 0, + "unexpected validationErrors[0].errors length" + ); + assertEq(res.orderDetails.length, 1, "unexpected orderDetails length"); + assertEq( + res.offerFulfillments.length, + 1, + "unexpected offerFulfillments length" + ); + assertEq( + res.considerationFulfillments.length, + 1, + "unexpected considerationFulfillments length" + ); + assertEq(res.fulfillments.length, 0, "unexpected fulfillments length"); + // Specific to match* methods. + assertEq( + res.unspentOfferComponents.length, + 1, + "unexpected unspentOfferComponents length" + ); + // Specific to match* methods. + assertEq( + res.unmetConsiderationComponents.length, + 1, + "unexpected unmetConsiderationComponents length" + ); + // No fulfillment related stuff in this case, so no explicit executions. + assertEq( + res.explicitExecutions.length, + 0, + "unexpected explicitExecutions length" + ); + + // 2 ether to seaport + // ERC721 from seller to buyer + // 1 ether from seaport to buyer + // 1 ether from buyer to seller + assertEq( + res.implicitExecutions.length, + 4, + "unexpected implicitExecutions length" + ); + + assertEq( + res.implicitExecutionsPre.length, + 0, + "unexpected implicitExecutionsPre length" + ); + assertEq( + res.implicitExecutionsPost.length, + 0, + "unexpected implicitExecutionsPost length" + ); + assertEq( + res.nativeTokensReturned, + 1 ether, + "unexpected nativeTokensReturned amount" + ); + } + function test_inferredCriteria() public { NavigatorAdvancedOrder[] memory orders = new NavigatorAdvancedOrder[]( 1 From d48dbf761278681350bcffa9c50a7648a454235c Mon Sep 17 00:00:00 2001 From: djviau Date: Thu, 14 Sep 2023 10:44:43 -0400 Subject: [PATCH 6/8] put helm in a less disruptive place --- {contracts/helpers => test/foundry/utils}/helm.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename {contracts/helpers => test/foundry/utils}/helm.sol (99%) diff --git a/contracts/helpers/helm.sol b/test/foundry/utils/helm.sol similarity index 99% rename from contracts/helpers/helm.sol rename to test/foundry/utils/helm.sol index 5a45a8201..4a950275e 100644 --- a/contracts/helpers/helm.sol +++ b/test/foundry/utils/helm.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.13; -import "forge-std/console.sol"; +import { console } from "forge-std/console.sol"; +// import { console2 as console } from "forge-std/console2.sol"; import { LibString } from "solady/src/utils/LibString.sol"; From d3be694cbeab77c4b15af18fa22a7e087dc5a088 Mon Sep 17 00:00:00 2001 From: djviau Date: Thu, 14 Sep 2023 13:27:24 -0400 Subject: [PATCH 7/8] fix test failure presumably related to a foundry update --- test/foundry/FulfillOrderTest.t.sol | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/test/foundry/FulfillOrderTest.t.sol b/test/foundry/FulfillOrderTest.t.sol index 761961d94..6cf179d93 100644 --- a/test/foundry/FulfillOrderTest.t.sol +++ b/test/foundry/FulfillOrderTest.t.sol @@ -2,18 +2,21 @@ pragma solidity ^0.8.17; -import { OrderType, ItemType } from "seaport-types/src/lib/ConsiderationEnums.sol"; +import { + ItemType, + OrderType +} from "seaport-types/src/lib/ConsiderationEnums.sol"; import { ConsiderationInterface } from "seaport-types/src/interfaces/ConsiderationInterface.sol"; import { - Order, - OfferItem, - OrderParameters, ConsiderationItem, - OrderComponents + OfferItem, + Order, + OrderComponents, + OrderParameters } from "seaport-types/src/lib/ConsiderationStructs.sol"; import { BaseOrderTest } from "./utils/BaseOrderTest.sol"; @@ -2548,6 +2551,10 @@ contract FulfillOrderTest is BaseOrderTest { function fulfillOrderRevertCounterIncremented( Context memory context ) external stateless { + // Roll to a high block to get a blockhash that's high enough to produce + // a non-0 value when right shifted by 128 bits. + vm.roll(type(uint248).max); + test1155_1.mint(bob, 1, 1); addErc1155OfferItem(1, 1); addEthConsiderationItem(payable(bob), 1); From 09d715ef7aace7dae3b95b0a482fe43d6e183109 Mon Sep 17 00:00:00 2001 From: djviau Date: Mon, 18 Sep 2023 15:57:40 -0400 Subject: [PATCH 8/8] remove helm --- test/foundry/utils/helm.sol | 706 ------------------------------------ 1 file changed, 706 deletions(-) delete mode 100644 test/foundry/utils/helm.sol diff --git a/test/foundry/utils/helm.sol b/test/foundry/utils/helm.sol deleted file mode 100644 index 4a950275e..000000000 --- a/test/foundry/utils/helm.sol +++ /dev/null @@ -1,706 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.13; - -import { console } from "forge-std/console.sol"; -// import { console2 as console } from "forge-std/console2.sol"; - -import { LibString } from "solady/src/utils/LibString.sol"; - -import { - BasicOrderType, - ItemType, - OrderType, - Side -} from "seaport-types/src/lib/ConsiderationEnums.sol"; - -import { - AdditionalRecipient, - AdvancedOrder, - BasicOrderParameters, - ConsiderationItem, - CriteriaResolver, - Execution, - Fulfillment, - FulfillmentComponent, - OfferItem, - Order, - OrderComponents, - OrderParameters, - ReceivedItem, - SpentItem, - ZoneParameters -} from "seaport-types/src/lib/ConsiderationStructs.sol"; - -/** - * @title helm - * @author snotrocket.eth - * @notice helm is an extension of the console.sol library that provides - * additional logging functionality for Seaport structs. - */ -library helm { - function log(OrderComponents memory orderComponents) public view { - logOrderComponents(orderComponents, 0); - } - - function log(OrderComponents[] memory orderComponentsArray) public view { - console.log(gStr(0, "orderComponentsArray: [")); - for (uint256 j = 0; j < orderComponentsArray.length; j++) { - logOrderComponents(orderComponentsArray[j], 1); - } - console.log(gStr(0, "]")); - } - - function logOrderComponents( - OrderComponents memory oc, - uint256 i // indent - ) internal view { - console.log(gStr(i, "OrderComponents: {")); - console.log(gStr(i + 1, "offerer", oc.offerer)); - console.log(gStr(i + 1, "zone", oc.zone)); - logOffer(oc.offer, i + 1); - logConsideration(oc.consideration, i + 1); - console.log(gStr(i + 1, "orderType", _orderTypeStr(oc.orderType))); - console.log(gStr(i + 1, "startTime", oc.startTime)); - console.log(gStr(i + 1, "endTime", oc.endTime)); - console.log(gStr(i + 1, "zoneHash", oc.zoneHash)); - console.log(gStr(i + 1, "salt", oc.salt)); - console.log(gStr(i + 1, "conduitKey", oc.conduitKey)); - console.log(gStr(i + 1, "counter", oc.counter)); - console.log(gStr(i, "}")); - } - - function log(OfferItem memory offerItem) public view { - logOfferItem(offerItem, 0); - } - - function log(OfferItem[] memory offerItemArray) public view { - console.log(gStr(0, "offerItemArray: [")); - for (uint256 j = 0; j < offerItemArray.length; j++) { - logOfferItem(offerItemArray[j], 1); - } - console.log(gStr(0, "]")); - } - - function logOfferItem( - OfferItem memory oi, - uint256 i // indent - ) internal view { - console.log(gStr(i, "OfferItem: {")); - console.log(gStr(i + 1, "itemType", _itemTypeStr(oi.itemType))); - console.log(gStr(i + 1, "token", oi.token)); - console.log( - gStr(i + 1, "identifierOrCriteria", oi.identifierOrCriteria) - ); - console.log(gStr(i + 1, "startAmount", oi.startAmount)); - console.log(gStr(i + 1, "endAmount", oi.endAmount)); - console.log(gStr(i, "}")); - } - - function log(ConsiderationItem memory considerationItem) public view { - logConsiderationItem(considerationItem, 0); - } - - function log( - ConsiderationItem[] memory considerationItemArray - ) public view { - console.log(gStr(0, "considerationItemArray: [")); - for (uint256 j = 0; j < considerationItemArray.length; j++) { - logConsiderationItem(considerationItemArray[j], 1); - } - console.log(gStr(0, "]")); - } - - function logConsiderationItem( - ConsiderationItem memory ci, - uint256 i // indent - ) internal view { - console.log(gStr(i, "ConsiderationItem: {")); - console.log(gStr(i + 1, "itemType", _itemTypeStr(ci.itemType))); - console.log(gStr(i + 1, "token", ci.token)); - console.log( - gStr(i + 1, "identifierOrCriteria", ci.identifierOrCriteria) - ); - console.log(gStr(i + 1, "startAmount", ci.startAmount)); - console.log(gStr(i + 1, "endAmount", ci.endAmount)); - console.log(gStr(i, "}")); - } - - function log(SpentItem memory spentItem) public view { - logSpentItem(spentItem, 0); - } - - function log(SpentItem[] memory spentItemArray) public view { - console.log(gStr(0, "spentItemArray: [")); - for (uint256 j = 0; j < spentItemArray.length; j++) { - logSpentItem(spentItemArray[j], 1); - } - console.log(gStr(0, "]")); - } - - function logSpentItem( - SpentItem memory si, - uint256 i // indent - ) internal view { - console.log(gStr(i, "SpentItem: {")); - console.log(gStr(i + 1, "itemType", _itemTypeStr(si.itemType))); - console.log(gStr(i + 1, "token", si.token)); - console.log(gStr(i + 1, "identifier", si.identifier)); - console.log(gStr(i + 1, "amount", si.amount)); - console.log(gStr(i, "}")); - } - - function log(ReceivedItem memory receivedItem) public view { - logReceivedItem(receivedItem, 0); - } - - function log(ReceivedItem[] memory receivedItemArray) public view { - console.log(gStr(0, "receivedItemArray: [")); - for (uint256 j = 0; j < receivedItemArray.length; j++) { - logReceivedItem(receivedItemArray[j], 1); - } - console.log(gStr(0, "]")); - } - - function logReceivedItem( - ReceivedItem memory ri, - uint256 i // indent - ) internal view { - console.log(gStr(i, "ReceivedItem: {")); - console.log(gStr(i + 1, "itemType", _itemTypeStr(ri.itemType))); - console.log(gStr(i + 1, "token", ri.token)); - console.log(gStr(i + 1, "identifier", ri.identifier)); - console.log(gStr(i + 1, "amount", ri.amount)); - console.log(gStr(i + 1, "recipient", ri.recipient)); - console.log(gStr(i, "}")); - } - - function log(BasicOrderParameters memory basicOrderParameters) public view { - logBasicOrderParameters(basicOrderParameters, 0); - } - - function log( - BasicOrderParameters[] memory basicOrderParametersArray - ) public view { - console.log(gStr(0, "basicOrderParametersArray: [")); - for (uint256 j = 0; j < basicOrderParametersArray.length; j++) { - logBasicOrderParameters(basicOrderParametersArray[j], 1); - } - console.log(gStr(0, "]")); - } - - function logBasicOrderParameters( - BasicOrderParameters memory bop, - uint256 i // indent - ) internal view { - console.log(gStr(i, "BasicOrderParameters: {")); - console.log(gStr(i + 1, "considerationToken", bop.considerationToken)); - console.log( - gStr(i + 1, "considerationIdentifier", bop.considerationIdentifier) - ); - console.log( - gStr(i + 1, "considerationAmount", bop.considerationAmount) - ); - console.log(gStr(i + 1, "offerer", bop.offerer)); - console.log(gStr(i + 1, "zone", bop.zone)); - console.log(gStr(i + 1, "offerToken", bop.offerToken)); - console.log(gStr(i + 1, "offerIdentifier", bop.offerIdentifier)); - console.log(gStr(i + 1, "offerAmount", bop.offerAmount)); - console.log( - gStr( - i + 1, - "basicOrderType", - _basicOrderTypeStr(bop.basicOrderType) - ) - ); - console.log(gStr(i + 1, "startTime", bop.startTime)); - console.log(gStr(i + 1, "endTime", bop.endTime)); - console.log(gStr(i + 1, "zoneHash", bop.zoneHash)); - console.log(gStr(i + 1, "salt", bop.salt)); - console.log(gStr(i + 1, "offererConduitKey", bop.offererConduitKey)); - console.log( - gStr(i + 1, "fulfillerConduitKey", bop.fulfillerConduitKey) - ); - console.log( - gStr( - i + 1, - "totalOriginalAdditionalRecipients", - bop.totalOriginalAdditionalRecipients - ) - ); - console.log(gStr(i + 1, "additionalRecipients: [")); - for (uint256 j = 0; j < bop.additionalRecipients.length; j++) { - logAdditionalRecipient(bop.additionalRecipients[j], i + 1); - } - console.log(gStr(i + 1, "]")); - console.log(gStr(i + 1, "signature", bop.signature)); - console.log(gStr(i, "}")); - } - - function log(AdditionalRecipient memory additionalRecipient) public view { - logAdditionalRecipient(additionalRecipient, 0); - } - - function log( - AdditionalRecipient[] memory additionalRecipientArray - ) public view { - console.log(gStr(0, "additionalRecipientArray: [")); - for (uint256 j = 0; j < additionalRecipientArray.length; j++) { - logAdditionalRecipient(additionalRecipientArray[j], 1); - } - console.log(gStr(0, "]")); - } - - function logAdditionalRecipient( - AdditionalRecipient memory ar, - uint256 i // indent - ) internal view { - console.log(gStr(i, "AdditionalRecipient: {")); - console.log(gStr(i + 1, "recipient", ar.recipient)); - console.log(gStr(i + 1, "amount", ar.amount)); - console.log(gStr(i, "}")); - } - - function log(OrderParameters memory orderParameters) public view { - logOrderParameters(orderParameters, 0); - } - - function log(OrderParameters[] memory orderParametersArray) public view { - console.log(gStr(0, "orderParametersArray: [")); - for (uint256 j = 0; j < orderParametersArray.length; j++) { - logOrderParameters(orderParametersArray[j], 1); - } - console.log(gStr(0, "]")); - } - - function logOrderParameters( - OrderParameters memory op, - uint256 i // indent - ) internal view { - console.log(gStr(i, "OrderParameters: {")); - console.log(gStr(i + 1, "offerer", op.offerer)); - console.log(gStr(i + 1, "zone", op.zone)); - logOffer(op.offer, i + 1); - logConsideration(op.consideration, i + 1); - console.log(gStr(i + 1, "orderType", _orderTypeStr(op.orderType))); - console.log(gStr(i + 1, "startTime", op.startTime)); - console.log(gStr(i + 1, "endTime", op.endTime)); - console.log(gStr(i + 1, "zoneHash", op.zoneHash)); - console.log(gStr(i + 1, "salt", op.salt)); - console.log(gStr(i + 1, "conduitKey", op.conduitKey)); - console.log( - gStr( - i + 1, - "totalOriginalConsiderationItems", - op.totalOriginalConsiderationItems - ) - ); - console.log(gStr(i, "}")); - } - - function log(Order memory order) public view { - logOrder(order, 0); - } - - function log(Order[] memory orderArray) public view { - console.log(gStr(0, "orderArray: [")); - for (uint256 j = 0; j < orderArray.length; j++) { - logOrder(orderArray[j], 1); - } - console.log(gStr(0, "]")); - } - - function logOrder( - Order memory order, - uint256 i /* indent */ - ) internal view { - console.log(gStr(i, "Order: {")); - logOrderParameters(order.parameters, i + 1); - console.log(gStr(i + 1, "signature", order.signature)); - console.log(gStr(i, "}")); - } - - function log(AdvancedOrder memory advancedOrder) public view { - logAdvancedOrder(advancedOrder, 0); - } - - function log(AdvancedOrder[] memory advancedOrderArray) public view { - console.log(gStr(0, "advancedOrderArray: [")); - for (uint256 j = 0; j < advancedOrderArray.length; j++) { - logAdvancedOrder(advancedOrderArray[j], 1); - } - console.log(gStr(0, "]")); - } - - function logAdvancedOrder( - AdvancedOrder memory advancedOrder, - uint256 i // indent - ) internal view { - console.log(gStr(i, "AdvancedOrder: {")); - logOrderParameters(advancedOrder.parameters, i + 1); - console.log(gStr(i + 1, "numerator", advancedOrder.numerator)); - console.log(gStr(i + 1, "denominator", advancedOrder.denominator)); - console.log(gStr(i + 1, "signature", advancedOrder.signature)); - console.log(gStr(i + 1, "extraData", advancedOrder.extraData)); - console.log(gStr(i, "}")); - } - - function log(CriteriaResolver memory criteriaResolver) public view { - logCriteriaResolver(criteriaResolver, 0); - } - - function log(CriteriaResolver[] memory criteriaResolverArray) public view { - console.log(gStr(0, "criteriaResolverArray: [")); - for (uint256 j = 0; j < criteriaResolverArray.length; j++) { - logCriteriaResolver(criteriaResolverArray[j], 1); - } - console.log(gStr(0, "]")); - } - - function logCriteriaResolver( - CriteriaResolver memory cr, - uint256 i // indent - ) internal view { - console.log(gStr(i, "CriteriaResolver: {")); - console.log(gStr(i + 1, "orderIndex", cr.orderIndex)); - console.log(gStr(i + 1, "side", _sideStr(cr.side))); - console.log(gStr(i + 1, "index", cr.index)); - console.log(gStr(i + 1, "identifier", cr.identifier)); - for (uint256 j = 0; j < cr.criteriaProof.length; j++) { - console.log(gStr(i + 2, "criteriaProof", cr.criteriaProof[j])); - } - console.log(gStr(i, "}")); - } - - function log(Fulfillment memory fulfillment) public view { - logFulfillment(fulfillment, 0); - } - - function log(Fulfillment[] memory fulfillmentArray) public view { - console.log(gStr(0, "fulfillmentArray: [")); - for (uint256 j = 0; j < fulfillmentArray.length; j++) { - logFulfillment(fulfillmentArray[j], 1); - } - console.log(gStr(0, "]")); - } - - function logFulfillment( - Fulfillment memory f, - uint256 i // indent - ) internal view { - console.log(gStr(i, "Fulfillment: {")); - console.log(gStr(i + 1, "offerComponents: [")); - for (uint256 j = 0; j < f.offerComponents.length; j++) { - logFulfillmentComponent(f.offerComponents[j], i + 2); - } - console.log(gStr(i + 1, "]")); - console.log(gStr(i + 1, "considerationComponents: [")); - for (uint256 j = 0; j < f.considerationComponents.length; j++) { - logFulfillmentComponent(f.considerationComponents[j], i + 2); - } - console.log(gStr(i + 1, "]")); - console.log(gStr(i, "}")); - } - - function log(FulfillmentComponent memory fulfillmentComponent) public view { - logFulfillmentComponent(fulfillmentComponent, 0); - } - - function log( - FulfillmentComponent[] memory fulfillmentComponentArray - ) public view { - console.log(gStr(0, "fulfillmentComponentArray: [")); - for (uint256 j = 0; j < fulfillmentComponentArray.length; j++) { - logFulfillmentComponent(fulfillmentComponentArray[j], 1); - } - console.log(gStr(0, "]")); - } - - function logFulfillmentComponent( - FulfillmentComponent memory fc, - uint256 i // indent - ) internal view { - console.log(gStr(i, "FulfillmentComponent: {")); - console.log(gStr(i + 1, "orderIndex", fc.orderIndex)); - console.log(gStr(i + 1, "itemIndex", fc.itemIndex)); - console.log(gStr(i, "}")); - } - - function log(Execution memory execution) public view { - logExecution(execution, 0); - } - - function log(Execution[] memory executionArray) public view { - console.log(gStr(0, "executionArray: [")); - for (uint256 j = 0; j < executionArray.length; j++) { - logExecution(executionArray[j], 1); - } - console.log(gStr(0, "]")); - } - - function logExecution( - Execution memory execution, - uint256 i // indent - ) internal view { - console.log(gStr(i, "Execution: {")); - logReceivedItem(execution.item, i + 1); - console.log(gStr(i + 1, "offerer", execution.offerer)); - console.log(gStr(i + 1, "conduitKey", execution.conduitKey)); - console.log(gStr(i, "}")); - } - - function log(ZoneParameters memory zoneParameters) public view { - logZoneParameters(zoneParameters, 0); - } - - function log(ZoneParameters[] memory zoneParametersArray) public view { - console.log(gStr(0, "zoneParametersArray: [")); - for (uint256 j = 0; j < zoneParametersArray.length; j++) { - logZoneParameters(zoneParametersArray[j], 1); - } - console.log(gStr(0, "]")); - } - - function logZoneParameters( - ZoneParameters memory zp, - uint256 i // indent - ) internal view { - console.log(gStr(i, "ZoneParameters: {")); - console.log(gStr(i + 1, "orderHash", zp.orderHash)); - console.log(gStr(i + 1, "fulfiller", zp.fulfiller)); - console.log(gStr(i + 1, "offerer", zp.offerer)); - console.log(gStr(i + 1, "offer: [")); - for (uint256 j = 0; j < zp.offer.length; j++) { - logSpentItem(zp.offer[j], i + 1); - } - console.log(gStr(i + 1, "]")); - console.log(gStr(i + 1, "consideration: [")); - for (uint256 j = 0; j < zp.consideration.length; j++) { - logReceivedItem(zp.consideration[j], i + 1); - } - console.log(gStr(i + 1, "]")); - console.log(gStr(i + 1, "extraData", zp.extraData)); - console.log(gStr(i + 1, "orderHashes: [")); - for (uint256 j = 0; j < zp.orderHashes.length; j++) { - console.log(gStr(i + 2, "", zp.orderHashes[j])); - } - console.log(gStr(i + 1, "]")); - console.log(gStr(i + 1, "startTime", zp.startTime)); - console.log(gStr(i + 1, "endTime", zp.endTime)); - console.log(gStr(i + 1, "zoneHash", zp.zoneHash)); - console.log(gStr(i, "}")); - } - - //////////////////////////////////////////////////////////////////////////// - // Helpers // - //////////////////////////////////////////////////////////////////////////// - - function generateIndentString( - uint256 i // indent - ) public pure returns (string memory) { - string memory indentString = ""; - for (uint256 j = 0; j < i; j++) { - indentString = string.concat(indentString, " "); - } - return indentString; - } - - function gStr( - // generateString - uint256 i, // indent - string memory stringToIndent - ) public pure returns (string memory) { - string memory indentString = generateIndentString(i); - return string.concat(indentString, stringToIndent); - } - - function gStr( - uint256 i, // indent - string memory labelString, - string memory valueString - ) public pure returns (string memory) { - string memory indentString = generateIndentString(i); - return - string.concat( - indentString, - string.concat(labelString, ": ", valueString) - ); - } - - function gStr( - uint256 i, // indent - string memory labelString, - uint256 value - ) public pure returns (string memory) { - string memory indentString = generateIndentString(i); - return - string.concat( - indentString, - string.concat(labelString, ": ", LibString.toString(value)) - ); - } - - function gStr( - uint256 i, // indent - string memory labelString, - address value - ) public pure returns (string memory) { - string memory indentString = generateIndentString(i); - return - string.concat( - indentString, - string.concat(labelString, ": ", LibString.toHexString(value)) - ); - } - - function gStr( - uint256 i, // indent - string memory labelString, - bytes32 value - ) public pure returns (string memory) { - string memory indentString = generateIndentString(i); - return - string.concat( - indentString, - string.concat( - labelString, - ": ", - LibString.toHexString(uint256(value)) - ) - ); - } - - function gStr( - uint256 i, // indent - string memory labelString, - bytes memory value - ) public pure returns (string memory) { - string memory indentString = generateIndentString(i); - return - string.concat( - indentString, - string.concat(labelString, ": ", LibString.toHexString(value)) - ); - } - - //////////////////////////////////////////////////////////////////////////// - // Log Arrays // - //////////////////////////////////////////////////////////////////////////// - - function logOffer( - OfferItem[] memory offer, - uint256 i /* indent */ - ) public view { - console.log(gStr(i, "offer: [")); - for (uint256 j = 0; j < offer.length; j++) { - logOfferItem(offer[j], i + 1); - } - console.log(gStr(i, "]")); - } - - function logConsideration( - ConsiderationItem[] memory consideration, - uint256 i // indent - ) public view { - console.log(gStr(i, "consideration: [")); - for (uint256 j = 0; j < consideration.length; j++) { - logConsiderationItem(consideration[j], i + 1); - } - console.log(gStr(i, "]")); - } - - //////////////////////////////////////////////////////////////////////////// - // Get Enum String Values // - //////////////////////////////////////////////////////////////////////////// - - function _itemTypeStr( - ItemType itemType - ) internal pure returns (string memory) { - if (itemType == ItemType.NATIVE) return "NATIVE"; - if (itemType == ItemType.ERC20) return "ERC20"; - if (itemType == ItemType.ERC721) return "ERC721"; - if (itemType == ItemType.ERC1155) return "ERC1155"; - if (itemType == ItemType.ERC721_WITH_CRITERIA) - return "ERC721_WITH_CRITERIA"; - if (itemType == ItemType.ERC1155_WITH_CRITERIA) - return "ERC1155_WITH_CRITERIA"; - - return "UNKNOWN"; - } - - function _orderTypeStr( - OrderType orderType - ) internal pure returns (string memory) { - if (orderType == OrderType.FULL_OPEN) return "FULL_OPEN"; - if (orderType == OrderType.PARTIAL_OPEN) return "PARTIAL_OPEN"; - if (orderType == OrderType.FULL_RESTRICTED) return "FULL_RESTRICTED"; - if (orderType == OrderType.PARTIAL_RESTRICTED) - return "PARTIAL_RESTRICTED"; - if (orderType == OrderType.CONTRACT) return "CONTRACT"; - - return "UNKNOWN"; - } - - function _basicOrderTypeStr( - BasicOrderType basicOrderType - ) internal pure returns (string memory) { - if (basicOrderType == BasicOrderType.ETH_TO_ERC721_FULL_OPEN) - return "ETH_TO_ERC721_FULL_OPEN"; - if (basicOrderType == BasicOrderType.ETH_TO_ERC721_PARTIAL_OPEN) - return "ETH_TO_ERC721_PARTIAL_OPEN"; - if (basicOrderType == BasicOrderType.ETH_TO_ERC721_FULL_RESTRICTED) - return "ETH_TO_ERC721_FULL_RESTRICTED"; - if (basicOrderType == BasicOrderType.ETH_TO_ERC721_PARTIAL_RESTRICTED) - return "ETH_TO_ERC721_PARTIAL_RESTRICTED"; - if (basicOrderType == BasicOrderType.ETH_TO_ERC1155_FULL_OPEN) - return "ETH_TO_ERC1155_FULL_OPEN"; - if (basicOrderType == BasicOrderType.ETH_TO_ERC1155_PARTIAL_OPEN) - return "ETH_TO_ERC1155_PARTIAL_OPEN"; - if (basicOrderType == BasicOrderType.ETH_TO_ERC1155_FULL_RESTRICTED) - return "ETH_TO_ERC1155_FULL_RESTRICTED"; - if (basicOrderType == BasicOrderType.ETH_TO_ERC1155_PARTIAL_RESTRICTED) - return "ETH_TO_ERC1155_PARTIAL_RESTRICTED"; - if (basicOrderType == BasicOrderType.ERC20_TO_ERC721_FULL_OPEN) - return "ERC20_TO_ERC721_FULL_OPEN"; - if (basicOrderType == BasicOrderType.ERC20_TO_ERC721_PARTIAL_OPEN) - return "ERC20_TO_ERC721_PARTIAL_OPEN"; - if (basicOrderType == BasicOrderType.ERC20_TO_ERC721_FULL_RESTRICTED) - return "ERC20_TO_ERC721_FULL_RESTRICTED"; - if (basicOrderType == BasicOrderType.ERC20_TO_ERC721_PARTIAL_RESTRICTED) - return "ERC20_TO_ERC721_PARTIAL_RESTRICTED"; - if (basicOrderType == BasicOrderType.ERC20_TO_ERC1155_FULL_OPEN) - return "ERC20_TO_ERC1155_FULL_OPEN"; - if (basicOrderType == BasicOrderType.ERC20_TO_ERC1155_PARTIAL_OPEN) - return "ERC20_TO_ERC1155_PARTIAL_OPEN"; - if (basicOrderType == BasicOrderType.ERC20_TO_ERC1155_FULL_RESTRICTED) - return "ERC20_TO_ERC1155_FULL_RESTRICTED"; - if ( - basicOrderType == BasicOrderType.ERC20_TO_ERC1155_PARTIAL_RESTRICTED - ) return "ERC20_TO_ERC1155_PARTIAL_RESTRICTED"; - if (basicOrderType == BasicOrderType.ERC721_TO_ERC20_FULL_OPEN) - return "ERC721_TO_ERC20_FULL_OPEN"; - if (basicOrderType == BasicOrderType.ERC721_TO_ERC20_PARTIAL_OPEN) - return "ERC721_TO_ERC20_PARTIAL_OPEN"; - if (basicOrderType == BasicOrderType.ERC721_TO_ERC20_FULL_RESTRICTED) - return "ERC721_TO_ERC20_FULL_RESTRICTED"; - if (basicOrderType == BasicOrderType.ERC721_TO_ERC20_PARTIAL_RESTRICTED) - return "ERC721_TO_ERC20_PARTIAL_RESTRICTED"; - if (basicOrderType == BasicOrderType.ERC1155_TO_ERC20_FULL_OPEN) - return "ERC1155_TO_ERC20_FULL_OPEN"; - if (basicOrderType == BasicOrderType.ERC1155_TO_ERC20_PARTIAL_OPEN) - return "ERC1155_TO_ERC20_PARTIAL_OPEN"; - if (basicOrderType == BasicOrderType.ERC1155_TO_ERC20_FULL_RESTRICTED) - return "ERC1155_TO_ERC20_FULL_RESTRICTED"; - if ( - basicOrderType == BasicOrderType.ERC1155_TO_ERC20_PARTIAL_RESTRICTED - ) return "ERC1155_TO_ERC20_PARTIAL_RESTRICTED"; - - return "UNKNOWN"; - } - - function _sideStr(Side side) internal pure returns (string memory) { - if (side == Side.OFFER) return "OFFER"; - if (side == Side.CONSIDERATION) return "CONSIDERATION"; - - return "UNKNOWN"; - } -}