diff --git a/contracts/helpers/navigator/SeaportNavigator.sol b/contracts/helpers/navigator/SeaportNavigator.sol index f82e7c8ff..9997b33a3 100644 --- a/contracts/helpers/navigator/SeaportNavigator.sol +++ b/contracts/helpers/navigator/SeaportNavigator.sol @@ -45,6 +45,7 @@ contract SeaportNavigator is SeaportNavigatorInterface { HelperInterface public immutable validatorHelper; HelperInterface public immutable orderDetailsHelper; HelperInterface public immutable fulfillmentsHelper; + HelperInterface public immutable suggestedActionHelper; HelperInterface public immutable executionsHelper; HelperInterface[] public helpers; @@ -55,6 +56,7 @@ contract SeaportNavigator is SeaportNavigatorInterface { address _validatorHelper, address _orderDetailsHelper, address _fulfillmentsHelper, + address _suggestedActionHelper, address _executionsHelper ) { requestValidator = HelperInterface(_requestValidator); @@ -72,6 +74,9 @@ contract SeaportNavigator is SeaportNavigatorInterface { fulfillmentsHelper = HelperInterface(_fulfillmentsHelper); helpers.push(fulfillmentsHelper); + suggestedActionHelper = HelperInterface(_suggestedActionHelper); + helpers.push(suggestedActionHelper); + executionsHelper = HelperInterface(_executionsHelper); helpers.push(executionsHelper); } diff --git a/contracts/helpers/navigator/lib/ExecutionsHelper.sol b/contracts/helpers/navigator/lib/ExecutionsHelper.sol index fc4050619..83669e2de 100644 --- a/contracts/helpers/navigator/lib/ExecutionsHelper.sol +++ b/contracts/helpers/navigator/lib/ExecutionsHelper.sol @@ -13,6 +13,6 @@ contract ExecutionsHelper is HelperInterface { function prepare( NavigatorContext memory context ) public view returns (NavigatorContext memory) { - return context.withSuggestedAction().withExecutions(); + return context.withExecutions(); } } diff --git a/contracts/helpers/navigator/lib/NavigatorContextLib.sol b/contracts/helpers/navigator/lib/NavigatorContextLib.sol index c3b8a5e25..a00ea9f0b 100644 --- a/contracts/helpers/navigator/lib/NavigatorContextLib.sol +++ b/contracts/helpers/navigator/lib/NavigatorContextLib.sol @@ -46,8 +46,8 @@ library NavigatorContextLib { context.response = NavigatorResponse({ orders: new AdvancedOrder[](0), criteriaResolvers: new CriteriaResolver[](0), - suggestedAction: bytes4(0), suggestedActionName: "", + suggestedCallData: hex"", validationErrors: new ErrorsAndWarnings[](0), orderDetails: new OrderDetails[](0), offerFulfillments: new FulfillmentComponent[][](0), diff --git a/contracts/helpers/navigator/lib/NavigatorExecutionsLib.sol b/contracts/helpers/navigator/lib/NavigatorExecutionsLib.sol index 628a0f28f..5941f0829 100644 --- a/contracts/helpers/navigator/lib/NavigatorExecutionsLib.sol +++ b/contracts/helpers/navigator/lib/NavigatorExecutionsLib.sol @@ -26,24 +26,10 @@ import { UnavailableReason } from "seaport-sol/src/SpaceEnums.sol"; import { OrderDetails } from "seaport-sol/src/fulfillments/lib/Structs.sol"; -import { Family, Structure, OrderStructureLib } from "./OrderStructureLib.sol"; - import { NavigatorContext } from "./SeaportNavigatorTypes.sol"; library NavigatorExecutionsLib { using ExecutionHelper for FulfillmentDetails; - using OrderStructureLib for AdvancedOrder[]; - - /** - * @dev Bad request error: provided orders cannot be fulfilled. - */ - error CannotFulfillProvidedCombinedOrder(); - - /** - * @dev Bad request error: provided orders include an invalid combination of - * native tokens and unavailable orders. - */ - error InvalidNativeTokenUnavailableCombination(); /** * @dev Internal error: Could not select a fulfillment method for the provided @@ -51,11 +37,6 @@ library NavigatorExecutionsLib { */ error UnknownAction(); - /** - * @dev Internal error: Could not find selector for the suggested action. - */ - error UnknownSelector(); - /** * @dev Calculate executions for the provided orders and add them to the * NavigatorResponse. @@ -63,7 +44,8 @@ library NavigatorExecutionsLib { function withExecutions( NavigatorContext memory context ) internal pure returns (NavigatorContext memory) { - bytes4 _suggestedAction = context.response.suggestedAction; + bytes memory callData = context.response.suggestedCallData; + bytes4 _suggestedAction = bytes4(callData); FulfillmentDetails memory fulfillmentDetails = FulfillmentDetails({ orders: context.response.orderDetails, recipient: payable(context.request.recipient), @@ -133,202 +115,4 @@ library NavigatorExecutionsLib { context.response.nativeTokensReturned = nativeTokensReturned; return context; } - - /** - * @dev Choose a suggested fulfillment method based on the structure of the - * orders and add it to the NavigatorResponse. - */ - function withSuggestedAction( - NavigatorContext memory context - ) internal view returns (NavigatorContext memory) { - context.response.suggestedAction = action(context); - context.response.suggestedActionName = actionName(context); - return context; - } - - /** - * @dev Add the human-readable name of the selected fulfillment method to - * the NavigatorResponse. - */ - function actionName( - NavigatorContext memory context - ) internal view returns (string memory) { - bytes4 selector = action(context); - if (selector == 0xe7acab24) return "fulfillAdvancedOrder"; - if (selector == 0x87201b41) return "fulfillAvailableAdvancedOrders"; - if (selector == 0xed98a574) return "fulfillAvailableOrders"; - if (selector == 0xfb0f3ee1) return "fulfillBasicOrder"; - if (selector == 0x00000000) return "fulfillBasicOrder_efficient_6GL6yc"; - if (selector == 0xb3a34c4c) return "fulfillOrder"; - if (selector == 0xf2d12b12) return "matchAdvancedOrders"; - if (selector == 0xa8174404) return "matchOrders"; - - revert UnknownSelector(); - } - - /** - * @dev Choose a suggested fulfillment method based on the structure of the - * orders. - */ - function action( - NavigatorContext memory context - ) internal view returns (bytes4) { - Family family = context.response.orders.getFamily(); - - bool invalidOfferItemsLocated = mustUseMatch(context); - - Structure structure = context.response.orders.getStructure( - address(context.request.seaport) - ); - - bool hasUnavailable = context.request.maximumFulfilled < - context.response.orders.length; - for (uint256 i = 0; i < context.response.orderDetails.length; ++i) { - if ( - context.response.orderDetails[i].unavailableReason != - UnavailableReason.AVAILABLE - ) { - hasUnavailable = true; - break; - } - } - - if (hasUnavailable) { - if (invalidOfferItemsLocated) { - revert InvalidNativeTokenUnavailableCombination(); - } - - if (structure == Structure.ADVANCED) { - return - ConsiderationInterface - .fulfillAvailableAdvancedOrders - .selector; - } else { - return ConsiderationInterface.fulfillAvailableOrders.selector; - } - } - - if (family == Family.SINGLE && !invalidOfferItemsLocated) { - if (structure == Structure.BASIC) { - return - ConsiderationInterface - .fulfillBasicOrder_efficient_6GL6yc - .selector; - } - - if (structure == Structure.STANDARD) { - return ConsiderationInterface.fulfillOrder.selector; - } - - if (structure == Structure.ADVANCED) { - return ConsiderationInterface.fulfillAdvancedOrder.selector; - } - } - - bool cannotMatch = (context - .response - .unmetConsiderationComponents - .length != - 0 || - hasUnavailable); - - if (cannotMatch && invalidOfferItemsLocated) { - revert CannotFulfillProvidedCombinedOrder(); - } - - if (cannotMatch) { - if (structure == Structure.ADVANCED) { - return - ConsiderationInterface - .fulfillAvailableAdvancedOrders - .selector; - } else { - return ConsiderationInterface.fulfillAvailableOrders.selector; - } - } else if (invalidOfferItemsLocated) { - if (structure == Structure.ADVANCED) { - return ConsiderationInterface.matchAdvancedOrders.selector; - } else { - return ConsiderationInterface.matchOrders.selector; - } - } else { - if (structure == Structure.ADVANCED) { - return - context.request.preferMatch - ? ConsiderationInterface.matchAdvancedOrders.selector - : ConsiderationInterface - .fulfillAvailableAdvancedOrders - .selector; - } else { - return - context.request.preferMatch - ? ConsiderationInterface.matchOrders.selector - : ConsiderationInterface - .fulfillAvailableOrders - .selector; - } - } - } - - /** - * @dev Return whether the provided orders must be matched using matchOrders - * or matchAdvancedOrders. - */ - function mustUseMatch( - NavigatorContext memory context - ) internal pure returns (bool) { - OrderDetails[] memory orders = context.response.orderDetails; - - for (uint256 i = 0; i < orders.length; ++i) { - OrderDetails memory order = orders[i]; - - if (order.isContract) { - continue; - } - - for (uint256 j = 0; j < order.offer.length; ++j) { - if (order.offer[j].itemType == ItemType.NATIVE) { - return true; - } - } - } - - if (context.request.caller == context.request.recipient) { - return false; - } - - for (uint256 i = 0; i < orders.length; ++i) { - OrderDetails memory order = orders[i]; - - for (uint256 j = 0; j < order.offer.length; ++j) { - SpentItem memory item = order.offer[j]; - - if (item.itemType != ItemType.ERC721) { - continue; - } - - for (uint256 k = 0; k < orders.length; ++k) { - OrderDetails memory comparisonOrder = orders[k]; - for ( - uint256 l = 0; - l < comparisonOrder.consideration.length; - ++l - ) { - ReceivedItem memory considerationItem = comparisonOrder - .consideration[l]; - - if ( - considerationItem.itemType == ItemType.ERC721 && - considerationItem.identifier == item.identifier && - considerationItem.token == item.token - ) { - return true; - } - } - } - } - } - - return false; - } } diff --git a/contracts/helpers/navigator/lib/NavigatorSuggestedActionLib.sol b/contracts/helpers/navigator/lib/NavigatorSuggestedActionLib.sol new file mode 100644 index 000000000..cd30c3440 --- /dev/null +++ b/contracts/helpers/navigator/lib/NavigatorSuggestedActionLib.sol @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +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 { UnavailableReason } from "seaport-sol/src/SpaceEnums.sol"; + +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 { NavigatorContext } from "./SeaportNavigatorTypes.sol"; + +library NavigatorSuggestedActionLib { + using OrderStructureLib for AdvancedOrder; + using OrderStructureLib for AdvancedOrder[]; + using AdvancedOrderLib for AdvancedOrder; + using AdvancedOrderLib for AdvancedOrder[]; + + /** + * @dev Bad request error: provided orders cannot be fulfilled. + */ + error CannotFulfillProvidedCombinedOrder(); + + /** + * @dev Bad request error: provided orders include an invalid combination of + * native tokens and unavailable orders. + */ + error InvalidNativeTokenUnavailableCombination(); + + /** + * @dev Internal error: Could not find selector for the suggested action. + */ + error UnknownSelector(); + + /** + * @dev Choose a suggested fulfillment method based on the structure of the + * orders and add it to the NavigatorResponse. + */ + function withSuggestedAction( + NavigatorContext memory context + ) internal view returns (NavigatorContext memory) { + bytes memory callData = suggestedCallData(context); + bytes4 selector = bytes4(callData); + context.response.suggestedActionName = actionName(selector); + context.response.suggestedCallData = callData; + return context; + } + + /** + * @dev Add the human-readable name of the selected fulfillment method to + * the NavigatorResponse. + */ + function actionName(bytes4 selector) internal pure returns (string memory) { + if (selector == 0xe7acab24) return "fulfillAdvancedOrder"; + if (selector == 0x87201b41) return "fulfillAvailableAdvancedOrders"; + if (selector == 0xed98a574) return "fulfillAvailableOrders"; + if (selector == 0xfb0f3ee1) return "fulfillBasicOrder"; + if (selector == 0x00000000) return "fulfillBasicOrder_efficient_6GL6yc"; + if (selector == 0xb3a34c4c) return "fulfillOrder"; + if (selector == 0xf2d12b12) return "matchAdvancedOrders"; + if (selector == 0xa8174404) return "matchOrders"; + + revert UnknownSelector(); + } + + /** + * @dev Choose a suggested fulfillment method based on the structure of the + * orders. + */ + function suggestedCallData( + NavigatorContext memory context + ) internal view returns (bytes memory) { + Family family = context.response.orders.getFamily(); + + bool invalidOfferItemsLocated = mustUseMatch(context); + + Structure structure = context.response.orders.getStructure( + address(context.request.seaport) + ); + + bool hasUnavailable = context.request.maximumFulfilled < + context.response.orders.length; + for (uint256 i = 0; i < context.response.orderDetails.length; ++i) { + if ( + context.response.orderDetails[i].unavailableReason != + UnavailableReason.AVAILABLE + ) { + hasUnavailable = true; + break; + } + } + + if (hasUnavailable) { + if (invalidOfferItemsLocated) { + revert InvalidNativeTokenUnavailableCombination(); + } + + if (structure == Structure.ADVANCED) { + return + abi.encodeCall( + ConsiderationInterface.fulfillAvailableAdvancedOrders, + ( + context.response.orders, + context.response.criteriaResolvers, + context.response.offerFulfillments, + context.response.considerationFulfillments, + context.request.fulfillerConduitKey, + context.request.recipient, + context.request.maximumFulfilled + ) + ); + } else { + return + abi.encodeCall( + ConsiderationInterface.fulfillAvailableOrders, + ( + context.response.orders.toOrders(), + context.response.offerFulfillments, + context.response.considerationFulfillments, + context.request.fulfillerConduitKey, + context.request.maximumFulfilled + ) + ); + } + } + + if (family == Family.SINGLE && !invalidOfferItemsLocated) { + if (structure == Structure.BASIC) { + AdvancedOrder memory order = context.response.orders[0]; + return + abi.encodeCall( + ConsiderationInterface + .fulfillBasicOrder_efficient_6GL6yc, + ( + order.toBasicOrderParameters( + order.getBasicOrderType() + ) + ) + ); + } + + if (structure == Structure.STANDARD) { + return + abi.encodeCall( + ConsiderationInterface.fulfillOrder, + ( + context.response.orders[0].toOrder(), + context.request.fulfillerConduitKey + ) + ); + } + + if (structure == Structure.ADVANCED) { + return + abi.encodeCall( + ConsiderationInterface.fulfillAdvancedOrder, + ( + context.response.orders[0], + context.response.criteriaResolvers, + context.request.fulfillerConduitKey, + context.request.recipient + ) + ); + } + } + + bool cannotMatch = (context + .response + .unmetConsiderationComponents + .length != + 0 || + hasUnavailable); + + if (cannotMatch && invalidOfferItemsLocated) { + revert CannotFulfillProvidedCombinedOrder(); + } + + if (cannotMatch) { + if (structure == Structure.ADVANCED) { + return + abi.encodeCall( + ConsiderationInterface.fulfillAvailableAdvancedOrders, + ( + context.response.orders, + context.response.criteriaResolvers, + context.response.offerFulfillments, + context.response.considerationFulfillments, + context.request.fulfillerConduitKey, + context.request.recipient, + context.request.maximumFulfilled + ) + ); + } else { + return + abi.encodeCall( + ConsiderationInterface.fulfillAvailableOrders, + ( + context.response.orders.toOrders(), + context.response.offerFulfillments, + context.response.considerationFulfillments, + context.request.fulfillerConduitKey, + context.request.maximumFulfilled + ) + ); + } + } else if (invalidOfferItemsLocated) { + if (structure == Structure.ADVANCED) { + return + abi.encodeCall( + ConsiderationInterface.fulfillAvailableAdvancedOrders, + ( + context.response.orders, + context.response.criteriaResolvers, + context.response.offerFulfillments, + context.response.considerationFulfillments, + context.request.fulfillerConduitKey, + context.request.recipient, + context.request.maximumFulfilled + ) + ); + } else { + return + abi.encodeCall( + ConsiderationInterface.matchOrders, + ( + context.response.orders.toOrders(), + context.response.fulfillments + ) + ); + } + } else { + if (structure == Structure.ADVANCED) { + if (context.request.preferMatch) { + return + abi.encodeCall( + ConsiderationInterface.matchAdvancedOrders, + ( + context.response.orders, + context.response.criteriaResolvers, + context.response.fulfillments, + context.request.recipient + ) + ); + } else { + return + abi.encodeCall( + ConsiderationInterface + .fulfillAvailableAdvancedOrders, + ( + context.response.orders, + context.response.criteriaResolvers, + context.response.offerFulfillments, + context.response.considerationFulfillments, + context.request.fulfillerConduitKey, + context.request.recipient, + context.request.maximumFulfilled + ) + ); + } + } else { + if (context.request.preferMatch) { + return + abi.encodeCall( + ConsiderationInterface.matchOrders, + ( + context.response.orders.toOrders(), + context.response.fulfillments + ) + ); + } else { + return + abi.encodeCall( + ConsiderationInterface.fulfillAvailableOrders, + ( + context.response.orders.toOrders(), + context.response.offerFulfillments, + context.response.considerationFulfillments, + context.request.fulfillerConduitKey, + context.request.maximumFulfilled + ) + ); + } + } + } + } + + /** + * @dev Return whether the provided orders must be matched using matchOrders + * or matchAdvancedOrders. + */ + function mustUseMatch( + NavigatorContext memory context + ) internal pure returns (bool) { + OrderDetails[] memory orders = context.response.orderDetails; + + for (uint256 i = 0; i < orders.length; ++i) { + OrderDetails memory order = orders[i]; + + if (order.isContract) { + continue; + } + + for (uint256 j = 0; j < order.offer.length; ++j) { + if (order.offer[j].itemType == ItemType.NATIVE) { + return true; + } + } + } + + if (context.request.caller == context.request.recipient) { + return false; + } + + for (uint256 i = 0; i < orders.length; ++i) { + OrderDetails memory order = orders[i]; + + for (uint256 j = 0; j < order.offer.length; ++j) { + SpentItem memory item = order.offer[j]; + + if (item.itemType != ItemType.ERC721) { + continue; + } + + for (uint256 k = 0; k < orders.length; ++k) { + OrderDetails memory comparisonOrder = orders[k]; + for ( + uint256 l = 0; + l < comparisonOrder.consideration.length; + ++l + ) { + ReceivedItem memory considerationItem = comparisonOrder + .consideration[l]; + + if ( + considerationItem.itemType == ItemType.ERC721 && + considerationItem.identifier == item.identifier && + considerationItem.token == item.token + ) { + return true; + } + } + } + } + } + + return false; + } +} diff --git a/contracts/helpers/navigator/lib/SeaportNavigatorTypes.sol b/contracts/helpers/navigator/lib/SeaportNavigatorTypes.sol index 9fb6ff2cc..2314f8e36 100644 --- a/contracts/helpers/navigator/lib/SeaportNavigatorTypes.sol +++ b/contracts/helpers/navigator/lib/SeaportNavigatorTypes.sol @@ -125,16 +125,16 @@ struct NavigatorResponse { * based on provided criteria constraints. */ CriteriaResolver[] criteriaResolvers; - /** - * @dev Selector of the suggested Seaport fulfillment method for the - * provided orders. - */ - bytes4 suggestedAction; /** * @dev Human-readable name of the suggested Seaport fulfillment method for * the provided orders. */ string suggestedActionName; + /** + * @dev Encoded calldata for the suggested Seaport fulfillment method, + * provided orders, and context args. + */ + bytes suggestedCallData; /** * @dev Array of errors and warnings returned by SeaportValidator for the * provided orders, by order index in the orders array. diff --git a/contracts/helpers/navigator/lib/SuggestedActionHelper.sol b/contracts/helpers/navigator/lib/SuggestedActionHelper.sol new file mode 100644 index 000000000..858ce6c3b --- /dev/null +++ b/contracts/helpers/navigator/lib/SuggestedActionHelper.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import { NavigatorSuggestedActionLib } from "./NavigatorSuggestedActionLib.sol"; + +import { NavigatorContext } from "./SeaportNavigatorTypes.sol"; + +import { HelperInterface } from "./HelperInterface.sol"; + +contract SuggestedActionHelper is HelperInterface { + using NavigatorSuggestedActionLib for NavigatorContext; + + function prepare( + NavigatorContext memory context + ) public view returns (NavigatorContext memory) { + return context.withSuggestedAction(); + } +} diff --git a/script/NavigatorDeployer.s.sol b/script/NavigatorDeployer.s.sol index fe033981d..5c6a0f45c 100644 --- a/script/NavigatorDeployer.s.sol +++ b/script/NavigatorDeployer.s.sol @@ -29,6 +29,9 @@ import { import { FulfillmentsHelper } from "../contracts/helpers/navigator/lib/FulfillmentsHelper.sol"; +import { + SuggestedActionHelper +} from "../contracts/helpers/navigator/lib/SuggestedActionHelper.sol"; import { ExecutionsHelper } from "../contracts/helpers/navigator/lib/ExecutionsHelper.sol"; @@ -137,6 +140,10 @@ contract NavigatorDeployer is Script { "FulfillmentsHelper", type(FulfillmentsHelper).creationCode ); + address suggestedActionHelper = deploy( + "SuggestedActionHelper", + type(SuggestedActionHelper).creationCode + ); address executionsHelper = deploy( "ExecutionsHelper", type(ExecutionsHelper).creationCode @@ -152,6 +159,7 @@ contract NavigatorDeployer is Script { validatorHelper, orderDetailsHelper, fulfillmentsHelper, + suggestedActionHelper, executionsHelper ) ) diff --git a/test/foundry/new/SeaportNavigator.t.sol b/test/foundry/new/SeaportNavigator.t.sol index d62c37782..1560582b1 100644 --- a/test/foundry/new/SeaportNavigator.t.sol +++ b/test/foundry/new/SeaportNavigator.t.sol @@ -12,7 +12,8 @@ import { ItemType, SeaportInterface, Side, - CriteriaResolver + CriteriaResolver, + ConsiderationInterface } from "seaport-sol/src/SeaportSol.sol"; import { @@ -34,6 +35,12 @@ 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"; @@ -42,6 +49,9 @@ 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"; @@ -65,6 +75,8 @@ contract SeaportNavigatorTestSuite is using OrderComponentsLib for OrderComponents; using OrderLib for Order; using AdvancedOrderLib for AdvancedOrder; + 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 = @@ -164,16 +176,23 @@ contract SeaportNavigatorTestSuite is preferMatch: false }) ); - assertEq( - res.suggestedAction, - seaport.fulfillBasicOrder_efficient_6GL6yc.selector, - "unexpected action selected" - ); assertEq( res.suggestedActionName, "fulfillBasicOrder_efficient_6GL6yc", "unexpected actionName selected" ); + assertEq( + res.suggestedCallData, + abi.encodeCall( + ConsiderationInterface.fulfillBasicOrder_efficient_6GL6yc, + ( + advancedOrder.toBasicOrderParameters( + advancedOrder.getBasicOrderType() + ) + ) + ), + "unexpected suggested calldata" + ); assertEq( res.validationErrors.length, 1, @@ -268,16 +287,19 @@ contract SeaportNavigatorTestSuite is preferMatch: false }) ); - assertEq( - res.suggestedAction, - seaport.fulfillOrder.selector, - "unexpected action selected" - ); assertEq( res.suggestedActionName, "fulfillOrder", "unexpected actionName selected" ); + assertEq( + res.suggestedCallData, + abi.encodeCall( + ConsiderationInterface.fulfillOrder, + (advancedOrder.toOrder(), bytes32(0)) + ), + "unexpected suggested calldata" + ); assertEq( res.validationErrors.length, 1, diff --git a/test/foundry/new/SeaportNavigatorTest.sol b/test/foundry/new/SeaportNavigatorTest.sol index 2883b6e7d..f13f4d274 100644 --- a/test/foundry/new/SeaportNavigatorTest.sol +++ b/test/foundry/new/SeaportNavigatorTest.sol @@ -22,6 +22,9 @@ import { import { FulfillmentsHelper } from "../../../contracts/helpers/navigator/lib/FulfillmentsHelper.sol"; +import { + SuggestedActionHelper +} from "../../../contracts/helpers/navigator/lib/SuggestedActionHelper.sol"; import { ExecutionsHelper } from "../../../contracts/helpers/navigator/lib/ExecutionsHelper.sol"; @@ -32,6 +35,8 @@ contract SeaportNavigatorTest { HelperInterface internal validatorHelper = new ValidatorHelper(); HelperInterface internal orderDetailsHelper = new OrderDetailsHelper(); HelperInterface internal fulfillmentsHelper = new FulfillmentsHelper(); + HelperInterface internal suggestedActionHelper = + new SuggestedActionHelper(); HelperInterface internal executionsHelper = new ExecutionsHelper(); SeaportNavigator internal navigator = @@ -41,6 +46,7 @@ contract SeaportNavigatorTest { address(validatorHelper), address(orderDetailsHelper), address(fulfillmentsHelper), + address(suggestedActionHelper), address(executionsHelper) ); }