More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0xe359c0f70ff8503fd4991aae6d85454ebac4296cdc175e52aed6ea228d582f75 | Fulfill Basic Or... | (pending) | 7 hrs ago | IN | 0.00001 ETH | (Pending) | |||
0x2bcd3b3768754ba52dcb3467ac050386cd95353d195cef969c76c82ee3c528ec | Match Advanced O... | (pending) | 21 hrs ago | IN | 0 ETH | (Pending) | |||
0x0c249941a7dd07ab06a8572d086ceee3fa96261afdc069dbae1249f4ba1d90ce | Fulfill Advanced... | (pending) | 22 hrs ago | IN | 0.001486 ETH | (Pending) | |||
0xc52500cfb6596e14085c052cbc970c518655a0e471df79898290c2d88bf99fe3 | 0x00000000 | (pending) | 22 hrs ago | IN | 0 ETH | (Pending) | |||
0x791377d4a701de2e1ba6925cf990fc9369da4bfb09d206e73eef8de470d3da17 | 0x00000000 | (pending) | 25 hrs ago | IN | 0.002 ETH | (Pending) | |||
0x563e6bdad2c9b582f061383ccd17566ebd9af0d20ae8190185851f49c3b2487e | Fulfill Basic Or... | (pending) | 27 hrs ago | IN | 0.00001 ETH | (Pending) | |||
Match Advanced O... | 20495839 | 135 days ago | IN | 0 ETH | 0.00005445 | ||||
Match Advanced O... | 20495838 | 135 days ago | IN | 0 ETH | 0.00004487 | ||||
Match Advanced O... | 20453630 | 140 days ago | IN | 0 ETH | 0.00006065 | ||||
Match Advanced O... | 20453433 | 141 days ago | IN | 0 ETH | 0.00006599 | ||||
Cancel | 20453427 | 141 days ago | IN | 0 ETH | 0.00005841 | ||||
Match Advanced O... | 20453427 | 141 days ago | IN | 0 ETH | 0.00006253 | ||||
Cancel | 20453378 | 141 days ago | IN | 0 ETH | 0.00005843 | ||||
Fulfill Basic Or... | 20453325 | 141 days ago | IN | 0.0001 ETH | 0.00003311 | ||||
Fulfill Basic Or... | 20453092 | 141 days ago | IN | 0.02 ETH | 0.00003339 | ||||
Match Advanced O... | 20452790 | 141 days ago | IN | 0 ETH | 0.00006685 | ||||
Fulfill Availabl... | 20452698 | 141 days ago | IN | 2 wei | 0.00005852 | ||||
Fulfill Availabl... | 20452698 | 141 days ago | IN | 0 ETH | 0.00005201 | ||||
Match Advanced O... | 20408462 | 147 days ago | IN | 0 ETH | 0.000067 | ||||
Fulfill Basic Or... | 20393949 | 149 days ago | IN | 0.0009 ETH | 0.00003619 | ||||
Fulfill Basic Or... | 20251160 | 169 days ago | IN | 0.001 ETH | 0.00004403 | ||||
Fulfill Basic Or... | 20251159 | 169 days ago | IN | 0.001 ETH | 0.00004474 | ||||
Fulfill Basic Or... | 20251159 | 169 days ago | IN | 0.001 ETH | 0.00004474 | ||||
Fulfill Basic Or... | 20251158 | 169 days ago | IN | 0.001 ETH | 0.00003774 | ||||
Fulfill Basic Or... | 20251075 | 169 days ago | IN | 0.0015 ETH | 0.00003634 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
20453427 | 141 days ago | 0.00407 ETH | ||||
20453262 | 141 days ago | 0.00289 ETH | ||||
20149599 | 183 days ago | 0.0001 ETH | ||||
19800198 | 232 days ago | 0.0018 ETH | ||||
18295230 | 443 days ago | 0.002478 ETH | ||||
18289656 | 444 days ago | 0.00138 ETH | ||||
18132986 | 465 days ago | 0.000052 ETH | ||||
18132986 | 465 days ago | 0.002548 ETH | ||||
18108836 | 469 days ago | 0.0011 ETH | ||||
18099122 | 470 days ago | 0.00015 ETH | ||||
18099122 | 470 days ago | 0.02985 ETH | ||||
18099122 | 470 days ago | 0.03 ETH | ||||
18084857 | 472 days ago | 0.000002 ETH | ||||
18084857 | 472 days ago | 0.000005 ETH | ||||
18084857 | 472 days ago | 0.000093 ETH | ||||
18065887 | 475 days ago | 0.00002 ETH | ||||
18065887 | 475 days ago | 0.00098 ETH | ||||
18065887 | 475 days ago | 0.001 ETH | ||||
18026691 | 480 days ago | 0.0012 ETH | ||||
18026691 | 480 days ago | 0.000072 ETH | ||||
18026691 | 480 days ago | 0.001428 ETH | ||||
18026691 | 480 days ago | 0.0573 ETH | ||||
18026534 | 480 days ago | 0.0004 ETH | ||||
18026534 | 480 days ago | 0.001 ETH | ||||
18026534 | 480 days ago | 0.001 ETH |
Loading...
Loading
Contract Name:
Seaport
Compiler Version
v0.8.17+commit.8df45f5f
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { Consideration } from "./lib/Consideration.sol"; /** * @title Seaport * @custom:version 1.4 * @author 0age (0age.eth) * @custom:coauthor d1ll0n (d1ll0n.eth) * @custom:coauthor transmissions11 (t11s.eth) * @custom:coauthor James Wenzel (emo.eth) * @custom:contributor Kartik (slokh.eth) * @custom:contributor LeFevre (lefevre.eth) * @custom:contributor Joseph Schiarizzi (CupOJoseph.eth) * @custom:contributor Aspyn Palatnick (stuckinaboot.eth) * @custom:contributor Stephan Min (stephanm.eth) * @custom:contributor Ryan Ghods (ralxz.eth) * @custom:contributor Daniel Viau (snotrocket.eth) * @custom:contributor hack3r-0m (hack3r-0m.eth) * @custom:contributor Diego Estevez (antidiego.eth) * @custom:contributor Chomtana (chomtana.eth) * @custom:contributor Saw-mon and Natalie (sawmonandnatalie.eth) * @custom:contributor 0xBeans (0xBeans.eth) * @custom:contributor 0x4non (punkdev.eth) * @custom:contributor Laurence E. Day (norsefire.eth) * @custom:contributor vectorized.eth (vectorized.eth) * @custom:contributor karmacoma (karmacoma.eth) * @custom:contributor horsefacts (horsefacts.eth) * @custom:contributor UncarvedBlock (uncarvedblock.eth) * @custom:contributor Zoraiz Mahmood (zorz.eth) * @custom:contributor William Poulin (wpoulin.eth) * @custom:contributor Rajiv Patel-O'Connor (rajivpoc.eth) * @custom:contributor tserg (tserg.eth) * @custom:contributor cygaar (cygaar.eth) * @custom:contributor Meta0xNull (meta0xnull.eth) * @custom:contributor gpersoon (gpersoon.eth) * @custom:contributor Matt Solomon (msolomon.eth) * @custom:contributor Weikang Song (weikangs.eth) * @custom:contributor zer0dot (zer0dot.eth) * @custom:contributor Mudit Gupta (mudit.eth) * @custom:contributor leonardoalt (leoalt.eth) * @custom:contributor cmichel (cmichel.eth) * @custom:contributor PraneshASP (pranesh.eth) * @custom:contributor JasperAlexander (jasperalexander.eth) * @custom:contributor Ellahi (ellahi.eth) * @custom:contributor zaz (1zaz1.eth) * @custom:contributor berndartmueller (berndartmueller.eth) * @custom:contributor dmfxyz (dmfxyz.eth) * @custom:contributor daltoncoder (dontkillrobots.eth) * @custom:contributor 0xf4ce (0xf4ce.eth) * @custom:contributor phaze (phaze.eth) * @custom:contributor hrkrshnn (hrkrshnn.eth) * @custom:contributor axic (axic.eth) * @custom:contributor leastwood (leastwood.eth) * @custom:contributor 0xsanson (sanson.eth) * @custom:contributor blockdev (blockd3v.eth) * @custom:contributor fiveoutofnine (fiveoutofnine.eth) * @custom:contributor shuklaayush (shuklaayush.eth) * @custom:contributor dravee (dravee.eth) * @custom:contributor 0xPatissier * @custom:contributor pcaversaccio * @custom:contributor David Eiber * @custom:contributor csanuragjain * @custom:contributor sach1r0 * @custom:contributor twojoy0 * @custom:contributor ori_dabush * @custom:contributor Daniel Gelfand * @custom:contributor okkothejawa * @custom:contributor FlameHorizon * @custom:contributor vdrg * @custom:contributor dmitriia * @custom:contributor bokeh-eth * @custom:contributor asutorufos * @custom:contributor rfart(rfa) * @custom:contributor Riley Holterhus * @custom:contributor big-tech-sux * @notice Seaport is a generalized native token/ERC20/ERC721/ERC1155 * marketplace with lightweight methods for common routes as well as * more flexible methods for composing advanced orders or groups of * orders. Each order contains an arbitrary number of items that may be * spent (the "offer") along with an arbitrary number of items that must * be received back by the indicated recipients (the "consideration"). */ contract Seaport is Consideration { /** * @notice Derive and set hashes, reference chainId, and associated domain * separator during deployment. * * @param conduitController A contract that deploys conduits, or proxies * that may optionally be used to transfer approved * ERC20/721/1155 tokens. */ constructor(address conduitController) Consideration(conduitController) {} /** * @dev Internal pure function to retrieve and return the name of this * contract. * * @return The name of this contract. */ function _name() internal pure override returns (string memory) { // Return the name of the contract. assembly { mstore(0x20, 0x20) mstore(0x47, 0x07536561706f7274) return(0x20, 0x60) } } /** * @dev Internal pure function to retrieve the name of this contract as a * string that will be used to derive the name hash in the constructor. * * @return The name of this contract as a string. */ function _nameString() internal pure override returns (string memory) { // Return the name of the contract. return "Seaport"; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { ConsiderationInterface } from "../interfaces/ConsiderationInterface.sol"; import { AdvancedOrder, BasicOrderParameters, CriteriaResolver, Execution, Fulfillment, FulfillmentComponent, Order, OrderComponents } from "./ConsiderationStructs.sol"; import { OrderCombiner } from "./OrderCombiner.sol"; import { CalldataStart, CalldataPointer } from "../helpers/PointerLibraries.sol"; import { Offset_fulfillAdvancedOrder_criteriaResolvers, Offset_fulfillAvailableAdvancedOrders_cnsdrationFlflmnts, Offset_fulfillAvailableAdvancedOrders_criteriaResolvers, Offset_fulfillAvailableAdvancedOrders_offerFulfillments, Offset_fulfillAvailableOrders_considerationFulfillments, Offset_fulfillAvailableOrders_offerFulfillments, Offset_matchAdvancedOrders_criteriaResolvers, Offset_matchAdvancedOrders_fulfillments, Offset_matchOrders_fulfillments, OrderParameters_counter_offset } from "./ConsiderationConstants.sol"; /** * @title Consideration * @author 0age (0age.eth) * @custom:coauthor d1ll0n (d1ll0n.eth) * @custom:coauthor transmissions11 (t11s.eth) * @custom:coauthor James Wenzel (emo.eth) * @custom:version 1.4 * @notice Consideration is a generalized native token/ERC20/ERC721/ERC1155 * marketplace that provides lightweight methods for common routes as * well as more flexible methods for composing advanced orders or groups * of orders. Each order contains an arbitrary number of items that may * be spent (the "offer") along with an arbitrary number of items that * must be received back by the indicated recipients (the * "consideration"). */ contract Consideration is ConsiderationInterface, OrderCombiner { /** * @notice Derive and set hashes, reference chainId, and associated domain * separator during deployment. * * @param conduitController A contract that deploys conduits, or proxies * that may optionally be used to transfer approved * ERC20/721/1155 tokens. */ constructor(address conduitController) OrderCombiner(conduitController) {} /** * @notice Accept native token transfers during execution that may then be * used to facilitate native token transfers, where any tokens that * remain will be transferred to the caller. Native tokens are only * acceptable mid-fulfillment (and not during basic fulfillment). */ receive() external payable { // Ensure the reentrancy guard is currently set to accept native tokens. _assertAcceptingNativeTokens(); } /** * @notice Fulfill an order offering an ERC20, ERC721, or ERC1155 item by * supplying Ether (or other native tokens), ERC20 tokens, an ERC721 * item, or an ERC1155 item as consideration. Six permutations are * supported: Native token to ERC721, Native token to ERC1155, ERC20 * to ERC721, ERC20 to ERC1155, ERC721 to ERC20, and ERC1155 to * ERC20 (with native tokens supplied as msg.value). For an order to * be eligible for fulfillment via this method, it must contain a * single offer item (though that item may have a greater amount if * the item is not an ERC721). An arbitrary number of "additional * recipients" may also be supplied which will each receive native * tokens or ERC20 items from the fulfiller as consideration. Refer * to the documentation for a more comprehensive summary of how to * utilize this method and what orders are compatible with it. * * @param parameters Additional information on the fulfilled order. Note * that the offerer and the fulfiller must first approve * this contract (or their chosen conduit if indicated) * before any tokens can be transferred. Also note that * contract recipients of ERC1155 consideration items must * implement `onERC1155Received` to receive those items. * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillBasicOrder( BasicOrderParameters calldata parameters ) external payable override returns (bool fulfilled) { // Validate and fulfill the basic order. fulfilled = _validateAndFulfillBasicOrder(parameters); } /** * @notice Fulfill an order offering an ERC20, ERC721, or ERC1155 item by * supplying Ether (or other native tokens), ERC20 tokens, an ERC721 * item, or an ERC1155 item as consideration. Six permutations are * supported: Native token to ERC721, Native token to ERC1155, ERC20 * to ERC721, ERC20 to ERC1155, ERC721 to ERC20, and ERC1155 to * ERC20 (with native tokens supplied as msg.value). For an order to * be eligible for fulfillment via this method, it must contain a * single offer item (though that item may have a greater amount if * the item is not an ERC721). An arbitrary number of "additional * recipients" may also be supplied which will each receive native * tokens or ERC20 items from the fulfiller as consideration. Refer * to the documentation for a more comprehensive summary of how to * utilize this method and what orders are compatible with it. Note * that this function costs less gas than `fulfillBasicOrder` due to * the zero bytes in the function selector (0x00000000) which also * results in earlier function dispatch. * * @param parameters Additional information on the fulfilled order. Note * that the offerer and the fulfiller must first approve * this contract (or their chosen conduit if indicated) * before any tokens can be transferred. Also note that * contract recipients of ERC1155 consideration items must * implement `onERC1155Received` to receive those items. * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillBasicOrder_efficient_6GL6yc( BasicOrderParameters calldata parameters ) external payable override returns (bool fulfilled) { // Validate and fulfill the basic order. fulfilled = _validateAndFulfillBasicOrder(parameters); } /** * @notice Fulfill an order with an arbitrary number of items for offer and * consideration. Note that this function does not support * criteria-based orders or partial filling of orders (though * filling the remainder of a partially-filled order is supported). * * @custom:param order The order to fulfill. Note that both the * offerer and the fulfiller must first approve * this contract (or the corresponding conduit if * indicated) to transfer any relevant tokens on * their behalf and that contracts must implement * `onERC1155Received` to receive ERC1155 tokens * as consideration. * @param fulfillerConduitKey A bytes32 value indicating what conduit, if * any, to source the fulfiller's token approvals * from. The zero hash signifies that no conduit * should be used (and direct approvals set on * this contract). * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillOrder( /** * @custom:name order */ Order calldata, bytes32 fulfillerConduitKey ) external payable override returns (bool fulfilled) { // Convert order to "advanced" order, then validate and fulfill it. fulfilled = _validateAndFulfillAdvancedOrder( _toAdvancedOrderReturnType(_decodeOrderAsAdvancedOrder)( CalldataStart.pptr() ), new CriteriaResolver[](0), // No criteria resolvers supplied. fulfillerConduitKey, msg.sender ); } /** * @notice Fill an order, fully or partially, with an arbitrary number of * items for offer and consideration alongside criteria resolvers * containing specific token identifiers and associated proofs. * * @custom:param advancedOrder The order to fulfill along with the * fraction of the order to attempt to fill. * Note that both the offerer and the * fulfiller must first approve this * contract (or their conduit if indicated * by the order) to transfer any relevant * tokens on their behalf and that contracts * must implement `onERC1155Received` to * receive ERC1155 tokens as consideration. * Also note that all offer and * consideration components must have no * remainder after multiplication of the * respective amount with the supplied * fraction for the partial fill to be * considered valid. * @custom:param criteriaResolvers An array where each element contains a * reference to a specific offer or * consideration, a token identifier, and a * proof that the supplied token identifier * is contained in the merkle root held by * the item in question's criteria element. * Note that an empty criteria indicates * that any (transferable) token identifier * on the token in question is valid and * that no associated proof needs to be * supplied. * @param fulfillerConduitKey A bytes32 value indicating what conduit, * if any, to source the fulfiller's token * approvals from. The zero hash signifies * that no conduit should be used (and * direct approvals set on this contract). * @param recipient The intended recipient for all received * items, with `address(0)` indicating that * the caller should receive the items. * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillAdvancedOrder( /** * @custom:name advancedOrder */ AdvancedOrder calldata, /** * @custom:name criteriaResolvers */ CriteriaResolver[] calldata, bytes32 fulfillerConduitKey, address recipient ) external payable override returns (bool fulfilled) { // Validate and fulfill the order. fulfilled = _validateAndFulfillAdvancedOrder( _toAdvancedOrderReturnType(_decodeAdvancedOrder)( CalldataStart.pptr() ), _toCriteriaResolversReturnType(_decodeCriteriaResolvers)( CalldataStart.pptr( Offset_fulfillAdvancedOrder_criteriaResolvers ) ), fulfillerConduitKey, _substituteCallerForEmptyRecipient(recipient) ); } /** * @notice Attempt to fill a group of orders, each with an arbitrary number * of items for offer and consideration. Any order that is not * currently active, has already been fully filled, or has been * cancelled will be omitted. Remaining offer and consideration * items will then be aggregated where possible as indicated by the * supplied offer and consideration component arrays and aggregated * items will be transferred to the fulfiller or to each intended * recipient, respectively. Note that a failing item transfer or an * issue with order formatting will cause the entire batch to fail. * Note that this function does not support criteria-based orders or * partial filling of orders (though filling the remainder of a * partially-filled order is supported). * * @custom:param orders The orders to fulfill. Note that * both the offerer and the * fulfiller must first approve this * contract (or the corresponding * conduit if indicated) to transfer * any relevant tokens on their * behalf and that contracts must * implement `onERC1155Received` to * receive ERC1155 tokens as * consideration. * @custom:param offerFulfillments An array of FulfillmentComponent * arrays indicating which offer * items to attempt to aggregate * when preparing executions. Note * that any offer items not included * as part of a fulfillment will be * sent unaggregated to the caller. * @custom:param considerationFulfillments An array of FulfillmentComponent * arrays indicating which * consideration items to attempt to * aggregate when preparing * executions. * @param fulfillerConduitKey A bytes32 value indicating what * conduit, if any, to source the * fulfiller's token approvals from. * The zero hash signifies that no * conduit should be used (and * direct approvals set on this * contract). * @param maximumFulfilled The maximum number of orders to * fulfill. * * @return availableOrders An array of booleans indicating if each order * with an index corresponding to the index of the * returned boolean was fulfillable or not. * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function fulfillAvailableOrders( /** * @custom:name orders */ Order[] calldata, /** * @custom:name offerFulfillments */ FulfillmentComponent[][] calldata, /** * @custom:name considerationFulfillments */ FulfillmentComponent[][] calldata, bytes32 fulfillerConduitKey, uint256 maximumFulfilled ) external payable override returns ( bool[] memory /* availableOrders */, Execution[] memory /* executions */ ) { // Convert orders to "advanced" orders and fulfill all available orders. return _fulfillAvailableAdvancedOrders( _toAdvancedOrdersReturnType(_decodeOrdersAsAdvancedOrders)( CalldataStart.pptr() ), // Convert to advanced orders. new CriteriaResolver[](0), // No criteria resolvers supplied. _toNestedFulfillmentComponentsReturnType( _decodeNestedFulfillmentComponents )( CalldataStart.pptr( Offset_fulfillAvailableOrders_offerFulfillments ) ), _toNestedFulfillmentComponentsReturnType( _decodeNestedFulfillmentComponents )( CalldataStart.pptr( Offset_fulfillAvailableOrders_considerationFulfillments ) ), fulfillerConduitKey, msg.sender, maximumFulfilled ); } /** * @notice Attempt to fill a group of orders, fully or partially, with an * arbitrary number of items for offer and consideration per order * alongside criteria resolvers containing specific token * identifiers and associated proofs. Any order that is not * currently active, has already been fully filled, or has been * cancelled will be omitted. Remaining offer and consideration * items will then be aggregated where possible as indicated by the * supplied offer and consideration component arrays and aggregated * items will be transferred to the fulfiller or to each intended * recipient, respectively. Note that a failing item transfer or an * issue with order formatting will cause the entire batch to fail. * * @custom:param advancedOrders The orders to fulfill along with * the fraction of those orders to * attempt to fill. Note that both * the offerer and the fulfiller * must first approve this contract * (or their conduit if indicated by * the order) to transfer any * relevant tokens on their behalf * and that contracts must implement * `onERC1155Received` to receive * ERC1155 tokens as consideration. * Also note that all offer and * consideration components must * have no remainder after * multiplication of the respective * amount with the supplied fraction * for an order's partial fill * amount to be considered valid. * @custom:param criteriaResolvers An array where each element * contains a reference to a * specific offer or consideration, * a token identifier, and a proof * that the supplied token * identifier is contained in the * merkle root held by the item in * question's criteria element. Note * that an empty criteria indicates * that any (transferable) token * identifier on the token in * question is valid and that no * associated proof needs to be * supplied. * @custom:param offerFulfillments An array of FulfillmentComponent * arrays indicating which offer * items to attempt to aggregate * when preparing executions. Note * that any offer items not included * as part of a fulfillment will be * sent unaggregated to the caller. * @custom:param considerationFulfillments An array of FulfillmentComponent * arrays indicating which * consideration items to attempt to * aggregate when preparing * executions. * @param fulfillerConduitKey A bytes32 value indicating what * conduit, if any, to source the * fulfiller's token approvals from. * The zero hash signifies that no * conduit should be used (and * direct approvals set on this * contract). * @param recipient The intended recipient for all * received items, with `address(0)` * indicating that the caller should * receive the offer items. * @param maximumFulfilled The maximum number of orders to * fulfill. * * @return availableOrders An array of booleans indicating if each order * with an index corresponding to the index of the * returned boolean was fulfillable or not. * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function fulfillAvailableAdvancedOrders( /** * @custom:name advancedOrders */ AdvancedOrder[] calldata, /** * @custom:name criteriaResolvers */ CriteriaResolver[] calldata, /** * @custom:name offerFulfillments */ FulfillmentComponent[][] calldata, /** * @custom:name considerationFulfillments */ FulfillmentComponent[][] calldata, bytes32 fulfillerConduitKey, address recipient, uint256 maximumFulfilled ) external payable override returns ( bool[] memory /* availableOrders */, Execution[] memory /* executions */ ) { // Fulfill all available orders. return _fulfillAvailableAdvancedOrders( _toAdvancedOrdersReturnType(_decodeAdvancedOrders)( CalldataStart.pptr() ), _toCriteriaResolversReturnType(_decodeCriteriaResolvers)( CalldataStart.pptr( Offset_fulfillAvailableAdvancedOrders_criteriaResolvers ) ), _toNestedFulfillmentComponentsReturnType( _decodeNestedFulfillmentComponents )( CalldataStart.pptr( Offset_fulfillAvailableAdvancedOrders_offerFulfillments ) ), _toNestedFulfillmentComponentsReturnType( _decodeNestedFulfillmentComponents )( CalldataStart.pptr( Offset_fulfillAvailableAdvancedOrders_cnsdrationFlflmnts ) ), fulfillerConduitKey, _substituteCallerForEmptyRecipient(recipient), maximumFulfilled ); } /** * @notice Match an arbitrary number of orders, each with an arbitrary * number of items for offer and consideration along with a set of * fulfillments allocating offer components to consideration * components. Note that this function does not support * criteria-based or partial filling of orders (though filling the * remainder of a partially-filled order is supported). Any unspent * offer item amounts or native tokens will be transferred to the * caller. * * @custom:param orders The orders to match. Note that both the * offerer and fulfiller on each order must first * approve this contract (or their conduit if * indicated by the order) to transfer any * relevant tokens on their behalf and each * consideration recipient must implement * `onERC1155Received` to receive ERC1155 tokens. * @custom:param fulfillments An array of elements allocating offer * components to consideration components. Note * that each consideration component must be * fully met for the match operation to be valid, * and that any unspent offer items will be sent * unaggregated to the caller. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. Note that unspent offer item amounts or native * tokens will not be reflected as part of this array. */ function matchOrders( /** * @custom:name orders */ Order[] calldata, /** * @custom:name fulfillments */ Fulfillment[] calldata ) external payable override returns (Execution[] memory /* executions */) { // Convert to advanced, validate, and match orders using fulfillments. return _matchAdvancedOrders( _toAdvancedOrdersReturnType(_decodeOrdersAsAdvancedOrders)( CalldataStart.pptr() ), new CriteriaResolver[](0), // No criteria resolvers supplied. _toFulfillmentsReturnType(_decodeFulfillments)( CalldataStart.pptr(Offset_matchOrders_fulfillments) ), msg.sender ); } /** * @notice Match an arbitrary number of full, partial, or contract orders, * each with an arbitrary number of items for offer and * consideration, supplying criteria resolvers containing specific * token identifiers and associated proofs as well as fulfillments * allocating offer components to consideration components. Any * unspent offer item amounts will be transferred to the designated * recipient (with the null address signifying to use the caller) * and any unspent native tokens will be returned to the caller. * * @custom:param advancedOrders The advanced orders to match. Note that * both the offerer and fulfiller on each * order must first approve this contract * (or their conduit if indicated by the * order) to transfer any relevant tokens on * their behalf and each consideration * recipient must implement * `onERC1155Received` to receive ERC1155 * tokens. Also note that the offer and * consideration components for each order * must have no remainder after multiplying * the respective amount with the supplied * fraction for the group of partial fills * to be considered valid. * @custom:param criteriaResolvers An array where each element contains a * reference to a specific offer or * consideration, a token identifier, and a * proof that the supplied token identifier * is contained in the merkle root held by * the item in question's criteria element. * Note that an empty criteria indicates * that any (transferable) token identifier * on the token in question is valid and * that no associated proof needs to be * supplied. * @custom:param fulfillments An array of elements allocating offer * components to consideration components. * Note that each consideration component * must be fully met for the match operation * to be valid, and that any unspent offer * items will be sent unaggregated to the * designated recipient. * @param recipient The intended recipient for all unspent * offer item amounts, or the caller if the * null address is supplied. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. Note that unspent offer item amounts or * native tokens will not be reflected as part of this * array. */ function matchAdvancedOrders( /** * @custom:name advancedOrders */ AdvancedOrder[] calldata, /** * @custom:name criteriaResolvers */ CriteriaResolver[] calldata, /** * @custom:name fulfillments */ Fulfillment[] calldata, address recipient ) external payable override returns (Execution[] memory /* executions */) { // Validate and match the advanced orders using supplied fulfillments. return _matchAdvancedOrders( _toAdvancedOrdersReturnType(_decodeAdvancedOrders)( CalldataStart.pptr() ), _toCriteriaResolversReturnType(_decodeCriteriaResolvers)( CalldataStart.pptr( Offset_matchAdvancedOrders_criteriaResolvers ) ), _toFulfillmentsReturnType(_decodeFulfillments)( CalldataStart.pptr(Offset_matchAdvancedOrders_fulfillments) ), _substituteCallerForEmptyRecipient(recipient) ); } /** * @notice Cancel an arbitrary number of orders. Note that only the offerer * or the zone of a given order may cancel it. Callers should ensure * that the intended order was cancelled by calling `getOrderStatus` * and confirming that `isCancelled` returns `true`. * * @param orders The orders to cancel. * * @return cancelled A boolean indicating whether the supplied orders have * been successfully cancelled. */ function cancel( OrderComponents[] calldata orders ) external override returns (bool cancelled) { // Cancel the orders. cancelled = _cancel(orders); } /** * @notice Validate an arbitrary number of orders, thereby registering their * signatures as valid and allowing the fulfiller to skip signature * verification on fulfillment. Note that validated orders may still * be unfulfillable due to invalid item amounts or other factors; * callers should determine whether validated orders are fulfillable * by simulating the fulfillment call prior to execution. Also note * that anyone can validate a signed order, but only the offerer can * validate an order without supplying a signature. * * @custom:param orders The orders to validate. * * @return validated A boolean indicating whether the supplied orders have * been successfully validated. */ function validate( /** * @custom:name orders */ Order[] calldata ) external override returns (bool /* validated */) { return _validate(_toOrdersReturnType(_decodeOrders)(CalldataStart.pptr())); } /** * @notice Cancel all orders from a given offerer with a given zone in bulk * by incrementing a counter. Note that only the offerer may * increment the counter. * * @return newCounter The new counter. */ function incrementCounter() external override returns (uint256 newCounter) { // Increment current counter for the supplied offerer. Note that the // counter is incremented by a large, quasi-random interval. newCounter = _incrementCounter(); } /** * @notice Retrieve the order hash for a given order. * * @custom:param order The components of the order. * * @return orderHash The order hash. */ function getOrderHash( /** * @custom:name order */ OrderComponents calldata ) external view override returns (bytes32 orderHash) { CalldataPointer orderPointer = CalldataStart.pptr(); // Derive order hash by supplying order parameters along with counter. orderHash = _deriveOrderHash( _toOrderParametersReturnType( _decodeOrderComponentsAsOrderParameters )(orderPointer), // Read order counter orderPointer.offset(OrderParameters_counter_offset).readUint256() ); } /** * @notice Retrieve the status of a given order by hash, including whether * the order has been cancelled or validated and the fraction of the * order that has been filled. Since the _orderStatus[orderHash] * does not get set for contract orders, getOrderStatus will always * return (false, false, 0, 0) for those hashes. Note that this * function is susceptible to view reentrancy and so should be used * with care when calling from other contracts. * * @param orderHash The order hash in question. * * @return isValidated A boolean indicating whether the order in question * has been validated (i.e. previously approved or * partially filled). * @return isCancelled A boolean indicating whether the order in question * has been cancelled. * @return totalFilled The total portion of the order that has been filled * (i.e. the "numerator"). * @return totalSize The total size of the order that is either filled or * unfilled (i.e. the "denominator"). */ function getOrderStatus( bytes32 orderHash ) external view override returns ( bool isValidated, bool isCancelled, uint256 totalFilled, uint256 totalSize ) { // Retrieve the order status using the order hash. return _getOrderStatus(orderHash); } /** * @notice Retrieve the current counter for a given offerer. * * @param offerer The offerer in question. * * @return counter The current counter. */ function getCounter( address offerer ) external view override returns (uint256 counter) { // Return the counter for the supplied offerer. counter = _getCounter(offerer); } /** * @notice Retrieve configuration information for this contract. * * @return version The contract version. * @return domainSeparator The domain separator for this contract. * @return conduitController The conduit Controller set for this contract. */ function information() external view override returns ( string memory version, bytes32 domainSeparator, address conduitController ) { // Return the information for this contract. return _information(); } /** * @dev Gets the contract offerer nonce for the specified contract offerer. * Note that this function is susceptible to view reentrancy and so * should be used with care when calling from other contracts. * * @param contractOfferer The contract offerer for which to get the nonce. * * @return nonce The contract offerer nonce. */ function getContractOffererNonce( address contractOfferer ) external view override returns (uint256 nonce) { nonce = _contractNonces[contractOfferer]; } /** * @notice Retrieve the name of this contract. * * @return contractName The name of this contract. */ function name() external pure override returns (string memory /* contractName */) { // Return the name of the contract. return _name(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { AdvancedOrder, BasicOrderParameters, CriteriaResolver, Execution, Fulfillment, FulfillmentComponent, Order, OrderComponents } from "../lib/ConsiderationStructs.sol"; /** * @title ConsiderationInterface * @author 0age * @custom:version 1.4 * @notice Consideration is a generalized native token/ERC20/ERC721/ERC1155 * marketplace. It minimizes external calls to the greatest extent * possible and provides lightweight methods for common routes as well * as more flexible methods for composing advanced orders. * * @dev ConsiderationInterface contains all external function interfaces for * Consideration. */ interface ConsiderationInterface { /** * @notice Fulfill an order offering an ERC721 token by supplying Ether (or * the native token for the given chain) as consideration for the * order. An arbitrary number of "additional recipients" may also be * supplied which will each receive native tokens from the fulfiller * as consideration. * * @param parameters Additional information on the fulfilled order. Note * that the offerer must first approve this contract (or * their preferred conduit if indicated by the order) for * their offered ERC721 token to be transferred. * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillBasicOrder( BasicOrderParameters calldata parameters ) external payable returns (bool fulfilled); /** * @notice Fulfill an order with an arbitrary number of items for offer and * consideration. Note that this function does not support * criteria-based orders or partial filling of orders (though * filling the remainder of a partially-filled order is supported). * * @param order The order to fulfill. Note that both the * offerer and the fulfiller must first approve * this contract (or the corresponding conduit if * indicated) to transfer any relevant tokens on * their behalf and that contracts must implement * `onERC1155Received` to receive ERC1155 tokens * as consideration. * @param fulfillerConduitKey A bytes32 value indicating what conduit, if * any, to source the fulfiller's token approvals * from. The zero hash signifies that no conduit * should be used, with direct approvals set on * Consideration. * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillOrder( Order calldata order, bytes32 fulfillerConduitKey ) external payable returns (bool fulfilled); /** * @notice Fill an order, fully or partially, with an arbitrary number of * items for offer and consideration alongside criteria resolvers * containing specific token identifiers and associated proofs. * * @param advancedOrder The order to fulfill along with the fraction * of the order to attempt to fill. Note that * both the offerer and the fulfiller must first * approve this contract (or their preferred * conduit if indicated by the order) to transfer * any relevant tokens on their behalf and that * contracts must implement `onERC1155Received` * to receive ERC1155 tokens as consideration. * Also note that all offer and consideration * components must have no remainder after * multiplication of the respective amount with * the supplied fraction for the partial fill to * be considered valid. * @param criteriaResolvers An array where each element contains a * reference to a specific offer or * consideration, a token identifier, and a proof * that the supplied token identifier is * contained in the merkle root held by the item * in question's criteria element. Note that an * empty criteria indicates that any * (transferable) token identifier on the token * in question is valid and that no associated * proof needs to be supplied. * @param fulfillerConduitKey A bytes32 value indicating what conduit, if * any, to source the fulfiller's token approvals * from. The zero hash signifies that no conduit * should be used, with direct approvals set on * Consideration. * @param recipient The intended recipient for all received items, * with `address(0)` indicating that the caller * should receive the items. * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillAdvancedOrder( AdvancedOrder calldata advancedOrder, CriteriaResolver[] calldata criteriaResolvers, bytes32 fulfillerConduitKey, address recipient ) external payable returns (bool fulfilled); /** * @notice Attempt to fill a group of orders, each with an arbitrary number * of items for offer and consideration. Any order that is not * currently active, has already been fully filled, or has been * cancelled will be omitted. Remaining offer and consideration * items will then be aggregated where possible as indicated by the * supplied offer and consideration component arrays and aggregated * items will be transferred to the fulfiller or to each intended * recipient, respectively. Note that a failing item transfer or an * issue with order formatting will cause the entire batch to fail. * Note that this function does not support criteria-based orders or * partial filling of orders (though filling the remainder of a * partially-filled order is supported). * * @param orders The orders to fulfill. Note that both * the offerer and the fulfiller must first * approve this contract (or the * corresponding conduit if indicated) to * transfer any relevant tokens on their * behalf and that contracts must implement * `onERC1155Received` to receive ERC1155 * tokens as consideration. * @param offerFulfillments An array of FulfillmentComponent arrays * indicating which offer items to attempt * to aggregate when preparing executions. * @param considerationFulfillments An array of FulfillmentComponent arrays * indicating which consideration items to * attempt to aggregate when preparing * executions. * @param fulfillerConduitKey A bytes32 value indicating what conduit, * if any, to source the fulfiller's token * approvals from. The zero hash signifies * that no conduit should be used, with * direct approvals set on this contract. * @param maximumFulfilled The maximum number of orders to fulfill. * * @return availableOrders An array of booleans indicating if each order * with an index corresponding to the index of the * returned boolean was fulfillable or not. * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. Note that unspent offer item amounts or * native tokens will not be reflected as part of * this array. */ function fulfillAvailableOrders( Order[] calldata orders, FulfillmentComponent[][] calldata offerFulfillments, FulfillmentComponent[][] calldata considerationFulfillments, bytes32 fulfillerConduitKey, uint256 maximumFulfilled ) external payable returns (bool[] memory availableOrders, Execution[] memory executions); /** * @notice Attempt to fill a group of orders, fully or partially, with an * arbitrary number of items for offer and consideration per order * alongside criteria resolvers containing specific token * identifiers and associated proofs. Any order that is not * currently active, has already been fully filled, or has been * cancelled will be omitted. Remaining offer and consideration * items will then be aggregated where possible as indicated by the * supplied offer and consideration component arrays and aggregated * items will be transferred to the fulfiller or to each intended * recipient, respectively. Note that a failing item transfer or an * issue with order formatting will cause the entire batch to fail. * * @param advancedOrders The orders to fulfill along with the * fraction of those orders to attempt to * fill. Note that both the offerer and the * fulfiller must first approve this * contract (or their preferred conduit if * indicated by the order) to transfer any * relevant tokens on their behalf and that * contracts must implement * `onERC1155Received` to enable receipt of * ERC1155 tokens as consideration. Also * note that all offer and consideration * components must have no remainder after * multiplication of the respective amount * with the supplied fraction for an * order's partial fill amount to be * considered valid. * @param criteriaResolvers An array where each element contains a * reference to a specific offer or * consideration, a token identifier, and a * proof that the supplied token identifier * is contained in the merkle root held by * the item in question's criteria element. * Note that an empty criteria indicates * that any (transferable) token * identifier on the token in question is * valid and that no associated proof needs * to be supplied. * @param offerFulfillments An array of FulfillmentComponent arrays * indicating which offer items to attempt * to aggregate when preparing executions. * @param considerationFulfillments An array of FulfillmentComponent arrays * indicating which consideration items to * attempt to aggregate when preparing * executions. * @param fulfillerConduitKey A bytes32 value indicating what conduit, * if any, to source the fulfiller's token * approvals from. The zero hash signifies * that no conduit should be used, with * direct approvals set on this contract. * @param recipient The intended recipient for all received * items, with `address(0)` indicating that * the caller should receive the items. * @param maximumFulfilled The maximum number of orders to fulfill. * * @return availableOrders An array of booleans indicating if each order * with an index corresponding to the index of the * returned boolean was fulfillable or not. * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. Note that unspent offer item amounts or * native tokens will not be reflected as part of * this array. */ function fulfillAvailableAdvancedOrders( AdvancedOrder[] calldata advancedOrders, CriteriaResolver[] calldata criteriaResolvers, FulfillmentComponent[][] calldata offerFulfillments, FulfillmentComponent[][] calldata considerationFulfillments, bytes32 fulfillerConduitKey, address recipient, uint256 maximumFulfilled ) external payable returns (bool[] memory availableOrders, Execution[] memory executions); /** * @notice Match an arbitrary number of orders, each with an arbitrary * number of items for offer and consideration along with a set of * fulfillments allocating offer components to consideration * components. Note that this function does not support * criteria-based or partial filling of orders (though filling the * remainder of a partially-filled order is supported). Any unspent * offer item amounts or native tokens will be transferred to the * caller. * * @param orders The orders to match. Note that both the offerer and * fulfiller on each order must first approve this * contract (or their conduit if indicated by the order) * to transfer any relevant tokens on their behalf and * each consideration recipient must implement * `onERC1155Received` to enable ERC1155 token receipt. * @param fulfillments An array of elements allocating offer components to * consideration components. Note that each * consideration component must be fully met for the * match operation to be valid. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. Note that unspent offer item amounts or * native tokens will not be reflected as part of this * array. */ function matchOrders( Order[] calldata orders, Fulfillment[] calldata fulfillments ) external payable returns (Execution[] memory executions); /** * @notice Match an arbitrary number of full or partial orders, each with an * arbitrary number of items for offer and consideration, supplying * criteria resolvers containing specific token identifiers and * associated proofs as well as fulfillments allocating offer * components to consideration components. Any unspent offer item * amounts will be transferred to the designated recipient (with the * null address signifying to use the caller) and any unspent native * tokens will be returned to the caller. * * @param orders The advanced orders to match. Note that both the * offerer and fulfiller on each order must first * approve this contract (or a preferred conduit if * indicated by the order) to transfer any relevant * tokens on their behalf and each consideration * recipient must implement `onERC1155Received` in * order to receive ERC1155 tokens. Also note that * the offer and consideration components for each * order must have no remainder after multiplying * the respective amount with the supplied fraction * in order for the group of partial fills to be * considered valid. * @param criteriaResolvers An array where each element contains a reference * to a specific order as well as that order's * offer or consideration, a token identifier, and * a proof that the supplied token identifier is * contained in the order's merkle root. Note that * an empty root indicates that any (transferable) * token identifier is valid and that no associated * proof needs to be supplied. * @param fulfillments An array of elements allocating offer components * to consideration components. Note that each * consideration component must be fully met in * order for the match operation to be valid. * @param recipient The intended recipient for all unspent offer * item amounts, or the caller if the null address * is supplied. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. Note that unspent offer item amounts or native * tokens will not be reflected as part of this array. */ function matchAdvancedOrders( AdvancedOrder[] calldata orders, CriteriaResolver[] calldata criteriaResolvers, Fulfillment[] calldata fulfillments, address recipient ) external payable returns (Execution[] memory executions); /** * @notice Cancel an arbitrary number of orders. Note that only the offerer * or the zone of a given order may cancel it. Callers should ensure * that the intended order was cancelled by calling `getOrderStatus` * and confirming that `isCancelled` returns `true`. * * @param orders The orders to cancel. * * @return cancelled A boolean indicating whether the supplied orders have * been successfully cancelled. */ function cancel( OrderComponents[] calldata orders ) external returns (bool cancelled); /** * @notice Validate an arbitrary number of orders, thereby registering their * signatures as valid and allowing the fulfiller to skip signature * verification on fulfillment. Note that validated orders may still * be unfulfillable due to invalid item amounts or other factors; * callers should determine whether validated orders are fulfillable * by simulating the fulfillment call prior to execution. Also note * that anyone can validate a signed order, but only the offerer can * validate an order without supplying a signature. * * @param orders The orders to validate. * * @return validated A boolean indicating whether the supplied orders have * been successfully validated. */ function validate( Order[] calldata orders ) external returns (bool validated); /** * @notice Cancel all orders from a given offerer with a given zone in bulk * by incrementing a counter. Note that only the offerer may * increment the counter. * * @return newCounter The new counter. */ function incrementCounter() external returns (uint256 newCounter); /** * @notice Fulfill an order offering an ERC721 token by supplying Ether (or * the native token for the given chain) as consideration for the * order. An arbitrary number of "additional recipients" may also be * supplied which will each receive native tokens from the fulfiller * as consideration. Note that this function costs less gas than * `fulfillBasicOrder` due to the zero bytes in the function * selector (0x00000000) which also results in earlier function * dispatch. * * @param parameters Additional information on the fulfilled order. Note * that the offerer must first approve this contract (or * their preferred conduit if indicated by the order) for * their offered ERC721 token to be transferred. * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillBasicOrder_efficient_6GL6yc( BasicOrderParameters calldata parameters ) external payable returns (bool fulfilled); /** * @notice Retrieve the order hash for a given order. * * @param order The components of the order. * * @return orderHash The order hash. */ function getOrderHash( OrderComponents calldata order ) external view returns (bytes32 orderHash); /** * @notice Retrieve the status of a given order by hash, including whether * the order has been cancelled or validated and the fraction of the * order that has been filled. * * @param orderHash The order hash in question. * * @return isValidated A boolean indicating whether the order in question * has been validated (i.e. previously approved or * partially filled). * @return isCancelled A boolean indicating whether the order in question * has been cancelled. * @return totalFilled The total portion of the order that has been filled * (i.e. the "numerator"). * @return totalSize The total size of the order that is either filled or * unfilled (i.e. the "denominator"). */ function getOrderStatus( bytes32 orderHash ) external view returns ( bool isValidated, bool isCancelled, uint256 totalFilled, uint256 totalSize ); /** * @notice Retrieve the current counter for a given offerer. * * @param offerer The offerer in question. * * @return counter The current counter. */ function getCounter( address offerer ) external view returns (uint256 counter); /** * @notice Retrieve configuration information for this contract. * * @return version The contract version. * @return domainSeparator The domain separator for this contract. * @return conduitController The conduit Controller set for this contract. */ function information() external view returns ( string memory version, bytes32 domainSeparator, address conduitController ); function getContractOffererNonce( address contractOfferer ) external view returns (uint256 nonce); /** * @notice Retrieve the name of this contract. * * @return contractName The name of this contract. */ function name() external view returns (string memory contractName); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { BasicOrderType, ItemType, OrderType, Side } from "./ConsiderationEnums.sol"; import { CalldataPointer, MemoryPointer } from "../helpers/PointerLibraries.sol"; /** * @dev An order contains eleven components: an offerer, a zone (or account that * can cancel the order or restrict who can fulfill the order depending on * the type), the order type (specifying partial fill support as well as * restricted order status), the start and end time, a hash that will be * provided to the zone when validating restricted orders, a salt, a key * corresponding to a given conduit, a counter, and an arbitrary number of * offer items that can be spent along with consideration items that must * be received by their respective recipient. */ struct OrderComponents { address offerer; address zone; OfferItem[] offer; ConsiderationItem[] consideration; OrderType orderType; uint256 startTime; uint256 endTime; bytes32 zoneHash; uint256 salt; bytes32 conduitKey; uint256 counter; } /** * @dev An offer item has five components: an item type (ETH or other native * tokens, ERC20, ERC721, and ERC1155, as well as criteria-based ERC721 and * ERC1155), a token address, a dual-purpose "identifierOrCriteria" * component that will either represent a tokenId or a merkle root * depending on the item type, and a start and end amount that support * increasing or decreasing amounts over the duration of the respective * order. */ struct OfferItem { ItemType itemType; address token; uint256 identifierOrCriteria; uint256 startAmount; uint256 endAmount; } /** * @dev A consideration item has the same five components as an offer item and * an additional sixth component designating the required recipient of the * item. */ struct ConsiderationItem { ItemType itemType; address token; uint256 identifierOrCriteria; uint256 startAmount; uint256 endAmount; address payable recipient; } /** * @dev A spent item is translated from a utilized offer item and has four * components: an item type (ETH or other native tokens, ERC20, ERC721, and * ERC1155), a token address, a tokenId, and an amount. */ struct SpentItem { ItemType itemType; address token; uint256 identifier; uint256 amount; } /** * @dev A received item is translated from a utilized consideration item and has * the same four components as a spent item, as well as an additional fifth * component designating the required recipient of the item. */ struct ReceivedItem { ItemType itemType; address token; uint256 identifier; uint256 amount; address payable recipient; } /** * @dev For basic orders involving ETH / native / ERC20 <=> ERC721 / ERC1155 * matching, a group of six functions may be called that only requires a * subset of the usual order arguments. Note the use of a "basicOrderType" * enum; this represents both the usual order type as well as the "route" * of the basic order (a simple derivation function for the basic order * type is `basicOrderType = orderType + (4 * basicOrderRoute)`.) */ struct BasicOrderParameters { // calldata offset address considerationToken; // 0x24 uint256 considerationIdentifier; // 0x44 uint256 considerationAmount; // 0x64 address payable offerer; // 0x84 address zone; // 0xa4 address offerToken; // 0xc4 uint256 offerIdentifier; // 0xe4 uint256 offerAmount; // 0x104 BasicOrderType basicOrderType; // 0x124 uint256 startTime; // 0x144 uint256 endTime; // 0x164 bytes32 zoneHash; // 0x184 uint256 salt; // 0x1a4 bytes32 offererConduitKey; // 0x1c4 bytes32 fulfillerConduitKey; // 0x1e4 uint256 totalOriginalAdditionalRecipients; // 0x204 AdditionalRecipient[] additionalRecipients; // 0x224 bytes signature; // 0x244 // Total length, excluding dynamic array data: 0x264 (580) } /** * @dev Basic orders can supply any number of additional recipients, with the * implied assumption that they are supplied from the offered ETH (or other * native token) or ERC20 token for the order. */ struct AdditionalRecipient { uint256 amount; address payable recipient; } /** * @dev The full set of order components, with the exception of the counter, * must be supplied when fulfilling more sophisticated orders or groups of * orders. The total number of original consideration items must also be * supplied, as the caller may specify additional consideration items. */ struct OrderParameters { address offerer; // 0x00 address zone; // 0x20 OfferItem[] offer; // 0x40 ConsiderationItem[] consideration; // 0x60 OrderType orderType; // 0x80 uint256 startTime; // 0xa0 uint256 endTime; // 0xc0 bytes32 zoneHash; // 0xe0 uint256 salt; // 0x100 bytes32 conduitKey; // 0x120 uint256 totalOriginalConsiderationItems; // 0x140 // offer.length // 0x160 } /** * @dev Orders require a signature in addition to the other order parameters. */ struct Order { OrderParameters parameters; bytes signature; } /** * @dev Advanced orders include a numerator (i.e. a fraction to attempt to fill) * and a denominator (the total size of the order) in addition to the * signature and other order parameters. It also supports an optional field * for supplying extra data; this data will be provided to the zone if the * order type is restricted and the zone is not the caller, or will be * provided to the offerer as context for contract order types. */ struct AdvancedOrder { OrderParameters parameters; uint120 numerator; uint120 denominator; bytes signature; bytes extraData; } /** * @dev Orders can be validated (either explicitly via `validate`, or as a * consequence of a full or partial fill), specifically cancelled (they can * also be cancelled in bulk via incrementing a per-zone counter), and * partially or fully filled (with the fraction filled represented by a * numerator and denominator). */ struct OrderStatus { bool isValidated; bool isCancelled; uint120 numerator; uint120 denominator; } /** * @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; } /** * @dev A fulfillment is applied to a group of orders. It decrements a series of * offer and consideration items, then generates a single execution * element. A given fulfillment can be applied to as many offer and * consideration items as desired, but must contain at least one offer and * at least one consideration that match. The fulfillment must also remain * consistent on all key parameters across all offer items (same offerer, * token, type, tokenId, and conduit preference) as well as across all * consideration items (token, type, tokenId, and recipient). */ struct Fulfillment { FulfillmentComponent[] offerComponents; FulfillmentComponent[] considerationComponents; } /** * @dev Each fulfillment component contains one index referencing a specific * order and another referencing a specific offer or consideration item. */ struct FulfillmentComponent { uint256 orderIndex; uint256 itemIndex; } /** * @dev An execution is triggered once all consideration items have been zeroed * out. It sends the item in question from the offerer to the item's * recipient, optionally sourcing approvals from either this contract * directly or from the offerer's chosen conduit if one is specified. An * execution is not provided as an argument, but rather is derived via * orders, criteria resolvers, and fulfillments (where the total number of * executions will be less than or equal to the total number of indicated * fulfillments) and returned as part of `matchOrders`. */ struct Execution { ReceivedItem item; address offerer; bytes32 conduitKey; } /** * @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; } /** * @dev Zones and contract offerers can communicate which schemas they implement * along with any associated metadata related to each schema. */ struct Schema { uint256 id; bytes metadata; } using StructPointers for OrderComponents global; using StructPointers for OfferItem global; using StructPointers for ConsiderationItem global; using StructPointers for SpentItem global; using StructPointers for ReceivedItem global; using StructPointers for BasicOrderParameters global; using StructPointers for AdditionalRecipient global; using StructPointers for OrderParameters global; using StructPointers for Order global; using StructPointers for AdvancedOrder global; using StructPointers for OrderStatus global; using StructPointers for CriteriaResolver global; using StructPointers for Fulfillment global; using StructPointers for FulfillmentComponent global; using StructPointers for Execution global; using StructPointers for ZoneParameters global; /** * @dev This library provides a set of functions for converting structs to * pointers. */ library StructPointers { /** * @dev Get a MemoryPointer from OrderComponents. * * @param obj The OrderComponents object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( OrderComponents memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from OrderComponents. * * @param obj The OrderComponents object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( OrderComponents calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from OfferItem. * * @param obj The OfferItem object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( OfferItem memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from OfferItem. * * @param obj The OfferItem object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( OfferItem calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from ConsiderationItem. * * @param obj The ConsiderationItem object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( ConsiderationItem memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from ConsiderationItem. * * @param obj The ConsiderationItem object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( ConsiderationItem calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from SpentItem. * * @param obj The SpentItem object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( SpentItem memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from SpentItem. * * @param obj The SpentItem object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( SpentItem calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from ReceivedItem. * * @param obj The ReceivedItem object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( ReceivedItem memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from ReceivedItem. * * @param obj The ReceivedItem object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( ReceivedItem calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from BasicOrderParameters. * * @param obj The BasicOrderParameters object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( BasicOrderParameters memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from BasicOrderParameters. * * @param obj The BasicOrderParameters object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( BasicOrderParameters calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from AdditionalRecipient. * * @param obj The AdditionalRecipient object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( AdditionalRecipient memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from AdditionalRecipient. * * @param obj The AdditionalRecipient object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( AdditionalRecipient calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from OrderParameters. * * @param obj The OrderParameters object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( OrderParameters memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from OrderParameters. * * @param obj The OrderParameters object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( OrderParameters calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from Order. * * @param obj The Order object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( Order memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from Order. * * @param obj The Order object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( Order calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from AdvancedOrder. * * @param obj The AdvancedOrder object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( AdvancedOrder memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from AdvancedOrder. * * @param obj The AdvancedOrder object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( AdvancedOrder calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from OrderStatus. * * @param obj The OrderStatus object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( OrderStatus memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from OrderStatus. * * @param obj The OrderStatus object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( OrderStatus calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from CriteriaResolver. * * @param obj The CriteriaResolver object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( CriteriaResolver memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from CriteriaResolver. * * @param obj The CriteriaResolver object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( CriteriaResolver calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from Fulfillment. * * @param obj The Fulfillment object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( Fulfillment memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from Fulfillment. * * @param obj The Fulfillment object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( Fulfillment calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from FulfillmentComponent. * * @param obj The FulfillmentComponent object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( FulfillmentComponent memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from FulfillmentComponent. * * @param obj The FulfillmentComponent object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( FulfillmentComponent calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from Execution. * * @param obj The Execution object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( Execution memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from Execution. * * @param obj The Execution object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( Execution calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from ZoneParameters. * * @param obj The ZoneParameters object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( ZoneParameters memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from ZoneParameters. * * @param obj The ZoneParameters object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( ZoneParameters calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { Side, ItemType, OrderType } from "./ConsiderationEnums.sol"; import { AdvancedOrder, ConsiderationItem, CriteriaResolver, Execution, Fulfillment, FulfillmentComponent, OfferItem, OrderParameters, ReceivedItem } from "./ConsiderationStructs.sol"; import { OrderFulfiller } from "./OrderFulfiller.sol"; import { FulfillmentApplier } from "./FulfillmentApplier.sol"; import { _revertConsiderationNotMet, _revertInsufficientNativeTokensSupplied, _revertInvalidNativeOfferItem, _revertNoSpecifiedOrdersAvailable } from "./ConsiderationErrors.sol"; import { AccumulatorDisarmed, ConsiderationItem_recipient_offset, Execution_offerer_offset, NonMatchSelector_InvalidErrorValue, NonMatchSelector_MagicMask, OneWord, OneWordShift, OrdersMatchedTopic0, ReceivedItem_amount_offset, ReceivedItem_recipient_offset, TwoWords } from "./ConsiderationConstants.sol"; /** * @title OrderCombiner * @author 0age * @notice OrderCombiner contains logic for fulfilling combinations of orders, * either by matching offer items to consideration items or by * fulfilling orders where available. */ contract OrderCombiner is OrderFulfiller, FulfillmentApplier { /** * @dev Derive and set hashes, reference chainId, and associated domain * separator during deployment. * * @param conduitController A contract that deploys conduits, or proxies * that may optionally be used to transfer approved * ERC20/721/1155 tokens. */ constructor(address conduitController) OrderFulfiller(conduitController) {} /** * @notice Internal function to attempt to fill a group of orders, fully or * partially, with an arbitrary number of items for offer and * consideration per order alongside criteria resolvers containing * specific token identifiers and associated proofs. Any order that * is not currently active, has already been fully filled, or has * been cancelled will be omitted. Remaining offer and consideration * items will then be aggregated where possible as indicated by the * supplied offer and consideration component arrays and aggregated * items will be transferred to the fulfiller or to each intended * recipient, respectively. Note that a failing item transfer or an * issue with order formatting will cause the entire batch to fail. * * @param advancedOrders The orders to fulfill along with the * fraction of those orders to attempt to * fill. Note that both the offerer and the * fulfiller must first approve this * contract (or a conduit if indicated by * the order) to transfer any relevant * tokens on their behalf and that * contracts must implement * `onERC1155Received` in order to receive * ERC1155 tokens as consideration. Also * note that all offer and consideration * components must have no remainder after * multiplication of the respective amount * with the supplied fraction for an * order's partial fill amount to be * considered valid. * @param criteriaResolvers An array where each element contains a * reference to a specific offer or * consideration, a token identifier, and a * proof that the supplied token identifier * is contained in the merkle root held by * the item in question's criteria element. * Note that an empty criteria indicates * that any (transferable) token * identifier on the token in question is * valid and that no associated proof needs * to be supplied. * @param offerFulfillments An array of FulfillmentComponent arrays * indicating which offer items to attempt * to aggregate when preparing executions. * @param considerationFulfillments An array of FulfillmentComponent arrays * indicating which consideration items to * attempt to aggregate when preparing * executions. * @param fulfillerConduitKey A bytes32 value indicating what conduit, * if any, to source the fulfiller's token * approvals from. The zero hash signifies * that no conduit should be used (and * direct approvals set on Consideration). * @param recipient The intended recipient for all received * items. * @param maximumFulfilled The maximum number of orders to fulfill. * * @return availableOrders An array of booleans indicating if each order * with an index corresponding to the index of the * returned boolean was fulfillable or not. * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function _fulfillAvailableAdvancedOrders( AdvancedOrder[] memory advancedOrders, CriteriaResolver[] memory criteriaResolvers, FulfillmentComponent[][] memory offerFulfillments, FulfillmentComponent[][] memory considerationFulfillments, bytes32 fulfillerConduitKey, address recipient, uint256 maximumFulfilled ) internal returns ( bool[] memory /* availableOrders */, Execution[] memory /* executions */ ) { // Validate orders, apply amounts, & determine if they utilize conduits. ( bytes32[] memory orderHashes, bool containsNonOpen ) = _validateOrdersAndPrepareToFulfill( advancedOrders, criteriaResolvers, false, // Signifies that invalid orders should NOT revert. maximumFulfilled, recipient ); // Aggregate used offer and consideration items and execute transfers. return _executeAvailableFulfillments( advancedOrders, offerFulfillments, considerationFulfillments, fulfillerConduitKey, recipient, orderHashes, containsNonOpen ); } /** * @dev Internal function to validate a group of orders, update their * statuses, reduce amounts by their previously filled fractions, apply * criteria resolvers, and emit OrderFulfilled events. Note that this * function needs to be called before * _aggregateValidFulfillmentConsiderationItems to set the memory * layout that _aggregateValidFulfillmentConsiderationItems depends on. * * @param advancedOrders The advanced orders to validate and reduce by * their previously filled amounts. * @param criteriaResolvers An array where each element contains a reference * to a specific order as well as that order's * offer or consideration, a token identifier, and * a proof that the supplied token identifier is * contained in the order's merkle root. Note that * a root of zero indicates that any transferable * token identifier is valid and that no proof * needs to be supplied. * @param revertOnInvalid A boolean indicating whether to revert on any * order being invalid; setting this to false will * instead cause the invalid order to be skipped. * @param maximumFulfilled The maximum number of orders to fulfill. * @param recipient The intended recipient for all items that do not * already have a designated recipient and are not * already used as part of a provided fulfillment. * * @return orderHashes The hashes of the orders being fulfilled. * @return containsNonOpen A boolean indicating whether any restricted or * contract orders are present within the provided * array of advanced orders. */ function _validateOrdersAndPrepareToFulfill( AdvancedOrder[] memory advancedOrders, CriteriaResolver[] memory criteriaResolvers, bool revertOnInvalid, uint256 maximumFulfilled, address recipient ) internal returns (bytes32[] memory orderHashes, bool containsNonOpen) { // Ensure this function cannot be triggered during a reentrant call. _setReentrancyGuard(true); // Native tokens accepted during execution. // Declare an error buffer indicating status of any native offer items. // Native tokens may only be provided as part of contract orders or when // fulfilling via matchOrders or matchAdvancedOrders; if bits indicating // these conditions are not met have been set, throw. uint256 invalidNativeOfferItemErrorBuffer; // Use assembly to set the value for the second bit of the error buffer. assembly { /** * Use the 231st bit of the error buffer to indicate whether the * current function is not matchAdvancedOrders or matchOrders. * * sig func * ----------------------------------------------------------------- * 1010100000010111010001000 0 000100 matchOrders * 1111001011010001001010110 0 010010 matchAdvancedOrders * 1110110110011000101001010 1 110100 fulfillAvailableOrders * 1000011100100000000110110 1 000001 fulfillAvailableAdvancedOrders * ^ 7th bit */ invalidNativeOfferItemErrorBuffer := and( NonMatchSelector_MagicMask, calldataload(0) ) } // Declare variables for later use. AdvancedOrder memory advancedOrder; uint256 terminalMemoryOffset; unchecked { // Read length of orders array and place on the stack. uint256 totalOrders = advancedOrders.length; // Track the order hash for each order being fulfilled. orderHashes = new bytes32[](totalOrders); // Determine the memory offset to terminate on during loops. terminalMemoryOffset = (totalOrders + 1) << OneWordShift; } // Skip overflow checks as all for loops are indexed starting at zero. unchecked { // Declare inner variables. OfferItem[] memory offer; ConsiderationItem[] memory consideration; // Iterate over each order. for (uint256 i = OneWord; i < terminalMemoryOffset; i += OneWord) { // Retrieve order using assembly to bypass out-of-range check. assembly { advancedOrder := mload(add(advancedOrders, i)) } // Determine if max number orders have already been fulfilled. if (maximumFulfilled == 0) { // Mark fill fraction as zero as the order will not be used. advancedOrder.numerator = 0; // Continue iterating through the remaining orders. continue; } // Validate it, update status, and determine fraction to fill. ( bytes32 orderHash, uint256 numerator, uint256 denominator ) = _validateOrderAndUpdateStatus( advancedOrder, revertOnInvalid ); // Do not track hash or adjust prices if order is not fulfilled. if (numerator == 0) { // Mark fill fraction as zero if the order is not fulfilled. advancedOrder.numerator = 0; // Continue iterating through the remaining orders. continue; } // Otherwise, track the order hash in question. assembly { mstore(add(orderHashes, i), orderHash) } // Decrement the number of fulfilled orders. // Skip underflow check as the condition before // implies that maximumFulfilled > 0. --maximumFulfilled; // Place the start time for the order on the stack. uint256 startTime = advancedOrder.parameters.startTime; // Place the end time for the order on the stack. uint256 endTime = advancedOrder.parameters.endTime; // Retrieve array of offer items for the order in question. offer = advancedOrder.parameters.offer; // Read length of offer array and place on the stack. uint256 totalOfferItems = offer.length; { // Determine the order type, used to check for eligibility // for native token offer items as well as for the presence // of restricted and contract orders (or non-open orders). OrderType orderType = advancedOrder.parameters.orderType; // Utilize assembly to efficiently check for order types. // Note that these checks expect that there are no order // types beyond the current set (0-4) and will need to be // modified if more order types are added. assembly { // Declare a variable indicating if the order is not a // contract order. Cache in scratch space to avoid stack // depth errors. let isNonContract := lt(orderType, 4) mstore(0, isNonContract) // Update the variable indicating if the order is not an // open order, remaining set if it has been set already. containsNonOpen := or(containsNonOpen, gt(orderType, 1)) } } // Iterate over each offer item on the order. for (uint256 j = 0; j < totalOfferItems; ++j) { // Retrieve the offer item. OfferItem memory offerItem = offer[j]; // If the offer item is for the native token and the order // type is not a contract order type, set the first bit of // the error buffer to true. assembly { invalidNativeOfferItemErrorBuffer := or( invalidNativeOfferItemErrorBuffer, lt(mload(offerItem), mload(0)) ) } // Apply order fill fraction to offer item end amount. uint256 endAmount = _getFraction( numerator, denominator, offerItem.endAmount ); // Reuse same fraction if start and end amounts are equal. if (offerItem.startAmount == offerItem.endAmount) { // Apply derived amount to both start and end amount. offerItem.startAmount = endAmount; } else { // Apply order fill fraction to offer item start amount. offerItem.startAmount = _getFraction( numerator, denominator, offerItem.startAmount ); } // Adjust offer amount using current time; round down. uint256 currentAmount = _locateCurrentAmount( offerItem.startAmount, endAmount, startTime, endTime, false // round down ); // Update amounts in memory to match the current amount. // Note that the end amount is used to track spent amounts. offerItem.startAmount = currentAmount; offerItem.endAmount = currentAmount; } // Retrieve array of consideration items for order in question. consideration = (advancedOrder.parameters.consideration); // Read length of consideration array and place on the stack. uint256 totalConsiderationItems = consideration.length; // Iterate over each consideration item on the order. for (uint256 j = 0; j < totalConsiderationItems; ++j) { // Retrieve the consideration item. ConsiderationItem memory considerationItem = ( consideration[j] ); // Apply fraction to consideration item end amount. uint256 endAmount = _getFraction( numerator, denominator, considerationItem.endAmount ); // Reuse same fraction if start and end amounts are equal. if ( considerationItem.startAmount == considerationItem.endAmount ) { // Apply derived amount to both start and end amount. considerationItem.startAmount = endAmount; } else { // Apply fraction to consideration item start amount. considerationItem.startAmount = _getFraction( numerator, denominator, considerationItem.startAmount ); } // Adjust consideration amount using current time; round up. uint256 currentAmount = ( _locateCurrentAmount( considerationItem.startAmount, endAmount, startTime, endTime, true // round up ) ); considerationItem.startAmount = currentAmount; // Utilize assembly to manually "shift" the recipient value, // then to copy the start amount to the recipient. // Note that this sets up the memory layout that is // subsequently relied upon by // _aggregateValidFulfillmentConsiderationItems. assembly { // Derive the pointer to the recipient using the item // pointer along with the offset to the recipient. let considerationItemRecipientPtr := add( considerationItem, ConsiderationItem_recipient_offset // recipient ) // Write recipient to endAmount, as endAmount is not // used from this point on and can be repurposed to fit // the layout of a ReceivedItem. mstore( add( considerationItem, ReceivedItem_recipient_offset // old endAmount ), mload(considerationItemRecipientPtr) ) // Write startAmount to recipient, as recipient is not // used from this point on and can be repurposed to // track received amounts. mstore(considerationItemRecipientPtr, currentAmount) } } } } // If the first bit is set, a native offer item was encountered on an // order that is not a contract order. If the 231st bit is set in the // error buffer, the current function is not matchOrders or // matchAdvancedOrders. If the value is 1 + (1 << 230), then both the // 1st and 231st bits were set; in that case, revert with an error. if ( invalidNativeOfferItemErrorBuffer == NonMatchSelector_InvalidErrorValue ) { _revertInvalidNativeOfferItem(); } // Apply criteria resolvers to each order as applicable. _applyCriteriaResolvers(advancedOrders, criteriaResolvers); // Emit an event for each order signifying that it has been fulfilled. // Skip overflow checks as all for loops are indexed starting at zero. unchecked { bytes32 orderHash; // Iterate over each order. for (uint256 i = OneWord; i < terminalMemoryOffset; i += OneWord) { assembly { orderHash := mload(add(orderHashes, i)) } // Do not emit an event if no order hash is present. if (orderHash == bytes32(0)) { continue; } // Retrieve order using assembly to bypass out-of-range check. assembly { advancedOrder := mload(add(advancedOrders, i)) } // Retrieve parameters for the order in question. OrderParameters memory orderParameters = ( advancedOrder.parameters ); // Emit an OrderFulfilled event. _emitOrderFulfilledEvent( orderHash, orderParameters.offerer, orderParameters.zone, recipient, orderParameters.offer, orderParameters.consideration ); } } } /** * @dev Internal function to fulfill a group of validated orders, fully or * partially, with an arbitrary number of items for offer and * consideration per order and to execute transfers. Any order that is * not currently active, has already been fully filled, or has been * cancelled will be omitted. Remaining offer and consideration items * will then be aggregated where possible as indicated by the supplied * offer and consideration component arrays and aggregated items will * be transferred to the fulfiller or to each intended recipient, * respectively. Note that a failing item transfer or an issue with * order formatting will cause the entire batch to fail. * * @param advancedOrders The orders to fulfill along with the * fraction of those orders to attempt to * fill. Note that both the offerer and the * fulfiller must first approve this * contract (or the conduit if indicated by * the order) to transfer any relevant * tokens on their behalf and that * contracts must implement * `onERC1155Received` in order to receive * ERC1155 tokens as consideration. Also * note that all offer and consideration * components must have no remainder after * multiplication of the respective amount * with the supplied fraction for an * order's partial fill amount to be * considered valid. * @param offerFulfillments An array of FulfillmentComponent arrays * indicating which offer items to attempt * to aggregate when preparing executions. * @param considerationFulfillments An array of FulfillmentComponent arrays * indicating which consideration items to * attempt to aggregate when preparing * executions. * @param fulfillerConduitKey A bytes32 value indicating what conduit, * if any, to source the fulfiller's token * approvals from. The zero hash signifies * that no conduit should be used, with * direct approvals set on Consideration. * @param recipient The intended recipient for all items * that do not already have a designated * recipient and are not already used as * part of a provided fulfillment. * @param orderHashes An array of order hashes for each order. * @param containsNonOpen A boolean indicating whether any * restricted or contract orders are * present within the provided array of * advanced orders. * * @return availableOrders An array of booleans indicating if each order * with an index corresponding to the index of the * returned boolean was fulfillable or not. * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function _executeAvailableFulfillments( AdvancedOrder[] memory advancedOrders, FulfillmentComponent[][] memory offerFulfillments, FulfillmentComponent[][] memory considerationFulfillments, bytes32 fulfillerConduitKey, address recipient, bytes32[] memory orderHashes, bool containsNonOpen ) internal returns (bool[] memory availableOrders, Execution[] memory executions) { // Retrieve length of offer fulfillments array and place on the stack. uint256 totalOfferFulfillments = offerFulfillments.length; // Retrieve length of consideration fulfillments array & place on stack. uint256 totalConsiderationFulfillments = ( considerationFulfillments.length ); // Allocate an execution for each offer and consideration fulfillment. executions = new Execution[]( totalOfferFulfillments + totalConsiderationFulfillments ); // Skip overflow checks as all for loops are indexed starting at zero. unchecked { // Track number of filtered executions. uint256 totalFilteredExecutions = 0; // Iterate over each offer fulfillment. for (uint256 i = 0; i < totalOfferFulfillments; ) { // Derive aggregated execution corresponding with fulfillment. Execution memory execution = _aggregateAvailable( advancedOrders, Side.OFFER, offerFulfillments[i], fulfillerConduitKey, recipient ); // If the execution is filterable... if (_isFilterableExecution(execution)) { // Increment total filtered executions. ++totalFilteredExecutions; } else { // Otherwise, assign the execution to the executions array. executions[i - totalFilteredExecutions] = execution; } // Increment iterator. ++i; } // Iterate over each consideration fulfillment. for (uint256 i = 0; i < totalConsiderationFulfillments; ) { // Derive aggregated execution corresponding with fulfillment. Execution memory execution = _aggregateAvailable( advancedOrders, Side.CONSIDERATION, considerationFulfillments[i], fulfillerConduitKey, address(0) // unused ); // If the execution is filterable... if (_isFilterableExecution(execution)) { // Increment total filtered executions. ++totalFilteredExecutions; } else { // Otherwise, assign the execution to the executions array. executions[ i + totalOfferFulfillments - totalFilteredExecutions ] = execution; } // Increment iterator. ++i; } // If some number of executions have been filtered... if (totalFilteredExecutions != 0) { // reduce the total length of the executions array. assembly { mstore( executions, sub(mload(executions), totalFilteredExecutions) ) } } } // Revert if no orders are available. if (executions.length == 0) { _revertNoSpecifiedOrdersAvailable(); } // Perform final checks and return. availableOrders = _performFinalChecksAndExecuteOrders( advancedOrders, executions, orderHashes, recipient, containsNonOpen ); return (availableOrders, executions); } /** * @dev Internal function to perform a final check that each consideration * item for an arbitrary number of fulfilled orders has been met and to * trigger associated executions, transferring the respective items. * * @param advancedOrders The orders to check and perform executions for. * @param executions An array of elements indicating the sequence of * transfers to perform when fulfilling the given * orders. * @param orderHashes An array of order hashes for each order. * @param recipient The intended recipient for all items that do not * already have a designated recipient and are not * used as part of a provided fulfillment. * @param containsNonOpen A boolean indicating whether any restricted or * contract orders are present within the provided * array of advanced orders. * * @return availableOrders An array of booleans indicating if each order * with an index corresponding to the index of the * returned boolean was fulfillable or not. */ function _performFinalChecksAndExecuteOrders( AdvancedOrder[] memory advancedOrders, Execution[] memory executions, bytes32[] memory orderHashes, address recipient, bool containsNonOpen ) internal returns (bool[] memory /* availableOrders */) { // Retrieve the length of the advanced orders array and place on stack. uint256 totalOrders = advancedOrders.length; // Initialize array for tracking available orders. bool[] memory availableOrders = new bool[](totalOrders); // Initialize an accumulator array. From this point forward, no new // memory regions can be safely allocated until the accumulator is no // longer being utilized, as the accumulator operates in an open-ended // fashion from this memory pointer; existing memory may still be // accessed and modified, however. bytes memory accumulator = new bytes(AccumulatorDisarmed); { // Declare a variable for the available native token balance. uint256 nativeTokenBalance; // Retrieve the length of the executions array and place on stack. uint256 totalExecutions = executions.length; // Iterate over each execution. for (uint256 i = 0; i < totalExecutions; ) { // Retrieve the execution and the associated received item. Execution memory execution = executions[i]; ReceivedItem memory item = execution.item; // If execution transfers native tokens, reduce value available. if (item.itemType == ItemType.NATIVE) { // Get the current available balance of native tokens. assembly { nativeTokenBalance := selfbalance() } // Ensure that sufficient native tokens are still available. if (item.amount > nativeTokenBalance) { _revertInsufficientNativeTokensSupplied(); } } // Transfer the item specified by the execution. _transfer( item, execution.offerer, execution.conduitKey, accumulator ); // Skip overflow check as for loop is indexed starting at zero. unchecked { ++i; } } } // Skip overflow checks as all for loops are indexed starting at zero. unchecked { // Iterate over each order. for (uint256 i = 0; i < totalOrders; ++i) { // Retrieve the order in question. AdvancedOrder memory advancedOrder = advancedOrders[i]; // Skip the order in question if not being not fulfilled. if (advancedOrder.numerator == 0) { // Explicitly set availableOrders at the given index to // guard against the possibility of dirtied memory. availableOrders[i] = false; continue; } // Mark the order as available. availableOrders[i] = true; // Retrieve the order parameters. OrderParameters memory parameters = advancedOrder.parameters; { // Retrieve offer items. OfferItem[] memory offer = parameters.offer; // Read length of offer array & place on the stack. uint256 totalOfferItems = offer.length; // Iterate over each offer item to restore it. for (uint256 j = 0; j < totalOfferItems; ++j) { // Retrieve the offer item in question. OfferItem memory offerItem = offer[j]; // Transfer to recipient if unspent amount is not zero. // Note that the transfer will not be reflected in the // executions array. if (offerItem.startAmount != 0) { _transfer( _fromOfferItemToReceivedItemWithRecipient( offerItem, recipient ), parameters.offerer, parameters.conduitKey, accumulator ); } // Restore original amount on the offer item. offerItem.startAmount = offerItem.endAmount; } } { // Read consideration items & ensure they are fulfilled. ConsiderationItem[] memory consideration = ( parameters.consideration ); // Read length of consideration array & place on stack. uint256 totalConsiderationItems = consideration.length; // Iterate over each consideration item. for (uint256 j = 0; j < totalConsiderationItems; ++j) { ConsiderationItem memory considerationItem = ( consideration[j] ); // Retrieve remaining amount on consideration item. uint256 unmetAmount = considerationItem.startAmount; // Revert if the remaining amount is not zero. if (unmetAmount != 0) { _revertConsiderationNotMet(i, j, unmetAmount); } // Utilize assembly to restore the original value. assembly { // Write recipient to startAmount. mstore( add( considerationItem, ReceivedItem_amount_offset ), mload( add( considerationItem, ConsiderationItem_recipient_offset ) ) ) } } } } } // Trigger any accumulated transfers via call to the conduit. _triggerIfArmed(accumulator); // Determine whether any native token balance remains. uint256 remainingNativeTokenBalance; assembly { remainingNativeTokenBalance := selfbalance() } // Return any remaining native token balance to the caller. if (remainingNativeTokenBalance != 0) { _transferNativeTokens( payable(msg.sender), remainingNativeTokenBalance ); } // If any restricted or contract orders are present in the group of // orders being fulfilled, perform any validateOrder or ratifyOrder // calls after all executions and related transfers are complete. if (containsNonOpen) { // Iterate over each order a second time. for (uint256 i = 0; i < totalOrders; ) { // Ensure the order in question is being fulfilled. if (availableOrders[i]) { // Check restricted orders and contract orders. _assertRestrictedAdvancedOrderValidity( advancedOrders[i], orderHashes, orderHashes[i] ); } // Skip overflow checks as for loop is indexed starting at zero. unchecked { ++i; } } } // Clear the reentrancy guard. _clearReentrancyGuard(); // Return the array containing available orders. return availableOrders; } /** * @dev Internal function to emit an OrdersMatched event using the same * memory region as the existing order hash array. * * @param orderHashes An array of order hashes to include as an argument for * the OrdersMatched event. */ function _emitOrdersMatched(bytes32[] memory orderHashes) internal { assembly { // Load the array length from memory. let length := mload(orderHashes) // Get the full size of the event data - one word for the offset, // one for the array length and one per hash. let dataSize := add(TwoWords, shl(OneWordShift, length)) // Get pointer to start of data, reusing word before array length // for the offset. let dataPointer := sub(orderHashes, OneWord) // Cache the existing word in memory at the offset pointer. let cache := mload(dataPointer) // Write an offset of 32. mstore(dataPointer, OneWord) // Emit the OrdersMatched event. log1(dataPointer, dataSize, OrdersMatchedTopic0) // Restore the cached word. mstore(dataPointer, cache) } } /** * @dev Internal function to match an arbitrary number of full or partial * orders, each with an arbitrary number of items for offer and * consideration, supplying criteria resolvers containing specific * token identifiers and associated proofs as well as fulfillments * allocating offer components to consideration components. * * @param advancedOrders The advanced orders to match. Note that both the * offerer and fulfiller on each order must first * approve this contract (or their conduit if * indicated by the order) to transfer any relevant * tokens on their behalf and each consideration * recipient must implement `onERC1155Received` in * order to receive ERC1155 tokens. Also note that * the offer and consideration components for each * order must have no remainder after multiplying * the respective amount with the supplied fraction * in order for the group of partial fills to be * considered valid. * @param criteriaResolvers An array where each element contains a reference * to a specific order as well as that order's * offer or consideration, a token identifier, and * a proof that the supplied token identifier is * contained in the order's merkle root. Note that * an empty root indicates that any (transferable) * token identifier is valid and that no associated * proof needs to be supplied. * @param fulfillments An array of elements allocating offer components * to consideration components. Note that each * consideration component must be fully met in * order for the match operation to be valid. * @param recipient The intended recipient for all unspent offer * item amounts. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function _matchAdvancedOrders( AdvancedOrder[] memory advancedOrders, CriteriaResolver[] memory criteriaResolvers, Fulfillment[] memory fulfillments, address recipient ) internal returns (Execution[] memory /* executions */) { // Validate orders, update order status, and determine item amounts. ( bytes32[] memory orderHashes, bool containsNonOpen ) = _validateOrdersAndPrepareToFulfill( advancedOrders, criteriaResolvers, true, // Signifies that invalid orders should revert. advancedOrders.length, recipient ); // Emit OrdersMatched event, providing an array of matched order hashes. _emitOrdersMatched(orderHashes); // Fulfill the orders using the supplied fulfillments and recipient. return _fulfillAdvancedOrders( advancedOrders, fulfillments, orderHashes, recipient, containsNonOpen ); } /** * @dev Internal function to fulfill an arbitrary number of orders, either * full or partial, after validating, adjusting amounts, and applying * criteria resolvers. * * @param advancedOrders The orders to match, including a fraction to * attempt to fill for each order. * @param fulfillments An array of elements allocating offer components * to consideration components. Note that the final * amount of each consideration component must be * zero for a match operation to be considered valid. * @param orderHashes An array of order hashes for each order. * @param recipient The intended recipient for all items that do not * already have a designated recipient and are not * used as part of a provided fulfillment. * @param containsNonOpen A boolean indicating whether any restricted or * contract orders are present within the provided * array of advanced orders. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function _fulfillAdvancedOrders( AdvancedOrder[] memory advancedOrders, Fulfillment[] memory fulfillments, bytes32[] memory orderHashes, address recipient, bool containsNonOpen ) internal returns (Execution[] memory executions) { // Retrieve fulfillments array length and place on the stack. uint256 totalFulfillments = fulfillments.length; // Allocate executions by fulfillment and apply them to each execution. executions = new Execution[](totalFulfillments); // Skip overflow checks as all for loops are indexed starting at zero. unchecked { // Track number of filtered executions. uint256 totalFilteredExecutions = 0; // Iterate over each fulfillment. for (uint256 i = 0; i < totalFulfillments; ++i) { /// Retrieve the fulfillment in question. Fulfillment memory fulfillment = fulfillments[i]; // Derive the execution corresponding with the fulfillment. Execution memory execution = _applyFulfillment( advancedOrders, fulfillment.offerComponents, fulfillment.considerationComponents, i ); // If the execution is filterable... if (_isFilterableExecution(execution)) { // Increment total filtered executions. ++totalFilteredExecutions; } else { // Otherwise, assign the execution to the executions array. executions[i - totalFilteredExecutions] = execution; } } // If some number of executions have been filtered... if (totalFilteredExecutions != 0) { // reduce the total length of the executions array. assembly { mstore( executions, sub(mload(executions), totalFilteredExecutions) ) } } } // Perform final checks and execute orders. _performFinalChecksAndExecuteOrders( advancedOrders, executions, orderHashes, recipient, containsNonOpen ); // Return the executions array. return executions; } /** * @dev Internal pure function to determine whether a given execution is * filterable and may be removed from the executions array. The offerer * and the recipient must be the same address and the item type cannot * indicate a native token transfer. * * @param execution The execution to check for filterability. * * @return filterable A boolean indicating whether the execution in question * can be filtered from the executions array. */ function _isFilterableExecution( Execution memory execution ) internal pure returns (bool filterable) { // Utilize assembly to efficiently determine if execution is filterable. assembly { // Retrieve the received item referenced by the execution. let item := mload(execution) // Determine whether the execution is filterable. filterable := and( // Determine if offerer and recipient are the same address. eq( // Retrieve the recipient's address from the received item. mload(add(item, ReceivedItem_recipient_offset)), // Retrieve the offerer's address from the execution. mload(add(execution, Execution_offerer_offset)) ), // Determine if received item's item type is non-zero, thereby // indicating that the execution does not involve native tokens. iszero(iszero(mload(item))) ) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; type CalldataPointer is uint256; type ReturndataPointer is uint256; type MemoryPointer is uint256; using CalldataPointerLib for CalldataPointer global; using MemoryPointerLib for MemoryPointer global; using ReturndataPointerLib for ReturndataPointer global; using CalldataReaders for CalldataPointer global; using ReturndataReaders for ReturndataPointer global; using MemoryReaders for MemoryPointer global; using MemoryWriters for MemoryPointer global; CalldataPointer constant CalldataStart = CalldataPointer.wrap(0x04); MemoryPointer constant FreeMemoryPPtr = MemoryPointer.wrap(0x40); uint256 constant IdentityPrecompileAddress = 0x4; uint256 constant OffsetOrLengthMask = 0xffffffff; uint256 constant _OneWord = 0x20; uint256 constant _FreeMemoryPointerSlot = 0x40; /// @dev Allocates `size` bytes in memory by increasing the free memory pointer /// and returns the memory pointer to the first byte of the allocated region. // (Free functions cannot have visibility.) // solhint-disable-next-line func-visibility function malloc(uint256 size) pure returns (MemoryPointer mPtr) { assembly { mPtr := mload(_FreeMemoryPointerSlot) mstore(_FreeMemoryPointerSlot, add(mPtr, size)) } } // (Free functions cannot have visibility.) // solhint-disable-next-line func-visibility function getFreeMemoryPointer() pure returns (MemoryPointer mPtr) { mPtr = FreeMemoryPPtr.readMemoryPointer(); } // (Free functions cannot have visibility.) // solhint-disable-next-line func-visibility function setFreeMemoryPointer(MemoryPointer mPtr) pure { FreeMemoryPPtr.write(mPtr); } library CalldataPointerLib { function lt( CalldataPointer a, CalldataPointer b ) internal pure returns (bool c) { assembly { c := lt(a, b) } } function gt( CalldataPointer a, CalldataPointer b ) internal pure returns (bool c) { assembly { c := gt(a, b) } } function eq( CalldataPointer a, CalldataPointer b ) internal pure returns (bool c) { assembly { c := eq(a, b) } } /// @dev Resolves an offset stored at `cdPtr + headOffset` to a calldata. /// pointer `cdPtr` must point to some parent object with a dynamic /// type's head stored at `cdPtr + headOffset`. function pptr( CalldataPointer cdPtr, uint256 headOffset ) internal pure returns (CalldataPointer cdPtrChild) { cdPtrChild = cdPtr.offset( cdPtr.offset(headOffset).readUint256() & OffsetOrLengthMask ); } /// @dev Resolves an offset stored at `cdPtr` to a calldata pointer. /// `cdPtr` must point to some parent object with a dynamic type as its /// first member, e.g. `struct { bytes data; }` function pptr( CalldataPointer cdPtr ) internal pure returns (CalldataPointer cdPtrChild) { cdPtrChild = cdPtr.offset(cdPtr.readUint256() & OffsetOrLengthMask); } /// @dev Returns the calldata pointer one word after `cdPtr`. function next( CalldataPointer cdPtr ) internal pure returns (CalldataPointer cdPtrNext) { assembly { cdPtrNext := add(cdPtr, _OneWord) } } /// @dev Returns the calldata pointer `_offset` bytes after `cdPtr`. function offset( CalldataPointer cdPtr, uint256 _offset ) internal pure returns (CalldataPointer cdPtrNext) { assembly { cdPtrNext := add(cdPtr, _offset) } } /// @dev Copies `size` bytes from calldata starting at `src` to memory at /// `dst`. function copy( CalldataPointer src, MemoryPointer dst, uint256 size ) internal pure { assembly { calldatacopy(dst, src, size) } } } library ReturndataPointerLib { function lt( ReturndataPointer a, ReturndataPointer b ) internal pure returns (bool c) { assembly { c := lt(a, b) } } function gt( ReturndataPointer a, ReturndataPointer b ) internal pure returns (bool c) { assembly { c := gt(a, b) } } function eq( ReturndataPointer a, ReturndataPointer b ) internal pure returns (bool c) { assembly { c := eq(a, b) } } /// @dev Resolves an offset stored at `rdPtr + headOffset` to a returndata /// pointer. `rdPtr` must point to some parent object with a dynamic /// type's head stored at `rdPtr + headOffset`. function pptr( ReturndataPointer rdPtr, uint256 headOffset ) internal pure returns (ReturndataPointer rdPtrChild) { rdPtrChild = rdPtr.offset( rdPtr.offset(headOffset).readUint256() & OffsetOrLengthMask ); } /// @dev Resolves an offset stored at `rdPtr` to a returndata pointer. /// `rdPtr` must point to some parent object with a dynamic type as its /// first member, e.g. `struct { bytes data; }` function pptr( ReturndataPointer rdPtr ) internal pure returns (ReturndataPointer rdPtrChild) { rdPtrChild = rdPtr.offset(rdPtr.readUint256() & OffsetOrLengthMask); } /// @dev Returns the returndata pointer one word after `cdPtr`. function next( ReturndataPointer rdPtr ) internal pure returns (ReturndataPointer rdPtrNext) { assembly { rdPtrNext := add(rdPtr, _OneWord) } } /// @dev Returns the returndata pointer `_offset` bytes after `cdPtr`. function offset( ReturndataPointer rdPtr, uint256 _offset ) internal pure returns (ReturndataPointer rdPtrNext) { assembly { rdPtrNext := add(rdPtr, _offset) } } /// @dev Copies `size` bytes from returndata starting at `src` to memory at /// `dst`. function copy( ReturndataPointer src, MemoryPointer dst, uint256 size ) internal pure { assembly { returndatacopy(dst, src, size) } } } library MemoryPointerLib { function copy( MemoryPointer src, MemoryPointer dst, uint256 size ) internal view { assembly { let success := staticcall( gas(), IdentityPrecompileAddress, src, size, dst, size ) if or(iszero(returndatasize()), iszero(success)) { revert(0, 0) } } } function lt( MemoryPointer a, MemoryPointer b ) internal pure returns (bool c) { assembly { c := lt(a, b) } } function gt( MemoryPointer a, MemoryPointer b ) internal pure returns (bool c) { assembly { c := gt(a, b) } } function eq( MemoryPointer a, MemoryPointer b ) internal pure returns (bool c) { assembly { c := eq(a, b) } } /// @dev Returns the memory pointer one word after `mPtr`. function next( MemoryPointer mPtr ) internal pure returns (MemoryPointer mPtrNext) { assembly { mPtrNext := add(mPtr, _OneWord) } } /// @dev Returns the memory pointer `_offset` bytes after `mPtr`. function offset( MemoryPointer mPtr, uint256 _offset ) internal pure returns (MemoryPointer mPtrNext) { assembly { mPtrNext := add(mPtr, _offset) } } /// @dev Resolves a pointer pointer at `mPtr + headOffset` to a memory /// pointer. `mPtr` must point to some parent object with a dynamic /// type's pointer stored at `mPtr + headOffset`. function pptr( MemoryPointer mPtr, uint256 headOffset ) internal pure returns (MemoryPointer mPtrChild) { mPtrChild = mPtr.offset(headOffset).readMemoryPointer(); } /// @dev Resolves a pointer pointer stored at `mPtr` to a memory pointer. /// `mPtr` must point to some parent object with a dynamic type as its /// first member, e.g. `struct { bytes data; }` function pptr( MemoryPointer mPtr ) internal pure returns (MemoryPointer mPtrChild) { mPtrChild = mPtr.readMemoryPointer(); } } library CalldataReaders { /// @dev Reads the value at `cdPtr` and applies a mask to return only the /// last 4 bytes. function readMaskedUint256( CalldataPointer cdPtr ) internal pure returns (uint256 value) { value = cdPtr.readUint256() & OffsetOrLengthMask; } /// @dev Reads the bool at `cdPtr` in calldata. function readBool( CalldataPointer cdPtr ) internal pure returns (bool value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the address at `cdPtr` in calldata. function readAddress( CalldataPointer cdPtr ) internal pure returns (address value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes1 at `cdPtr` in calldata. function readBytes1( CalldataPointer cdPtr ) internal pure returns (bytes1 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes2 at `cdPtr` in calldata. function readBytes2( CalldataPointer cdPtr ) internal pure returns (bytes2 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes3 at `cdPtr` in calldata. function readBytes3( CalldataPointer cdPtr ) internal pure returns (bytes3 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes4 at `cdPtr` in calldata. function readBytes4( CalldataPointer cdPtr ) internal pure returns (bytes4 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes5 at `cdPtr` in calldata. function readBytes5( CalldataPointer cdPtr ) internal pure returns (bytes5 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes6 at `cdPtr` in calldata. function readBytes6( CalldataPointer cdPtr ) internal pure returns (bytes6 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes7 at `cdPtr` in calldata. function readBytes7( CalldataPointer cdPtr ) internal pure returns (bytes7 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes8 at `cdPtr` in calldata. function readBytes8( CalldataPointer cdPtr ) internal pure returns (bytes8 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes9 at `cdPtr` in calldata. function readBytes9( CalldataPointer cdPtr ) internal pure returns (bytes9 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes10 at `cdPtr` in calldata. function readBytes10( CalldataPointer cdPtr ) internal pure returns (bytes10 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes11 at `cdPtr` in calldata. function readBytes11( CalldataPointer cdPtr ) internal pure returns (bytes11 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes12 at `cdPtr` in calldata. function readBytes12( CalldataPointer cdPtr ) internal pure returns (bytes12 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes13 at `cdPtr` in calldata. function readBytes13( CalldataPointer cdPtr ) internal pure returns (bytes13 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes14 at `cdPtr` in calldata. function readBytes14( CalldataPointer cdPtr ) internal pure returns (bytes14 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes15 at `cdPtr` in calldata. function readBytes15( CalldataPointer cdPtr ) internal pure returns (bytes15 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes16 at `cdPtr` in calldata. function readBytes16( CalldataPointer cdPtr ) internal pure returns (bytes16 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes17 at `cdPtr` in calldata. function readBytes17( CalldataPointer cdPtr ) internal pure returns (bytes17 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes18 at `cdPtr` in calldata. function readBytes18( CalldataPointer cdPtr ) internal pure returns (bytes18 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes19 at `cdPtr` in calldata. function readBytes19( CalldataPointer cdPtr ) internal pure returns (bytes19 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes20 at `cdPtr` in calldata. function readBytes20( CalldataPointer cdPtr ) internal pure returns (bytes20 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes21 at `cdPtr` in calldata. function readBytes21( CalldataPointer cdPtr ) internal pure returns (bytes21 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes22 at `cdPtr` in calldata. function readBytes22( CalldataPointer cdPtr ) internal pure returns (bytes22 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes23 at `cdPtr` in calldata. function readBytes23( CalldataPointer cdPtr ) internal pure returns (bytes23 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes24 at `cdPtr` in calldata. function readBytes24( CalldataPointer cdPtr ) internal pure returns (bytes24 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes25 at `cdPtr` in calldata. function readBytes25( CalldataPointer cdPtr ) internal pure returns (bytes25 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes26 at `cdPtr` in calldata. function readBytes26( CalldataPointer cdPtr ) internal pure returns (bytes26 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes27 at `cdPtr` in calldata. function readBytes27( CalldataPointer cdPtr ) internal pure returns (bytes27 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes28 at `cdPtr` in calldata. function readBytes28( CalldataPointer cdPtr ) internal pure returns (bytes28 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes29 at `cdPtr` in calldata. function readBytes29( CalldataPointer cdPtr ) internal pure returns (bytes29 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes30 at `cdPtr` in calldata. function readBytes30( CalldataPointer cdPtr ) internal pure returns (bytes30 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes31 at `cdPtr` in calldata. function readBytes31( CalldataPointer cdPtr ) internal pure returns (bytes31 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes32 at `cdPtr` in calldata. function readBytes32( CalldataPointer cdPtr ) internal pure returns (bytes32 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint8 at `cdPtr` in calldata. function readUint8( CalldataPointer cdPtr ) internal pure returns (uint8 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint16 at `cdPtr` in calldata. function readUint16( CalldataPointer cdPtr ) internal pure returns (uint16 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint24 at `cdPtr` in calldata. function readUint24( CalldataPointer cdPtr ) internal pure returns (uint24 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint32 at `cdPtr` in calldata. function readUint32( CalldataPointer cdPtr ) internal pure returns (uint32 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint40 at `cdPtr` in calldata. function readUint40( CalldataPointer cdPtr ) internal pure returns (uint40 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint48 at `cdPtr` in calldata. function readUint48( CalldataPointer cdPtr ) internal pure returns (uint48 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint56 at `cdPtr` in calldata. function readUint56( CalldataPointer cdPtr ) internal pure returns (uint56 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint64 at `cdPtr` in calldata. function readUint64( CalldataPointer cdPtr ) internal pure returns (uint64 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint72 at `cdPtr` in calldata. function readUint72( CalldataPointer cdPtr ) internal pure returns (uint72 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint80 at `cdPtr` in calldata. function readUint80( CalldataPointer cdPtr ) internal pure returns (uint80 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint88 at `cdPtr` in calldata. function readUint88( CalldataPointer cdPtr ) internal pure returns (uint88 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint96 at `cdPtr` in calldata. function readUint96( CalldataPointer cdPtr ) internal pure returns (uint96 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint104 at `cdPtr` in calldata. function readUint104( CalldataPointer cdPtr ) internal pure returns (uint104 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint112 at `cdPtr` in calldata. function readUint112( CalldataPointer cdPtr ) internal pure returns (uint112 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint120 at `cdPtr` in calldata. function readUint120( CalldataPointer cdPtr ) internal pure returns (uint120 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint128 at `cdPtr` in calldata. function readUint128( CalldataPointer cdPtr ) internal pure returns (uint128 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint136 at `cdPtr` in calldata. function readUint136( CalldataPointer cdPtr ) internal pure returns (uint136 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint144 at `cdPtr` in calldata. function readUint144( CalldataPointer cdPtr ) internal pure returns (uint144 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint152 at `cdPtr` in calldata. function readUint152( CalldataPointer cdPtr ) internal pure returns (uint152 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint160 at `cdPtr` in calldata. function readUint160( CalldataPointer cdPtr ) internal pure returns (uint160 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint168 at `cdPtr` in calldata. function readUint168( CalldataPointer cdPtr ) internal pure returns (uint168 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint176 at `cdPtr` in calldata. function readUint176( CalldataPointer cdPtr ) internal pure returns (uint176 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint184 at `cdPtr` in calldata. function readUint184( CalldataPointer cdPtr ) internal pure returns (uint184 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint192 at `cdPtr` in calldata. function readUint192( CalldataPointer cdPtr ) internal pure returns (uint192 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint200 at `cdPtr` in calldata. function readUint200( CalldataPointer cdPtr ) internal pure returns (uint200 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint208 at `cdPtr` in calldata. function readUint208( CalldataPointer cdPtr ) internal pure returns (uint208 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint216 at `cdPtr` in calldata. function readUint216( CalldataPointer cdPtr ) internal pure returns (uint216 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint224 at `cdPtr` in calldata. function readUint224( CalldataPointer cdPtr ) internal pure returns (uint224 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint232 at `cdPtr` in calldata. function readUint232( CalldataPointer cdPtr ) internal pure returns (uint232 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint240 at `cdPtr` in calldata. function readUint240( CalldataPointer cdPtr ) internal pure returns (uint240 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint248 at `cdPtr` in calldata. function readUint248( CalldataPointer cdPtr ) internal pure returns (uint248 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint256 at `cdPtr` in calldata. function readUint256( CalldataPointer cdPtr ) internal pure returns (uint256 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int8 at `cdPtr` in calldata. function readInt8( CalldataPointer cdPtr ) internal pure returns (int8 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int16 at `cdPtr` in calldata. function readInt16( CalldataPointer cdPtr ) internal pure returns (int16 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int24 at `cdPtr` in calldata. function readInt24( CalldataPointer cdPtr ) internal pure returns (int24 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int32 at `cdPtr` in calldata. function readInt32( CalldataPointer cdPtr ) internal pure returns (int32 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int40 at `cdPtr` in calldata. function readInt40( CalldataPointer cdPtr ) internal pure returns (int40 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int48 at `cdPtr` in calldata. function readInt48( CalldataPointer cdPtr ) internal pure returns (int48 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int56 at `cdPtr` in calldata. function readInt56( CalldataPointer cdPtr ) internal pure returns (int56 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int64 at `cdPtr` in calldata. function readInt64( CalldataPointer cdPtr ) internal pure returns (int64 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int72 at `cdPtr` in calldata. function readInt72( CalldataPointer cdPtr ) internal pure returns (int72 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int80 at `cdPtr` in calldata. function readInt80( CalldataPointer cdPtr ) internal pure returns (int80 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int88 at `cdPtr` in calldata. function readInt88( CalldataPointer cdPtr ) internal pure returns (int88 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int96 at `cdPtr` in calldata. function readInt96( CalldataPointer cdPtr ) internal pure returns (int96 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int104 at `cdPtr` in calldata. function readInt104( CalldataPointer cdPtr ) internal pure returns (int104 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int112 at `cdPtr` in calldata. function readInt112( CalldataPointer cdPtr ) internal pure returns (int112 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int120 at `cdPtr` in calldata. function readInt120( CalldataPointer cdPtr ) internal pure returns (int120 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int128 at `cdPtr` in calldata. function readInt128( CalldataPointer cdPtr ) internal pure returns (int128 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int136 at `cdPtr` in calldata. function readInt136( CalldataPointer cdPtr ) internal pure returns (int136 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int144 at `cdPtr` in calldata. function readInt144( CalldataPointer cdPtr ) internal pure returns (int144 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int152 at `cdPtr` in calldata. function readInt152( CalldataPointer cdPtr ) internal pure returns (int152 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int160 at `cdPtr` in calldata. function readInt160( CalldataPointer cdPtr ) internal pure returns (int160 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int168 at `cdPtr` in calldata. function readInt168( CalldataPointer cdPtr ) internal pure returns (int168 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int176 at `cdPtr` in calldata. function readInt176( CalldataPointer cdPtr ) internal pure returns (int176 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int184 at `cdPtr` in calldata. function readInt184( CalldataPointer cdPtr ) internal pure returns (int184 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int192 at `cdPtr` in calldata. function readInt192( CalldataPointer cdPtr ) internal pure returns (int192 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int200 at `cdPtr` in calldata. function readInt200( CalldataPointer cdPtr ) internal pure returns (int200 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int208 at `cdPtr` in calldata. function readInt208( CalldataPointer cdPtr ) internal pure returns (int208 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int216 at `cdPtr` in calldata. function readInt216( CalldataPointer cdPtr ) internal pure returns (int216 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int224 at `cdPtr` in calldata. function readInt224( CalldataPointer cdPtr ) internal pure returns (int224 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int232 at `cdPtr` in calldata. function readInt232( CalldataPointer cdPtr ) internal pure returns (int232 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int240 at `cdPtr` in calldata. function readInt240( CalldataPointer cdPtr ) internal pure returns (int240 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int248 at `cdPtr` in calldata. function readInt248( CalldataPointer cdPtr ) internal pure returns (int248 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int256 at `cdPtr` in calldata. function readInt256( CalldataPointer cdPtr ) internal pure returns (int256 value) { assembly { value := calldataload(cdPtr) } } } library ReturndataReaders { /// @dev Reads value at `rdPtr` & applies a mask to return only last 4 bytes function readMaskedUint256( ReturndataPointer rdPtr ) internal pure returns (uint256 value) { value = rdPtr.readUint256() & OffsetOrLengthMask; } /// @dev Reads the bool at `rdPtr` in returndata. function readBool( ReturndataPointer rdPtr ) internal pure returns (bool value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the address at `rdPtr` in returndata. function readAddress( ReturndataPointer rdPtr ) internal pure returns (address value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes1 at `rdPtr` in returndata. function readBytes1( ReturndataPointer rdPtr ) internal pure returns (bytes1 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes2 at `rdPtr` in returndata. function readBytes2( ReturndataPointer rdPtr ) internal pure returns (bytes2 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes3 at `rdPtr` in returndata. function readBytes3( ReturndataPointer rdPtr ) internal pure returns (bytes3 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes4 at `rdPtr` in returndata. function readBytes4( ReturndataPointer rdPtr ) internal pure returns (bytes4 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes5 at `rdPtr` in returndata. function readBytes5( ReturndataPointer rdPtr ) internal pure returns (bytes5 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes6 at `rdPtr` in returndata. function readBytes6( ReturndataPointer rdPtr ) internal pure returns (bytes6 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes7 at `rdPtr` in returndata. function readBytes7( ReturndataPointer rdPtr ) internal pure returns (bytes7 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes8 at `rdPtr` in returndata. function readBytes8( ReturndataPointer rdPtr ) internal pure returns (bytes8 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes9 at `rdPtr` in returndata. function readBytes9( ReturndataPointer rdPtr ) internal pure returns (bytes9 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes10 at `rdPtr` in returndata. function readBytes10( ReturndataPointer rdPtr ) internal pure returns (bytes10 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes11 at `rdPtr` in returndata. function readBytes11( ReturndataPointer rdPtr ) internal pure returns (bytes11 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes12 at `rdPtr` in returndata. function readBytes12( ReturndataPointer rdPtr ) internal pure returns (bytes12 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes13 at `rdPtr` in returndata. function readBytes13( ReturndataPointer rdPtr ) internal pure returns (bytes13 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes14 at `rdPtr` in returndata. function readBytes14( ReturndataPointer rdPtr ) internal pure returns (bytes14 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes15 at `rdPtr` in returndata. function readBytes15( ReturndataPointer rdPtr ) internal pure returns (bytes15 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes16 at `rdPtr` in returndata. function readBytes16( ReturndataPointer rdPtr ) internal pure returns (bytes16 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes17 at `rdPtr` in returndata. function readBytes17( ReturndataPointer rdPtr ) internal pure returns (bytes17 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes18 at `rdPtr` in returndata. function readBytes18( ReturndataPointer rdPtr ) internal pure returns (bytes18 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes19 at `rdPtr` in returndata. function readBytes19( ReturndataPointer rdPtr ) internal pure returns (bytes19 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes20 at `rdPtr` in returndata. function readBytes20( ReturndataPointer rdPtr ) internal pure returns (bytes20 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes21 at `rdPtr` in returndata. function readBytes21( ReturndataPointer rdPtr ) internal pure returns (bytes21 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes22 at `rdPtr` in returndata. function readBytes22( ReturndataPointer rdPtr ) internal pure returns (bytes22 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes23 at `rdPtr` in returndata. function readBytes23( ReturndataPointer rdPtr ) internal pure returns (bytes23 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes24 at `rdPtr` in returndata. function readBytes24( ReturndataPointer rdPtr ) internal pure returns (bytes24 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes25 at `rdPtr` in returndata. function readBytes25( ReturndataPointer rdPtr ) internal pure returns (bytes25 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes26 at `rdPtr` in returndata. function readBytes26( ReturndataPointer rdPtr ) internal pure returns (bytes26 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes27 at `rdPtr` in returndata. function readBytes27( ReturndataPointer rdPtr ) internal pure returns (bytes27 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes28 at `rdPtr` in returndata. function readBytes28( ReturndataPointer rdPtr ) internal pure returns (bytes28 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes29 at `rdPtr` in returndata. function readBytes29( ReturndataPointer rdPtr ) internal pure returns (bytes29 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes30 at `rdPtr` in returndata. function readBytes30( ReturndataPointer rdPtr ) internal pure returns (bytes30 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes31 at `rdPtr` in returndata. function readBytes31( ReturndataPointer rdPtr ) internal pure returns (bytes31 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes32 at `rdPtr` in returndata. function readBytes32( ReturndataPointer rdPtr ) internal pure returns (bytes32 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint8 at `rdPtr` in returndata. function readUint8( ReturndataPointer rdPtr ) internal pure returns (uint8 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint16 at `rdPtr` in returndata. function readUint16( ReturndataPointer rdPtr ) internal pure returns (uint16 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint24 at `rdPtr` in returndata. function readUint24( ReturndataPointer rdPtr ) internal pure returns (uint24 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint32 at `rdPtr` in returndata. function readUint32( ReturndataPointer rdPtr ) internal pure returns (uint32 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint40 at `rdPtr` in returndata. function readUint40( ReturndataPointer rdPtr ) internal pure returns (uint40 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint48 at `rdPtr` in returndata. function readUint48( ReturndataPointer rdPtr ) internal pure returns (uint48 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint56 at `rdPtr` in returndata. function readUint56( ReturndataPointer rdPtr ) internal pure returns (uint56 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint64 at `rdPtr` in returndata. function readUint64( ReturndataPointer rdPtr ) internal pure returns (uint64 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint72 at `rdPtr` in returndata. function readUint72( ReturndataPointer rdPtr ) internal pure returns (uint72 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint80 at `rdPtr` in returndata. function readUint80( ReturndataPointer rdPtr ) internal pure returns (uint80 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint88 at `rdPtr` in returndata. function readUint88( ReturndataPointer rdPtr ) internal pure returns (uint88 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint96 at `rdPtr` in returndata. function readUint96( ReturndataPointer rdPtr ) internal pure returns (uint96 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint104 at `rdPtr` in returndata. function readUint104( ReturndataPointer rdPtr ) internal pure returns (uint104 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint112 at `rdPtr` in returndata. function readUint112( ReturndataPointer rdPtr ) internal pure returns (uint112 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint120 at `rdPtr` in returndata. function readUint120( ReturndataPointer rdPtr ) internal pure returns (uint120 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint128 at `rdPtr` in returndata. function readUint128( ReturndataPointer rdPtr ) internal pure returns (uint128 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint136 at `rdPtr` in returndata. function readUint136( ReturndataPointer rdPtr ) internal pure returns (uint136 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint144 at `rdPtr` in returndata. function readUint144( ReturndataPointer rdPtr ) internal pure returns (uint144 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint152 at `rdPtr` in returndata. function readUint152( ReturndataPointer rdPtr ) internal pure returns (uint152 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint160 at `rdPtr` in returndata. function readUint160( ReturndataPointer rdPtr ) internal pure returns (uint160 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint168 at `rdPtr` in returndata. function readUint168( ReturndataPointer rdPtr ) internal pure returns (uint168 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint176 at `rdPtr` in returndata. function readUint176( ReturndataPointer rdPtr ) internal pure returns (uint176 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint184 at `rdPtr` in returndata. function readUint184( ReturndataPointer rdPtr ) internal pure returns (uint184 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint192 at `rdPtr` in returndata. function readUint192( ReturndataPointer rdPtr ) internal pure returns (uint192 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint200 at `rdPtr` in returndata. function readUint200( ReturndataPointer rdPtr ) internal pure returns (uint200 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint208 at `rdPtr` in returndata. function readUint208( ReturndataPointer rdPtr ) internal pure returns (uint208 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint216 at `rdPtr` in returndata. function readUint216( ReturndataPointer rdPtr ) internal pure returns (uint216 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint224 at `rdPtr` in returndata. function readUint224( ReturndataPointer rdPtr ) internal pure returns (uint224 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint232 at `rdPtr` in returndata. function readUint232( ReturndataPointer rdPtr ) internal pure returns (uint232 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint240 at `rdPtr` in returndata. function readUint240( ReturndataPointer rdPtr ) internal pure returns (uint240 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint248 at `rdPtr` in returndata. function readUint248( ReturndataPointer rdPtr ) internal pure returns (uint248 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint256 at `rdPtr` in returndata. function readUint256( ReturndataPointer rdPtr ) internal pure returns (uint256 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int8 at `rdPtr` in returndata. function readInt8( ReturndataPointer rdPtr ) internal pure returns (int8 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int16 at `rdPtr` in returndata. function readInt16( ReturndataPointer rdPtr ) internal pure returns (int16 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int24 at `rdPtr` in returndata. function readInt24( ReturndataPointer rdPtr ) internal pure returns (int24 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int32 at `rdPtr` in returndata. function readInt32( ReturndataPointer rdPtr ) internal pure returns (int32 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int40 at `rdPtr` in returndata. function readInt40( ReturndataPointer rdPtr ) internal pure returns (int40 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int48 at `rdPtr` in returndata. function readInt48( ReturndataPointer rdPtr ) internal pure returns (int48 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int56 at `rdPtr` in returndata. function readInt56( ReturndataPointer rdPtr ) internal pure returns (int56 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int64 at `rdPtr` in returndata. function readInt64( ReturndataPointer rdPtr ) internal pure returns (int64 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int72 at `rdPtr` in returndata. function readInt72( ReturndataPointer rdPtr ) internal pure returns (int72 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int80 at `rdPtr` in returndata. function readInt80( ReturndataPointer rdPtr ) internal pure returns (int80 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int88 at `rdPtr` in returndata. function readInt88( ReturndataPointer rdPtr ) internal pure returns (int88 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int96 at `rdPtr` in returndata. function readInt96( ReturndataPointer rdPtr ) internal pure returns (int96 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int104 at `rdPtr` in returndata. function readInt104( ReturndataPointer rdPtr ) internal pure returns (int104 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int112 at `rdPtr` in returndata. function readInt112( ReturndataPointer rdPtr ) internal pure returns (int112 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int120 at `rdPtr` in returndata. function readInt120( ReturndataPointer rdPtr ) internal pure returns (int120 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int128 at `rdPtr` in returndata. function readInt128( ReturndataPointer rdPtr ) internal pure returns (int128 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int136 at `rdPtr` in returndata. function readInt136( ReturndataPointer rdPtr ) internal pure returns (int136 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int144 at `rdPtr` in returndata. function readInt144( ReturndataPointer rdPtr ) internal pure returns (int144 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int152 at `rdPtr` in returndata. function readInt152( ReturndataPointer rdPtr ) internal pure returns (int152 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int160 at `rdPtr` in returndata. function readInt160( ReturndataPointer rdPtr ) internal pure returns (int160 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int168 at `rdPtr` in returndata. function readInt168( ReturndataPointer rdPtr ) internal pure returns (int168 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int176 at `rdPtr` in returndata. function readInt176( ReturndataPointer rdPtr ) internal pure returns (int176 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int184 at `rdPtr` in returndata. function readInt184( ReturndataPointer rdPtr ) internal pure returns (int184 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int192 at `rdPtr` in returndata. function readInt192( ReturndataPointer rdPtr ) internal pure returns (int192 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int200 at `rdPtr` in returndata. function readInt200( ReturndataPointer rdPtr ) internal pure returns (int200 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int208 at `rdPtr` in returndata. function readInt208( ReturndataPointer rdPtr ) internal pure returns (int208 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int216 at `rdPtr` in returndata. function readInt216( ReturndataPointer rdPtr ) internal pure returns (int216 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int224 at `rdPtr` in returndata. function readInt224( ReturndataPointer rdPtr ) internal pure returns (int224 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int232 at `rdPtr` in returndata. function readInt232( ReturndataPointer rdPtr ) internal pure returns (int232 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int240 at `rdPtr` in returndata. function readInt240( ReturndataPointer rdPtr ) internal pure returns (int240 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int248 at `rdPtr` in returndata. function readInt248( ReturndataPointer rdPtr ) internal pure returns (int248 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int256 at `rdPtr` in returndata. function readInt256( ReturndataPointer rdPtr ) internal pure returns (int256 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } } library MemoryReaders { /// @dev Reads the memory pointer at `mPtr` in memory. function readMemoryPointer( MemoryPointer mPtr ) internal pure returns (MemoryPointer value) { assembly { value := mload(mPtr) } } /// @dev Reads value at `mPtr` & applies a mask to return only last 4 bytes function readMaskedUint256( MemoryPointer mPtr ) internal pure returns (uint256 value) { value = mPtr.readUint256() & OffsetOrLengthMask; } /// @dev Reads the bool at `mPtr` in memory. function readBool(MemoryPointer mPtr) internal pure returns (bool value) { assembly { value := mload(mPtr) } } /// @dev Reads the address at `mPtr` in memory. function readAddress( MemoryPointer mPtr ) internal pure returns (address value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes1 at `mPtr` in memory. function readBytes1( MemoryPointer mPtr ) internal pure returns (bytes1 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes2 at `mPtr` in memory. function readBytes2( MemoryPointer mPtr ) internal pure returns (bytes2 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes3 at `mPtr` in memory. function readBytes3( MemoryPointer mPtr ) internal pure returns (bytes3 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes4 at `mPtr` in memory. function readBytes4( MemoryPointer mPtr ) internal pure returns (bytes4 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes5 at `mPtr` in memory. function readBytes5( MemoryPointer mPtr ) internal pure returns (bytes5 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes6 at `mPtr` in memory. function readBytes6( MemoryPointer mPtr ) internal pure returns (bytes6 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes7 at `mPtr` in memory. function readBytes7( MemoryPointer mPtr ) internal pure returns (bytes7 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes8 at `mPtr` in memory. function readBytes8( MemoryPointer mPtr ) internal pure returns (bytes8 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes9 at `mPtr` in memory. function readBytes9( MemoryPointer mPtr ) internal pure returns (bytes9 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes10 at `mPtr` in memory. function readBytes10( MemoryPointer mPtr ) internal pure returns (bytes10 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes11 at `mPtr` in memory. function readBytes11( MemoryPointer mPtr ) internal pure returns (bytes11 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes12 at `mPtr` in memory. function readBytes12( MemoryPointer mPtr ) internal pure returns (bytes12 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes13 at `mPtr` in memory. function readBytes13( MemoryPointer mPtr ) internal pure returns (bytes13 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes14 at `mPtr` in memory. function readBytes14( MemoryPointer mPtr ) internal pure returns (bytes14 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes15 at `mPtr` in memory. function readBytes15( MemoryPointer mPtr ) internal pure returns (bytes15 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes16 at `mPtr` in memory. function readBytes16( MemoryPointer mPtr ) internal pure returns (bytes16 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes17 at `mPtr` in memory. function readBytes17( MemoryPointer mPtr ) internal pure returns (bytes17 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes18 at `mPtr` in memory. function readBytes18( MemoryPointer mPtr ) internal pure returns (bytes18 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes19 at `mPtr` in memory. function readBytes19( MemoryPointer mPtr ) internal pure returns (bytes19 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes20 at `mPtr` in memory. function readBytes20( MemoryPointer mPtr ) internal pure returns (bytes20 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes21 at `mPtr` in memory. function readBytes21( MemoryPointer mPtr ) internal pure returns (bytes21 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes22 at `mPtr` in memory. function readBytes22( MemoryPointer mPtr ) internal pure returns (bytes22 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes23 at `mPtr` in memory. function readBytes23( MemoryPointer mPtr ) internal pure returns (bytes23 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes24 at `mPtr` in memory. function readBytes24( MemoryPointer mPtr ) internal pure returns (bytes24 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes25 at `mPtr` in memory. function readBytes25( MemoryPointer mPtr ) internal pure returns (bytes25 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes26 at `mPtr` in memory. function readBytes26( MemoryPointer mPtr ) internal pure returns (bytes26 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes27 at `mPtr` in memory. function readBytes27( MemoryPointer mPtr ) internal pure returns (bytes27 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes28 at `mPtr` in memory. function readBytes28( MemoryPointer mPtr ) internal pure returns (bytes28 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes29 at `mPtr` in memory. function readBytes29( MemoryPointer mPtr ) internal pure returns (bytes29 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes30 at `mPtr` in memory. function readBytes30( MemoryPointer mPtr ) internal pure returns (bytes30 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes31 at `mPtr` in memory. function readBytes31( MemoryPointer mPtr ) internal pure returns (bytes31 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes32 at `mPtr` in memory. function readBytes32( MemoryPointer mPtr ) internal pure returns (bytes32 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint8 at `mPtr` in memory. function readUint8(MemoryPointer mPtr) internal pure returns (uint8 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint16 at `mPtr` in memory. function readUint16( MemoryPointer mPtr ) internal pure returns (uint16 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint24 at `mPtr` in memory. function readUint24( MemoryPointer mPtr ) internal pure returns (uint24 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint32 at `mPtr` in memory. function readUint32( MemoryPointer mPtr ) internal pure returns (uint32 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint40 at `mPtr` in memory. function readUint40( MemoryPointer mPtr ) internal pure returns (uint40 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint48 at `mPtr` in memory. function readUint48( MemoryPointer mPtr ) internal pure returns (uint48 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint56 at `mPtr` in memory. function readUint56( MemoryPointer mPtr ) internal pure returns (uint56 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint64 at `mPtr` in memory. function readUint64( MemoryPointer mPtr ) internal pure returns (uint64 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint72 at `mPtr` in memory. function readUint72( MemoryPointer mPtr ) internal pure returns (uint72 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint80 at `mPtr` in memory. function readUint80( MemoryPointer mPtr ) internal pure returns (uint80 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint88 at `mPtr` in memory. function readUint88( MemoryPointer mPtr ) internal pure returns (uint88 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint96 at `mPtr` in memory. function readUint96( MemoryPointer mPtr ) internal pure returns (uint96 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint104 at `mPtr` in memory. function readUint104( MemoryPointer mPtr ) internal pure returns (uint104 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint112 at `mPtr` in memory. function readUint112( MemoryPointer mPtr ) internal pure returns (uint112 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint120 at `mPtr` in memory. function readUint120( MemoryPointer mPtr ) internal pure returns (uint120 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint128 at `mPtr` in memory. function readUint128( MemoryPointer mPtr ) internal pure returns (uint128 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint136 at `mPtr` in memory. function readUint136( MemoryPointer mPtr ) internal pure returns (uint136 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint144 at `mPtr` in memory. function readUint144( MemoryPointer mPtr ) internal pure returns (uint144 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint152 at `mPtr` in memory. function readUint152( MemoryPointer mPtr ) internal pure returns (uint152 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint160 at `mPtr` in memory. function readUint160( MemoryPointer mPtr ) internal pure returns (uint160 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint168 at `mPtr` in memory. function readUint168( MemoryPointer mPtr ) internal pure returns (uint168 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint176 at `mPtr` in memory. function readUint176( MemoryPointer mPtr ) internal pure returns (uint176 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint184 at `mPtr` in memory. function readUint184( MemoryPointer mPtr ) internal pure returns (uint184 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint192 at `mPtr` in memory. function readUint192( MemoryPointer mPtr ) internal pure returns (uint192 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint200 at `mPtr` in memory. function readUint200( MemoryPointer mPtr ) internal pure returns (uint200 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint208 at `mPtr` in memory. function readUint208( MemoryPointer mPtr ) internal pure returns (uint208 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint216 at `mPtr` in memory. function readUint216( MemoryPointer mPtr ) internal pure returns (uint216 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint224 at `mPtr` in memory. function readUint224( MemoryPointer mPtr ) internal pure returns (uint224 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint232 at `mPtr` in memory. function readUint232( MemoryPointer mPtr ) internal pure returns (uint232 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint240 at `mPtr` in memory. function readUint240( MemoryPointer mPtr ) internal pure returns (uint240 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint248 at `mPtr` in memory. function readUint248( MemoryPointer mPtr ) internal pure returns (uint248 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint256 at `mPtr` in memory. function readUint256( MemoryPointer mPtr ) internal pure returns (uint256 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int8 at `mPtr` in memory. function readInt8(MemoryPointer mPtr) internal pure returns (int8 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int16 at `mPtr` in memory. function readInt16(MemoryPointer mPtr) internal pure returns (int16 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int24 at `mPtr` in memory. function readInt24(MemoryPointer mPtr) internal pure returns (int24 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int32 at `mPtr` in memory. function readInt32(MemoryPointer mPtr) internal pure returns (int32 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int40 at `mPtr` in memory. function readInt40(MemoryPointer mPtr) internal pure returns (int40 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int48 at `mPtr` in memory. function readInt48(MemoryPointer mPtr) internal pure returns (int48 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int56 at `mPtr` in memory. function readInt56(MemoryPointer mPtr) internal pure returns (int56 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int64 at `mPtr` in memory. function readInt64(MemoryPointer mPtr) internal pure returns (int64 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int72 at `mPtr` in memory. function readInt72(MemoryPointer mPtr) internal pure returns (int72 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int80 at `mPtr` in memory. function readInt80(MemoryPointer mPtr) internal pure returns (int80 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int88 at `mPtr` in memory. function readInt88(MemoryPointer mPtr) internal pure returns (int88 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int96 at `mPtr` in memory. function readInt96(MemoryPointer mPtr) internal pure returns (int96 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int104 at `mPtr` in memory. function readInt104( MemoryPointer mPtr ) internal pure returns (int104 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int112 at `mPtr` in memory. function readInt112( MemoryPointer mPtr ) internal pure returns (int112 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int120 at `mPtr` in memory. function readInt120( MemoryPointer mPtr ) internal pure returns (int120 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int128 at `mPtr` in memory. function readInt128( MemoryPointer mPtr ) internal pure returns (int128 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int136 at `mPtr` in memory. function readInt136( MemoryPointer mPtr ) internal pure returns (int136 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int144 at `mPtr` in memory. function readInt144( MemoryPointer mPtr ) internal pure returns (int144 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int152 at `mPtr` in memory. function readInt152( MemoryPointer mPtr ) internal pure returns (int152 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int160 at `mPtr` in memory. function readInt160( MemoryPointer mPtr ) internal pure returns (int160 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int168 at `mPtr` in memory. function readInt168( MemoryPointer mPtr ) internal pure returns (int168 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int176 at `mPtr` in memory. function readInt176( MemoryPointer mPtr ) internal pure returns (int176 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int184 at `mPtr` in memory. function readInt184( MemoryPointer mPtr ) internal pure returns (int184 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int192 at `mPtr` in memory. function readInt192( MemoryPointer mPtr ) internal pure returns (int192 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int200 at `mPtr` in memory. function readInt200( MemoryPointer mPtr ) internal pure returns (int200 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int208 at `mPtr` in memory. function readInt208( MemoryPointer mPtr ) internal pure returns (int208 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int216 at `mPtr` in memory. function readInt216( MemoryPointer mPtr ) internal pure returns (int216 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int224 at `mPtr` in memory. function readInt224( MemoryPointer mPtr ) internal pure returns (int224 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int232 at `mPtr` in memory. function readInt232( MemoryPointer mPtr ) internal pure returns (int232 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int240 at `mPtr` in memory. function readInt240( MemoryPointer mPtr ) internal pure returns (int240 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int248 at `mPtr` in memory. function readInt248( MemoryPointer mPtr ) internal pure returns (int248 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int256 at `mPtr` in memory. function readInt256( MemoryPointer mPtr ) internal pure returns (int256 value) { assembly { value := mload(mPtr) } } } library MemoryWriters { /// @dev Writes `valuePtr` to memory at `mPtr`. function write(MemoryPointer mPtr, MemoryPointer valuePtr) internal pure { assembly { mstore(mPtr, valuePtr) } } /// @dev Writes a boolean `value` to `mPtr` in memory. function write(MemoryPointer mPtr, bool value) internal pure { assembly { mstore(mPtr, value) } } /// @dev Writes an address `value` to `mPtr` in memory. function write(MemoryPointer mPtr, address value) internal pure { assembly { mstore(mPtr, value) } } /// @dev Writes a bytes32 `value` to `mPtr` in memory. /// Separate name to disambiguate literal write parameters. function writeBytes32(MemoryPointer mPtr, bytes32 value) internal pure { assembly { mstore(mPtr, value) } } /// @dev Writes a uint256 `value` to `mPtr` in memory. function write(MemoryPointer mPtr, uint256 value) internal pure { assembly { mstore(mPtr, value) } } /// @dev Writes an int256 `value` to `mPtr` in memory. /// Separate name to disambiguate literal write parameters. function writeInt(MemoryPointer mPtr, int256 value) internal pure { assembly { mstore(mPtr, value) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /* * -------------------------- Disambiguation & Other Notes --------------------- * - The term "head" is used as it is in the documentation for ABI encoding, * but only in reference to dynamic types, i.e. it always refers to the * offset or pointer to the body of a dynamic type. In calldata, the head * is always an offset (relative to the parent object), while in memory, * the head is always the pointer to the body. More information found here: * https://docs.soliditylang.org/en/v0.8.17/abi-spec.html#argument-encoding * - Note that the length of an array is separate from and precedes the * head of the array. * * - The term "body" is used in place of the term "head" used in the ABI * documentation. It refers to the start of the data for a dynamic type, * e.g. the first word of a struct or the first word of the first element * in an array. * * - The term "pointer" is used to describe the absolute position of a value * and never an offset relative to another value. * - The suffix "_ptr" refers to a memory pointer. * - The suffix "_cdPtr" refers to a calldata pointer. * * - The term "offset" is used to describe the position of a value relative * to some parent value. For example, OrderParameters_conduit_offset is the * offset to the "conduit" value in the OrderParameters struct relative to * the start of the body. * - Note: Offsets are used to derive pointers. * * - Some structs have pointers defined for all of their fields in this file. * Lines which are commented out are fields that are not used in the * codebase but have been left in for readability. */ // Declare constants for name, version, and reentrancy sentinel values. // Name is right padded, so it touches the length which is left padded. This // enables writing both values at once. Length goes at byte 95 in memory, and // name fills bytes 96-109, so both values can be written left-padded to 77. uint256 constant NameLengthPtr = 0x4D; uint256 constant NameWithLength = 0x0d436F6E73696465726174696F6E; uint256 constant information_version_offset = 0; uint256 constant information_version_cd_offset = 0x60; uint256 constant information_domainSeparator_offset = 0x20; uint256 constant information_conduitController_offset = 0x40; uint256 constant information_versionLengthPtr = 0x63; uint256 constant information_versionWithLength = 0x03312e34; // 1.4 uint256 constant information_length = 0xa0; uint256 constant _NOT_ENTERED = 1; uint256 constant _ENTERED = 2; uint256 constant _ENTERED_AND_ACCEPTING_NATIVE_TOKENS = 3; uint256 constant Offset_fulfillAdvancedOrder_criteriaResolvers = 0x20; uint256 constant Offset_fulfillAvailableOrders_offerFulfillments = 0x20; uint256 constant Offset_fulfillAvailableOrders_considerationFulfillments = 0x40; uint256 constant Offset_fulfillAvailableAdvancedOrders_criteriaResolvers = 0x20; uint256 constant Offset_fulfillAvailableAdvancedOrders_offerFulfillments = 0x40; uint256 constant Offset_fulfillAvailableAdvancedOrders_cnsdrationFlflmnts = ( 0x60 ); uint256 constant Offset_matchOrders_fulfillments = 0x20; uint256 constant Offset_matchAdvancedOrders_criteriaResolvers = 0x20; uint256 constant Offset_matchAdvancedOrders_fulfillments = 0x40; // Common Offsets // Offsets for identically positioned fields shared by: // OfferItem, ConsiderationItem, SpentItem, ReceivedItem uint256 constant Selector_length = 0x4; uint256 constant Common_token_offset = 0x20; uint256 constant Common_identifier_offset = 0x40; uint256 constant Common_amount_offset = 0x60; uint256 constant Common_endAmount_offset = 0x80; uint256 constant SpentItem_size = 0x80; uint256 constant SpentItem_size_shift = 0x7; uint256 constant OfferItem_size = 0xa0; uint256 constant OfferItem_size_with_length = 0xc0; uint256 constant ReceivedItem_size_excluding_recipient = 0x80; uint256 constant ReceivedItem_size = 0xa0; uint256 constant ReceivedItem_amount_offset = 0x60; uint256 constant ReceivedItem_recipient_offset = 0x80; uint256 constant ReceivedItem_CommonParams_size = 0x60; uint256 constant ConsiderationItem_size = 0xc0; uint256 constant ConsiderationItem_size_with_length = 0xe0; uint256 constant ConsiderationItem_recipient_offset = 0xa0; // Store the same constant in an abbreviated format for a line length fix. uint256 constant ConsiderItem_recipient_offset = 0xa0; uint256 constant Execution_offerer_offset = 0x20; uint256 constant Execution_conduit_offset = 0x40; // uint256 constant OrderParameters_offerer_offset = 0x00; uint256 constant OrderParameters_zone_offset = 0x20; uint256 constant OrderParameters_offer_head_offset = 0x40; uint256 constant OrderParameters_consideration_head_offset = 0x60; // uint256 constant OrderParameters_orderType_offset = 0x80; uint256 constant OrderParameters_startTime_offset = 0xa0; uint256 constant OrderParameters_endTime_offset = 0xc0; uint256 constant OrderParameters_zoneHash_offset = 0xe0; // uint256 constant OrderParameters_salt_offset = 0x100; uint256 constant OrderParameters_conduit_offset = 0x120; uint256 constant OrderParameters_counter_offset = 0x140; uint256 constant Fulfillment_itemIndex_offset = 0x20; uint256 constant AdvancedOrder_head_size = 0xa0; uint256 constant AdvancedOrder_numerator_offset = 0x20; uint256 constant AdvancedOrder_denominator_offset = 0x40; uint256 constant AdvancedOrder_signature_offset = 0x60; uint256 constant AdvancedOrder_extraData_offset = 0x80; uint256 constant OrderStatus_ValidatedAndNotCancelled = 1; uint256 constant OrderStatus_filledNumerator_offset = 0x10; uint256 constant OrderStatus_filledDenominator_offset = 0x88; uint256 constant ThirtyOneBytes = 0x1f; uint256 constant OneWord = 0x20; uint256 constant TwoWords = 0x40; uint256 constant ThreeWords = 0x60; uint256 constant FourWords = 0x80; uint256 constant FiveWords = 0xa0; uint256 constant OneWordShift = 0x5; uint256 constant TwoWordsShift = 0x6; uint256 constant SixtyThreeBytes = 0x3f; uint256 constant OnlyFullWordMask = 0xffffffe0; uint256 constant FreeMemoryPointerSlot = 0x40; uint256 constant ZeroSlot = 0x60; uint256 constant DefaultFreeMemoryPointer = 0x80; uint256 constant Slot0x80 = 0x80; uint256 constant Slot0xA0 = 0xa0; // uint256 constant BasicOrder_endAmount_cdPtr = 0x104; uint256 constant BasicOrder_common_params_size = 0xa0; uint256 constant BasicOrder_considerationHashesArray_ptr = 0x160; uint256 constant BasicOrder_receivedItemByteMap = ( 0x0000010102030000000000000000000000000000000000000000000000000000 ); uint256 constant BasicOrder_offeredItemByteMap = ( 0x0203020301010000000000000000000000000000000000000000000000000000 ); bytes32 constant OrdersMatchedTopic0 = ( 0x4b9f2d36e1b4c93de62cc077b00b1a91d84b6c31b4a14e012718dcca230689e7 ); uint256 constant EIP712_Order_size = 0x180; uint256 constant EIP712_OfferItem_size = 0xc0; uint256 constant EIP712_ConsiderationItem_size = 0xe0; uint256 constant AdditionalRecipient_size = 0x40; uint256 constant AdditionalRecipient_size_shift = 0x6; uint256 constant EIP712_DomainSeparator_offset = 0x02; uint256 constant EIP712_OrderHash_offset = 0x22; uint256 constant EIP712_DigestPayload_size = 0x42; uint256 constant EIP712_domainData_nameHash_offset = 0x20; uint256 constant EIP712_domainData_versionHash_offset = 0x40; uint256 constant EIP712_domainData_chainId_offset = 0x60; uint256 constant EIP712_domainData_verifyingContract_offset = 0x80; uint256 constant EIP712_domainData_size = 0xa0; // Minimum BulkOrder proof size: 64 bytes for signature + 3 for key + 32 for 1 // sibling. Maximum BulkOrder proof size: 65 bytes for signature + 3 for key + // 768 for 24 siblings. uint256 constant BulkOrderProof_minSize = 0x63; uint256 constant BulkOrderProof_rangeSize = 0x2e2; uint256 constant BulkOrderProof_lengthAdjustmentBeforeMask = 0x1d; uint256 constant BulkOrderProof_lengthRangeAfterMask = 0x2; uint256 constant BulkOrderProof_keyShift = 0xe8; uint256 constant BulkOrderProof_keySize = 0x3; uint256 constant BulkOrder_Typehash_Height_One = ( 0x3ca2711d29384747a8f61d60aad3c450405f7aaff5613541dee28df2d6986d32 ); uint256 constant BulkOrder_Typehash_Height_Two = ( 0xbf8e29b89f29ed9b529c154a63038ffca562f8d7cd1e2545dda53a1b582dde30 ); uint256 constant BulkOrder_Typehash_Height_Three = ( 0x53c6f6856e13104584dd0797ca2b2779202dc2597c6066a42e0d8fe990b0024d ); uint256 constant BulkOrder_Typehash_Height_Four = ( 0xa02eb7ff164c884e5e2c336dc85f81c6a93329d8e9adf214b32729b894de2af1 ); uint256 constant BulkOrder_Typehash_Height_Five = ( 0x39c9d33c18e050dda0aeb9a8086fb16fc12d5d64536780e1da7405a800b0b9f6 ); uint256 constant BulkOrder_Typehash_Height_Six = ( 0x1c19f71958cdd8f081b4c31f7caf5c010b29d12950be2fa1c95070dc47e30b55 ); uint256 constant BulkOrder_Typehash_Height_Seven = ( 0xca74fab2fece9a1d58234a274220ad05ca096a92ef6a1ca1750b9d90c948955c ); uint256 constant BulkOrder_Typehash_Height_Eight = ( 0x7ff98d9d4e55d876c5cfac10b43c04039522f3ddfb0ea9bfe70c68cfb5c7cc14 ); uint256 constant BulkOrder_Typehash_Height_Nine = ( 0xbed7be92d41c56f9e59ac7a6272185299b815ddfabc3f25deb51fe55fe2f9e8a ); uint256 constant BulkOrder_Typehash_Height_Ten = ( 0xd1d97d1ef5eaa37a4ee5fbf234e6f6d64eb511eb562221cd7edfbdde0848da05 ); uint256 constant BulkOrder_Typehash_Height_Eleven = ( 0x896c3f349c4da741c19b37fec49ed2e44d738e775a21d9c9860a69d67a3dae53 ); uint256 constant BulkOrder_Typehash_Height_Twelve = ( 0xbb98d87cc12922b83759626c5f07d72266da9702d19ffad6a514c73a89002f5f ); uint256 constant BulkOrder_Typehash_Height_Thirteen = ( 0xe6ae19322608dd1f8a8d56aab48ed9c28be489b689f4b6c91268563efc85f20e ); uint256 constant BulkOrder_Typehash_Height_Fourteen = ( 0x6b5b04cbae4fcb1a9d78e7b2dfc51a36933d023cf6e347e03d517b472a852590 ); uint256 constant BulkOrder_Typehash_Height_Fifteen = ( 0xd1eb68309202b7106b891e109739dbbd334a1817fe5d6202c939e75cf5e35ca9 ); uint256 constant BulkOrder_Typehash_Height_Sixteen = ( 0x1da3eed3ecef6ebaa6e5023c057ec2c75150693fd0dac5c90f4a142f9879fde8 ); uint256 constant BulkOrder_Typehash_Height_Seventeen = ( 0xeee9a1392aa395c7002308119a58f2582777a75e54e0c1d5d5437bd2e8bf6222 ); uint256 constant BulkOrder_Typehash_Height_Eighteen = ( 0xc3939feff011e53ab8c35ca3370aad54c5df1fc2938cd62543174fa6e7d85877 ); uint256 constant BulkOrder_Typehash_Height_Nineteen = ( 0x0efca7572ac20f5ae84db0e2940674f7eca0a4726fa1060ffc2d18cef54b203d ); uint256 constant BulkOrder_Typehash_Height_Twenty = ( 0x5a4f867d3d458dabecad65f6201ceeaba0096df2d0c491cc32e6ea4e64350017 ); uint256 constant BulkOrder_Typehash_Height_TwentyOne = ( 0x80987079d291feebf21c2230e69add0f283cee0b8be492ca8050b4185a2ff719 ); uint256 constant BulkOrder_Typehash_Height_TwentyTwo = ( 0x3bd8cff538aba49a9c374c806d277181e9651624b3e31111bc0624574f8bca1d ); uint256 constant BulkOrder_Typehash_Height_TwentyThree = ( 0x5d6a3f098a0bc373f808c619b1bb4028208721b3c4f8d6bc8a874d659814eb76 ); uint256 constant BulkOrder_Typehash_Height_TwentyFour = ( 0x1d51df90cba8de7637ca3e8fe1e3511d1dc2f23487d05dbdecb781860c21ac1c ); uint256 constant receivedItemsHash_ptr = 0x60; /* * Memory layout in _prepareBasicFulfillmentFromCalldata of * data for OrderFulfilled * * event OrderFulfilled( * bytes32 orderHash, * address indexed offerer, * address indexed zone, * address fulfiller, * SpentItem[] offer, * > (itemType, token, id, amount) * ReceivedItem[] consideration * > (itemType, token, id, amount, recipient) * ) * * - 0x00: orderHash * - 0x20: fulfiller * - 0x40: offer offset (0x80) * - 0x60: consideration offset (0x120) * - 0x80: offer.length (1) * - 0xa0: offerItemType * - 0xc0: offerToken * - 0xe0: offerIdentifier * - 0x100: offerAmount * - 0x120: consideration.length (1 + additionalRecipients.length) * - 0x140: considerationItemType * - 0x160: considerationToken * - 0x180: considerationIdentifier * - 0x1a0: considerationAmount * - 0x1c0: considerationRecipient * - ... */ // Minimum length of the OrderFulfilled event data. // Must be added to the size of the ReceivedItem array for additionalRecipients // (0xa0 * additionalRecipients.length) to calculate full size of the buffer. uint256 constant OrderFulfilled_baseSize = 0x1e0; uint256 constant OrderFulfilled_selector = ( 0x9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f31 ); // Minimum offset in memory to OrderFulfilled event data. // Must be added to the size of the EIP712 hash array for additionalRecipients // (32 * additionalRecipients.length) to calculate the pointer to event data. uint256 constant OrderFulfilled_baseOffset = 0x180; uint256 constant OrderFulfilled_consideration_length_baseOffset = 0x2a0; uint256 constant OrderFulfilled_offer_length_baseOffset = 0x200; // Related constants used for restricted order checks on basic orders. uint256 constant OrderFulfilled_baseDataSize = 0x160; // uint256 constant ValidateOrder_offerDataOffset = 0x184; // uint256 constant RatifyOrder_offerDataOffset = 0xc4; // uint256 constant OrderFulfilled_orderHash_offset = 0x00; uint256 constant OrderFulfilled_fulfiller_offset = 0x20; uint256 constant OrderFulfilled_offer_head_offset = 0x40; uint256 constant OrderFulfilled_offer_body_offset = 0x80; uint256 constant OrderFulfilled_consideration_head_offset = 0x60; uint256 constant OrderFulfilled_consideration_body_offset = 0x120; // BasicOrderParameters uint256 constant BasicOrder_parameters_cdPtr = 0x04; uint256 constant BasicOrder_considerationToken_cdPtr = 0x24; uint256 constant BasicOrder_considerationIdentifier_cdPtr = 0x44; uint256 constant BasicOrder_considerationAmount_cdPtr = 0x64; uint256 constant BasicOrder_offerer_cdPtr = 0x84; uint256 constant BasicOrder_zone_cdPtr = 0xa4; uint256 constant BasicOrder_offerToken_cdPtr = 0xc4; uint256 constant BasicOrder_offerIdentifier_cdPtr = 0xe4; uint256 constant BasicOrder_offerAmount_cdPtr = 0x104; uint256 constant BasicOrder_basicOrderType_cdPtr = 0x124; uint256 constant BasicOrder_startTime_cdPtr = 0x144; uint256 constant BasicOrder_endTime_cdPtr = 0x164; // uint256 constant BasicOrder_zoneHash_cdPtr = 0x184; // uint256 constant BasicOrder_salt_cdPtr = 0x1a4; uint256 constant BasicOrder_offererConduit_cdPtr = 0x1c4; uint256 constant BasicOrder_fulfillerConduit_cdPtr = 0x1e4; uint256 constant BasicOrder_totalOriginalAdditionalRecipients_cdPtr = 0x204; uint256 constant BasicOrder_additionalRecipients_head_cdPtr = 0x224; uint256 constant BasicOrder_signature_cdPtr = 0x244; uint256 constant BasicOrder_additionalRecipients_length_cdPtr = 0x264; uint256 constant BasicOrder_additionalRecipients_data_cdPtr = 0x284; uint256 constant BasicOrder_parameters_ptr = 0x20; uint256 constant BasicOrder_basicOrderType_range = 0x18; // 24 values /* * Memory layout in _prepareBasicFulfillmentFromCalldata of * EIP712 data for ConsiderationItem * - 0x80: ConsiderationItem EIP-712 typehash (constant) * - 0xa0: itemType * - 0xc0: token * - 0xe0: identifier * - 0x100: startAmount * - 0x120: endAmount * - 0x140: recipient */ uint256 constant BasicOrder_considerationItem_typeHash_ptr = 0x80; // memoryPtr uint256 constant BasicOrder_considerationItem_itemType_ptr = 0xa0; uint256 constant BasicOrder_considerationItem_token_ptr = 0xc0; uint256 constant BasicOrder_considerationItem_identifier_ptr = 0xe0; uint256 constant BasicOrder_considerationItem_startAmount_ptr = 0x100; uint256 constant BasicOrder_considerationItem_endAmount_ptr = 0x120; // uint256 constant BasicOrder_considerationItem_recipient_ptr = 0x140; /* * Memory layout in _prepareBasicFulfillmentFromCalldata of * EIP712 data for OfferItem * - 0x80: OfferItem EIP-712 typehash (constant) * - 0xa0: itemType * - 0xc0: token * - 0xe0: identifier (reused for offeredItemsHash) * - 0x100: startAmount * - 0x120: endAmount */ uint256 constant BasicOrder_offerItem_typeHash_ptr = 0x80; uint256 constant BasicOrder_offerItem_itemType_ptr = 0xa0; uint256 constant BasicOrder_offerItem_token_ptr = 0xc0; // uint256 constant BasicOrder_offerItem_identifier_ptr = 0xe0; // uint256 constant BasicOrder_offerItem_startAmount_ptr = 0x100; uint256 constant BasicOrder_offerItem_endAmount_ptr = 0x120; /* * Memory layout in _prepareBasicFulfillmentFromCalldata of * EIP712 data for Order * - 0x80: Order EIP-712 typehash (constant) * - 0xa0: orderParameters.offerer * - 0xc0: orderParameters.zone * - 0xe0: keccak256(abi.encodePacked(offerHashes)) * - 0x100: keccak256(abi.encodePacked(considerationHashes)) * - 0x120: orderType * - 0x140: startTime * - 0x160: endTime * - 0x180: zoneHash * - 0x1a0: salt * - 0x1c0: conduit * - 0x1e0: _counters[orderParameters.offerer] (from storage) */ uint256 constant BasicOrder_order_typeHash_ptr = 0x80; uint256 constant BasicOrder_order_offerer_ptr = 0xa0; // uint256 constant BasicOrder_order_zone_ptr = 0xc0; uint256 constant BasicOrder_order_offerHashes_ptr = 0xe0; uint256 constant BasicOrder_order_considerationHashes_ptr = 0x100; uint256 constant BasicOrder_order_orderType_ptr = 0x120; uint256 constant BasicOrder_order_startTime_ptr = 0x140; // uint256 constant BasicOrder_order_endTime_ptr = 0x160; // uint256 constant BasicOrder_order_zoneHash_ptr = 0x180; // uint256 constant BasicOrder_order_salt_ptr = 0x1a0; // uint256 constant BasicOrder_order_conduitKey_ptr = 0x1c0; uint256 constant BasicOrder_order_counter_ptr = 0x1e0; uint256 constant BasicOrder_additionalRecipients_head_ptr = 0x240; uint256 constant BasicOrder_signature_ptr = 0x260; uint256 constant BasicOrder_startTimeThroughZoneHash_size = 0x60; uint256 constant ContractOrder_orderHash_offerer_shift = 0x60; uint256 constant Counter_blockhash_shift = 0x80; // Signature-related bytes32 constant EIP2098_allButHighestBitMask = ( 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ); bytes32 constant ECDSA_twentySeventhAndTwentyEighthBytesSet = ( 0x0000000000000000000000000000000000000000000000000000000101000000 ); uint256 constant ECDSA_MaxLength = 65; uint256 constant ECDSA_signature_s_offset = 0x40; uint256 constant ECDSA_signature_v_offset = 0x60; bytes32 constant EIP1271_isValidSignature_selector = ( 0x1626ba7e00000000000000000000000000000000000000000000000000000000 ); uint256 constant EIP1271_isValidSignature_digest_negativeOffset = 0x40; uint256 constant EIP1271_isValidSignature_selector_negativeOffset = 0x44; uint256 constant EIP1271_isValidSignature_calldata_baseLength = 0x64; uint256 constant EIP1271_isValidSignature_signature_head_offset = 0x40; uint256 constant EIP_712_PREFIX = ( 0x1901000000000000000000000000000000000000000000000000000000000000 ); uint256 constant ExtraGasBuffer = 0x20; uint256 constant CostPerWord = 0x3; uint256 constant MemoryExpansionCoefficientShift = 0x9; uint256 constant Create2AddressDerivation_ptr = 0x0b; uint256 constant Create2AddressDerivation_length = 0x55; uint256 constant MaskOverByteTwelve = ( 0x0000000000000000000000ff0000000000000000000000000000000000000000 ); uint256 constant MaskOverLastTwentyBytes = ( 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff ); uint256 constant AddressDirtyUpperBitThreshold = ( 0x0000000000000000000000010000000000000000000000000000000000000000 ); uint256 constant MaskOverFirstFourBytes = ( 0xffffffff00000000000000000000000000000000000000000000000000000000 ); uint256 constant Conduit_execute_signature = ( 0x4ce34aa200000000000000000000000000000000000000000000000000000000 ); uint256 constant MaxUint8 = 0xff; uint256 constant MaxUint120 = 0xffffffffffffffffffffffffffffff; uint256 constant Conduit_execute_ConduitTransfer_ptr = 0x20; uint256 constant Conduit_execute_ConduitTransfer_length = 0x01; uint256 constant Conduit_execute_ConduitTransfer_offset_ptr = 0x04; uint256 constant Conduit_execute_ConduitTransfer_length_ptr = 0x24; uint256 constant Conduit_execute_transferItemType_ptr = 0x44; uint256 constant Conduit_execute_transferToken_ptr = 0x64; uint256 constant Conduit_execute_transferFrom_ptr = 0x84; uint256 constant Conduit_execute_transferTo_ptr = 0xa4; uint256 constant Conduit_execute_transferIdentifier_ptr = 0xc4; uint256 constant Conduit_execute_transferAmount_ptr = 0xe4; uint256 constant OneConduitExecute_size = 0x104; // Sentinel value to indicate that the conduit accumulator is not armed. uint256 constant AccumulatorDisarmed = 0x20; uint256 constant AccumulatorArmed = 0x40; uint256 constant Accumulator_conduitKey_ptr = 0x20; uint256 constant Accumulator_selector_ptr = 0x40; uint256 constant Accumulator_array_offset_ptr = 0x44; uint256 constant Accumulator_array_length_ptr = 0x64; uint256 constant Accumulator_itemSizeOffsetDifference = 0x3c; uint256 constant Accumulator_array_offset = 0x20; uint256 constant Conduit_transferItem_size = 0xc0; uint256 constant Conduit_transferItem_token_ptr = 0x20; uint256 constant Conduit_transferItem_from_ptr = 0x40; uint256 constant Conduit_transferItem_to_ptr = 0x60; uint256 constant Conduit_transferItem_identifier_ptr = 0x80; uint256 constant Conduit_transferItem_amount_ptr = 0xa0; uint256 constant Ecrecover_precompile = 0x1; uint256 constant Ecrecover_args_size = 0x80; uint256 constant Signature_lower_v = 27; // Bitmask that only gives a non-zero value if masked with a non-match selector. uint256 constant NonMatchSelector_MagicMask = ( 0x4000000000000000000000000000000000000000000000000000000000 ); // First bit indicates that a NATIVE offer items has been used and the 231st bit // indicates that a non match selector has been called. uint256 constant NonMatchSelector_InvalidErrorValue = ( 0x4000000000000000000000000000000000000000000000000000000001 ); /** * @dev Selector and offsets for generateOrder * * function generateOrder( * address fulfiller, * SpentItem[] calldata minimumReceived, * SpentItem[] calldata maximumSpent, * bytes calldata context * ) */ uint256 constant generateOrder_selector = 0x98919765; uint256 constant generateOrder_selector_offset = 0x1c; uint256 constant generateOrder_head_offset = 0x04; uint256 constant generateOrder_minimumReceived_head_offset = 0x20; uint256 constant generateOrder_maximumSpent_head_offset = 0x40; uint256 constant generateOrder_context_head_offset = 0x60; uint256 constant generateOrder_base_tail_offset = 0x80; uint256 constant generateOrder_maximum_returndatasize = 0xffff; uint256 constant ratifyOrder_selector = 0xf4dd92ce; uint256 constant ratifyOrder_selector_offset = 0x1c; uint256 constant ratifyOrder_head_offset = 0x04; // uint256 constant ratifyOrder_offer_head_offset = 0x00; uint256 constant ratifyOrder_consideration_head_offset = 0x20; uint256 constant ratifyOrder_context_head_offset = 0x40; uint256 constant ratifyOrder_orderHashes_head_offset = 0x60; uint256 constant ratifyOrder_contractNonce_offset = 0x80; uint256 constant ratifyOrder_base_tail_offset = 0xa0; uint256 constant validateOrder_selector = 0x17b1f942; uint256 constant validateOrder_selector_offset = 0x1c; uint256 constant validateOrder_head_offset = 0x04; uint256 constant validateOrder_zoneParameters_offset = 0x20; // uint256 constant ZoneParameters_orderHash_offset = 0x00; uint256 constant ZoneParameters_fulfiller_offset = 0x20; uint256 constant ZoneParameters_offerer_offset = 0x40; uint256 constant ZoneParameters_offer_head_offset = 0x60; uint256 constant ZoneParameters_consideration_head_offset = 0x80; uint256 constant ZoneParameters_extraData_head_offset = 0xa0; uint256 constant ZoneParameters_orderHashes_head_offset = 0xc0; uint256 constant ZoneParameters_startTime_offset = 0xe0; uint256 constant ZoneParameters_endTime_offset = 0x100; uint256 constant ZoneParameters_zoneHash_offset = 0x120; uint256 constant ZoneParameters_base_tail_offset = 0x140; uint256 constant ZoneParameters_selectorAndPointer_length = 0x24; uint256 constant ZoneParameters_basicOrderFixedElements_length = 0x64; // ConsiderationDecoder Constants uint256 constant OrderParameters_head_size = 0x0160; uint256 constant OrderParameters_totalOriginalConsiderationItems_offset = ( 0x0140 ); uint256 constant AdvancedOrderPlusOrderParameters_head_size = 0x0200; uint256 constant Order_signature_offset = 0x20; uint256 constant Order_head_size = 0x40; uint256 constant AdvancedOrder_fixed_segment_0 = 0x40; uint256 constant CriteriaResolver_head_size = 0xa0; uint256 constant CriteriaResolver_fixed_segment_0 = 0x80; uint256 constant CriteriaResolver_criteriaProof_offset = 0x80; uint256 constant FulfillmentComponent_mem_tail_size = 0x40; uint256 constant FulfillmentComponent_mem_tail_size_shift = 0x6; uint256 constant Fulfillment_head_size = 0x40; uint256 constant Fulfillment_considerationComponents_offset = 0x20; uint256 constant OrderComponents_OrderParameters_common_head_size = 0x0140;
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; enum OrderType { // 0: no partial fills, anyone can execute FULL_OPEN, // 1: partial fills supported, anyone can execute PARTIAL_OPEN, // 2: no partial fills, only offerer or zone can execute FULL_RESTRICTED, // 3: partial fills supported, only offerer or zone can execute PARTIAL_RESTRICTED, // 4: contract order type CONTRACT } enum BasicOrderType { // 0: no partial fills, anyone can execute ETH_TO_ERC721_FULL_OPEN, // 1: partial fills supported, anyone can execute ETH_TO_ERC721_PARTIAL_OPEN, // 2: no partial fills, only offerer or zone can execute ETH_TO_ERC721_FULL_RESTRICTED, // 3: partial fills supported, only offerer or zone can execute ETH_TO_ERC721_PARTIAL_RESTRICTED, // 4: no partial fills, anyone can execute ETH_TO_ERC1155_FULL_OPEN, // 5: partial fills supported, anyone can execute ETH_TO_ERC1155_PARTIAL_OPEN, // 6: no partial fills, only offerer or zone can execute ETH_TO_ERC1155_FULL_RESTRICTED, // 7: partial fills supported, only offerer or zone can execute ETH_TO_ERC1155_PARTIAL_RESTRICTED, // 8: no partial fills, anyone can execute ERC20_TO_ERC721_FULL_OPEN, // 9: partial fills supported, anyone can execute ERC20_TO_ERC721_PARTIAL_OPEN, // 10: no partial fills, only offerer or zone can execute ERC20_TO_ERC721_FULL_RESTRICTED, // 11: partial fills supported, only offerer or zone can execute ERC20_TO_ERC721_PARTIAL_RESTRICTED, // 12: no partial fills, anyone can execute ERC20_TO_ERC1155_FULL_OPEN, // 13: partial fills supported, anyone can execute ERC20_TO_ERC1155_PARTIAL_OPEN, // 14: no partial fills, only offerer or zone can execute ERC20_TO_ERC1155_FULL_RESTRICTED, // 15: partial fills supported, only offerer or zone can execute ERC20_TO_ERC1155_PARTIAL_RESTRICTED, // 16: no partial fills, anyone can execute ERC721_TO_ERC20_FULL_OPEN, // 17: partial fills supported, anyone can execute ERC721_TO_ERC20_PARTIAL_OPEN, // 18: no partial fills, only offerer or zone can execute ERC721_TO_ERC20_FULL_RESTRICTED, // 19: partial fills supported, only offerer or zone can execute ERC721_TO_ERC20_PARTIAL_RESTRICTED, // 20: no partial fills, anyone can execute ERC1155_TO_ERC20_FULL_OPEN, // 21: partial fills supported, anyone can execute ERC1155_TO_ERC20_PARTIAL_OPEN, // 22: no partial fills, only offerer or zone can execute ERC1155_TO_ERC20_FULL_RESTRICTED, // 23: partial fills supported, only offerer or zone can execute ERC1155_TO_ERC20_PARTIAL_RESTRICTED } enum BasicOrderRouteType { // 0: provide Ether (or other native token) to receive offered ERC721 item. ETH_TO_ERC721, // 1: provide Ether (or other native token) to receive offered ERC1155 item. ETH_TO_ERC1155, // 2: provide ERC20 item to receive offered ERC721 item. ERC20_TO_ERC721, // 3: provide ERC20 item to receive offered ERC1155 item. ERC20_TO_ERC1155, // 4: provide ERC721 item to receive offered ERC20 item. ERC721_TO_ERC20, // 5: provide ERC1155 item to receive offered ERC20 item. ERC1155_TO_ERC20 } enum ItemType { // 0: ETH on mainnet, MATIC on polygon, etc. NATIVE, // 1: ERC20 items (ERC777 and ERC20 analogues could also technically work) ERC20, // 2: ERC721 items ERC721, // 3: ERC1155 items ERC1155, // 4: ERC721 items where a number of tokenIds are supported ERC721_WITH_CRITERIA, // 5: ERC1155 items where a number of ids are supported ERC1155_WITH_CRITERIA } enum Side { // 0: Items that can be spent OFFER, // 1: Items that must be received CONSIDERATION }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { ItemType, OrderType } from "./ConsiderationEnums.sol"; import { AdvancedOrder, ConsiderationItem, CriteriaResolver, OfferItem, OrderParameters, ReceivedItem, SpentItem } from "./ConsiderationStructs.sol"; import { BasicOrderFulfiller } from "./BasicOrderFulfiller.sol"; import { CriteriaResolution } from "./CriteriaResolution.sol"; import { AmountDeriver } from "./AmountDeriver.sol"; import { _revertInsufficientNativeTokensSupplied, _revertInvalidNativeOfferItem } from "./ConsiderationErrors.sol"; import { AccumulatorDisarmed, ConsiderationItem_recipient_offset, ReceivedItem_amount_offset, ReceivedItem_recipient_offset } from "./ConsiderationConstants.sol"; /** * @title OrderFulfiller * @author 0age * @notice OrderFulfiller contains logic related to order fulfillment where a * single order is being fulfilled and where basic order fulfillment is * not available as an option. */ contract OrderFulfiller is BasicOrderFulfiller, CriteriaResolution, AmountDeriver { /** * @dev Derive and set hashes, reference chainId, and associated domain * separator during deployment. * * @param conduitController A contract that deploys conduits, or proxies * that may optionally be used to transfer approved * ERC20/721/1155 tokens. */ constructor( address conduitController ) BasicOrderFulfiller(conduitController) {} /** * @dev Internal function to validate an order and update its status, adjust * prices based on current time, apply criteria resolvers, determine * what portion to fill, and transfer relevant tokens. * * @param advancedOrder The order to fulfill as well as the fraction * to fill. Note that all offer and consideration * components must divide with no remainder for * the partial fill to be valid. * @param criteriaResolvers An array where each element contains a * reference to a specific offer or * consideration, a token identifier, and a proof * that the supplied token identifier is * contained in the order's merkle root. Note * that a criteria of zero indicates that any * (transferable) token identifier is valid and * that no proof needs to be supplied. * @param fulfillerConduitKey A bytes32 value indicating what conduit, if * any, to source the fulfiller's token approvals * from. The zero hash signifies that no conduit * should be used, with direct approvals set on * Consideration. * @param recipient The intended recipient for all received items. * * @return A boolean indicating whether the order has been fulfilled. */ function _validateAndFulfillAdvancedOrder( AdvancedOrder memory advancedOrder, CriteriaResolver[] memory criteriaResolvers, bytes32 fulfillerConduitKey, address recipient ) internal returns (bool) { // Ensure this function cannot be triggered during a reentrant call. _setReentrancyGuard( // Native tokens accepted during execution for contract order types. advancedOrder.parameters.orderType == OrderType.CONTRACT ); // Validate order, update status, and determine fraction to fill. ( bytes32 orderHash, uint256 fillNumerator, uint256 fillDenominator ) = _validateOrderAndUpdateStatus(advancedOrder, true); // Create an array with length 1 containing the order. AdvancedOrder[] memory advancedOrders = new AdvancedOrder[](1); // Populate the order as the first and only element of the new array. advancedOrders[0] = advancedOrder; // Apply criteria resolvers using generated orders and details arrays. _applyCriteriaResolvers(advancedOrders, criteriaResolvers); // Retrieve the order parameters after applying criteria resolvers. OrderParameters memory orderParameters = advancedOrders[0].parameters; // Perform each item transfer with the appropriate fractional amount. _applyFractionsAndTransferEach( orderParameters, fillNumerator, fillDenominator, fulfillerConduitKey, recipient ); // Declare empty bytes32 array and populate with the order hash. bytes32[] memory orderHashes = new bytes32[](1); orderHashes[0] = orderHash; // Ensure restricted orders have a valid submitter or pass a zone check. _assertRestrictedAdvancedOrderValidity( advancedOrders[0], orderHashes, orderHash ); // Emit an event signifying that the order has been fulfilled. _emitOrderFulfilledEvent( orderHash, orderParameters.offerer, orderParameters.zone, recipient, orderParameters.offer, orderParameters.consideration ); // Clear the reentrancy guard. _clearReentrancyGuard(); return true; } /** * @dev Internal function to transfer each item contained in a given single * order fulfillment after applying a respective fraction to the amount * being transferred. * * @param orderParameters The parameters for the fulfilled order. * @param numerator A value indicating the portion of the order * that should be filled. * @param denominator A value indicating the total order size. * @param fulfillerConduitKey A bytes32 value indicating what conduit, if * any, to source the fulfiller's token approvals * from. The zero hash signifies that no conduit * should be used, with direct approvals set on * Consideration. * @param recipient The intended recipient for all received items. */ function _applyFractionsAndTransferEach( OrderParameters memory orderParameters, uint256 numerator, uint256 denominator, bytes32 fulfillerConduitKey, address recipient ) internal { // Read start time & end time from order parameters and place on stack. uint256 startTime = orderParameters.startTime; uint256 endTime = orderParameters.endTime; // Initialize an accumulator array. From this point forward, no new // memory regions can be safely allocated until the accumulator is no // longer being utilized, as the accumulator operates in an open-ended // fashion from this memory pointer; existing memory may still be // accessed and modified, however. bytes memory accumulator = new bytes(AccumulatorDisarmed); // As of solidity 0.6.0, inline assembly cannot directly access function // definitions, but can still access locally scoped function variables. // This means that a local variable to reference the internal function // definition (using the same type), along with a local variable with // the desired type, must first be created. Then, the original function // pointer can be recast to the desired type. /** * Repurpose existing OfferItem memory regions on the offer array for * the order by overriding the _transfer function pointer to accept a * modified OfferItem argument in place of the usual ReceivedItem: * * ========= OfferItem ========== ====== ReceivedItem ====== * ItemType itemType; ------------> ItemType itemType; * address token; ----------------> address token; * uint256 identifierOrCriteria; -> uint256 identifier; * uint256 startAmount; ----------> uint256 amount; * uint256 endAmount; ------------> address recipient; */ // Declare a nested scope to minimize stack depth. unchecked { // Read offer array length from memory and place on stack. uint256 totalOfferItems = orderParameters.offer.length; // Create a variable to indicate whether the order has any // native offer items uint256 anyNativeItems; // Iterate over each offer on the order. // Skip overflow check as for loop is indexed starting at zero. for (uint256 i = 0; i < totalOfferItems; ++i) { // Retrieve the offer item. OfferItem memory offerItem = orderParameters.offer[i]; // Offer items for the native token can not be received outside // of a match order function except as part of a contract order. { ItemType itemType = offerItem.itemType; assembly { anyNativeItems := or(anyNativeItems, iszero(itemType)) } } // Declare an additional nested scope to minimize stack depth. { // Apply fill fraction to get offer item amount to transfer. uint256 amount = _applyFraction( offerItem.startAmount, offerItem.endAmount, numerator, denominator, startTime, endTime, false ); // Utilize assembly to set overloaded offerItem arguments. assembly { // Write new fractional amount to startAmount as amount. mstore( add(offerItem, ReceivedItem_amount_offset), amount ) // Write recipient to endAmount. mstore( add(offerItem, ReceivedItem_recipient_offset), recipient ) } } // Transfer the item from the offerer to the recipient. _toOfferItemInput(_transfer)( offerItem, orderParameters.offerer, orderParameters.conduitKey, accumulator ); } // If a non-contract order has native offer items, throw with an // `InvalidNativeOfferItem` custom error. { OrderType orderType = orderParameters.orderType; uint256 invalidNativeOfferItem; assembly { invalidNativeOfferItem := and( // Note that this check requires that there are no order // types beyond the current set (0-4). It will need to // be modified if more order types are added. lt(orderType, 4), anyNativeItems ) } if (invalidNativeOfferItem != 0) { _revertInvalidNativeOfferItem(); } } } // Declare a variable for the available native token balance. uint256 nativeTokenBalance; /** * Repurpose existing ConsiderationItem memory regions on the * consideration array for the order by overriding the _transfer * function pointer to accept a modified ConsiderationItem argument in * place of the usual ReceivedItem: * * ====== ConsiderationItem ===== ====== ReceivedItem ====== * ItemType itemType; ------------> ItemType itemType; * address token; ----------------> address token; * uint256 identifierOrCriteria;--> uint256 identifier; * uint256 startAmount; ----------> uint256 amount; * uint256 endAmount; /----> address recipient; * address recipient; ------/ */ // Declare a nested scope to minimize stack depth. unchecked { // Read consideration array length from memory and place on stack. uint256 totalConsiderationItems = orderParameters .consideration .length; // Iterate over each consideration item on the order. // Skip overflow check as for loop is indexed starting at zero. for (uint256 i = 0; i < totalConsiderationItems; ++i) { // Retrieve the consideration item. ConsiderationItem memory considerationItem = ( orderParameters.consideration[i] ); // Apply fraction & derive considerationItem amount to transfer. uint256 amount = _applyFraction( considerationItem.startAmount, considerationItem.endAmount, numerator, denominator, startTime, endTime, true ); // Use assembly to set overloaded considerationItem arguments. assembly { // Write derived fractional amount to startAmount as amount. mstore( add(considerationItem, ReceivedItem_amount_offset), amount ) // Write original recipient to endAmount as recipient. mstore( add(considerationItem, ReceivedItem_recipient_offset), mload( add( considerationItem, ConsiderationItem_recipient_offset ) ) ) } // Reduce available value if offer spent ETH or a native token. if (considerationItem.itemType == ItemType.NATIVE) { // Get the current available balance of native tokens. assembly { nativeTokenBalance := selfbalance() } // Ensure that sufficient native tokens are still available. if (amount > nativeTokenBalance) { _revertInsufficientNativeTokensSupplied(); } } // Transfer item from caller to recipient specified by the item. _toConsiderationItemInput(_transfer)( considerationItem, msg.sender, fulfillerConduitKey, accumulator ); } } // Trigger any remaining accumulated transfers via call to the conduit. _triggerIfArmed(accumulator); // Determine whether any native token balance remains. assembly { nativeTokenBalance := selfbalance() } // Return any remaining native token balance to the caller. if (nativeTokenBalance != 0) { _transferNativeTokens(payable(msg.sender), nativeTokenBalance); } } /** * @dev Internal function to emit an OrderFulfilled event. OfferItems are * translated into SpentItems and ConsiderationItems are translated * into ReceivedItems. * * @param orderHash The order hash. * @param offerer The offerer for the order. * @param zone The zone for the order. * @param recipient The recipient of the order, or the null address if * the order was fulfilled via order matching. * @param offer The offer items for the order. * @param consideration The consideration items for the order. */ function _emitOrderFulfilledEvent( bytes32 orderHash, address offerer, address zone, address recipient, OfferItem[] memory offer, ConsiderationItem[] memory consideration ) internal { // Cast already-modified offer memory region as spent items. SpentItem[] memory spentItems; assembly { spentItems := offer } // Cast already-modified consideration memory region as received items. ReceivedItem[] memory receivedItems; assembly { receivedItems := consideration } // Emit an event signifying that the order has been fulfilled. emit OrderFulfilled( orderHash, offerer, zone, recipient, spentItems, receivedItems ); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { ItemType, Side } from "./ConsiderationEnums.sol"; import { AdvancedOrder, Execution, FulfillmentComponent, ReceivedItem } from "./ConsiderationStructs.sol"; import { _revertMismatchedFulfillmentOfferAndConsiderationComponents, _revertMissingFulfillmentComponentOnAggregation, _revertOfferAndConsiderationRequiredOnFulfillment } from "./ConsiderationErrors.sol"; import { FulfillmentApplicationErrors } from "../interfaces/FulfillmentApplicationErrors.sol"; import { AdvancedOrder_numerator_offset, Common_amount_offset, Common_identifier_offset, Common_token_offset, Execution_conduit_offset, Execution_offerer_offset, Fulfillment_itemIndex_offset, OneWord, OneWordShift, OrderParameters_conduit_offset, OrderParameters_consideration_head_offset, OrderParameters_offer_head_offset, ReceivedItem_CommonParams_size, ReceivedItem_recipient_offset, ReceivedItem_size } from "./ConsiderationConstants.sol"; import { Error_selector_offset, InvalidFulfillmentComponentData_error_length, InvalidFulfillmentComponentData_error_selector, MissingItemAmount_error_length, MissingItemAmount_error_selector, Panic_arithmetic, Panic_error_code_ptr, Panic_error_length, Panic_error_selector } from "./ConsiderationErrorConstants.sol"; /** * @title FulfillmentApplier * @author 0age * @notice FulfillmentApplier contains logic related to applying fulfillments, * both as part of order matching (where offer items are matched to * consideration items) as well as fulfilling available orders (where * order items and consideration items are independently aggregated). */ contract FulfillmentApplier is FulfillmentApplicationErrors { /** * @dev Internal pure function to match offer items to consideration items * on a group of orders via a supplied fulfillment. * * @param advancedOrders The orders to match. * @param offerComponents An array designating offer components to * match to consideration components. * @param considerationComponents An array designating consideration * components to match to offer components. * Note that each consideration amount must * be zero in order for the match operation * to be valid. * @param fulfillmentIndex The index of the fulfillment being * applied. * * @return execution The transfer performed as a result of the fulfillment. */ function _applyFulfillment( AdvancedOrder[] memory advancedOrders, FulfillmentComponent[] memory offerComponents, FulfillmentComponent[] memory considerationComponents, uint256 fulfillmentIndex ) internal pure returns (Execution memory execution) { // Ensure 1+ of both offer and consideration components are supplied. if ( offerComponents.length == 0 || considerationComponents.length == 0 ) { _revertOfferAndConsiderationRequiredOnFulfillment(); } // Declare a new Execution struct. Execution memory considerationExecution; // Validate & aggregate consideration items to new Execution object. _aggregateValidFulfillmentConsiderationItems( advancedOrders, considerationComponents, considerationExecution ); // Retrieve the consideration item from the execution struct. ReceivedItem memory considerationItem = considerationExecution.item; // Skip aggregating offer items if no consideration items are available. if (considerationItem.amount == 0) { // Set the offerer and recipient to null address and the item type // to a non-native item type if the execution amount is zero. This // will cause the execution item to be skipped. considerationExecution.offerer = address(0); considerationExecution.item.recipient = payable(0); considerationExecution.item.itemType = ItemType.ERC20; return considerationExecution; } // Recipient does not need to be specified because it will always be set // to that of the consideration. // Validate & aggregate offer items to Execution object. _aggregateValidFulfillmentOfferItems( advancedOrders, offerComponents, execution ); // Ensure offer & consideration item types, tokens, & identifiers match. // (a != b || c != d || e != f) == (((a ^ b) | (c ^ d) | (e ^ f)) != 0), // but the second expression requires less gas to evaluate. if ( ((uint8(execution.item.itemType) ^ uint8(considerationItem.itemType)) | (uint160(execution.item.token) ^ uint160(considerationItem.token)) | (execution.item.identifier ^ considerationItem.identifier)) != 0 ) { _revertMismatchedFulfillmentOfferAndConsiderationComponents( fulfillmentIndex ); } // If total consideration amount exceeds the offer amount... if (considerationItem.amount > execution.item.amount) { // Retrieve the first consideration component from the fulfillment. FulfillmentComponent memory targetComponent = ( considerationComponents[0] ); // Skip underflow check as the conditional being true implies that // considerationItem.amount > execution.item.amount. unchecked { // Add excess consideration item amount to original order array. advancedOrders[targetComponent.orderIndex] .parameters .consideration[targetComponent.itemIndex] .startAmount = (considerationItem.amount - execution.item.amount); } } else { // Retrieve the first offer component from the fulfillment. FulfillmentComponent memory targetComponent = offerComponents[0]; // Skip underflow check as the conditional being false implies that // execution.item.amount >= considerationItem.amount. unchecked { // Add excess offer item amount to the original array of orders. advancedOrders[targetComponent.orderIndex] .parameters .offer[targetComponent.itemIndex] .startAmount = (execution.item.amount - considerationItem.amount); } // Reduce total offer amount to equal the consideration amount. execution.item.amount = considerationItem.amount; } // Reuse consideration recipient. execution.item.recipient = considerationItem.recipient; // Return the final execution that will be triggered for relevant items. return execution; // Execution(considerationItem, offerer, conduitKey); } /** * @dev Internal view function to aggregate offer or consideration items * from a group of orders into a single execution via a supplied array * of fulfillment components. Items that are not available to aggregate * will not be included in the aggregated execution. * * @param advancedOrders The orders to aggregate. * @param side The side (i.e. offer or consideration). * @param fulfillmentComponents An array designating item components to * aggregate if part of an available order. * @param fulfillerConduitKey A bytes32 value indicating what conduit, if * any, to source the fulfiller's token * approvals from. The zero hash signifies that * no conduit should be used, with approvals * set directly on this contract. * @param recipient The intended recipient for all received * items. * * @return execution The transfer performed as a result of the fulfillment. */ function _aggregateAvailable( AdvancedOrder[] memory advancedOrders, Side side, FulfillmentComponent[] memory fulfillmentComponents, bytes32 fulfillerConduitKey, address recipient ) internal view returns (Execution memory execution) { // Skip overflow / underflow checks; conditions checked or unreachable. unchecked { // Retrieve fulfillment components array length and place on stack. // Ensure at least one fulfillment component has been supplied. if (fulfillmentComponents.length == 0) { _revertMissingFulfillmentComponentOnAggregation(side); } // Retrieve the received item on the execution being returned. ReceivedItem memory item = execution.item; // If the fulfillment components are offer components... if (side == Side.OFFER) { // Set the supplied recipient on the execution item. item.recipient = payable(recipient); // Return execution for aggregated items provided by offerer. _aggregateValidFulfillmentOfferItems( advancedOrders, fulfillmentComponents, execution ); } else { // Otherwise, fulfillment components are consideration // components. Return execution for aggregated items provided by // the fulfiller. _aggregateValidFulfillmentConsiderationItems( advancedOrders, fulfillmentComponents, execution ); // Set the caller as the offerer on the execution. execution.offerer = msg.sender; // Set fulfiller conduit key as the conduit key on execution. execution.conduitKey = fulfillerConduitKey; } // Set the offerer and recipient to null address and the item type // to a non-native item type if the execution amount is zero. This // will cause the execution item to be skipped. if (item.amount == 0) { execution.offerer = address(0); item.recipient = payable(0); item.itemType = ItemType.ERC20; } } } /** * @dev Internal pure function to aggregate a group of offer items using * supplied directives on which component items are candidates for * aggregation, skipping items on orders that are not available. * * @param advancedOrders The orders to aggregate offer items from. * @param offerComponents An array of FulfillmentComponent structs * indicating the order index and item index of each * candidate offer item for aggregation. * @param execution The execution to apply the aggregation to. */ function _aggregateValidFulfillmentOfferItems( AdvancedOrder[] memory advancedOrders, FulfillmentComponent[] memory offerComponents, Execution memory execution ) internal pure { assembly { // Declare a variable for the final aggregated item amount. let amount // Declare a variable to track errors encountered with amount. let errorBuffer // Declare a variable for the hash of itemType, token, & identifier. let dataHash // Iterate over each offer component. for { // Create variable to track position in offerComponents head. let fulfillmentHeadPtr := offerComponents // Get position one word past last element in head of array. let endPtr := add( offerComponents, shl(OneWordShift, mload(offerComponents)) ) } lt(fulfillmentHeadPtr, endPtr) { } { // Increment position in considerationComponents head. fulfillmentHeadPtr := add(fulfillmentHeadPtr, OneWord) // Retrieve the order index using the fulfillment pointer. let orderIndex := mload(mload(fulfillmentHeadPtr)) // Ensure that the order index is not out of range. if iszero(lt(orderIndex, mload(advancedOrders))) { throwInvalidFulfillmentComponentData() } // Read advancedOrders[orderIndex] pointer from its array head. let orderPtr := mload( // Calculate head position of advancedOrders[orderIndex]. add( add(advancedOrders, OneWord), shl(OneWordShift, orderIndex) ) ) // Read the pointer to OrderParameters from the AdvancedOrder. let paramsPtr := mload(orderPtr) // Retrieve item index using an offset of fulfillment pointer. let itemIndex := mload( add(mload(fulfillmentHeadPtr), Fulfillment_itemIndex_offset) ) let offerItemPtr { // Load the offer array pointer. let offerArrPtr := mload( add(paramsPtr, OrderParameters_offer_head_offset) ) // If the offer item index is out of range or the numerator // is zero, skip this item. if or( iszero(lt(itemIndex, mload(offerArrPtr))), iszero( mload(add(orderPtr, AdvancedOrder_numerator_offset)) ) ) { continue } // Retrieve offer item pointer using the item index. offerItemPtr := mload( add( // Get pointer to beginning of receivedItem. add(offerArrPtr, OneWord), // Calculate offset to pointer for desired order. shl(OneWordShift, itemIndex) ) ) } // Declare a separate scope for the amount update. { // Retrieve amount pointer using consideration item pointer. let amountPtr := add(offerItemPtr, Common_amount_offset) // Add offer item amount to execution amount. let newAmount := add(amount, mload(amountPtr)) // Update error buffer: // 1 = zero amount, 2 = overflow, 3 = both. errorBuffer := or( errorBuffer, or( shl(1, lt(newAmount, amount)), iszero(mload(amountPtr)) ) ) // Update the amount to the new, summed amount. amount := newAmount // Zero out amount on original item to indicate it is spent. mstore(amountPtr, 0) } // Retrieve ReceivedItem pointer from Execution. let receivedItem := mload(execution) // Check if this is the first valid fulfillment item. switch iszero(dataHash) case 1 { // On first valid item, populate the received item in memory // for later comparison. // Set the item type on the received item. mstore(receivedItem, mload(offerItemPtr)) // Set the token on the received item. mstore( add(receivedItem, Common_token_offset), mload(add(offerItemPtr, Common_token_offset)) ) // Set the identifier on the received item. mstore( add(receivedItem, Common_identifier_offset), mload(add(offerItemPtr, Common_identifier_offset)) ) // Set offerer on returned execution using order pointer. mstore( add(execution, Execution_offerer_offset), mload(paramsPtr) ) // Set execution conduitKey via order pointer offset. mstore( add(execution, Execution_conduit_offset), mload(add(paramsPtr, OrderParameters_conduit_offset)) ) // Calculate the hash of (itemType, token, identifier). dataHash := keccak256( receivedItem, ReceivedItem_CommonParams_size ) // If component index > 0, swap component pointer with // pointer to first component so that any remainder after // fulfillment can be added back to the first item. let firstFulfillmentHeadPtr := add(offerComponents, OneWord) if xor(firstFulfillmentHeadPtr, fulfillmentHeadPtr) { let firstFulfillmentPtr := mload( firstFulfillmentHeadPtr ) let fulfillmentPtr := mload(fulfillmentHeadPtr) mstore(firstFulfillmentHeadPtr, fulfillmentPtr) } } default { // Compare every subsequent item to the first. if or( or( // The offerer must match on both items. xor( mload(paramsPtr), mload(add(execution, Execution_offerer_offset)) ), // The conduit key must match on both items. xor( mload( add( paramsPtr, OrderParameters_conduit_offset ) ), mload(add(execution, Execution_conduit_offset)) ) ), // The itemType, token, and identifier must match. xor( dataHash, keccak256( offerItemPtr, ReceivedItem_CommonParams_size ) ) ) { // Throw if any of the requirements are not met. throwInvalidFulfillmentComponentData() } } } // Write final amount to execution. mstore(add(mload(execution), Common_amount_offset), amount) // Determine whether the error buffer contains a nonzero error code. if errorBuffer { // If errorBuffer is 1, an item had an amount of zero. if eq(errorBuffer, 1) { // Store left-padded selector with push4 (reduces bytecode) // mem[28:32] = selector mstore(0, MissingItemAmount_error_selector) // revert(abi.encodeWithSignature("MissingItemAmount()")) revert( Error_selector_offset, MissingItemAmount_error_length ) } // If errorBuffer is not 1 or 0, the sum overflowed. // Panic! throwOverflow() } // Declare function for reverts on invalid fulfillment data. function throwInvalidFulfillmentComponentData() { // Store left-padded selector (uses push4 and reduces code size) mstore(0, InvalidFulfillmentComponentData_error_selector) // revert(abi.encodeWithSignature( // "InvalidFulfillmentComponentData()" // )) revert( Error_selector_offset, InvalidFulfillmentComponentData_error_length ) } // Declare function for reverts due to arithmetic overflows. function throwOverflow() { // Store the Panic error signature. mstore(0, Panic_error_selector) // Store the arithmetic (0x11) panic code. mstore(Panic_error_code_ptr, Panic_arithmetic) // revert(abi.encodeWithSignature("Panic(uint256)", 0x11)) revert(Error_selector_offset, Panic_error_length) } } } /** * @dev Internal pure function to aggregate a group of consideration items * using supplied directives on which component items are candidates * for aggregation, skipping items on orders that are not available. * Note that this function depends on memory layout affected by an * earlier call to _validateOrdersAndPrepareToFulfill. The memory for * the consideration arrays needs to be updated before calling * _aggregateValidFulfillmentConsiderationItems. * _validateOrdersAndPrepareToFulfill is called in _matchAdvancedOrders * and _fulfillAvailableAdvancedOrders in the current version. * * @param advancedOrders The orders to aggregate consideration * items from. * @param considerationComponents An array of FulfillmentComponent structs * indicating the order index and item index * of each candidate consideration item for * aggregation. * @param execution The execution to apply the aggregation to. */ function _aggregateValidFulfillmentConsiderationItems( AdvancedOrder[] memory advancedOrders, FulfillmentComponent[] memory considerationComponents, Execution memory execution ) internal pure { // Utilize assembly in order to efficiently aggregate the items. assembly { // Declare a variable for the final aggregated item amount. let amount // Create variable to track errors encountered with amount. let errorBuffer // Declare variable for hash(itemType, token, identifier, recipient) let dataHash // Iterate over each consideration component. for { // Track position in considerationComponents head. let fulfillmentHeadPtr := considerationComponents // Get position one word past last element in head of array. let endPtr := add( considerationComponents, shl(OneWordShift, mload(considerationComponents)) ) } lt(fulfillmentHeadPtr, endPtr) { } { // Increment position in considerationComponents head. fulfillmentHeadPtr := add(fulfillmentHeadPtr, OneWord) // Retrieve the order index using the fulfillment pointer. let orderIndex := mload(mload(fulfillmentHeadPtr)) // Ensure that the order index is not out of range. if iszero(lt(orderIndex, mload(advancedOrders))) { throwInvalidFulfillmentComponentData() } // Read advancedOrders[orderIndex] pointer from its array head. let orderPtr := mload( // Calculate head position of advancedOrders[orderIndex]. add( add(advancedOrders, OneWord), shl(OneWordShift, orderIndex) ) ) // Retrieve item index using an offset of fulfillment pointer. let itemIndex := mload( add(mload(fulfillmentHeadPtr), Fulfillment_itemIndex_offset) ) let considerationItemPtr { // Load consideration array pointer. let considerationArrPtr := mload( add( // Read OrderParameters pointer from AdvancedOrder. mload(orderPtr), OrderParameters_consideration_head_offset ) ) // If the consideration item index is out of range or the // numerator is zero, skip this item. if or( iszero(lt(itemIndex, mload(considerationArrPtr))), iszero( mload(add(orderPtr, AdvancedOrder_numerator_offset)) ) ) { continue } // Retrieve consideration item pointer using the item index. considerationItemPtr := mload( add( // Get pointer to beginning of receivedItem. add(considerationArrPtr, OneWord), // Calculate offset to pointer for desired order. shl(OneWordShift, itemIndex) ) ) } // Declare a separate scope for the amount update. { // Retrieve amount pointer using consideration item pointer. let amountPtr := add( considerationItemPtr, Common_amount_offset ) // Add consideration item amount to execution amount. let newAmount := add(amount, mload(amountPtr)) // Update error buffer: // 1 = zero amount, 2 = overflow, 3 = both. errorBuffer := or( errorBuffer, or( shl(1, lt(newAmount, amount)), iszero(mload(amountPtr)) ) ) // Update the amount to the new, summed amount. amount := newAmount // Zero out original item amount to indicate it is credited. mstore(amountPtr, 0) } // Retrieve ReceivedItem pointer from Execution. let receivedItem := mload(execution) switch iszero(dataHash) case 1 { // On first valid item, populate the received item in // memory for later comparison. // Set the item type on the received item. mstore(receivedItem, mload(considerationItemPtr)) // Set the token on the received item. mstore( add(receivedItem, Common_token_offset), mload(add(considerationItemPtr, Common_token_offset)) ) // Set the identifier on the received item. mstore( add(receivedItem, Common_identifier_offset), mload( add(considerationItemPtr, Common_identifier_offset) ) ) // Set the recipient on the received item. Note that this // depends on the memory layout established by the // _validateOrdersAndPrepareToFulfill function. mstore( add(receivedItem, ReceivedItem_recipient_offset), mload( add( considerationItemPtr, ReceivedItem_recipient_offset ) ) ) // Calculate the hash of (itemType, token, identifier, // recipient). This is run after amount is set to zero, so // there will be one blank word after identifier included in // the hash buffer. dataHash := keccak256( considerationItemPtr, ReceivedItem_size ) // If component index > 0, swap component pointer with // pointer to first component so that any remainder after // fulfillment can be added back to the first item. let firstFulfillmentHeadPtr := add( considerationComponents, OneWord ) if xor(firstFulfillmentHeadPtr, fulfillmentHeadPtr) { let firstFulfillmentPtr := mload( firstFulfillmentHeadPtr ) let fulfillmentPtr := mload(fulfillmentHeadPtr) mstore(firstFulfillmentHeadPtr, fulfillmentPtr) } } default { // Compare every subsequent item to the first; the item // type, token, identifier and recipient must match. if xor( dataHash, // Calculate the hash of (itemType, token, identifier, // recipient). This is run after amount is set to zero, // so there will be one blank word after identifier // included in the hash buffer. keccak256(considerationItemPtr, ReceivedItem_size) ) { // Throw if any of the requirements are not met. throwInvalidFulfillmentComponentData() } } } // Retrieve ReceivedItem pointer from Execution. let receivedItem := mload(execution) // Write final amount to execution. mstore(add(receivedItem, Common_amount_offset), amount) // Determine whether the error buffer contains a nonzero error code. if errorBuffer { // If errorBuffer is 1, an item had an amount of zero. if eq(errorBuffer, 1) { // Store left-padded selector with push4, mem[28:32] mstore(0, MissingItemAmount_error_selector) // revert(abi.encodeWithSignature("MissingItemAmount()")) revert( Error_selector_offset, MissingItemAmount_error_length ) } // If errorBuffer is not 1 or 0, `amount` overflowed. // Panic! throwOverflow() } // Declare function for reverts on invalid fulfillment data. function throwInvalidFulfillmentComponentData() { // Store the InvalidFulfillmentComponentData error signature. mstore(0, InvalidFulfillmentComponentData_error_selector) // revert(abi.encodeWithSignature( // "InvalidFulfillmentComponentData()" // )) revert( Error_selector_offset, InvalidFulfillmentComponentData_error_length ) } // Declare function for reverts due to arithmetic overflows. function throwOverflow() { // Store the Panic error signature. mstore(0, Panic_error_selector) // Store the arithmetic (0x11) panic code. mstore(Panic_error_code_ptr, Panic_arithmetic) // revert(abi.encodeWithSignature("Panic(uint256)", 0x11)) revert(Error_selector_offset, Panic_error_length) } } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { Side } from "./ConsiderationEnums.sol"; import { BadFraction_error_length, BadFraction_error_selector, CannotCancelOrder_error_length, CannotCancelOrder_error_selector, ConsiderationLengthNotEqualToTotalOriginal_error_length, ConsiderationLengthNotEqualToTotalOriginal_error_selector, ConsiderationNotMet_error_considerationIndex_ptr, ConsiderationNotMet_error_length, ConsiderationNotMet_error_orderIndex_ptr, ConsiderationNotMet_error_selector, ConsiderationNotMet_error_shortfallAmount_ptr, CriteriaNotEnabledForItem_error_length, CriteriaNotEnabledForItem_error_selector, Error_selector_offset, InsufficientNativeTokensSupplied_error_length, InsufficientNativeTokensSupplied_error_selector, InvalidBasicOrderParameterEncoding_error_length, InvalidBasicOrderParameterEncoding_error_selector, InvalidCallToConduit_error_conduit_ptr, InvalidCallToConduit_error_length, InvalidCallToConduit_error_selector, InvalidConduit_error_conduit_ptr, InvalidConduit_error_conduitKey_ptr, InvalidConduit_error_length, InvalidConduit_error_selector, InvalidContractOrder_error_length, InvalidContractOrder_error_orderHash_ptr, InvalidContractOrder_error_selector, InvalidERC721TransferAmount_error_amount_ptr, InvalidERC721TransferAmount_error_length, InvalidERC721TransferAmount_error_selector, InvalidMsgValue_error_length, InvalidMsgValue_error_selector, InvalidMsgValue_error_value_ptr, InvalidNativeOfferItem_error_length, InvalidNativeOfferItem_error_selector, InvalidProof_error_length, InvalidProof_error_selector, InvalidTime_error_endTime_ptr, InvalidTime_error_length, InvalidTime_error_selector, InvalidTime_error_startTime_ptr, MismatchedOfferAndConsiderationComponents_error_idx_ptr, MismatchedOfferAndConsiderationComponents_error_length, MismatchedOfferAndConsiderationComponents_error_selector, MissingFulfillmentComponentOnAggregation_error_length, MissingFulfillmentComponentOnAggregation_error_selector, MissingFulfillmentComponentOnAggregation_error_side_ptr, MissingOriginalConsiderationItems_error_length, MissingOriginalConsiderationItems_error_selector, NoReentrantCalls_error_length, NoReentrantCalls_error_selector, NoSpecifiedOrdersAvailable_error_length, NoSpecifiedOrdersAvailable_error_selector, OfferAndConsiderationRequiredOnFulfillment_error_length, OfferAndConsiderationRequiredOnFulfillment_error_selector, OrderAlreadyFilled_error_length, OrderAlreadyFilled_error_orderHash_ptr, OrderAlreadyFilled_error_selector, OrderCriteriaResolverOutOfRange_error_length, OrderCriteriaResolverOutOfRange_error_selector, OrderCriteriaResolverOutOfRange_error_side_ptr, OrderIsCancelled_error_length, OrderIsCancelled_error_orderHash_ptr, OrderIsCancelled_error_selector, OrderPartiallyFilled_error_length, OrderPartiallyFilled_error_orderHash_ptr, OrderPartiallyFilled_error_selector, PartialFillsNotEnabledForOrder_error_length, PartialFillsNotEnabledForOrder_error_selector, UnresolvedConsiderationCriteria_error_considerationIdx_ptr, UnresolvedConsiderationCriteria_error_length, UnresolvedConsiderationCriteria_error_orderIndex_ptr, UnresolvedConsiderationCriteria_error_selector, UnresolvedOfferCriteria_error_length, UnresolvedOfferCriteria_error_offerIndex_ptr, UnresolvedOfferCriteria_error_orderIndex_ptr, UnresolvedOfferCriteria_error_selector, UnusedItemParameters_error_length, UnusedItemParameters_error_selector } from "./ConsiderationErrorConstants.sol"; /** * @dev Reverts the current transaction with a "BadFraction" error message. */ function _revertBadFraction() pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, BadFraction_error_selector) // revert(abi.encodeWithSignature("BadFraction()")) revert(Error_selector_offset, BadFraction_error_length) } } /** * @dev Reverts the current transaction with a "ConsiderationNotMet" error * message, including the provided order index, consideration index, and * shortfall amount. * * @param orderIndex The index of the order that did not meet the * consideration criteria. * @param considerationIndex The index of the consideration item that did not * meet its criteria. * @param shortfallAmount The amount by which the consideration criteria were * not met. */ function _revertConsiderationNotMet( uint256 orderIndex, uint256 considerationIndex, uint256 shortfallAmount ) pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, ConsiderationNotMet_error_selector) // Store arguments. mstore(ConsiderationNotMet_error_orderIndex_ptr, orderIndex) mstore( ConsiderationNotMet_error_considerationIndex_ptr, considerationIndex ) mstore(ConsiderationNotMet_error_shortfallAmount_ptr, shortfallAmount) // revert(abi.encodeWithSignature( // "ConsiderationNotMet(uint256,uint256,uint256)", // orderIndex, // considerationIndex, // shortfallAmount // )) revert(Error_selector_offset, ConsiderationNotMet_error_length) } } /** * @dev Reverts the current transaction with a "CriteriaNotEnabledForItem" error * message. */ function _revertCriteriaNotEnabledForItem() pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, CriteriaNotEnabledForItem_error_selector) // revert(abi.encodeWithSignature("CriteriaNotEnabledForItem()")) revert(Error_selector_offset, CriteriaNotEnabledForItem_error_length) } } /** * @dev Reverts the current transaction with an * "InsufficientNativeTokensSupplied" error message. */ function _revertInsufficientNativeTokensSupplied() pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, InsufficientNativeTokensSupplied_error_selector) // revert(abi.encodeWithSignature("InsufficientNativeTokensSupplied()")) revert( Error_selector_offset, InsufficientNativeTokensSupplied_error_length ) } } /** * @dev Reverts the current transaction with an * "InvalidBasicOrderParameterEncoding" error message. */ function _revertInvalidBasicOrderParameterEncoding() pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, InvalidBasicOrderParameterEncoding_error_selector) // revert(abi.encodeWithSignature( // "InvalidBasicOrderParameterEncoding()" // )) revert( Error_selector_offset, InvalidBasicOrderParameterEncoding_error_length ) } } /** * @dev Reverts the current transaction with an "InvalidCallToConduit" error * message, including the provided address of the conduit that was called * improperly. * * @param conduit The address of the conduit that was called improperly. */ function _revertInvalidCallToConduit(address conduit) pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, InvalidCallToConduit_error_selector) // Store argument. mstore(InvalidCallToConduit_error_conduit_ptr, conduit) // revert(abi.encodeWithSignature( // "InvalidCallToConduit(address)", // conduit // )) revert(Error_selector_offset, InvalidCallToConduit_error_length) } } /** * @dev Reverts the current transaction with an "CannotCancelOrder" error * message. */ function _revertCannotCancelOrder() pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, CannotCancelOrder_error_selector) // revert(abi.encodeWithSignature("CannotCancelOrder()")) revert(Error_selector_offset, CannotCancelOrder_error_length) } } /** * @dev Reverts the current transaction with an "InvalidConduit" error message, * including the provided key and address of the invalid conduit. * * @param conduitKey The key of the invalid conduit. * @param conduit The address of the invalid conduit. */ function _revertInvalidConduit(bytes32 conduitKey, address conduit) pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, InvalidConduit_error_selector) // Store arguments. mstore(InvalidConduit_error_conduitKey_ptr, conduitKey) mstore(InvalidConduit_error_conduit_ptr, conduit) // revert(abi.encodeWithSignature( // "InvalidConduit(bytes32,address)", // conduitKey, // conduit // )) revert(Error_selector_offset, InvalidConduit_error_length) } } /** * @dev Reverts the current transaction with an "InvalidERC721TransferAmount" * error message. * * @param amount The invalid amount. */ function _revertInvalidERC721TransferAmount(uint256 amount) pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, InvalidERC721TransferAmount_error_selector) // Store argument. mstore(InvalidERC721TransferAmount_error_amount_ptr, amount) // revert(abi.encodeWithSignature( // "InvalidERC721TransferAmount(uint256)", // amount // )) revert(Error_selector_offset, InvalidERC721TransferAmount_error_length) } } /** * @dev Reverts the current transaction with an "InvalidMsgValue" error message, * including the invalid value that was sent in the transaction's * `msg.value` field. * * @param value The invalid value that was sent in the transaction's `msg.value` * field. */ function _revertInvalidMsgValue(uint256 value) pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, InvalidMsgValue_error_selector) // Store argument. mstore(InvalidMsgValue_error_value_ptr, value) // revert(abi.encodeWithSignature("InvalidMsgValue(uint256)", value)) revert(Error_selector_offset, InvalidMsgValue_error_length) } } /** * @dev Reverts the current transaction with an "InvalidNativeOfferItem" error * message. */ function _revertInvalidNativeOfferItem() pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, InvalidNativeOfferItem_error_selector) // revert(abi.encodeWithSignature("InvalidNativeOfferItem()")) revert(Error_selector_offset, InvalidNativeOfferItem_error_length) } } /** * @dev Reverts the current transaction with an "InvalidProof" error message. */ function _revertInvalidProof() pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, InvalidProof_error_selector) // revert(abi.encodeWithSignature("InvalidProof()")) revert(Error_selector_offset, InvalidProof_error_length) } } /** * @dev Reverts the current transaction with an "InvalidContractOrder" error * message. * * @param orderHash The hash of the contract order that caused the error. */ function _revertInvalidContractOrder(bytes32 orderHash) pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, InvalidContractOrder_error_selector) // Store arguments. mstore(InvalidContractOrder_error_orderHash_ptr, orderHash) // revert(abi.encodeWithSignature( // "InvalidContractOrder(bytes32)", // orderHash // )) revert(Error_selector_offset, InvalidContractOrder_error_length) } } /** * @dev Reverts the current transaction with an "InvalidTime" error message. * * @param startTime The time at which the order becomes active. * @param endTime The time at which the order becomes inactive. */ function _revertInvalidTime(uint256 startTime, uint256 endTime) pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, InvalidTime_error_selector) // Store arguments. mstore(InvalidTime_error_startTime_ptr, startTime) mstore(InvalidTime_error_endTime_ptr, endTime) // revert(abi.encodeWithSignature( // "InvalidTime(uint256,uint256)", // startTime, // endTime // )) revert(Error_selector_offset, InvalidTime_error_length) } } /** * @dev Reverts execution with a * "MismatchedFulfillmentOfferAndConsiderationComponents" error message. * * @param fulfillmentIndex The index of the fulfillment that caused the * error. */ function _revertMismatchedFulfillmentOfferAndConsiderationComponents( uint256 fulfillmentIndex ) pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, MismatchedOfferAndConsiderationComponents_error_selector) // Store fulfillment index argument. mstore( MismatchedOfferAndConsiderationComponents_error_idx_ptr, fulfillmentIndex ) // revert(abi.encodeWithSignature( // "MismatchedFulfillmentOfferAndConsiderationComponents(uint256)", // fulfillmentIndex // )) revert( Error_selector_offset, MismatchedOfferAndConsiderationComponents_error_length ) } } /** * @dev Reverts execution with a "MissingFulfillmentComponentOnAggregation" * error message. * * @param side The side of the fulfillment component that is missing (0 for * offer, 1 for consideration). * */ function _revertMissingFulfillmentComponentOnAggregation(Side side) pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, MissingFulfillmentComponentOnAggregation_error_selector) // Store argument. mstore(MissingFulfillmentComponentOnAggregation_error_side_ptr, side) // revert(abi.encodeWithSignature( // "MissingFulfillmentComponentOnAggregation(uint8)", // side // )) revert( Error_selector_offset, MissingFulfillmentComponentOnAggregation_error_length ) } } /** * @dev Reverts execution with a "MissingOriginalConsiderationItems" error * message. */ function _revertMissingOriginalConsiderationItems() pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, MissingOriginalConsiderationItems_error_selector) // revert(abi.encodeWithSignature( // "MissingOriginalConsiderationItems()" // )) revert( Error_selector_offset, MissingOriginalConsiderationItems_error_length ) } } /** * @dev Reverts execution with a "NoReentrantCalls" error message. */ function _revertNoReentrantCalls() pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, NoReentrantCalls_error_selector) // revert(abi.encodeWithSignature("NoReentrantCalls()")) revert(Error_selector_offset, NoReentrantCalls_error_length) } } /** * @dev Reverts execution with a "NoSpecifiedOrdersAvailable" error message. */ function _revertNoSpecifiedOrdersAvailable() pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, NoSpecifiedOrdersAvailable_error_selector) // revert(abi.encodeWithSignature("NoSpecifiedOrdersAvailable()")) revert(Error_selector_offset, NoSpecifiedOrdersAvailable_error_length) } } /** * @dev Reverts execution with a "OfferAndConsiderationRequiredOnFulfillment" * error message. */ function _revertOfferAndConsiderationRequiredOnFulfillment() pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, OfferAndConsiderationRequiredOnFulfillment_error_selector) // revert(abi.encodeWithSignature( // "OfferAndConsiderationRequiredOnFulfillment()" // )) revert( Error_selector_offset, OfferAndConsiderationRequiredOnFulfillment_error_length ) } } /** * @dev Reverts execution with an "OrderAlreadyFilled" error message. * * @param orderHash The hash of the order that has already been filled. */ function _revertOrderAlreadyFilled(bytes32 orderHash) pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, OrderAlreadyFilled_error_selector) // Store argument. mstore(OrderAlreadyFilled_error_orderHash_ptr, orderHash) // revert(abi.encodeWithSignature( // "OrderAlreadyFilled(bytes32)", // orderHash // )) revert(Error_selector_offset, OrderAlreadyFilled_error_length) } } /** * @dev Reverts execution with an "OrderCriteriaResolverOutOfRange" error * message. * * @param side The side of the criteria that is missing (0 for offer, 1 for * consideration). * */ function _revertOrderCriteriaResolverOutOfRange(Side side) pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, OrderCriteriaResolverOutOfRange_error_selector) // Store argument. mstore(OrderCriteriaResolverOutOfRange_error_side_ptr, side) // revert(abi.encodeWithSignature( // "OrderCriteriaResolverOutOfRange(uint8)", // side // )) revert( Error_selector_offset, OrderCriteriaResolverOutOfRange_error_length ) } } /** * @dev Reverts execution with an "OrderIsCancelled" error message. * * @param orderHash The hash of the order that has already been cancelled. */ function _revertOrderIsCancelled(bytes32 orderHash) pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, OrderIsCancelled_error_selector) // Store argument. mstore(OrderIsCancelled_error_orderHash_ptr, orderHash) // revert(abi.encodeWithSignature( // "OrderIsCancelled(bytes32)", // orderHash // )) revert(Error_selector_offset, OrderIsCancelled_error_length) } } /** * @dev Reverts execution with an "OrderPartiallyFilled" error message. * * @param orderHash The hash of the order that has already been partially * filled. */ function _revertOrderPartiallyFilled(bytes32 orderHash) pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, OrderPartiallyFilled_error_selector) // Store argument. mstore(OrderPartiallyFilled_error_orderHash_ptr, orderHash) // revert(abi.encodeWithSignature( // "OrderPartiallyFilled(bytes32)", // orderHash // )) revert(Error_selector_offset, OrderPartiallyFilled_error_length) } } /** * @dev Reverts execution with a "PartialFillsNotEnabledForOrder" error message. */ function _revertPartialFillsNotEnabledForOrder() pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, PartialFillsNotEnabledForOrder_error_selector) // revert(abi.encodeWithSignature("PartialFillsNotEnabledForOrder()")) revert( Error_selector_offset, PartialFillsNotEnabledForOrder_error_length ) } } /** * @dev Reverts execution with an "UnresolvedConsiderationCriteria" error * message. */ function _revertUnresolvedConsiderationCriteria( uint256 orderIndex, uint256 considerationIndex ) pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, UnresolvedConsiderationCriteria_error_selector) // Store orderIndex and considerationIndex arguments. mstore(UnresolvedConsiderationCriteria_error_orderIndex_ptr, orderIndex) mstore( UnresolvedConsiderationCriteria_error_considerationIdx_ptr, considerationIndex ) // revert(abi.encodeWithSignature( // "UnresolvedConsiderationCriteria(uint256, uint256)", // orderIndex, // considerationIndex // )) revert( Error_selector_offset, UnresolvedConsiderationCriteria_error_length ) } } /** * @dev Reverts execution with an "UnresolvedOfferCriteria" error message. */ function _revertUnresolvedOfferCriteria( uint256 orderIndex, uint256 offerIndex ) pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, UnresolvedOfferCriteria_error_selector) // Store arguments. mstore(UnresolvedOfferCriteria_error_orderIndex_ptr, orderIndex) mstore(UnresolvedOfferCriteria_error_offerIndex_ptr, offerIndex) // revert(abi.encodeWithSignature( // "UnresolvedOfferCriteria(uint256, uint256)", // orderIndex, // offerIndex // )) revert(Error_selector_offset, UnresolvedOfferCriteria_error_length) } } /** * @dev Reverts execution with an "UnusedItemParameters" error message. */ function _revertUnusedItemParameters() pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, UnusedItemParameters_error_selector) // revert(abi.encodeWithSignature("UnusedItemParameters()")) revert(Error_selector_offset, UnusedItemParameters_error_length) } } /** * @dev Reverts execution with a "ConsiderationLengthNotEqualToTotalOriginal" * error message. */ function _revertConsiderationLengthNotEqualToTotalOriginal() pure { assembly { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, ConsiderationLengthNotEqualToTotalOriginal_error_selector) // revert(abi.encodeWithSignature( // "ConsiderationLengthNotEqualToTotalOriginal()" // )) revert( Error_selector_offset, ConsiderationLengthNotEqualToTotalOriginal_error_length ) } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { BasicOrderRouteType, ItemType, OrderType } from "./ConsiderationEnums.sol"; import { BasicOrderParameters } from "./ConsiderationStructs.sol"; import { OrderValidator } from "./OrderValidator.sol"; import { _revertInsufficientNativeTokensSupplied, _revertInvalidMsgValue, _revertInvalidERC721TransferAmount, _revertUnusedItemParameters } from "./ConsiderationErrors.sol"; import { AccumulatorDisarmed, AdditionalRecipient_size_shift, AdditionalRecipient_size, BasicOrder_additionalRecipients_data_cdPtr, BasicOrder_additionalRecipients_length_cdPtr, BasicOrder_basicOrderType_cdPtr, BasicOrder_common_params_size, BasicOrder_considerationAmount_cdPtr, BasicOrder_considerationHashesArray_ptr, BasicOrder_considerationIdentifier_cdPtr, BasicOrder_considerationItem_endAmount_ptr, BasicOrder_considerationItem_identifier_ptr, BasicOrder_considerationItem_itemType_ptr, BasicOrder_considerationItem_startAmount_ptr, BasicOrder_considerationItem_token_ptr, BasicOrder_considerationItem_typeHash_ptr, BasicOrder_considerationToken_cdPtr, BasicOrder_endTime_cdPtr, BasicOrder_fulfillerConduit_cdPtr, BasicOrder_offerAmount_cdPtr, BasicOrder_offeredItemByteMap, BasicOrder_offerer_cdPtr, BasicOrder_offererConduit_cdPtr, BasicOrder_offerIdentifier_cdPtr, BasicOrder_offerItem_endAmount_ptr, BasicOrder_offerItem_itemType_ptr, BasicOrder_offerItem_token_ptr, BasicOrder_offerItem_typeHash_ptr, BasicOrder_offerToken_cdPtr, BasicOrder_order_considerationHashes_ptr, BasicOrder_order_counter_ptr, BasicOrder_order_offerer_ptr, BasicOrder_order_offerHashes_ptr, BasicOrder_order_orderType_ptr, BasicOrder_order_startTime_ptr, BasicOrder_order_typeHash_ptr, BasicOrder_receivedItemByteMap, BasicOrder_startTime_cdPtr, BasicOrder_totalOriginalAdditionalRecipients_cdPtr, BasicOrder_zone_cdPtr, Common_token_offset, Conduit_execute_ConduitTransfer_length_ptr, Conduit_execute_ConduitTransfer_length, Conduit_execute_ConduitTransfer_offset_ptr, Conduit_execute_ConduitTransfer_ptr, Conduit_execute_signature, Conduit_execute_transferAmount_ptr, Conduit_execute_transferIdentifier_ptr, Conduit_execute_transferFrom_ptr, Conduit_execute_transferItemType_ptr, Conduit_execute_transferTo_ptr, Conduit_execute_transferToken_ptr, EIP712_ConsiderationItem_size, EIP712_OfferItem_size, EIP712_Order_size, FiveWords, FourWords, FreeMemoryPointerSlot, MaskOverLastTwentyBytes, OneConduitExecute_size, OneWord, OneWordShift, OrderFulfilled_baseOffset, OrderFulfilled_baseSize, OrderFulfilled_consideration_body_offset, OrderFulfilled_consideration_head_offset, OrderFulfilled_consideration_length_baseOffset, OrderFulfilled_fulfiller_offset, OrderFulfilled_offer_body_offset, OrderFulfilled_offer_head_offset, OrderFulfilled_offer_length_baseOffset, OrderFulfilled_selector, ReceivedItem_amount_offset, ReceivedItem_size, receivedItemsHash_ptr, ThreeWords, TwoWords, ZeroSlot } from "./ConsiderationConstants.sol"; import { Error_selector_offset, InvalidBasicOrderParameterEncoding_error_length, InvalidBasicOrderParameterEncoding_error_selector, InvalidTime_error_endTime_ptr, InvalidTime_error_length, InvalidTime_error_selector, InvalidTime_error_startTime_ptr, MissingOriginalConsiderationItems_error_length, MissingOriginalConsiderationItems_error_selector, UnusedItemParameters_error_length, UnusedItemParameters_error_selector } from "./ConsiderationErrorConstants.sol"; /** * @title BasicOrderFulfiller * @author 0age * @notice BasicOrderFulfiller contains functionality for fulfilling "basic" * orders with minimal overhead. See documentation for details on what * qualifies as a basic order. */ contract BasicOrderFulfiller is OrderValidator { /** * @dev Derive and set hashes, reference chainId, and associated domain * separator during deployment. * * @param conduitController A contract that deploys conduits, or proxies * that may optionally be used to transfer approved * ERC20/721/1155 tokens. */ constructor(address conduitController) OrderValidator(conduitController) {} /** * @dev Internal function to fulfill an order offering an ERC20, ERC721, or * ERC1155 item by supplying Ether (or other native tokens), ERC20 * tokens, an ERC721 item, or an ERC1155 item as consideration. Six * permutations are supported: Native token to ERC721, Native token to * ERC1155, ERC20 to ERC721, ERC20 to ERC1155, ERC721 to ERC20, and * ERC1155 to ERC20 (with native tokens supplied as msg.value). For an * order to be eligible for fulfillment via this method, it must * contain a single offer item (though that item may have a greater * amount if the item is not an ERC721). An arbitrary number of * "additional recipients" may also be supplied which will each receive * native tokens or ERC20 items from the fulfiller as consideration. * Refer to the documentation for a more comprehensive summary of how * to utilize this method and what orders are compatible with it. * * @param parameters Additional information on the fulfilled order. Note * that the offerer and the fulfiller must first approve * this contract (or their chosen conduit if indicated) * before any tokens can be transferred. Also note that * contract recipients of ERC1155 consideration items must * implement `onERC1155Received` in order to receive those * items. * * @return A boolean indicating whether the order has been fulfilled. */ function _validateAndFulfillBasicOrder( BasicOrderParameters calldata parameters ) internal returns (bool) { // Declare enums for order type & route to extract from basicOrderType. BasicOrderRouteType route; OrderType orderType; // Declare additional recipient item type to derive from the route type. ItemType additionalRecipientsItemType; bytes32 orderHash; // Utilize assembly to extract the order type and the basic order route. assembly { // Read basicOrderType from calldata. let basicOrderType := calldataload(BasicOrder_basicOrderType_cdPtr) // Mask all but 2 least-significant bits to derive the order type. orderType := and(basicOrderType, 3) // Divide basicOrderType by four to derive the route. route := shr(2, basicOrderType) // If route > 1 additionalRecipient items are ERC20 (1) else native // token (0). additionalRecipientsItemType := gt(route, 1) } { // Declare temporary variable for enforcing payable status. bool correctPayableStatus; // Utilize assembly to compare the route to the callvalue. assembly { // route 0 and 1 are payable, otherwise route is not payable. correctPayableStatus := eq( additionalRecipientsItemType, iszero(callvalue()) ) } // Revert if msg.value has not been supplied as part of payable // routes or has been supplied as part of non-payable routes. if (!correctPayableStatus) { _revertInvalidMsgValue(msg.value); } } // Declare more arguments that will be derived from route and calldata. address additionalRecipientsToken; ItemType offeredItemType; bool offerTypeIsAdditionalRecipientsType; // Declare scope for received item type to manage stack pressure. { ItemType receivedItemType; // Utilize assembly to retrieve function arguments and cast types. assembly { // Check if offered item type == additional recipient item type. offerTypeIsAdditionalRecipientsType := gt(route, 3) // If route > 3 additionalRecipientsToken is at 0xc4 else 0x24. additionalRecipientsToken := calldataload( add( BasicOrder_considerationToken_cdPtr, mul( offerTypeIsAdditionalRecipientsType, BasicOrder_common_params_size ) ) ) // If route > 2, receivedItemType is route - 2. If route is 2, // the receivedItemType is ERC20 (1). Otherwise, it is native // token (0). receivedItemType := byte(route, BasicOrder_receivedItemByteMap) // If route > 3, offeredItemType is ERC20 (1). Route is 2 or 3, // offeredItemType = route. Route is 0 or 1, it is route + 2. offeredItemType := byte(route, BasicOrder_offeredItemByteMap) } // Derive & validate order using parameters and update order status. orderHash = _prepareBasicFulfillmentFromCalldata( parameters, orderType, receivedItemType, additionalRecipientsItemType, additionalRecipientsToken, offeredItemType ); } // Declare conduitKey argument used by transfer functions. bytes32 conduitKey; // Utilize assembly to derive conduit (if relevant) based on route. assembly { // use offerer conduit for routes 0-3, fulfiller conduit otherwise. conduitKey := calldataload( add( BasicOrder_offererConduit_cdPtr, shl(OneWordShift, offerTypeIsAdditionalRecipientsType) ) ) } // Transfer tokens based on the route. if (additionalRecipientsItemType == ItemType.NATIVE) { // Ensure neither consideration token nor identifier are set. Note // that dirty upper bits in the consideration token will still cause // this error to be thrown. assembly { if or( calldataload(BasicOrder_considerationToken_cdPtr), calldataload(BasicOrder_considerationIdentifier_cdPtr) ) { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, UnusedItemParameters_error_selector) // revert(abi.encodeWithSignature("UnusedItemParameters()")) revert( Error_selector_offset, UnusedItemParameters_error_length ) } } // Transfer the ERC721 or ERC1155 item, bypassing the accumulator. _transferIndividual721Or1155Item(offeredItemType, conduitKey); // Transfer native to recipients, return excess to caller & wrap up. _transferNativeTokensAndFinalize(); } else { // Initialize an accumulator array. From this point forward, no new // memory regions can be safely allocated until the accumulator is // no longer being utilized, as the accumulator operates in an // open-ended fashion from this memory pointer; existing memory may // still be accessed and modified, however. bytes memory accumulator = new bytes(AccumulatorDisarmed); // Choose transfer method for ERC721 or ERC1155 item based on route. if (route == BasicOrderRouteType.ERC20_TO_ERC721) { // Transfer ERC721 to caller using offerer's conduit preference. _transferERC721( parameters.offerToken, parameters.offerer, msg.sender, parameters.offerIdentifier, parameters.offerAmount, conduitKey, accumulator ); } else if (route == BasicOrderRouteType.ERC20_TO_ERC1155) { // Transfer ERC1155 to caller with offerer's conduit preference. _transferERC1155( parameters.offerToken, parameters.offerer, msg.sender, parameters.offerIdentifier, parameters.offerAmount, conduitKey, accumulator ); } else if (route == BasicOrderRouteType.ERC721_TO_ERC20) { // Transfer ERC721 to offerer using caller's conduit preference. _transferERC721( parameters.considerationToken, msg.sender, parameters.offerer, parameters.considerationIdentifier, parameters.considerationAmount, conduitKey, accumulator ); } else { // route == BasicOrderRouteType.ERC1155_TO_ERC20 // Transfer ERC1155 to offerer with caller's conduit preference. _transferERC1155( parameters.considerationToken, msg.sender, parameters.offerer, parameters.considerationIdentifier, parameters.considerationAmount, conduitKey, accumulator ); } // Transfer ERC20 tokens to all recipients and wrap up. _transferERC20AndFinalize( offerTypeIsAdditionalRecipientsType, accumulator ); // Trigger any remaining accumulated transfers via call to conduit. _triggerIfArmed(accumulator); } // Determine whether order is restricted and, if so, that it is valid. _assertRestrictedBasicOrderValidity(orderHash, orderType, parameters); // Clear the reentrancy guard. _clearReentrancyGuard(); return true; } /** * @dev Internal function to prepare fulfillment of a basic order with * manual calldata and memory access. This calculates the order hash, * emits an OrderFulfilled event, and asserts basic order validity. * Note that calldata offsets must be validated as this function * accesses constant calldata pointers for dynamic types that match * default ABI encoding, but valid ABI encoding can use arbitrary * offsets. Checking that the offsets were produced by default encoding * will ensure that other functions using Solidity's calldata accessors * (which calculate pointers from the stored offsets) are reading the * same data as the order hash is derived from. Also note that this * function accesses memory directly. * * @param parameters The parameters of the basic order. * @param orderType The order type. * @param receivedItemType The item type of the initial * consideration item on the order. * @param additionalRecipientsItemType The item type of any additional * consideration item on the order. * @param additionalRecipientsToken The ERC20 token contract address (if * applicable) for any additional * consideration item on the order. * @param offeredItemType The item type of the offered item on * the order. * @return orderHash The calculated order hash. */ function _prepareBasicFulfillmentFromCalldata( BasicOrderParameters calldata parameters, OrderType orderType, ItemType receivedItemType, ItemType additionalRecipientsItemType, address additionalRecipientsToken, ItemType offeredItemType ) internal returns (bytes32 orderHash) { // Ensure this function cannot be triggered during a reentrant call. _setReentrancyGuard(false); // Native tokens rejected during execution. // Verify that calldata offsets for all dynamic types were produced by // default encoding. This ensures that the constants used for calldata // pointers to dynamic types are the same as those calculated by // Solidity using their offsets. Also verify that the basic order type // is within range. _assertValidBasicOrderParameters(); // Check for invalid time and missing original consideration items. // Utilize assembly so that constant calldata pointers can be applied. assembly { // Ensure current timestamp is between order start time & end time. if or( gt(calldataload(BasicOrder_startTime_cdPtr), timestamp()), iszero(gt(calldataload(BasicOrder_endTime_cdPtr), timestamp())) ) { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, InvalidTime_error_selector) // Store arguments. mstore( InvalidTime_error_startTime_ptr, calldataload(BasicOrder_startTime_cdPtr) ) mstore( InvalidTime_error_endTime_ptr, calldataload(BasicOrder_endTime_cdPtr) ) // revert(abi.encodeWithSignature( // "InvalidTime(uint256,uint256)", // startTime, // endTime // )) revert(Error_selector_offset, InvalidTime_error_length) } // Ensure consideration array length isn't less than total original. if lt( calldataload(BasicOrder_additionalRecipients_length_cdPtr), calldataload(BasicOrder_totalOriginalAdditionalRecipients_cdPtr) ) { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, MissingOriginalConsiderationItems_error_selector) // revert(abi.encodeWithSignature( // "MissingOriginalConsiderationItems()" // )) revert( Error_selector_offset, MissingOriginalConsiderationItems_error_length ) } } { /** * First, handle consideration items. Memory Layout: * 0x60: final hash of the array of consideration item hashes * 0x80-0x160: reused space for EIP712 hashing of each item * - 0x80: ConsiderationItem EIP-712 typehash (constant) * - 0xa0: itemType * - 0xc0: token * - 0xe0: identifier * - 0x100: startAmount * - 0x120: endAmount * - 0x140: recipient * 0x160-END_ARR: array of consideration item hashes * - 0x160: primary consideration item EIP712 hash * - 0x180-END_ARR: additional recipient item EIP712 hashes * END_ARR: beginning of data for OrderFulfilled event * - END_ARR + 0x120: length of ReceivedItem array * - END_ARR + 0x140: beginning of data for first ReceivedItem * (Note: END_ARR = 0x180 + RECIPIENTS_LENGTH * 0x20) */ // Load consideration item typehash from runtime and place on stack. bytes32 typeHash = _CONSIDERATION_ITEM_TYPEHASH; // Utilize assembly to enable reuse of memory regions and use // constant pointers when possible. assembly { /* * 1. Calculate the EIP712 ConsiderationItem hash for the * primary consideration item of the basic order. */ // Write ConsiderationItem type hash and item type to memory. mstore(BasicOrder_considerationItem_typeHash_ptr, typeHash) mstore( BasicOrder_considerationItem_itemType_ptr, receivedItemType ) // Copy calldata region with (token, identifier, amount) from // BasicOrderParameters to ConsiderationItem. The // considerationAmount is written to startAmount and endAmount // as basic orders do not have dynamic amounts. calldatacopy( BasicOrder_considerationItem_token_ptr, BasicOrder_considerationToken_cdPtr, ThreeWords ) // Copy calldata region with considerationAmount and offerer // from BasicOrderParameters to endAmount and recipient in // ConsiderationItem. calldatacopy( BasicOrder_considerationItem_endAmount_ptr, BasicOrder_considerationAmount_cdPtr, TwoWords ) // Calculate EIP712 ConsiderationItem hash and store it in the // array of EIP712 consideration hashes. mstore( BasicOrder_considerationHashesArray_ptr, keccak256( BasicOrder_considerationItem_typeHash_ptr, EIP712_ConsiderationItem_size ) ) /* * 2. Write a ReceivedItem struct for the primary consideration * item to the consideration array in OrderFulfilled. */ // Get the length of the additional recipients array. let totalAdditionalRecipients := calldataload( BasicOrder_additionalRecipients_length_cdPtr ) // Calculate pointer to length of OrderFulfilled consideration // array. let eventConsiderationArrPtr := add( OrderFulfilled_consideration_length_baseOffset, shl(OneWordShift, totalAdditionalRecipients) ) // Set the length of the consideration array to the number of // additional recipients, plus one for the primary consideration // item. mstore( eventConsiderationArrPtr, add(totalAdditionalRecipients, 1) ) // Overwrite the consideration array pointer so it points to the // body of the first element eventConsiderationArrPtr := add( eventConsiderationArrPtr, OneWord ) // Set itemType at start of the ReceivedItem memory region. mstore(eventConsiderationArrPtr, receivedItemType) // Copy calldata region (token, identifier, amount & recipient) // from BasicOrderParameters to ReceivedItem memory. calldatacopy( add(eventConsiderationArrPtr, Common_token_offset), BasicOrder_considerationToken_cdPtr, FourWords ) /* * 3. Calculate EIP712 ConsiderationItem hashes for original * additional recipients and add a ReceivedItem for each to the * consideration array in the OrderFulfilled event. The original * additional recipients are all the consideration items signed * by the offerer aside from the primary consideration items of * the order. Uses memory region from 0x80-0x160 as a buffer for * calculating EIP712 ConsiderationItem hashes. */ // Put pointer to consideration hashes array on the stack. // This will be updated as each additional recipient is hashed let considerationHashesPtr := BasicOrder_considerationHashesArray_ptr // Write item type, token, & identifier for additional recipient // to memory region for hashing EIP712 ConsiderationItem; these // values will be reused for each recipient. mstore( BasicOrder_considerationItem_itemType_ptr, additionalRecipientsItemType ) mstore( BasicOrder_considerationItem_token_ptr, additionalRecipientsToken ) mstore(BasicOrder_considerationItem_identifier_ptr, 0) // Declare a stack variable where all additional recipients will // be combined to guard against providing dirty upper bits. let combinedAdditionalRecipients // Read length of the additionalRecipients array from calldata // and iterate. totalAdditionalRecipients := calldataload( BasicOrder_totalOriginalAdditionalRecipients_cdPtr ) let i := 0 for {} lt(i, totalAdditionalRecipients) { i := add(i, 1) } { /* * Calculate EIP712 ConsiderationItem hash for recipient. */ // Retrieve calldata pointer for additional recipient. let additionalRecipientCdPtr := add( BasicOrder_additionalRecipients_data_cdPtr, mul(AdditionalRecipient_size, i) ) // Copy startAmount from calldata to the ConsiderationItem // struct. calldatacopy( BasicOrder_considerationItem_startAmount_ptr, additionalRecipientCdPtr, OneWord ) // Copy endAmount and recipient from calldata to the // ConsiderationItem struct. calldatacopy( BasicOrder_considerationItem_endAmount_ptr, additionalRecipientCdPtr, AdditionalRecipient_size ) // Include the recipient as part of combined recipients. combinedAdditionalRecipients := or( combinedAdditionalRecipients, calldataload(add(additionalRecipientCdPtr, OneWord)) ) // Add 1 word to the pointer as part of each loop to reduce // operations needed to get local offset into the array. considerationHashesPtr := add( considerationHashesPtr, OneWord ) // Calculate EIP712 ConsiderationItem hash and store it in // the array of consideration hashes. mstore( considerationHashesPtr, keccak256( BasicOrder_considerationItem_typeHash_ptr, EIP712_ConsiderationItem_size ) ) /* * Write ReceivedItem to OrderFulfilled data. */ // At this point, eventConsiderationArrPtr points to the // beginning of the ReceivedItem struct of the previous // element in the array. Increase it by the size of the // struct to arrive at the pointer for the current element. eventConsiderationArrPtr := add( eventConsiderationArrPtr, ReceivedItem_size ) // Write itemType to the ReceivedItem struct. mstore( eventConsiderationArrPtr, additionalRecipientsItemType ) // Write token to the next word of the ReceivedItem struct. mstore( add(eventConsiderationArrPtr, OneWord), additionalRecipientsToken ) // Copy endAmount & recipient words to ReceivedItem struct. calldatacopy( add( eventConsiderationArrPtr, ReceivedItem_amount_offset ), additionalRecipientCdPtr, TwoWords ) } /* * 4. Hash packed array of ConsiderationItem EIP712 hashes: * `keccak256(abi.encodePacked(receivedItemHashes))` * Note that it is set at 0x60 — all other memory begins at * 0x80. 0x60 is the "zero slot" and will be restored at the end * of the assembly section and before required by the compiler. */ mstore( receivedItemsHash_ptr, keccak256( BasicOrder_considerationHashesArray_ptr, shl(OneWordShift, add(totalAdditionalRecipients, 1)) ) ) /* * 5. Add a ReceivedItem for each tip to the consideration array * in the OrderFulfilled event. The tips are all the * consideration items that were not signed by the offerer and * were provided by the fulfiller. */ // Overwrite length to length of the additionalRecipients array. totalAdditionalRecipients := calldataload( BasicOrder_additionalRecipients_length_cdPtr ) for {} lt(i, totalAdditionalRecipients) { i := add(i, 1) } { // Retrieve calldata pointer for additional recipient. let additionalRecipientCdPtr := add( BasicOrder_additionalRecipients_data_cdPtr, mul(AdditionalRecipient_size, i) ) // At this point, eventConsiderationArrPtr points to the // beginning of the ReceivedItem struct of the previous // element in the array. Increase it by the size of the // struct to arrive at the pointer for the current element. eventConsiderationArrPtr := add( eventConsiderationArrPtr, ReceivedItem_size ) // Write itemType to the ReceivedItem struct. mstore( eventConsiderationArrPtr, additionalRecipientsItemType ) // Write token to the next word of the ReceivedItem struct. mstore( add(eventConsiderationArrPtr, OneWord), additionalRecipientsToken ) // Copy endAmount & recipient words to ReceivedItem struct. calldatacopy( add( eventConsiderationArrPtr, ReceivedItem_amount_offset ), additionalRecipientCdPtr, TwoWords ) // Include the recipient as part of combined recipients. combinedAdditionalRecipients := or( combinedAdditionalRecipients, calldataload(add(additionalRecipientCdPtr, OneWord)) ) } // Ensure no dirty upper bits on combined additional recipients. if gt(combinedAdditionalRecipients, MaskOverLastTwentyBytes) { // Store left-padded selector with push4 (reduces bytecode), // mem[28:32] = selector mstore(0, InvalidBasicOrderParameterEncoding_error_selector) // revert(abi.encodeWithSignature( // "InvalidBasicOrderParameterEncoding()" // )) revert( Error_selector_offset, InvalidBasicOrderParameterEncoding_error_length ) } } } { /** * Next, handle offered items. Memory Layout: * EIP712 data for OfferItem * - 0x80: OfferItem EIP-712 typehash (constant) * - 0xa0: itemType * - 0xc0: token * - 0xe0: identifier (reused for offeredItemsHash) * - 0x100: startAmount * - 0x120: endAmount */ // Place offer item typehash on the stack. bytes32 typeHash = _OFFER_ITEM_TYPEHASH; // Utilize assembly to enable reuse of memory regions when possible. assembly { /* * 1. Calculate OfferItem EIP712 hash */ // Write the OfferItem typeHash to memory. mstore(BasicOrder_offerItem_typeHash_ptr, typeHash) // Write the OfferItem item type to memory. mstore(BasicOrder_offerItem_itemType_ptr, offeredItemType) // Copy calldata region with (offerToken, offerIdentifier, // offerAmount) from OrderParameters to (token, identifier, // startAmount) in OfferItem struct. The offerAmount is written // to startAmount and endAmount as basic orders do not have // dynamic amounts. calldatacopy( BasicOrder_offerItem_token_ptr, BasicOrder_offerToken_cdPtr, ThreeWords ) // Copy offerAmount from calldata to endAmount in OfferItem // struct. calldatacopy( BasicOrder_offerItem_endAmount_ptr, BasicOrder_offerAmount_cdPtr, OneWord ) // Compute EIP712 OfferItem hash, write result to scratch space: // `keccak256(abi.encode(offeredItem))` mstore( 0, keccak256( BasicOrder_offerItem_typeHash_ptr, EIP712_OfferItem_size ) ) /* * 2. Calculate hash of array of EIP712 hashes and write the * result to the corresponding OfferItem struct: * `keccak256(abi.encodePacked(offerItemHashes))` */ mstore(BasicOrder_order_offerHashes_ptr, keccak256(0, OneWord)) /* * 3. Write SpentItem to offer array in OrderFulfilled event. */ let eventConsiderationArrPtr := add( OrderFulfilled_offer_length_baseOffset, shl( OneWordShift, calldataload( BasicOrder_additionalRecipients_length_cdPtr ) ) ) // Set a length of 1 for the offer array. mstore(eventConsiderationArrPtr, 1) // Write itemType to the SpentItem struct. mstore(add(eventConsiderationArrPtr, OneWord), offeredItemType) // Copy calldata region with (offerToken, offerIdentifier, // offerAmount) from OrderParameters to (token, identifier, // amount) in SpentItem struct. calldatacopy( add(eventConsiderationArrPtr, AdditionalRecipient_size), BasicOrder_offerToken_cdPtr, ThreeWords ) } } { /** * Once consideration items and offer items have been handled, * derive the final order hash. Memory Layout: * 0x80-0x1c0: EIP712 data for order * - 0x80: Order EIP-712 typehash (constant) * - 0xa0: orderParameters.offerer * - 0xc0: orderParameters.zone * - 0xe0: keccak256(abi.encodePacked(offerHashes)) * - 0x100: keccak256(abi.encodePacked(considerationHashes)) * - 0x120: orderParameters.basicOrderType (% 4 = orderType) * - 0x140: orderParameters.startTime * - 0x160: orderParameters.endTime * - 0x180: orderParameters.zoneHash * - 0x1a0: orderParameters.salt * - 0x1c0: orderParameters.conduitKey * - 0x1e0: _counters[orderParameters.offerer] (from storage) */ // Read the offerer from calldata and place on the stack. address offerer; assembly { offerer := calldataload(BasicOrder_offerer_cdPtr) } // Read offerer's current counter from storage and place on stack. uint256 counter = _getCounter(offerer); // Load order typehash from runtime code and place on stack. bytes32 typeHash = _ORDER_TYPEHASH; assembly { // Set the OrderItem typeHash in memory. mstore(BasicOrder_order_typeHash_ptr, typeHash) // Copy offerer and zone from OrderParameters in calldata to the // Order struct. calldatacopy( BasicOrder_order_offerer_ptr, BasicOrder_offerer_cdPtr, TwoWords ) // Copy receivedItemsHash from zero slot to the Order struct. mstore( BasicOrder_order_considerationHashes_ptr, mload(receivedItemsHash_ptr) ) // Write the supplied orderType to the Order struct. mstore(BasicOrder_order_orderType_ptr, orderType) // Copy startTime, endTime, zoneHash, salt & conduit from // calldata to the Order struct. calldatacopy( BasicOrder_order_startTime_ptr, BasicOrder_startTime_cdPtr, FiveWords ) // Write offerer's counter, retrieved from storage, to struct. mstore(BasicOrder_order_counter_ptr, counter) // Compute the EIP712 Order hash. orderHash := keccak256( BasicOrder_order_typeHash_ptr, EIP712_Order_size ) } } assembly { /** * After the order hash has been derived, emit OrderFulfilled event: * event OrderFulfilled( * bytes32 orderHash, * address indexed offerer, * address indexed zone, * address fulfiller, * SpentItem[] offer, * > (itemType, token, id, amount) * ReceivedItem[] consideration * > (itemType, token, id, amount, recipient) * ) * topic0 - OrderFulfilled event signature * topic1 - offerer * topic2 - zone * data: * - 0x00: orderHash * - 0x20: fulfiller * - 0x40: offer arr ptr (0x80) * - 0x60: consideration arr ptr (0x120) * - 0x80: offer arr len (1) * - 0xa0: offer.itemType * - 0xc0: offer.token * - 0xe0: offer.identifier * - 0x100: offer.amount * - 0x120: 1 + recipients.length * - 0x140: recipient 0 */ // Derive pointer to start of OrderFulfilled event data. let eventDataPtr := add( OrderFulfilled_baseOffset, shl( OneWordShift, calldataload(BasicOrder_additionalRecipients_length_cdPtr) ) ) // Write the order hash to the head of the event's data region. mstore(eventDataPtr, orderHash) // Write the fulfiller (i.e. the caller) next for receiver argument. mstore(add(eventDataPtr, OrderFulfilled_fulfiller_offset), caller()) // Write the SpentItem and ReceivedItem array offsets (constants). mstore( // SpentItem array offset add(eventDataPtr, OrderFulfilled_offer_head_offset), OrderFulfilled_offer_body_offset ) mstore( // ReceivedItem array offset add(eventDataPtr, OrderFulfilled_consideration_head_offset), OrderFulfilled_consideration_body_offset ) // Derive total data size including SpentItem and ReceivedItem data. // SpentItem portion is already included in the baseSize constant, // as there can only be one element in the array. let dataSize := add( OrderFulfilled_baseSize, mul( calldataload(BasicOrder_additionalRecipients_length_cdPtr), ReceivedItem_size ) ) // Emit OrderFulfilled log with three topics (the event signature // as well as the two indexed arguments, the offerer and the zone). log3( // Supply the pointer for event data in memory. eventDataPtr, // Supply the size of event data in memory. dataSize, // Supply the OrderFulfilled event signature. OrderFulfilled_selector, // Supply the first topic (the offerer). calldataload(BasicOrder_offerer_cdPtr), // Supply the second topic (the zone). calldataload(BasicOrder_zone_cdPtr) ) // Restore the zero slot. mstore(ZeroSlot, 0) // Update the free memory pointer so that event data is persisted. mstore(FreeMemoryPointerSlot, add(eventDataPtr, dataSize)) } // Verify and update the status of the derived order. _validateBasicOrderAndUpdateStatus(orderHash, parameters.signature); // Return the derived order hash. return orderHash; } /** * @dev Internal function to transfer an individual ERC721 or ERC1155 item * from a given originator to a given recipient. The accumulator will * be bypassed, meaning that this function should be utilized in cases * where multiple item transfers can be accumulated into a single * conduit call. Sufficient approvals must be set, either on the * respective conduit or on this contract. Note that this function may * only be safely called as part of basic orders, as it assumes a * specific calldata encoding structure that must first be validated. * * @param itemType The type of item to transfer, either ERC721 or ERC1155. * @param conduitKey A bytes32 value indicating what corresponding conduit, * if any, to source token approvals from. The zero hash * signifies that no conduit should be used, with direct * approvals set on this contract. */ function _transferIndividual721Or1155Item( ItemType itemType, bytes32 conduitKey ) internal { // Retrieve token, from, identifier, and amount from calldata using // fixed calldata offsets based on strict basic parameter encoding. address token; address from; uint256 identifier; uint256 amount; assembly { token := calldataload(BasicOrder_offerToken_cdPtr) from := calldataload(BasicOrder_offerer_cdPtr) identifier := calldataload(BasicOrder_offerIdentifier_cdPtr) amount := calldataload(BasicOrder_offerAmount_cdPtr) } // Determine if the transfer is to be performed via a conduit. if (conduitKey != bytes32(0)) { // Use free memory pointer as calldata offset for the conduit call. uint256 callDataOffset; // Utilize assembly to place each argument in free memory. assembly { // Retrieve the free memory pointer and use it as the offset. callDataOffset := mload(FreeMemoryPointerSlot) // Write ConduitInterface.execute.selector to memory. mstore(callDataOffset, Conduit_execute_signature) // Write the offset to the ConduitTransfer array in memory. mstore( add( callDataOffset, Conduit_execute_ConduitTransfer_offset_ptr ), Conduit_execute_ConduitTransfer_ptr ) // Write the length of the ConduitTransfer array to memory. mstore( add( callDataOffset, Conduit_execute_ConduitTransfer_length_ptr ), Conduit_execute_ConduitTransfer_length ) // Write the item type to memory. mstore( add(callDataOffset, Conduit_execute_transferItemType_ptr), itemType ) // Write the token to memory. mstore( add(callDataOffset, Conduit_execute_transferToken_ptr), token ) // Write the transfer source to memory. mstore( add(callDataOffset, Conduit_execute_transferFrom_ptr), from ) // Write the transfer recipient (the caller) to memory. mstore( add(callDataOffset, Conduit_execute_transferTo_ptr), caller() ) // Write the token identifier to memory. mstore( add(callDataOffset, Conduit_execute_transferIdentifier_ptr), identifier ) // Write the transfer amount to memory. mstore( add(callDataOffset, Conduit_execute_transferAmount_ptr), amount ) } // Perform the call to the conduit. _callConduitUsingOffsets( conduitKey, callDataOffset, OneConduitExecute_size ); } else { // Otherwise, determine whether it is an ERC721 or ERC1155 item. if (itemType == ItemType.ERC721) { // Ensure that exactly one 721 item is being transferred. if (amount != 1) { _revertInvalidERC721TransferAmount(amount); } // Perform transfer to caller via the token contract directly. _performERC721Transfer(token, from, msg.sender, identifier); } else { // Perform transfer to caller via the token contract directly. _performERC1155Transfer( token, from, msg.sender, identifier, amount ); } } } /** * @dev Internal function to transfer Ether (or other native tokens) to a * given recipient as part of basic order fulfillment. Note that * conduits are not utilized for native tokens as the transferred * amount must be provided as msg.value. Also note that this function * may only be safely called as part of basic orders, as it assumes a * specific calldata encoding structure that must first be validated. */ function _transferNativeTokensAndFinalize() internal { // Put native token value supplied by the caller on the stack. uint256 nativeTokensRemaining = msg.value; // Retrieve consideration amount, offerer, and total size of additional // recipients data from calldata using fixed offsets and place on stack. uint256 amount; address payable to; uint256 totalAdditionalRecipientsDataSize; assembly { amount := calldataload(BasicOrder_considerationAmount_cdPtr) to := calldataload(BasicOrder_offerer_cdPtr) totalAdditionalRecipientsDataSize := shl( AdditionalRecipient_size_shift, calldataload(BasicOrder_additionalRecipients_length_cdPtr) ) } uint256 additionalRecipientAmount; address payable recipient; // Skip overflow check as for loop is indexed starting at zero. unchecked { // Iterate over additional recipient data by two-word element. for ( uint256 i = 0; i < totalAdditionalRecipientsDataSize; i += AdditionalRecipient_size ) { assembly { // Retrieve calldata pointer for additional recipient. let additionalRecipientCdPtr := add( BasicOrder_additionalRecipients_data_cdPtr, i ) additionalRecipientAmount := calldataload( additionalRecipientCdPtr ) recipient := calldataload( add(OneWord, additionalRecipientCdPtr) ) } // Ensure that sufficient native tokens are available. if (additionalRecipientAmount > nativeTokensRemaining) { _revertInsufficientNativeTokensSupplied(); } // Reduce native token value available. Skip underflow check as // subtracted value is confirmed above as less than remaining. nativeTokensRemaining -= additionalRecipientAmount; // Transfer native tokens to the additional recipient. _transferNativeTokens(recipient, additionalRecipientAmount); } } // Ensure that sufficient native tokens are still available. if (amount > nativeTokensRemaining) { _revertInsufficientNativeTokensSupplied(); } // Transfer native tokens to the offerer. _transferNativeTokens(to, amount); // If any native tokens remain after transfers, return to the caller. if (nativeTokensRemaining > amount) { // Skip underflow check as nativeTokensRemaining > amount. unchecked { // Transfer remaining native tokens to the caller. _transferNativeTokens( payable(msg.sender), nativeTokensRemaining - amount ); } } } /** * @dev Internal function to transfer ERC20 tokens to a given recipient as * part of basic order fulfillment. Note that this function may only be * safely called as part of basic orders, as it assumes a specific * calldata encoding structure that must first be validated. Also note * that basic order parameters are retrieved using fixed offsets, this * requires that strict basic order encoding has already been verified. * * @param fromOfferer A boolean indicating whether to decrement amount from * the offered amount. * @param accumulator An open-ended array that collects transfers to execute * against a given conduit in a single call. */ function _transferERC20AndFinalize( bool fromOfferer, bytes memory accumulator ) internal { // Declare from and to variables determined by fromOfferer value. address from; address to; // Declare token and amount variables determined by fromOfferer value. address token; uint256 amount; // Declare and check identifier variable within an isolated scope. { // Declare identifier variable determined by fromOfferer value. uint256 identifier; // Set ERC20 token transfer variables based on fromOfferer boolean. if (fromOfferer) { // Use offerer as from value, msg.sender as to value, and offer // token, identifier, & amount values if token is from offerer. assembly { from := calldataload(BasicOrder_offerer_cdPtr) to := caller() token := calldataload(BasicOrder_offerToken_cdPtr) identifier := calldataload(BasicOrder_offerIdentifier_cdPtr) amount := calldataload(BasicOrder_offerAmount_cdPtr) } } else { // Otherwise, use msg.sender as from value, offerer as to value, // and consideration token, identifier, and amount values. assembly { from := caller() to := calldataload(BasicOrder_offerer_cdPtr) token := calldataload(BasicOrder_considerationToken_cdPtr) identifier := calldataload( BasicOrder_considerationIdentifier_cdPtr ) amount := calldataload(BasicOrder_considerationAmount_cdPtr) } } // Ensure that no identifier is supplied. if (identifier != 0) { _revertUnusedItemParameters(); } } // Determine the appropriate conduit to utilize. bytes32 conduitKey; // Utilize assembly to derive conduit (if relevant) based on route. assembly { // Use offerer conduit if fromOfferer, fulfiller conduit otherwise. conduitKey := calldataload( sub( BasicOrder_fulfillerConduit_cdPtr, shl(OneWordShift, fromOfferer) ) ) } // Retrieve total size of additional recipients data and place on stack. uint256 totalAdditionalRecipientsDataSize; assembly { totalAdditionalRecipientsDataSize := shl( AdditionalRecipient_size_shift, calldataload(BasicOrder_additionalRecipients_length_cdPtr) ) } uint256 additionalRecipientAmount; address recipient; // Iterate over each additional recipient. for (uint256 i = 0; i < totalAdditionalRecipientsDataSize; ) { assembly { // Retrieve calldata pointer for additional recipient. let additionalRecipientCdPtr := add( BasicOrder_additionalRecipients_data_cdPtr, i ) additionalRecipientAmount := calldataload( additionalRecipientCdPtr ) recipient := calldataload( add(OneWord, additionalRecipientCdPtr) ) } // Decrement the amount to transfer to fulfiller if indicated. if (fromOfferer) { amount -= additionalRecipientAmount; } // Transfer ERC20 tokens to additional recipient given approval. _transferERC20( token, from, recipient, additionalRecipientAmount, conduitKey, accumulator ); // Skip overflow check as for loop is indexed starting at zero. unchecked { i += AdditionalRecipient_size; } } // Transfer ERC20 token amount (from account must have proper approval). _transferERC20(token, from, to, amount, conduitKey, accumulator); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { ItemType, Side } from "./ConsiderationEnums.sol"; import { AdvancedOrder, CriteriaResolver, MemoryPointer, OfferItem, OrderParameters } from "./ConsiderationStructs.sol"; import { _revertCriteriaNotEnabledForItem, _revertInvalidProof, _revertOrderCriteriaResolverOutOfRange, _revertUnresolvedConsiderationCriteria, _revertUnresolvedOfferCriteria } from "./ConsiderationErrors.sol"; import { CriteriaResolutionErrors } from "../interfaces/CriteriaResolutionErrors.sol"; import { OneWord, OneWordShift, OrderParameters_consideration_head_offset, Selector_length, TwoWords } from "./ConsiderationConstants.sol"; import { ConsiderationCriteriaResolverOutOfRange_err_selector, Error_selector_offset, OfferCriteriaResolverOutOfRange_error_selector } from "./ConsiderationErrorConstants.sol"; /** * @title CriteriaResolution * @author 0age * @notice CriteriaResolution contains a collection of pure functions related to * resolving criteria-based items. */ contract CriteriaResolution is CriteriaResolutionErrors { /** * @dev Internal pure function to apply criteria resolvers containing * specific token identifiers and associated proofs to order items. * * @param advancedOrders The orders to apply criteria resolvers to. * @param criteriaResolvers An array where each element contains a * reference to a specific order as well as that * order's offer or consideration, a token * identifier, and a proof that the supplied token * identifier is contained in the order's merkle * root. Note that a root of zero indicates that * any transferable token identifier is valid and * that no proof needs to be supplied. */ function _applyCriteriaResolvers( AdvancedOrder[] memory advancedOrders, CriteriaResolver[] memory criteriaResolvers ) internal pure { // Skip overflow checks as all for loops are indexed starting at zero. unchecked { // Retrieve length of criteria resolvers array and place on stack. uint256 totalCriteriaResolvers = criteriaResolvers.length; // Retrieve length of orders array and place on stack. uint256 totalAdvancedOrders = advancedOrders.length; // Iterate over each criteria resolver. for (uint256 i = 0; i < totalCriteriaResolvers; ++i) { // Retrieve the criteria resolver. CriteriaResolver memory criteriaResolver = ( criteriaResolvers[i] ); // Read the order index from memory and place it on the stack. uint256 orderIndex = criteriaResolver.orderIndex; // Ensure that the order index is in range. if (orderIndex >= totalAdvancedOrders) { _revertOrderCriteriaResolverOutOfRange( criteriaResolver.side ); } // Retrieve the referenced advanced order. AdvancedOrder memory advancedOrder = advancedOrders[orderIndex]; // Skip criteria resolution for order if not fulfilled. if (advancedOrder.numerator == 0) { continue; } // Retrieve the parameters for the order. OrderParameters memory orderParameters = ( advancedOrder.parameters ); { // Get a pointer to the list of items to give to // _updateCriteriaItem. If the resolver refers to a // consideration item, this array pointer will be replaced // with the consideration array. OfferItem[] memory items = orderParameters.offer; // Read component index from memory and place it on stack. uint256 componentIndex = criteriaResolver.index; // Get error selector for `OfferCriteriaResolverOutOfRange`. uint256 errorSelector = ( OfferCriteriaResolverOutOfRange_error_selector ); // If the resolver refers to a consideration item... if (criteriaResolver.side != Side.OFFER) { // Get the pointer to `orderParameters.consideration` // Using the array directly has a significant impact on // the optimized compiler output. MemoryPointer considerationPtr = orderParameters .toMemoryPointer() .pptr(OrderParameters_consideration_head_offset); // Replace the items pointer with a pointer to the // consideration array. assembly { items := considerationPtr } // Replace the error selector with the selector for // `ConsiderationCriteriaResolverOutOfRange`. errorSelector = ( ConsiderationCriteriaResolverOutOfRange_err_selector ); } // Ensure that the component index is in range. if (componentIndex >= items.length) { assembly { // Revert with either // `OfferCriteriaResolverOutOfRange()` or // `ConsiderationCriteriaResolverOutOfRange()`, // depending on whether the resolver refers to a // consideration item. mstore(0, errorSelector) // revert(abi.encodeWithSignature( // "OfferCriteriaResolverOutOfRange()" // )) // or // revert(abi.encodeWithSignature( // "ConsiderationCriteriaResolverOutOfRange()" // )) revert(Error_selector_offset, Selector_length) } } // Apply the criteria resolver to the item in question. _updateCriteriaItem( items, componentIndex, criteriaResolver ); } } // Iterate over each advanced order. for (uint256 i = 0; i < totalAdvancedOrders; ++i) { // Retrieve the advanced order. AdvancedOrder memory advancedOrder = advancedOrders[i]; // Skip criteria resolution for order if not fulfilled. if (advancedOrder.numerator == 0) { continue; } // Retrieve the parameters for the order. OrderParameters memory orderParameters = ( advancedOrder.parameters ); // Read consideration length from memory and place on stack. uint256 totalItems = orderParameters.consideration.length; // Iterate over each consideration item on the order. for (uint256 j = 0; j < totalItems; ++j) { // Ensure item type no longer indicates criteria usage. if ( _isItemWithCriteria( orderParameters.consideration[j].itemType ) ) { _revertUnresolvedConsiderationCriteria(i, j); } } // Read offer length from memory and place on stack. totalItems = orderParameters.offer.length; // Iterate over each offer item on the order. for (uint256 j = 0; j < totalItems; ++j) { // Ensure item type no longer indicates criteria usage. if ( _isItemWithCriteria(orderParameters.offer[j].itemType) ) { _revertUnresolvedOfferCriteria(i, j); } } } } } /** * @dev Internal pure function to update a criteria item. * * @param offer The offer containing the item to update. * @param componentIndex The index of the item to update. * @param criteriaResolver The criteria resolver to use to update the item. */ function _updateCriteriaItem( OfferItem[] memory offer, uint256 componentIndex, CriteriaResolver memory criteriaResolver ) internal pure { // Retrieve relevant item using the component index. OfferItem memory offerItem = offer[componentIndex]; // Read item type and criteria from memory & place on stack. ItemType itemType = offerItem.itemType; // Ensure the specified item type indicates criteria usage. if (!_isItemWithCriteria(itemType)) { _revertCriteriaNotEnabledForItem(); } uint256 identifierOrCriteria = offerItem.identifierOrCriteria; // If criteria is not 0 (i.e. a collection-wide criteria-based item)... if (identifierOrCriteria != uint256(0)) { // Verify identifier inclusion in criteria root using proof. _verifyProof( criteriaResolver.identifier, identifierOrCriteria, criteriaResolver.criteriaProof ); } else if (criteriaResolver.criteriaProof.length != 0) { // Revert if non-empty proof is supplied for a collection-wide item. _revertInvalidProof(); } // Update item type to remove criteria usage. // Use assembly to operate on ItemType enum as a number. ItemType newItemType; assembly { // Item type 4 becomes 2 and item type 5 becomes 3. newItemType := sub(3, eq(itemType, 4)) } offerItem.itemType = newItemType; // Update identifier w/ supplied identifier. offerItem.identifierOrCriteria = criteriaResolver.identifier; } /** * @dev Internal pure function to check whether a given item type represents * a criteria-based ERC721 or ERC1155 item (e.g. an item that can be * resolved to one of a number of different identifiers at the time of * order fulfillment). * * @param itemType The item type in question. * * @return withCriteria A boolean indicating that the item type in question * represents a criteria-based item. */ function _isItemWithCriteria( ItemType itemType ) internal pure returns (bool withCriteria) { // ERC721WithCriteria is ItemType 4. ERC1155WithCriteria is ItemType 5. assembly { withCriteria := gt(itemType, 3) } } /** * @dev Internal pure function to ensure that a given element is contained * in a merkle root via a supplied proof. * * @param leaf The element for which to prove inclusion. * @param root The merkle root that inclusion will be proved against. * @param proof The merkle proof. */ function _verifyProof( uint256 leaf, uint256 root, bytes32[] memory proof ) internal pure { // Declare a variable that will be used to determine proof validity. bool isValid; // Utilize assembly to efficiently verify the proof against the root. assembly { // Store the leaf at the beginning of scratch space. mstore(0, leaf) // Derive the hash of the leaf to use as the initial proof element. let computedHash := keccak256(0, OneWord) // Get memory start location of the first element in proof array. let data := add(proof, OneWord) // Iterate over each proof element to compute the root hash. for { // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(data, shl(OneWordShift, mload(proof))) } lt(data, end) { // Increment by one word at a time. data := add(data, OneWord) } { // Get the proof element. let loadedData := mload(data) // Sort proof elements and place them in scratch space. // Slot of `computedHash` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(OneWordShift, gt(computedHash, loadedData)) // Store elements to hash contiguously in scratch space. Scratch // space is 64 bytes (0x00 - 0x3f) & both elements are 32 bytes. mstore(scratch, computedHash) mstore(xor(scratch, OneWord), loadedData) // Derive the updated hash. computedHash := keccak256(0, TwoWords) } // Compare the final hash to the supplied root. isValid := eq(computedHash, root) } // Revert if computed hash does not equal supplied root. if (!isValid) { _revertInvalidProof(); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { AmountDerivationErrors } from "../interfaces/AmountDerivationErrors.sol"; import { Error_selector_offset, InexactFraction_error_length, InexactFraction_error_selector } from "./ConsiderationErrorConstants.sol"; /** * @title AmountDeriver * @author 0age * @notice AmountDeriver contains view and pure functions related to deriving * item amounts based on partial fill quantity and on linear * interpolation based on current time when the start amount and end * amount differ. */ contract AmountDeriver is AmountDerivationErrors { /** * @dev Internal view function to derive the current amount of a given item * based on the current price, the starting price, and the ending * price. If the start and end prices differ, the current price will be * interpolated on a linear basis. Note that this function expects that * the startTime parameter of orderParameters is not greater than the * current block timestamp and that the endTime parameter is greater * than the current block timestamp. If this condition is not upheld, * duration / elapsed / remaining variables will underflow. * * @param startAmount The starting amount of the item. * @param endAmount The ending amount of the item. * @param startTime The starting time of the order. * @param endTime The end time of the order. * @param roundUp A boolean indicating whether the resultant amount * should be rounded up or down. * * @return amount The current amount. */ function _locateCurrentAmount( uint256 startAmount, uint256 endAmount, uint256 startTime, uint256 endTime, bool roundUp ) internal view returns (uint256 amount) { // Only modify end amount if it doesn't already equal start amount. if (startAmount != endAmount) { // Declare variables to derive in the subsequent unchecked scope. uint256 duration; uint256 elapsed; uint256 remaining; // Skip underflow checks as startTime <= block.timestamp < endTime. unchecked { // Derive the duration for the order and place it on the stack. duration = endTime - startTime; // Derive time elapsed since the order started & place on stack. elapsed = block.timestamp - startTime; // Derive time remaining until order expires and place on stack. remaining = duration - elapsed; } // Aggregate new amounts weighted by time with rounding factor. uint256 totalBeforeDivision = ((startAmount * remaining) + (endAmount * elapsed)); // Use assembly to combine operations and skip divide-by-zero check. assembly { // Multiply by iszero(iszero(totalBeforeDivision)) to ensure // amount is set to zero if totalBeforeDivision is zero, // as intermediate overflow can occur if it is zero. amount := mul( iszero(iszero(totalBeforeDivision)), // Subtract 1 from the numerator and add 1 to the result if // roundUp is true to get the proper rounding direction. // Division is performed with no zero check as duration // cannot be zero as long as startTime < endTime. add( div(sub(totalBeforeDivision, roundUp), duration), roundUp ) ) } // Return the current amount. return amount; } // Return the original amount as startAmount == endAmount. return endAmount; } /** * @dev Internal pure function to return a fraction of a given value and to * ensure the resultant value does not have any fractional component. * Note that this function assumes that zero will never be supplied as * the denominator parameter; invalid / undefined behavior will result * should a denominator of zero be provided. * * @param numerator A value indicating the portion of the order that * should be filled. * @param denominator A value indicating the total size of the order. Note * that this value cannot be equal to zero. * @param value The value for which to compute the fraction. * * @return newValue The value after applying the fraction. */ function _getFraction( uint256 numerator, uint256 denominator, uint256 value ) internal pure returns (uint256 newValue) { // Return value early in cases where the fraction resolves to 1. if (numerator == denominator) { return value; } // Ensure fraction can be applied to the value with no remainder. Note // that the denominator cannot be zero. assembly { // Ensure new value contains no remainder via mulmod operator. // Credit to @hrkrshnn + @axic for proposing this optimal solution. if mulmod(value, numerator, denominator) { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, InexactFraction_error_selector) // revert(abi.encodeWithSignature("InexactFraction()")) revert(Error_selector_offset, InexactFraction_error_length) } } // Multiply the numerator by the value and ensure no overflow occurs. uint256 valueTimesNumerator = value * numerator; // Divide and check for remainder. Note that denominator cannot be zero. assembly { // Perform division without zero check. newValue := div(valueTimesNumerator, denominator) } } /** * @dev Internal view function to apply a fraction to a consideration * or offer item. * * @param startAmount The starting amount of the item. * @param endAmount The ending amount of the item. * @param numerator A value indicating the portion of the order that * should be filled. * @param denominator A value indicating the total size of the order. * @param startTime The starting time of the order. * @param endTime The end time of the order. * @param roundUp A boolean indicating whether the resultant * amount should be rounded up or down. * * @return amount The received item to transfer with the final amount. */ function _applyFraction( uint256 startAmount, uint256 endAmount, uint256 numerator, uint256 denominator, uint256 startTime, uint256 endTime, bool roundUp ) internal view returns (uint256 amount) { // If start amount equals end amount, apply fraction to end amount. if (startAmount == endAmount) { // Apply fraction to end amount. amount = _getFraction(numerator, denominator, endAmount); } else { // Otherwise, apply fraction to both and interpolated final amount. amount = _locateCurrentAmount( _getFraction(numerator, denominator, startAmount), _getFraction(numerator, denominator, endAmount), startTime, endTime, roundUp ); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { OrderType } from "./ConsiderationEnums.sol"; import { AdvancedOrder, ConsiderationItem, OfferItem, Order, OrderComponents, OrderParameters, OrderStatus } from "./ConsiderationStructs.sol"; import { _revertBadFraction, _revertCannotCancelOrder, _revertConsiderationLengthNotEqualToTotalOriginal, _revertInvalidContractOrder, _revertPartialFillsNotEnabledForOrder } from "./ConsiderationErrors.sol"; import { Executor } from "./Executor.sol"; import { ZoneInteraction } from "./ZoneInteraction.sol"; import { MemoryPointer } from "../helpers/PointerLibraries.sol"; import { AdvancedOrder_denominator_offset, AdvancedOrder_numerator_offset, BasicOrder_offerer_cdPtr, Common_amount_offset, Common_endAmount_offset, Common_identifier_offset, Common_token_offset, ConsiderItem_recipient_offset, ContractOrder_orderHash_offerer_shift, MaxUint120, OrderStatus_filledDenominator_offset, OrderStatus_filledNumerator_offset, OrderStatus_ValidatedAndNotCancelled } from "./ConsiderationConstants.sol"; import { Error_selector_offset, Panic_arithmetic, Panic_error_code_ptr, Panic_error_length, Panic_error_selector } from "./ConsiderationErrorConstants.sol"; /** * @title OrderValidator * @author 0age * @notice OrderValidator contains functionality related to validating orders * and updating their status. */ contract OrderValidator is Executor, ZoneInteraction { // Track status of each order (validated, cancelled, and fraction filled). mapping(bytes32 => OrderStatus) private _orderStatus; // Track nonces for contract offerers. mapping(address => uint256) internal _contractNonces; /** * @dev Derive and set hashes, reference chainId, and associated domain * separator during deployment. * * @param conduitController A contract that deploys conduits, or proxies * that may optionally be used to transfer approved * ERC20/721/1155 tokens. */ constructor(address conduitController) Executor(conduitController) {} /** * @dev Internal function to verify and update the status of a basic order. * Note that this function may only be safely called as part of basic * orders, as it assumes a specific calldata encoding structure that * must first be validated. * * @param orderHash The hash of the order. * @param signature A signature from the offerer indicating that the order * has been approved. */ function _validateBasicOrderAndUpdateStatus( bytes32 orderHash, bytes calldata signature ) internal { // Retrieve offerer directly using fixed calldata offset based on strict // basic parameter encoding. address offerer; assembly { offerer := calldataload(BasicOrder_offerer_cdPtr) } // Retrieve the order status for the given order hash. OrderStatus storage orderStatus = _orderStatus[orderHash]; // Ensure order is fillable and is not cancelled. _verifyOrderStatus( orderHash, orderStatus, true, // Only allow unused orders when fulfilling basic orders. true // Signifies to revert if the order is invalid. ); // If the order is not already validated, verify the supplied signature. if (!orderStatus.isValidated) { _verifySignature(offerer, orderHash, signature); } // Update order status as fully filled, packing struct values. orderStatus.isValidated = true; orderStatus.isCancelled = false; orderStatus.numerator = 1; orderStatus.denominator = 1; } /** * @dev Internal function to validate an order, determine what portion to * fill, and update its status. The desired fill amount is supplied as * a fraction, as is the returned amount to fill. * * @param advancedOrder The order to fulfill as well as the fraction to * fill. Note that all offer and consideration * amounts must divide with no remainder in order * for a partial fill to be valid. * @param revertOnInvalid A boolean indicating whether to revert if the * order is invalid due to the time or status. * * @return orderHash The order hash. * @return numerator A value indicating the portion of the order that * will be filled. * @return denominator A value indicating the total size of the order. */ function _validateOrderAndUpdateStatus( AdvancedOrder memory advancedOrder, bool revertOnInvalid ) internal returns (bytes32 orderHash, uint256 numerator, uint256 denominator) { // Retrieve the parameters for the order. OrderParameters memory orderParameters = advancedOrder.parameters; // Ensure current timestamp falls between order start time and end time. if ( !_verifyTime( orderParameters.startTime, orderParameters.endTime, revertOnInvalid ) ) { // Assuming an invalid time and no revert, return zeroed out values. return (bytes32(0), 0, 0); } // Read numerator and denominator from memory and place on the stack. // Note that overflowed values are masked. assembly { numerator := and( mload(add(advancedOrder, AdvancedOrder_numerator_offset)), MaxUint120 ) denominator := and( mload(add(advancedOrder, AdvancedOrder_denominator_offset)), MaxUint120 ) } // Declare variable for tracking the validity of the supplied fraction. bool invalidFraction; // If the order is a contract order, return the generated order. if (orderParameters.orderType == OrderType.CONTRACT) { // Ensure that the numerator and denominator are both equal to 1. assembly { // (1 ^ nd =/= 0) => (nd =/= 1) => (n =/= 1) || (d =/= 1) // It's important that the values are 120-bit masked before // multiplication is applied. Otherwise, the last implication // above is not correct (mod 2^256). invalidFraction := xor(mul(numerator, denominator), 1) } // Revert if the supplied numerator and denominator are not valid. if (invalidFraction) { _revertBadFraction(); } // Return the generated order based on the order params and the // provided extra data. If revertOnInvalid is true, the function // will revert if the input is invalid. return _getGeneratedOrder( orderParameters, advancedOrder.extraData, revertOnInvalid ); } // Ensure numerator does not exceed denominator and is not zero. assembly { invalidFraction := or(gt(numerator, denominator), iszero(numerator)) } // Revert if the supplied numerator and denominator are not valid. if (invalidFraction) { _revertBadFraction(); } // If attempting partial fill (n < d) check order type & ensure support. if ( _doesNotSupportPartialFills( orderParameters.orderType, numerator, denominator ) ) { // Revert if partial fill was attempted on an unsupported order. _revertPartialFillsNotEnabledForOrder(); } // Retrieve current counter & use it w/ parameters to derive order hash. orderHash = _assertConsiderationLengthAndGetOrderHash(orderParameters); // Retrieve the order status using the derived order hash. OrderStatus storage orderStatus = _orderStatus[orderHash]; // Ensure order is fillable and is not cancelled. if ( !_verifyOrderStatus( orderHash, orderStatus, false, // Allow partially used orders to be filled. revertOnInvalid ) ) { // Assuming an invalid order status and no revert, return zero fill. return (orderHash, 0, 0); } // If the order is not already validated, verify the supplied signature. if (!orderStatus.isValidated) { _verifySignature( orderParameters.offerer, orderHash, advancedOrder.signature ); } assembly { let orderStatusSlot := orderStatus.slot // Read filled amount as numerator and denominator and put on stack. let filledNumerator := sload(orderStatusSlot) let filledDenominator := shr( OrderStatus_filledDenominator_offset, filledNumerator ) for { } 1 { } { if iszero(filledDenominator) { filledNumerator := numerator break } // Shift and mask to calculate the current filled numerator. filledNumerator := and( shr(OrderStatus_filledNumerator_offset, filledNumerator), MaxUint120 ) // If denominator of 1 supplied, fill entire remaining amount. if eq(denominator, 1) { numerator := sub(filledDenominator, filledNumerator) denominator := filledDenominator filledNumerator := filledDenominator break } // If supplied denominator equals to the current one: if eq(denominator, filledDenominator) { // Increment the filled numerator by the new numerator. filledNumerator := add(numerator, filledNumerator) // Once adjusted, if current + supplied numerator exceeds // the denominator: let carry := mul( sub(filledNumerator, denominator), gt(filledNumerator, denominator) ) numerator := sub(numerator, carry) filledNumerator := sub(filledNumerator, carry) break } // Otherwise, if supplied denominator differs from current one: filledNumerator := mul(filledNumerator, denominator) numerator := mul(numerator, filledDenominator) denominator := mul(denominator, filledDenominator) // Increment the filled numerator by the new numerator. filledNumerator := add(numerator, filledNumerator) // Once adjusted, if current + supplied numerator exceeds // denominator: let carry := mul( sub(filledNumerator, denominator), gt(filledNumerator, denominator) ) numerator := sub(numerator, carry) filledNumerator := sub(filledNumerator, carry) // Check filledNumerator and denominator for uint120 overflow. if or( gt(filledNumerator, MaxUint120), gt(denominator, MaxUint120) ) { // Derive greatest common divisor using euclidean algorithm. function gcd(_a, _b) -> out { for { } _b { } { let _c := _b _b := mod(_a, _c) _a := _c } out := _a } let scaleDown := gcd( numerator, gcd(filledNumerator, denominator) ) // Ensure that the divisor is at least one. let safeScaleDown := add(scaleDown, iszero(scaleDown)) // Scale all fractional values down by gcd. numerator := div(numerator, safeScaleDown) filledNumerator := div(filledNumerator, safeScaleDown) denominator := div(denominator, safeScaleDown) // Perform the overflow check a second time. if or( gt(filledNumerator, MaxUint120), gt(denominator, MaxUint120) ) { // Store the Panic error signature. mstore(0, Panic_error_selector) // Store the arithmetic (0x11) panic code. mstore(Panic_error_code_ptr, Panic_arithmetic) // revert(abi.encodeWithSignature( // "Panic(uint256)", 0x11 // )) revert(Error_selector_offset, Panic_error_length) } } break } // Update order status and fill amount, packing struct values. // [denominator: 15 bytes] [numerator: 15 bytes] // [isCancelled: 1 byte] [isValidated: 1 byte] sstore( orderStatusSlot, or( OrderStatus_ValidatedAndNotCancelled, or( shl( OrderStatus_filledNumerator_offset, filledNumerator ), shl(OrderStatus_filledDenominator_offset, denominator) ) ) ) } } /** * @dev Internal pure function to check the compatibility of two offer * or consideration items for contract orders. Note that the itemType * and identifier are reset in cases where criteria = 0 (collection- * wide offers), which means that a contract offerer has full latitude * to choose any identifier it wants mid-flight, in contrast to the * normal behavior, where the fulfiller can pick which identifier to * receive by providing a CriteriaResolver. * * @param originalItem The original offer or consideration item. * @param newItem The new offer or consideration item. * * @return isInvalid Error buffer indicating if items are incompatible. */ function _compareItems( MemoryPointer originalItem, MemoryPointer newItem ) internal pure returns (uint256 isInvalid) { assembly { let itemType := mload(originalItem) let identifier := mload(add(originalItem, Common_identifier_offset)) // Set returned identifier for criteria-based items w/ criteria = 0. if and(gt(itemType, 3), iszero(identifier)) { // replace item type itemType := sub(3, eq(itemType, 4)) identifier := mload(add(newItem, Common_identifier_offset)) } let originalAmount := mload(add(originalItem, Common_amount_offset)) let newAmount := mload(add(newItem, Common_amount_offset)) isInvalid := iszero( and( // originalItem.token == newItem.token && // originalItem.itemType == newItem.itemType and( eq( mload(add(originalItem, Common_token_offset)), mload(add(newItem, Common_token_offset)) ), eq(itemType, mload(newItem)) ), // originalItem.identifier == newItem.identifier && // originalItem.startAmount == originalItem.endAmount and( eq( identifier, mload(add(newItem, Common_identifier_offset)) ), eq( originalAmount, mload(add(originalItem, Common_endAmount_offset)) ) ) ) ) } } /** * @dev Internal pure function to check the compatibility of two recipients * on consideration items for contract orders. This check is skipped if * no recipient is originally supplied. * * @param originalRecipient The original consideration item recipient. * @param newRecipient The new consideration item recipient. * * @return isInvalid Error buffer indicating if recipients are incompatible. */ function _checkRecipients( address originalRecipient, address newRecipient ) internal pure returns (uint256 isInvalid) { assembly { isInvalid := iszero( or( iszero(originalRecipient), eq(newRecipient, originalRecipient) ) ) } } /** * @dev Internal function to generate a contract order. When a * collection-wide criteria-based item (criteria = 0) is provided as an * input to a contract order, the contract offerer has full latitude to * choose any identifier it wants mid-flight, which differs from the * usual behavior. For regular criteria-based orders with * identifierOrCriteria = 0, the fulfiller can pick which identifier to * receive by providing a CriteriaResolver. For contract offers with * identifierOrCriteria = 0, Seaport does not expect a corresponding * CriteriaResolver, and will revert if one is provided. * * @param orderParameters The parameters for the order. * @param context The context for generating the order. * @param revertOnInvalid Whether to revert on invalid input. * * @return orderHash The order hash. * @return numerator The numerator. * @return denominator The denominator. */ function _getGeneratedOrder( OrderParameters memory orderParameters, bytes memory context, bool revertOnInvalid ) internal returns (bytes32 orderHash, uint256 numerator, uint256 denominator) { // Ensure that consideration array length is equal to the total original // consideration items value. if ( orderParameters.consideration.length != orderParameters.totalOriginalConsiderationItems ) { _revertConsiderationLengthNotEqualToTotalOriginal(); } { address offerer = orderParameters.offerer; bool success; (MemoryPointer cdPtr, uint256 size) = _encodeGenerateOrder( orderParameters, context ); assembly { success := call(gas(), offerer, 0, cdPtr, size, 0, 0) } { // Note: overflow impossible; nonce can't increment that high. uint256 contractNonce; unchecked { // Note: nonce will be incremented even for skipped orders, // and even if generateOrder's return data does not satisfy // all the constraints. This is the case when errorBuffer // != 0 and revertOnInvalid == false. contractNonce = _contractNonces[offerer]++; } assembly { // Shift offerer address up 96 bytes and combine with nonce. orderHash := xor( contractNonce, shl(ContractOrder_orderHash_offerer_shift, offerer) ) } } // Revert or skip if the call to generate the contract order failed. if (!success) { return _revertOrReturnEmpty(revertOnInvalid, orderHash); } } // From this point onward, do not allow for skipping orders as the // contract offerer may have modified state in expectation of any named // consideration items being sent to their designated recipients. // Decode the returned contract order and/or update the error buffer. ( uint256 errorBuffer, OfferItem[] memory offer, ConsiderationItem[] memory consideration ) = _convertGetGeneratedOrderResult(_decodeGenerateOrderReturndata)(); // Revert if the returndata could not be decoded correctly. if (errorBuffer != 0) { _revertInvalidContractOrder(orderHash); } { // Designate lengths. uint256 originalOfferLength = orderParameters.offer.length; uint256 newOfferLength = offer.length; // Explicitly specified offer items cannot be removed. if (originalOfferLength > newOfferLength) { _revertInvalidContractOrder(orderHash); } // Iterate over each specified offer (e.g. minimumReceived) item. for (uint256 i = 0; i < originalOfferLength; ) { // Retrieve the pointer to the originally supplied item. MemoryPointer mPtrOriginal = orderParameters .offer[i] .toMemoryPointer(); // Retrieve the pointer to the newly returned item. MemoryPointer mPtrNew = offer[i].toMemoryPointer(); // Compare the items and update the error buffer accordingly. errorBuffer |= _cast( mPtrOriginal .offset(Common_amount_offset) .readUint256() > mPtrNew.offset(Common_amount_offset).readUint256() ) | _compareItems(mPtrOriginal, mPtrNew); // Increment the array (cannot overflow as index starts at 0). unchecked { ++i; } } // Assign the returned offer item in place of the original item. orderParameters.offer = offer; } { // Designate lengths & memory locations. ConsiderationItem[] memory originalConsiderationArray = ( orderParameters.consideration ); uint256 newConsiderationLength = consideration.length; // New consideration items cannot be created. if (newConsiderationLength > originalConsiderationArray.length) { _revertInvalidContractOrder(orderHash); } // Iterate over returned consideration & do not exceed maximumSpent. for (uint256 i = 0; i < newConsiderationLength; ) { // Retrieve the pointer to the originally supplied item. MemoryPointer mPtrOriginal = originalConsiderationArray[i] .toMemoryPointer(); // Retrieve the pointer to the newly returned item. MemoryPointer mPtrNew = consideration[i].toMemoryPointer(); // Compare the items and update the error buffer accordingly // and ensure that the recipients are equal when provided. errorBuffer |= _cast( mPtrNew.offset(Common_amount_offset).readUint256() > mPtrOriginal .offset(Common_amount_offset) .readUint256() ) | _compareItems(mPtrOriginal, mPtrNew) | _checkRecipients( mPtrOriginal .offset(ConsiderItem_recipient_offset) .readAddress(), mPtrNew .offset(ConsiderItem_recipient_offset) .readAddress() ); // Increment the array (cannot overflow as index starts at 0). unchecked { ++i; } } // Assign returned consideration item in place of the original item. orderParameters.consideration = consideration; } // Revert if any item comparison failed. if (errorBuffer != 0) { _revertInvalidContractOrder(orderHash); } // Return order hash and full fill amount (numerator & denominator = 1). return (orderHash, 1, 1); } /** * @dev Internal function to cancel an arbitrary number of orders. Note that * only the offerer or the zone of a given order may cancel it. Callers * should ensure that the intended order was cancelled by calling * `getOrderStatus` and confirming that `isCancelled` returns `true`. * Also note that contract orders are not cancellable. * * @param orders The orders to cancel. * * @return cancelled A boolean indicating whether the supplied orders were * successfully cancelled. */ function _cancel( OrderComponents[] calldata orders ) internal returns (bool cancelled) { // Ensure that the reentrancy guard is not currently set. _assertNonReentrant(); // Declare variables outside of the loop. OrderStatus storage orderStatus; // Declare a variable for tracking invariants in the loop. bool anyInvalidCallerOrContractOrder; // Skip overflow check as for loop is indexed starting at zero. unchecked { // Read length of the orders array from memory and place on stack. uint256 totalOrders = orders.length; // Iterate over each order. for (uint256 i = 0; i < totalOrders; ) { // Retrieve the order. OrderComponents calldata order = orders[i]; address offerer = order.offerer; address zone = order.zone; OrderType orderType = order.orderType; assembly { // If caller is neither the offerer nor zone, or a contract // order is present, flag anyInvalidCallerOrContractOrder. anyInvalidCallerOrContractOrder := or( anyInvalidCallerOrContractOrder, // orderType == CONTRACT || // !(caller == offerer || caller == zone) or( eq(orderType, 4), iszero( or(eq(caller(), offerer), eq(caller(), zone)) ) ) ) } bytes32 orderHash = _deriveOrderHash( _toOrderParametersReturnType( _decodeOrderComponentsAsOrderParameters )(order.toCalldataPointer()), order.counter ); // Retrieve the order status using the derived order hash. orderStatus = _orderStatus[orderHash]; // Update the order status as not valid and cancelled. orderStatus.isValidated = false; orderStatus.isCancelled = true; // Emit an event signifying that the order has been cancelled. emit OrderCancelled(orderHash, offerer, zone); // Increment counter inside body of loop for gas efficiency. ++i; } } if (anyInvalidCallerOrContractOrder) { _revertCannotCancelOrder(); } // Return a boolean indicating that orders were successfully cancelled. cancelled = true; } /** * @dev Internal function to validate an arbitrary number of orders, thereby * registering their signatures as valid and allowing the fulfiller to * skip signature verification on fulfillment. Note that validated * orders may still be unfulfillable due to invalid item amounts or * other factors; callers should determine whether validated orders are * fulfillable by simulating the fulfillment call prior to execution. * Also note that anyone can validate a signed order, but only the * offerer can validate an order without supplying a signature. * * @param orders The orders to validate. * * @return validated A boolean indicating whether the supplied orders were * successfully validated. */ function _validate( Order[] memory orders ) internal returns (bool validated) { // Ensure that the reentrancy guard is not currently set. _assertNonReentrant(); // Declare variables outside of the loop. OrderStatus storage orderStatus; bytes32 orderHash; address offerer; // Skip overflow check as for loop is indexed starting at zero. unchecked { // Read length of the orders array from memory and place on stack. uint256 totalOrders = orders.length; // Iterate over each order. for (uint256 i = 0; i < totalOrders; ++i) { // Retrieve the order. Order memory order = orders[i]; // Retrieve the order parameters. OrderParameters memory orderParameters = order.parameters; // Skip contract orders. if (orderParameters.orderType == OrderType.CONTRACT) { continue; } // Move offerer from memory to the stack. offerer = orderParameters.offerer; // Get current counter & use it w/ params to derive order hash. orderHash = _assertConsiderationLengthAndGetOrderHash( orderParameters ); // Retrieve the order status using the derived order hash. orderStatus = _orderStatus[orderHash]; // Ensure order is fillable and retrieve the filled amount. _verifyOrderStatus( orderHash, orderStatus, false, // Signifies that partially filled orders are valid. true // Signifies to revert if the order is invalid. ); // If the order has not already been validated... if (!orderStatus.isValidated) { // Ensure that consideration array length is equal to the // total original consideration items value. if ( orderParameters.consideration.length != orderParameters.totalOriginalConsiderationItems ) { _revertConsiderationLengthNotEqualToTotalOriginal(); } // Verify the supplied signature. _verifySignature(offerer, orderHash, order.signature); // Update order status to mark the order as valid. orderStatus.isValidated = true; // Emit an event signifying the order has been validated. emit OrderValidated(orderHash, orderParameters); } } } // Return a boolean indicating that orders were successfully validated. validated = true; } /** * @dev Internal view function to retrieve the status of a given order by * hash, including whether the order has been cancelled or validated * and the fraction of the order that has been filled. * * @param orderHash The order hash in question. * * @return isValidated A boolean indicating whether the order in question * has been validated (i.e. previously approved or * partially filled). * @return isCancelled A boolean indicating whether the order in question * has been cancelled. * @return totalFilled The total portion of the order that has been filled * (i.e. the "numerator"). * @return totalSize The total size of the order that is either filled or * unfilled (i.e. the "denominator"). */ function _getOrderStatus( bytes32 orderHash ) internal view returns ( bool isValidated, bool isCancelled, uint256 totalFilled, uint256 totalSize ) { // Retrieve the order status using the order hash. OrderStatus storage orderStatus = _orderStatus[orderHash]; // Return the fields on the order status. return ( orderStatus.isValidated, orderStatus.isCancelled, orderStatus.numerator, orderStatus.denominator ); } /** * @dev Internal pure function to either revert or return an empty tuple * depending on the value of `revertOnInvalid`. * * @param revertOnInvalid Whether to revert on invalid input. * @param contractOrderHash The contract order hash. * * @return orderHash The order hash. * @return numerator The numerator. * @return denominator The denominator. */ function _revertOrReturnEmpty( bool revertOnInvalid, bytes32 contractOrderHash ) internal pure returns (bytes32 orderHash, uint256 numerator, uint256 denominator) { if (revertOnInvalid) { _revertInvalidContractOrder(contractOrderHash); } return (contractOrderHash, 0, 0); } /** * @dev Internal pure function to check whether a given order type indicates * that partial fills are not supported (e.g. only "full fills" are * allowed for the order in question). * * @param orderType The order type in question. * @param numerator The numerator in question. * @param denominator The denominator in question. * * @return isFullOrder A boolean indicating whether the order type only * supports full fills. */ function _doesNotSupportPartialFills( OrderType orderType, uint256 numerator, uint256 denominator ) internal pure returns (bool isFullOrder) { // The "full" order types are even, while "partial" order types are odd. // Bitwise and by 1 is equivalent to modulo by 2, but 2 gas cheaper. The // check is only necessary if numerator is less than denominator. assembly { // Equivalent to `uint256(orderType) & 1 == 0`. isFullOrder := and( lt(numerator, denominator), iszero(and(orderType, 1)) ) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; uint256 constant Error_selector_offset = 0x1c; /* * error MissingFulfillmentComponentOnAggregation(uint8 side) * - Defined in FulfillmentApplicationErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: side * Revert buffer is memory[0x1c:0x40] */ uint256 constant MissingFulfillmentComponentOnAggregation_error_selector = ( 0x375c24c1 ); uint256 constant MissingFulfillmentComponentOnAggregation_error_side_ptr = 0x20; uint256 constant MissingFulfillmentComponentOnAggregation_error_length = 0x24; /* * error OfferAndConsiderationRequiredOnFulfillment() * - Defined in FulfillmentApplicationErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant OfferAndConsiderationRequiredOnFulfillment_error_selector = ( 0x98e9db6e ); uint256 constant OfferAndConsiderationRequiredOnFulfillment_error_length = 0x04; /* * error MismatchedFulfillmentOfferAndConsiderationComponents( * uint256 fulfillmentIndex * ) * - Defined in FulfillmentApplicationErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: fulfillmentIndex * Revert buffer is memory[0x1c:0x40] */ uint256 constant MismatchedOfferAndConsiderationComponents_error_selector = ( 0xbced929d ); uint256 constant MismatchedOfferAndConsiderationComponents_error_idx_ptr = 0x20; uint256 constant MismatchedOfferAndConsiderationComponents_error_length = 0x24; /* * error InvalidFulfillmentComponentData() * - Defined in FulfillmentApplicationErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InvalidFulfillmentComponentData_error_selector = 0x7fda7279; uint256 constant InvalidFulfillmentComponentData_error_length = 0x04; /* * error InexactFraction() * - Defined in AmountDerivationErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InexactFraction_error_selector = 0xc63cf089; uint256 constant InexactFraction_error_length = 0x04; /* * error OrderCriteriaResolverOutOfRange(uint8 side) * - Defined in CriteriaResolutionErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: side * Revert buffer is memory[0x1c:0x40] */ uint256 constant OrderCriteriaResolverOutOfRange_error_selector = 0x133c37c6; uint256 constant OrderCriteriaResolverOutOfRange_error_side_ptr = 0x20; uint256 constant OrderCriteriaResolverOutOfRange_error_length = 0x24; /* * error UnresolvedOfferCriteria(uint256 orderIndex, uint256 offerIndex) * - Defined in CriteriaResolutionErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: orderIndex * - 0x40: offerIndex * Revert buffer is memory[0x1c:0x60] */ uint256 constant UnresolvedOfferCriteria_error_selector = 0xd6929332; uint256 constant UnresolvedOfferCriteria_error_orderIndex_ptr = 0x20; uint256 constant UnresolvedOfferCriteria_error_offerIndex_ptr = 0x40; uint256 constant UnresolvedOfferCriteria_error_length = 0x44; /* * error UnresolvedConsiderationCriteria( * uint256 orderIndex, * uint256 considerationIndex * ) * - Defined in CriteriaResolutionErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: orderIndex * - 0x40: considerationIndex * Revert buffer is memory[0x1c:0x60] */ uint256 constant UnresolvedConsiderationCriteria_error_selector = 0xa8930e9a; uint256 constant UnresolvedConsiderationCriteria_error_orderIndex_ptr = 0x20; uint256 constant UnresolvedConsiderationCriteria_error_considerationIdx_ptr = ( 0x40 ); uint256 constant UnresolvedConsiderationCriteria_error_length = 0x44; /* * error OfferCriteriaResolverOutOfRange() * - Defined in CriteriaResolutionErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant OfferCriteriaResolverOutOfRange_error_selector = 0xbfb3f8ce; // uint256 constant OfferCriteriaResolverOutOfRange_error_length = 0x04; /* * error ConsiderationCriteriaResolverOutOfRange() * - Defined in CriteriaResolutionErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant ConsiderationCriteriaResolverOutOfRange_error_selector = ( 0x6088d7de ); uint256 constant ConsiderationCriteriaResolverOutOfRange_err_selector = ( 0x6088d7de ); // uint256 constant ConsiderationCriteriaResolverOutOfRange_error_length = 0x04; /* * error CriteriaNotEnabledForItem() * - Defined in CriteriaResolutionErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant CriteriaNotEnabledForItem_error_selector = 0x94eb6af6; uint256 constant CriteriaNotEnabledForItem_error_length = 0x04; /* * error InvalidProof() * - Defined in CriteriaResolutionErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InvalidProof_error_selector = 0x09bde339; uint256 constant InvalidProof_error_length = 0x04; /* * error InvalidRestrictedOrder(bytes32 orderHash) * - Defined in ZoneInteractionErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: orderHash * Revert buffer is memory[0x1c:0x40] */ uint256 constant InvalidRestrictedOrder_error_selector = 0xfb5014fc; uint256 constant InvalidRestrictedOrder_error_orderHash_ptr = 0x20; uint256 constant InvalidRestrictedOrder_error_length = 0x24; /* * error InvalidContractOrder(bytes32 orderHash) * - Defined in ZoneInteractionErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: orderHash * Revert buffer is memory[0x1c:0x40] */ uint256 constant InvalidContractOrder_error_selector = 0x93979285; uint256 constant InvalidContractOrder_error_orderHash_ptr = 0x20; uint256 constant InvalidContractOrder_error_length = 0x24; /* * error BadSignatureV(uint8 v) * - Defined in SignatureVerificationErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: v * Revert buffer is memory[0x1c:0x40] */ uint256 constant BadSignatureV_error_selector = 0x1f003d0a; uint256 constant BadSignatureV_error_v_ptr = 0x20; uint256 constant BadSignatureV_error_length = 0x24; /* * error InvalidSigner() * - Defined in SignatureVerificationErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InvalidSigner_error_selector = 0x815e1d64; uint256 constant InvalidSigner_error_length = 0x04; /* * error InvalidSignature() * - Defined in SignatureVerificationErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InvalidSignature_error_selector = 0x8baa579f; uint256 constant InvalidSignature_error_length = 0x04; /* * error BadContractSignature() * - Defined in SignatureVerificationErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant BadContractSignature_error_selector = 0x4f7fb80d; uint256 constant BadContractSignature_error_length = 0x04; /* * error InvalidERC721TransferAmount(uint256 amount) * - Defined in TokenTransferrerErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: amount * Revert buffer is memory[0x1c:0x40] */ uint256 constant InvalidERC721TransferAmount_error_selector = 0x69f95827; uint256 constant InvalidERC721TransferAmount_error_amount_ptr = 0x20; uint256 constant InvalidERC721TransferAmount_error_length = 0x24; /* * error MissingItemAmount() * - Defined in TokenTransferrerErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant MissingItemAmount_error_selector = 0x91b3e514; uint256 constant MissingItemAmount_error_length = 0x04; /* * error UnusedItemParameters() * - Defined in TokenTransferrerErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant UnusedItemParameters_error_selector = 0x6ab37ce7; uint256 constant UnusedItemParameters_error_length = 0x04; /* * error NoReentrantCalls() * - Defined in ReentrancyErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant NoReentrantCalls_error_selector = 0x7fa8a987; uint256 constant NoReentrantCalls_error_length = 0x04; /* * error OrderAlreadyFilled(bytes32 orderHash) * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: orderHash * Revert buffer is memory[0x1c:0x40] */ uint256 constant OrderAlreadyFilled_error_selector = 0x10fda3e1; uint256 constant OrderAlreadyFilled_error_orderHash_ptr = 0x20; uint256 constant OrderAlreadyFilled_error_length = 0x24; /* * error InvalidTime(uint256 startTime, uint256 endTime) * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: startTime * - 0x40: endTime * Revert buffer is memory[0x1c:0x60] */ uint256 constant InvalidTime_error_selector = 0x21ccfeb7; uint256 constant InvalidTime_error_startTime_ptr = 0x20; uint256 constant InvalidTime_error_endTime_ptr = 0x40; uint256 constant InvalidTime_error_length = 0x44; /* * error InvalidConduit(bytes32 conduitKey, address conduit) * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: conduitKey * - 0x40: conduit * Revert buffer is memory[0x1c:0x60] */ uint256 constant InvalidConduit_error_selector = 0x1cf99b26; uint256 constant InvalidConduit_error_conduitKey_ptr = 0x20; uint256 constant InvalidConduit_error_conduit_ptr = 0x40; uint256 constant InvalidConduit_error_length = 0x44; /* * error MissingOriginalConsiderationItems() * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant MissingOriginalConsiderationItems_error_selector = 0x466aa616; uint256 constant MissingOriginalConsiderationItems_error_length = 0x04; /* * error InvalidCallToConduit(address conduit) * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: conduit * Revert buffer is memory[0x1c:0x40] */ uint256 constant InvalidCallToConduit_error_selector = 0xd13d53d4; uint256 constant InvalidCallToConduit_error_conduit_ptr = 0x20; uint256 constant InvalidCallToConduit_error_length = 0x24; /* * error ConsiderationNotMet( * uint256 orderIndex, * uint256 considerationIndex, * uint256 shortfallAmount * ) * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: orderIndex * - 0x40: considerationIndex * - 0x60: shortfallAmount * Revert buffer is memory[0x1c:0x80] */ uint256 constant ConsiderationNotMet_error_selector = 0xa5f54208; uint256 constant ConsiderationNotMet_error_orderIndex_ptr = 0x20; uint256 constant ConsiderationNotMet_error_considerationIndex_ptr = 0x40; uint256 constant ConsiderationNotMet_error_shortfallAmount_ptr = 0x60; uint256 constant ConsiderationNotMet_error_length = 0x64; /* * error InsufficientNativeTokensSupplied() * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InsufficientNativeTokensSupplied_error_selector = 0x8ffff980; uint256 constant InsufficientNativeTokensSupplied_error_length = 0x04; /* * error NativeTokenTransferGenericFailure(address account, uint256 amount) * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: account * - 0x40: amount * Revert buffer is memory[0x1c:0x60] */ uint256 constant NativeTokenTransferGenericFailure_error_selector = 0xbc806b96; uint256 constant NativeTokenTransferGenericFailure_error_account_ptr = 0x20; uint256 constant NativeTokenTransferGenericFailure_error_amount_ptr = 0x40; uint256 constant NativeTokenTransferGenericFailure_error_length = 0x44; /* * error PartialFillsNotEnabledForOrder() * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant PartialFillsNotEnabledForOrder_error_selector = 0xa11b63ff; uint256 constant PartialFillsNotEnabledForOrder_error_length = 0x04; /* * error OrderIsCancelled(bytes32 orderHash) * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: orderHash * Revert buffer is memory[0x1c:0x40] */ uint256 constant OrderIsCancelled_error_selector = 0x1a515574; uint256 constant OrderIsCancelled_error_orderHash_ptr = 0x20; uint256 constant OrderIsCancelled_error_length = 0x24; /* * error OrderPartiallyFilled(bytes32 orderHash) * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: orderHash * Revert buffer is memory[0x1c:0x40] */ uint256 constant OrderPartiallyFilled_error_selector = 0xee9e0e63; uint256 constant OrderPartiallyFilled_error_orderHash_ptr = 0x20; uint256 constant OrderPartiallyFilled_error_length = 0x24; /* * error CannotCancelOrder() * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant CannotCancelOrder_error_selector = 0xfed398fc; uint256 constant CannotCancelOrder_error_length = 0x04; /* * error BadFraction() * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant BadFraction_error_selector = 0x5a052b32; uint256 constant BadFraction_error_length = 0x04; /* * error InvalidMsgValue(uint256 value) * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: value * Revert buffer is memory[0x1c:0x40] */ uint256 constant InvalidMsgValue_error_selector = 0xa61be9f0; uint256 constant InvalidMsgValue_error_value_ptr = 0x20; uint256 constant InvalidMsgValue_error_length = 0x24; /* * error InvalidBasicOrderParameterEncoding() * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InvalidBasicOrderParameterEncoding_error_selector = 0x39f3e3fd; uint256 constant InvalidBasicOrderParameterEncoding_error_length = 0x04; /* * error NoSpecifiedOrdersAvailable() * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant NoSpecifiedOrdersAvailable_error_selector = 0xd5da9a1b; uint256 constant NoSpecifiedOrdersAvailable_error_length = 0x04; /* * error InvalidNativeOfferItem() * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant InvalidNativeOfferItem_error_selector = 0x12d3f5a3; uint256 constant InvalidNativeOfferItem_error_length = 0x04; /* * error ConsiderationLengthNotEqualToTotalOriginal() * - Defined in ConsiderationEventsAndErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * Revert buffer is memory[0x1c:0x20] */ uint256 constant ConsiderationLengthNotEqualToTotalOriginal_error_selector = ( 0x2165628a ); uint256 constant ConsiderationLengthNotEqualToTotalOriginal_error_length = 0x04; /* * error Panic(uint256 code) * - Built-in Solidity error * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: code * Revert buffer is memory[0x1c:0x40] */ uint256 constant Panic_error_selector = 0x4e487b71; uint256 constant Panic_error_code_ptr = 0x20; uint256 constant Panic_error_length = 0x24; uint256 constant Panic_arithmetic = 0x11; // uint256 constant Panic_resource = 0x41;
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { ConduitInterface } from "../interfaces/ConduitInterface.sol"; import { ConduitItemType } from "../conduit/lib/ConduitEnums.sol"; import { ItemType } from "./ConsiderationEnums.sol"; import { ReceivedItem } from "./ConsiderationStructs.sol"; import { Verifiers } from "./Verifiers.sol"; import { TokenTransferrer } from "./TokenTransferrer.sol"; import { Accumulator_array_length_ptr, Accumulator_array_offset_ptr, Accumulator_array_offset, Accumulator_conduitKey_ptr, Accumulator_itemSizeOffsetDifference, Accumulator_selector_ptr, AccumulatorArmed, AccumulatorDisarmed, Conduit_transferItem_amount_ptr, Conduit_transferItem_from_ptr, Conduit_transferItem_identifier_ptr, Conduit_transferItem_size, Conduit_transferItem_to_ptr, Conduit_transferItem_token_ptr, FreeMemoryPointerSlot, OneWord, TwoWords } from "./ConsiderationConstants.sol"; import { Error_selector_offset, NativeTokenTransferGenericFailure_error_account_ptr, NativeTokenTransferGenericFailure_error_amount_ptr, NativeTokenTransferGenericFailure_error_length, NativeTokenTransferGenericFailure_error_selector } from "./ConsiderationErrorConstants.sol"; import { _revertInvalidCallToConduit, _revertInvalidConduit, _revertInvalidERC721TransferAmount, _revertUnusedItemParameters } from "./ConsiderationErrors.sol"; /** * @title Executor * @author 0age * @notice Executor contains functions related to processing executions (i.e. * transferring items, either directly or via conduits). */ contract Executor is Verifiers, TokenTransferrer { /** * @dev Derive and set hashes, reference chainId, and associated domain * separator during deployment. * * @param conduitController A contract that deploys conduits, or proxies * that may optionally be used to transfer approved * ERC20/721/1155 tokens. */ constructor(address conduitController) Verifiers(conduitController) {} /** * @dev Internal function to transfer a given item, either directly or via * a corresponding conduit. * * @param item The item to transfer, including an amount and a * recipient. * @param from The account supplying the item. * @param conduitKey A bytes32 value indicating what corresponding conduit, * if any, to source token approvals from. The zero hash * signifies that no conduit should be used, with direct * approvals set on this contract. * @param accumulator An open-ended array that collects transfers to execute * against a given conduit in a single call. */ function _transfer( ReceivedItem memory item, address from, bytes32 conduitKey, bytes memory accumulator ) internal { // If the item type indicates Ether or a native token... if (item.itemType == ItemType.NATIVE) { // Ensure neither the token nor the identifier parameters are set. if ((uint160(item.token) | item.identifier) != 0) { _revertUnusedItemParameters(); } // transfer the native tokens to the recipient. _transferNativeTokens(item.recipient, item.amount); } else if (item.itemType == ItemType.ERC20) { // Ensure that no identifier is supplied. if (item.identifier != 0) { _revertUnusedItemParameters(); } // Transfer ERC20 tokens from the source to the recipient. _transferERC20( item.token, from, item.recipient, item.amount, conduitKey, accumulator ); } else if (item.itemType == ItemType.ERC721) { // Transfer ERC721 token from the source to the recipient. _transferERC721( item.token, from, item.recipient, item.identifier, item.amount, conduitKey, accumulator ); } else { // Transfer ERC1155 token from the source to the recipient. _transferERC1155( item.token, from, item.recipient, item.identifier, item.amount, conduitKey, accumulator ); } } /** * @dev Internal function to transfer Ether or other native tokens to a * given recipient. * * @param to The recipient of the transfer. * @param amount The amount to transfer. */ function _transferNativeTokens( address payable to, uint256 amount ) internal { // Ensure that the supplied amount is non-zero. _assertNonZeroAmount(amount); // Declare a variable indicating whether the call was successful or not. bool success; assembly { // Transfer the native token and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } // If the call fails... if (!success) { // Revert and pass the revert reason along if one was returned. _revertWithReasonIfOneIsReturned(); // Otherwise, revert with a generic error message. assembly { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, NativeTokenTransferGenericFailure_error_selector) // Write `to` and `amount` arguments. mstore(NativeTokenTransferGenericFailure_error_account_ptr, to) mstore( NativeTokenTransferGenericFailure_error_amount_ptr, amount ) // revert(abi.encodeWithSignature( // "NativeTokenTransferGenericFailure(address,uint256)", // to, // amount // )) revert( Error_selector_offset, NativeTokenTransferGenericFailure_error_length ) } } } /** * @dev Internal function to transfer ERC20 tokens from a given originator * to a given recipient using a given conduit if applicable. Sufficient * approvals must be set on this contract or on a respective conduit. * * @param token The ERC20 token to transfer. * @param from The originator of the transfer. * @param to The recipient of the transfer. * @param amount The amount to transfer. * @param conduitKey A bytes32 value indicating what corresponding conduit, * if any, to source token approvals from. The zero hash * signifies that no conduit should be used, with direct * approvals set on this contract. * @param accumulator An open-ended array that collects transfers to execute * against a given conduit in a single call. */ function _transferERC20( address token, address from, address to, uint256 amount, bytes32 conduitKey, bytes memory accumulator ) internal { // Ensure that the supplied amount is non-zero. _assertNonZeroAmount(amount); // Trigger accumulated transfers if the conduits differ. _triggerIfArmedAndNotAccumulatable(accumulator, conduitKey); // If no conduit has been specified... if (conduitKey == bytes32(0)) { // Perform the token transfer directly. _performERC20Transfer(token, from, to, amount); } else { // Insert the call to the conduit into the accumulator. _insert( conduitKey, accumulator, ConduitItemType.ERC20, token, from, to, uint256(0), amount ); } } /** * @dev Internal function to transfer a single ERC721 token from a given * originator to a given recipient. Sufficient approvals must be set, * either on the respective conduit or on this contract itself. * * @param token The ERC721 token to transfer. * @param from The originator of the transfer. * @param to The recipient of the transfer. * @param identifier The tokenId to transfer (must be 1 for ERC721). * @param amount The amount to transfer. * @param conduitKey A bytes32 value indicating what corresponding conduit, * if any, to source token approvals from. The zero hash * signifies that no conduit should be used, with direct * approvals set on this contract. * @param accumulator An open-ended array that collects transfers to execute * against a given conduit in a single call. */ function _transferERC721( address token, address from, address to, uint256 identifier, uint256 amount, bytes32 conduitKey, bytes memory accumulator ) internal { // Trigger accumulated transfers if the conduits differ. _triggerIfArmedAndNotAccumulatable(accumulator, conduitKey); // If no conduit has been specified... if (conduitKey == bytes32(0)) { // Ensure that exactly one 721 item is being transferred. if (amount != 1) { _revertInvalidERC721TransferAmount(amount); } // Perform transfer via the token contract directly. _performERC721Transfer(token, from, to, identifier); } else { // Insert the call to the conduit into the accumulator. _insert( conduitKey, accumulator, ConduitItemType.ERC721, token, from, to, identifier, amount ); } } /** * @dev Internal function to transfer ERC1155 tokens from a given originator * to a given recipient. Sufficient approvals must be set, either on * the respective conduit or on this contract itself. * * @param token The ERC1155 token to transfer. * @param from The originator of the transfer. * @param to The recipient of the transfer. * @param identifier The id to transfer. * @param amount The amount to transfer. * @param conduitKey A bytes32 value indicating what corresponding conduit, * if any, to source token approvals from. The zero hash * signifies that no conduit should be used, with direct * approvals set on this contract. * @param accumulator An open-ended array that collects transfers to execute * against a given conduit in a single call. */ function _transferERC1155( address token, address from, address to, uint256 identifier, uint256 amount, bytes32 conduitKey, bytes memory accumulator ) internal { // Ensure that the supplied amount is non-zero. _assertNonZeroAmount(amount); // Trigger accumulated transfers if the conduits differ. _triggerIfArmedAndNotAccumulatable(accumulator, conduitKey); // If no conduit has been specified... if (conduitKey == bytes32(0)) { // Perform transfer via the token contract directly. _performERC1155Transfer(token, from, to, identifier, amount); } else { // Insert the call to the conduit into the accumulator. _insert( conduitKey, accumulator, ConduitItemType.ERC1155, token, from, to, identifier, amount ); } } /** * @dev Internal function to trigger a call to the conduit currently held by * the accumulator if the accumulator contains item transfers (i.e. it * is "armed") and the supplied conduit key does not match the key held * by the accumulator. * * @param accumulator An open-ended array that collects transfers to execute * against a given conduit in a single call. * @param conduitKey A bytes32 value indicating what corresponding conduit, * if any, to source token approvals from. The zero hash * signifies that no conduit should be used, with direct * approvals set on this contract. */ function _triggerIfArmedAndNotAccumulatable( bytes memory accumulator, bytes32 conduitKey ) internal { // Retrieve the current conduit key from the accumulator. bytes32 accumulatorConduitKey = _getAccumulatorConduitKey(accumulator); // Perform conduit call if the set key does not match the supplied key. if (accumulatorConduitKey != conduitKey) { _triggerIfArmed(accumulator); } } /** * @dev Internal function to trigger a call to the conduit currently held by * the accumulator if the accumulator contains item transfers (i.e. it * is "armed"). * * @param accumulator An open-ended array that collects transfers to execute * against a given conduit in a single call. */ function _triggerIfArmed(bytes memory accumulator) internal { // Exit if the accumulator is not "armed". if (accumulator.length != AccumulatorArmed) { return; } // Retrieve the current conduit key from the accumulator. bytes32 accumulatorConduitKey = _getAccumulatorConduitKey(accumulator); // Perform conduit call. _trigger(accumulatorConduitKey, accumulator); } /** * @dev Internal function to trigger a call to the conduit corresponding to * a given conduit key, supplying all accumulated item transfers. The * accumulator will be "disarmed" and reset in the process. * * @param conduitKey A bytes32 value indicating what corresponding conduit, * if any, to source token approvals from. The zero hash * signifies that no conduit should be used, with direct * approvals set on this contract. * @param accumulator An open-ended array that collects transfers to execute * against a given conduit in a single call. */ function _trigger(bytes32 conduitKey, bytes memory accumulator) internal { // Declare variables for offset in memory & size of calldata to conduit. uint256 callDataOffset; uint256 callDataSize; // Call the conduit with all the accumulated transfers. assembly { // Call begins at third word; the first is length or "armed" status, // and the second is the current conduit key. callDataOffset := add(accumulator, TwoWords) // 68 + items * 192 callDataSize := add( Accumulator_array_offset_ptr, mul( mload(add(accumulator, Accumulator_array_length_ptr)), Conduit_transferItem_size ) ) } // Call conduit derived from conduit key & supply accumulated transfers. _callConduitUsingOffsets(conduitKey, callDataOffset, callDataSize); // Reset accumulator length to signal that it is now "disarmed". assembly { mstore(accumulator, AccumulatorDisarmed) } } /** * @dev Internal function to perform a call to the conduit corresponding to * a given conduit key based on the offset and size of the calldata in * question in memory. * * @param conduitKey A bytes32 value indicating what corresponding * conduit, if any, to source token approvals from. * The zero hash signifies that no conduit should be * used, with direct approvals set on this contract. * @param callDataOffset The memory pointer where calldata is contained. * @param callDataSize The size of calldata in memory. */ function _callConduitUsingOffsets( bytes32 conduitKey, uint256 callDataOffset, uint256 callDataSize ) internal { // Derive the address of the conduit using the conduit key. address conduit = _deriveConduit(conduitKey); bool success; bytes4 result; // call the conduit. assembly { // Ensure first word of scratch space is empty. mstore(0, 0) // Perform call, placing first word of return data in scratch space. success := call( gas(), conduit, 0, callDataOffset, callDataSize, 0, OneWord ) // Take value from scratch space and place it on the stack. result := mload(0) } // If the call failed... if (!success) { // Pass along whatever revert reason was given by the conduit. _revertWithReasonIfOneIsReturned(); // Otherwise, revert with a generic error. _revertInvalidCallToConduit(conduit); } // Ensure result was extracted and matches EIP-1271 magic value. if (result != ConduitInterface.execute.selector) { _revertInvalidConduit(conduitKey, conduit); } } /** * @dev Internal pure function to retrieve the current conduit key set for * the accumulator. * * @param accumulator An open-ended array that collects transfers to execute * against a given conduit in a single call. * * @return accumulatorConduitKey The conduit key currently set for the * accumulator. */ function _getAccumulatorConduitKey( bytes memory accumulator ) internal pure returns (bytes32 accumulatorConduitKey) { // Retrieve the current conduit key from the accumulator. assembly { accumulatorConduitKey := mload( add(accumulator, Accumulator_conduitKey_ptr) ) } } /** * @dev Internal pure function to place an item transfer into an accumulator * that collects a series of transfers to execute against a given * conduit in a single call. * * @param conduitKey A bytes32 value indicating what corresponding conduit, * if any, to source token approvals from. The zero hash * signifies that no conduit should be used, with direct * approvals set on this contract. * @param accumulator An open-ended array that collects transfers to execute * against a given conduit in a single call. * @param itemType The type of the item to transfer. * @param token The token to transfer. * @param from The originator of the transfer. * @param to The recipient of the transfer. * @param identifier The tokenId to transfer. * @param amount The amount to transfer. */ function _insert( bytes32 conduitKey, bytes memory accumulator, ConduitItemType itemType, address token, address from, address to, uint256 identifier, uint256 amount ) internal pure { uint256 elements; // "Arm" and prime accumulator if it's not already armed. The sentinel // value is held in the length of the accumulator array. if (accumulator.length == AccumulatorDisarmed) { elements = 1; bytes4 selector = ConduitInterface.execute.selector; assembly { mstore(accumulator, AccumulatorArmed) // "arm" the accumulator. mstore(add(accumulator, Accumulator_conduitKey_ptr), conduitKey) mstore(add(accumulator, Accumulator_selector_ptr), selector) mstore( add(accumulator, Accumulator_array_offset_ptr), Accumulator_array_offset ) mstore(add(accumulator, Accumulator_array_length_ptr), elements) } } else { // Otherwise, increase the number of elements by one. assembly { elements := add( mload(add(accumulator, Accumulator_array_length_ptr)), 1 ) mstore(add(accumulator, Accumulator_array_length_ptr), elements) } } // Insert the item. assembly { let itemPointer := sub( add(accumulator, mul(elements, Conduit_transferItem_size)), Accumulator_itemSizeOffsetDifference ) mstore(itemPointer, itemType) mstore(add(itemPointer, Conduit_transferItem_token_ptr), token) mstore(add(itemPointer, Conduit_transferItem_from_ptr), from) mstore(add(itemPointer, Conduit_transferItem_to_ptr), to) mstore( add(itemPointer, Conduit_transferItem_identifier_ptr), identifier ) mstore(add(itemPointer, Conduit_transferItem_amount_ptr), amount) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { OrderType } from "./ConsiderationEnums.sol"; import { AdvancedOrder, BasicOrderParameters, OrderParameters } from "./ConsiderationStructs.sol"; import { ZoneInteractionErrors } from "../interfaces/ZoneInteractionErrors.sol"; import { LowLevelHelpers } from "./LowLevelHelpers.sol"; import { ConsiderationEncoder } from "./ConsiderationEncoder.sol"; import { MemoryPointer } from "../helpers/PointerLibraries.sol"; import { ContractOrder_orderHash_offerer_shift, MaskOverFirstFourBytes, OneWord, OrderParameters_zone_offset } from "./ConsiderationConstants.sol"; import { Error_selector_offset, InvalidContractOrder_error_selector, InvalidRestrictedOrder_error_length, InvalidRestrictedOrder_error_orderHash_ptr, InvalidRestrictedOrder_error_selector } from "./ConsiderationErrorConstants.sol"; /** * @title ZoneInteraction * @author 0age * @notice ZoneInteraction contains logic related to interacting with zones. */ contract ZoneInteraction is ConsiderationEncoder, ZoneInteractionErrors, LowLevelHelpers { /** * @dev Internal function to determine if an order has a restricted order * type and, if so, to ensure that either the zone is the caller or * that a call to `validateOrder` on the zone returns a magic value * indicating that the order is currently valid. Note that contract * orders are not accessible via the basic fulfillment method. * * @param orderHash The hash of the order. * @param orderType The order type. * @param parameters The parameters of the basic order. */ function _assertRestrictedBasicOrderValidity( bytes32 orderHash, OrderType orderType, BasicOrderParameters calldata parameters ) internal { // Order type 2-3 require zone be caller or zone to approve. // Note that in cases where fulfiller == zone, the restricted order // validation will be skipped. if (_isRestrictedAndCallerNotZone(orderType, parameters.zone)) { // Encode the `validateOrder` call in memory. (MemoryPointer callData, uint256 size) = _encodeValidateBasicOrder( orderHash, parameters ); // Perform `validateOrder` call and ensure magic value was returned. _callAndCheckStatus( parameters.zone, orderHash, callData, size, InvalidRestrictedOrder_error_selector ); } } /** * @dev Internal function to determine the post-execution validity of * restricted and contract orders. Restricted orders where the caller * is not the zone must successfully call `validateOrder` with the * correct magic value returned. Contract orders must successfully call * `ratifyOrder` with the correct magic value returned. * * @param advancedOrder The advanced order in question. * @param orderHashes The order hashes of each order included as part of * the current fulfillment. * @param orderHash The hash of the order. */ function _assertRestrictedAdvancedOrderValidity( AdvancedOrder memory advancedOrder, bytes32[] memory orderHashes, bytes32 orderHash ) internal { // Declare variables that will be assigned based on the order type. address target; uint256 errorSelector; MemoryPointer callData; uint256 size; // Retrieve the parameters of the order in question. OrderParameters memory parameters = advancedOrder.parameters; // OrderType 2-3 require zone to be caller or approve via validateOrder. if ( _isRestrictedAndCallerNotZone(parameters.orderType, parameters.zone) ) { // Encode the `validateOrder` call in memory. (callData, size) = _encodeValidateOrder( orderHash, parameters, advancedOrder.extraData, orderHashes ); // Set the target to the zone. target = ( parameters .toMemoryPointer() .offset(OrderParameters_zone_offset) .readAddress() ); // Set the restricted-order-specific error selector. errorSelector = InvalidRestrictedOrder_error_selector; } else if (parameters.orderType == OrderType.CONTRACT) { // Set the target to the offerer (note the offerer has no offset). target = parameters.toMemoryPointer().readAddress(); // Shift the target 96 bits to the left. uint256 shiftedOfferer; assembly { shiftedOfferer := shl( ContractOrder_orderHash_offerer_shift, target ) } // Encode the `ratifyOrder` call in memory. (callData, size) = _encodeRatifyOrder( orderHash, parameters, advancedOrder.extraData, orderHashes, shiftedOfferer ); // Set the contract-order-specific error selector. errorSelector = InvalidContractOrder_error_selector; } else { return; } // Perform call and ensure a corresponding magic value was returned. _callAndCheckStatus(target, orderHash, callData, size, errorSelector); } /** * @dev Determines whether the specified order type is restricted and the * caller is not the specified zone. * * @param orderType The type of the order to check. * @param zone The address of the zone to check against. * * @return mustValidate True if the order type is restricted and the caller * is not the specified zone, false otherwise. */ function _isRestrictedAndCallerNotZone( OrderType orderType, address zone ) internal view returns (bool mustValidate) { assembly { mustValidate := and( // Note that this check requires that there are no order types // beyond the current set (0-4). It will need to be modified if // more order types are added. and(lt(orderType, 4), gt(orderType, 1)), iszero(eq(caller(), zone)) ) } } /** * @dev Calls the specified target with the given data and checks the status * of the call. Revert reasons will be "bubbled up" if one is returned, * otherwise reverting calls will throw a generic error based on the * supplied error handler. * * @param target The address of the contract to call. * @param orderHash The hash of the order associated with the call. * @param callData The data to pass to the contract call. * @param size The size of calldata. * @param errorSelector The error handling function to call if the call * fails or the magic value does not match. */ function _callAndCheckStatus( address target, bytes32 orderHash, MemoryPointer callData, uint256 size, uint256 errorSelector ) internal { bool success; bool magicMatch; assembly { // Get magic value from the selector at start of provided calldata. let magic := and(mload(callData), MaskOverFirstFourBytes) // Clear the start of scratch space. mstore(0, 0) // Perform call, placing result in the first word of scratch space. success := call(gas(), target, 0, callData, size, 0, OneWord) // Determine if returned magic value matches the calldata selector. magicMatch := eq(magic, mload(0)) } // Revert if the call was not successful. if (!success) { // Revert and pass reason along if one was returned. _revertWithReasonIfOneIsReturned(); // If no reason was returned, revert with supplied error selector. assembly { mstore(0, errorSelector) mstore(InvalidRestrictedOrder_error_orderHash_ptr, orderHash) // revert(abi.encodeWithSelector( // "InvalidRestrictedOrder(bytes32)", // orderHash // )) revert( Error_selector_offset, InvalidRestrictedOrder_error_length ) } } // Revert if the correct magic value was not returned. if (!magicMatch) { // Revert with a generic error message. assembly { mstore(0, errorSelector) mstore(InvalidRestrictedOrder_error_orderHash_ptr, orderHash) // revert(abi.encodeWithSelector( // "InvalidRestrictedOrder(bytes32)", // orderHash // )) revert( Error_selector_offset, InvalidRestrictedOrder_error_length ) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ConduitBatch1155Transfer, ConduitTransfer } from "../conduit/lib/ConduitStructs.sol"; /** * @title ConduitInterface * @author 0age * @notice ConduitInterface contains all external function interfaces, events, * and errors for conduit contracts. */ interface ConduitInterface { /** * @dev Revert with an error when attempting to execute transfers using a * caller that does not have an open channel. */ error ChannelClosed(address channel); /** * @dev Revert with an error when attempting to update a channel to the * current status of that channel. */ error ChannelStatusAlreadySet(address channel, bool isOpen); /** * @dev Revert with an error when attempting to execute a transfer for an * item that does not have an ERC20/721/1155 item type. */ error InvalidItemType(); /** * @dev Revert with an error when attempting to update the status of a * channel from a caller that is not the conduit controller. */ error InvalidController(); /** * @dev Emit an event whenever a channel is opened or closed. * * @param channel The channel that has been updated. * @param open A boolean indicating whether the conduit is open or not. */ event ChannelUpdated(address indexed channel, bool open); /** * @notice Execute a sequence of ERC20/721/1155 transfers. Only a caller * with an open channel can call this function. * * @param transfers The ERC20/721/1155 transfers to perform. * * @return magicValue A magic value indicating that the transfers were * performed successfully. */ function execute( ConduitTransfer[] calldata transfers ) external returns (bytes4 magicValue); /** * @notice Execute a sequence of batch 1155 transfers. Only a caller with an * open channel can call this function. * * @param batch1155Transfers The 1155 batch transfers to perform. * * @return magicValue A magic value indicating that the transfers were * performed successfully. */ function executeBatch1155( ConduitBatch1155Transfer[] calldata batch1155Transfers ) external returns (bytes4 magicValue); /** * @notice Execute a sequence of transfers, both single and batch 1155. Only * a caller with an open channel can call this function. * * @param standardTransfers The ERC20/721/1155 transfers to perform. * @param batch1155Transfers The 1155 batch transfers to perform. * * @return magicValue A magic value indicating that the transfers were * performed successfully. */ function executeWithBatch1155( ConduitTransfer[] calldata standardTransfers, ConduitBatch1155Transfer[] calldata batch1155Transfers ) external returns (bytes4 magicValue); /** * @notice Open or close a given channel. Only callable by the controller. * * @param channel The channel to open or close. * @param isOpen The status of the channel (either open or closed). */ function updateChannel(address channel, bool isOpen) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; enum ConduitItemType { NATIVE, // unused ERC20, ERC721, ERC1155 }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { OrderStatus } from "./ConsiderationStructs.sol"; import { Assertions } from "./Assertions.sol"; import { SignatureVerification } from "./SignatureVerification.sol"; import { _revertInvalidTime, _revertOrderAlreadyFilled, _revertOrderIsCancelled, _revertOrderPartiallyFilled } from "./ConsiderationErrors.sol"; import { BulkOrderProof_keyShift, BulkOrderProof_keySize, BulkOrderProof_lengthAdjustmentBeforeMask, BulkOrderProof_lengthRangeAfterMask, BulkOrderProof_minSize, BulkOrderProof_rangeSize, ECDSA_MaxLength, OneWord, OneWordShift, ThirtyOneBytes, TwoWords } from "./ConsiderationConstants.sol"; /** * @title Verifiers * @author 0age * @notice Verifiers contains functions for performing verifications. */ contract Verifiers is Assertions, SignatureVerification { /** * @dev Derive and set hashes, reference chainId, and associated domain * separator during deployment. * * @param conduitController A contract that deploys conduits, or proxies * that may optionally be used to transfer approved * ERC20/721/1155 tokens. */ constructor(address conduitController) Assertions(conduitController) {} /** * @dev Internal view function to ensure that the current time falls within * an order's valid timespan. * * @param startTime The time at which the order becomes active. * @param endTime The time at which the order becomes inactive. * @param revertOnInvalid A boolean indicating whether to revert if the * order is not active. * * @return valid A boolean indicating whether the order is active. */ function _verifyTime( uint256 startTime, uint256 endTime, bool revertOnInvalid ) internal view returns (bool valid) { // Mark as valid if order has started and has not already ended. assembly { valid := and( iszero(gt(startTime, timestamp())), gt(endTime, timestamp()) ) } // Only revert on invalid if revertOnInvalid has been supplied as true. if (revertOnInvalid && !valid) { _revertInvalidTime(startTime, endTime); } } /** * @dev Internal view function to verify the signature of an order. An * ERC-1271 fallback will be attempted if either the signature length * is not 64 or 65 bytes or if the recovered signer does not match the * supplied offerer. Note that in cases where a 64 or 65 byte signature * is supplied, only standard ECDSA signatures that recover to a * non-zero address are supported. * * @param offerer The offerer for the order. * @param orderHash The order hash. * @param signature A signature from the offerer indicating that the order * has been approved. */ function _verifySignature( address offerer, bytes32 orderHash, bytes memory signature ) internal view { // Determine whether the offerer is the caller. bool offererIsCaller; assembly { offererIsCaller := eq(offerer, caller()) } // Skip signature verification if the offerer is the caller. if (offererIsCaller) { return; } // Derive the EIP-712 domain separator. bytes32 domainSeparator = _domainSeparator(); // Derive original EIP-712 digest using domain separator and order hash. bytes32 originalDigest = _deriveEIP712Digest( domainSeparator, orderHash ); // Read the length of the signature from memory and place on the stack. uint256 originalSignatureLength = signature.length; // Determine effective digest if signature has a valid bulk order size. bytes32 digest; if (_isValidBulkOrderSize(originalSignatureLength)) { // Rederive order hash and digest using bulk order proof. (orderHash) = _computeBulkOrderProof(signature, orderHash); digest = _deriveEIP712Digest(domainSeparator, orderHash); } else { // Supply the original digest as the effective digest. digest = originalDigest; } // Ensure that the signature for the digest is valid for the offerer. _assertValidSignature( offerer, digest, originalDigest, originalSignatureLength, signature ); } /** * @dev Determines whether the specified bulk order size is valid. * * @param signatureLength The signature length of the bulk order to check. * * @return validLength True if bulk order size is valid, false otherwise. */ function _isValidBulkOrderSize( uint256 signatureLength ) internal pure returns (bool validLength) { // Utilize assembly to validate the length; the equivalent logic is // (64 + x) + 3 + 32y where (0 <= x <= 1) and (1 <= y <= 24). assembly { validLength := and( lt( sub(signatureLength, BulkOrderProof_minSize), BulkOrderProof_rangeSize ), lt( and( add( signatureLength, BulkOrderProof_lengthAdjustmentBeforeMask ), ThirtyOneBytes ), BulkOrderProof_lengthRangeAfterMask ) ) } } /** * @dev Computes the bulk order hash for the specified proof and leaf. Note * that if an index that exceeds the number of orders in the bulk order * payload will instead "wrap around" and refer to an earlier index. * * @param proofAndSignature The proof and signature of the bulk order. * @param leaf The leaf of the bulk order tree. * * @return bulkOrderHash The bulk order hash. */ function _computeBulkOrderProof( bytes memory proofAndSignature, bytes32 leaf ) internal pure returns (bytes32 bulkOrderHash) { // Declare arguments for the root hash and the height of the proof. bytes32 root; uint256 height; // Utilize assembly to efficiently derive the root hash using the proof. assembly { // Retrieve the length of the proof, key, and signature combined. let fullLength := mload(proofAndSignature) // If proofAndSignature has odd length, it is a compact signature // with 64 bytes. let signatureLength := sub(ECDSA_MaxLength, and(fullLength, 1)) // Derive height (or depth of tree) with signature and proof length. height := shr(OneWordShift, sub(fullLength, signatureLength)) // Update the length in memory to only include the signature. mstore(proofAndSignature, signatureLength) // Derive the pointer for the key using the signature length. let keyPtr := add(proofAndSignature, add(OneWord, signatureLength)) // Retrieve the three-byte key using the derived pointer. let key := shr(BulkOrderProof_keyShift, mload(keyPtr)) /// Retrieve pointer to first proof element by applying a constant // for the key size to the derived key pointer. let proof := add(keyPtr, BulkOrderProof_keySize) // Compute level 1. let scratchPtr1 := shl(OneWordShift, and(key, 1)) mstore(scratchPtr1, leaf) mstore(xor(scratchPtr1, OneWord), mload(proof)) // Compute remaining proofs. for { let i := 1 } lt(i, height) { i := add(i, 1) } { proof := add(proof, OneWord) let scratchPtr := shl(OneWordShift, and(shr(i, key), 1)) mstore(scratchPtr, keccak256(0, TwoWords)) mstore(xor(scratchPtr, OneWord), mload(proof)) } // Compute root hash. root := keccak256(0, TwoWords) } // Retrieve appropriate typehash constant based on height. bytes32 rootTypeHash = _lookupBulkOrderTypehash(height); // Use the typehash and the root hash to derive final bulk order hash. assembly { mstore(0, rootTypeHash) mstore(OneWord, root) bulkOrderHash := keccak256(0, TwoWords) } } /** * @dev Internal view function to validate that a given order is fillable * and not cancelled based on the order status. * * @param orderHash The order hash. * @param orderStatus The status of the order, including whether it has * been cancelled and the fraction filled. * @param onlyAllowUnused A boolean flag indicating whether partial fills * are supported by the calling function. * @param revertOnInvalid A boolean indicating whether to revert if the * order has been cancelled or filled beyond the * allowable amount. * * @return valid A boolean indicating whether the order is valid. */ function _verifyOrderStatus( bytes32 orderHash, OrderStatus storage orderStatus, bool onlyAllowUnused, bool revertOnInvalid ) internal view returns (bool valid) { // Ensure that the order has not been cancelled. if (orderStatus.isCancelled) { // Only revert if revertOnInvalid has been supplied as true. if (revertOnInvalid) { _revertOrderIsCancelled(orderHash); } // Return false as the order status is invalid. return false; } // Read order status numerator from storage and place on stack. uint256 orderStatusNumerator = orderStatus.numerator; // If the order is not entirely unused... if (orderStatusNumerator != 0) { // ensure the order has not been partially filled when not allowed. if (onlyAllowUnused) { // Always revert on partial fills when onlyAllowUnused is true. _revertOrderPartiallyFilled(orderHash); } // Otherwise, ensure that order has not been entirely filled. else if (orderStatusNumerator >= orderStatus.denominator) { // Only revert if revertOnInvalid has been supplied as true. if (revertOnInvalid) { _revertOrderAlreadyFilled(orderHash); } // Return false as the order status is invalid. return false; } } // Return true as the order status is valid. valid = true; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { BadReturnValueFromERC20OnTransfer_error_amount_ptr, BadReturnValueFromERC20OnTransfer_error_from_ptr, BadReturnValueFromERC20OnTransfer_error_length, BadReturnValueFromERC20OnTransfer_error_selector, BadReturnValueFromERC20OnTransfer_error_to_ptr, BadReturnValueFromERC20OnTransfer_error_token_ptr, BatchTransfer1155Params_amounts_head_ptr, BatchTransfer1155Params_calldata_baseSize, BatchTransfer1155Params_data_head_ptr, BatchTransfer1155Params_data_length_basePtr, BatchTransfer1155Params_ids_head_ptr, BatchTransfer1155Params_ids_length_offset, BatchTransfer1155Params_ids_length_ptr, BatchTransfer1155Params_ptr, ConduitBatch1155Transfer_amounts_length_baseOffset, ConduitBatch1155Transfer_from_offset, ConduitBatch1155Transfer_ids_head_offset, ConduitBatch1155Transfer_ids_length_offset, ConduitBatch1155Transfer_usable_head_size, ConduitBatchTransfer_amounts_head_offset, CostPerWord, DefaultFreeMemoryPointer, ERC1155_safeBatchTransferFrom_signature, ERC1155_safeTransferFrom_amount_ptr, ERC1155_safeTransferFrom_data_length_offset, ERC1155_safeTransferFrom_data_length_ptr, ERC1155_safeTransferFrom_data_offset_ptr, ERC1155_safeTransferFrom_from_ptr, ERC1155_safeTransferFrom_id_ptr, ERC1155_safeTransferFrom_length, ERC1155_safeTransferFrom_sig_ptr, ERC1155_safeTransferFrom_signature, ERC1155_safeTransferFrom_to_ptr, ERC1155BatchTransferGenericFailure_error_signature, ERC1155BatchTransferGenericFailure_ids_offset, ERC1155BatchTransferGenericFailure_token_ptr, ERC20_transferFrom_amount_ptr, ERC20_transferFrom_from_ptr, ERC20_transferFrom_length, ERC20_transferFrom_sig_ptr, ERC20_transferFrom_signature, ERC20_transferFrom_to_ptr, ERC721_transferFrom_from_ptr, ERC721_transferFrom_id_ptr, ERC721_transferFrom_length, ERC721_transferFrom_sig_ptr, ERC721_transferFrom_signature, ERC721_transferFrom_to_ptr, ExtraGasBuffer, FreeMemoryPointerSlot, Generic_error_selector_offset, Invalid1155BatchTransferEncoding_length, Invalid1155BatchTransferEncoding_ptr, Invalid1155BatchTransferEncoding_selector, MemoryExpansionCoefficientShift, NoContract_error_account_ptr, NoContract_error_length, NoContract_error_selector, OneWord, OneWordShift, Slot0x80, Slot0xA0, Slot0xC0, ThirtyOneBytes, TokenTransferGenericFailure_err_identifier_ptr, TokenTransferGenericFailure_error_amount_ptr, TokenTransferGenericFailure_error_from_ptr, TokenTransferGenericFailure_error_identifier_ptr, TokenTransferGenericFailure_error_length, TokenTransferGenericFailure_error_selector, TokenTransferGenericFailure_error_to_ptr, TokenTransferGenericFailure_error_token_ptr, TwoWords, TwoWordsShift, ZeroSlot } from "./TokenTransferrerConstants.sol"; import { TokenTransferrerErrors } from "../interfaces/TokenTransferrerErrors.sol"; import { ConduitBatch1155Transfer } from "../conduit/lib/ConduitStructs.sol"; /** * @title TokenTransferrer * @author 0age * @custom:coauthor d1ll0n * @custom:coauthor transmissions11 * @notice TokenTransferrer is a library for performing optimized ERC20, ERC721, * ERC1155, and batch ERC1155 transfers, used by both Seaport as well as * by conduits deployed by the ConduitController. Use great caution when * considering these functions for use in other codebases, as there are * significant side effects and edge cases that need to be thoroughly * understood and carefully addressed. */ contract TokenTransferrer is TokenTransferrerErrors { /** * @dev Internal function to transfer ERC20 tokens from a given originator * to a given recipient. Sufficient approvals must be set on the * contract performing the transfer. * * @param token The ERC20 token to transfer. * @param from The originator of the transfer. * @param to The recipient of the transfer. * @param amount The amount to transfer. */ function _performERC20Transfer( address token, address from, address to, uint256 amount ) internal { // Utilize assembly to perform an optimized ERC20 token transfer. assembly { // The free memory pointer memory slot will be used when populating // call data for the transfer; read the value and restore it later. let memPointer := mload(FreeMemoryPointerSlot) // Write call data into memory, starting with function selector. mstore(ERC20_transferFrom_sig_ptr, ERC20_transferFrom_signature) mstore(ERC20_transferFrom_from_ptr, from) mstore(ERC20_transferFrom_to_ptr, to) mstore(ERC20_transferFrom_amount_ptr, amount) // Make call & copy up to 32 bytes of return data to scratch space. // Scratch space does not need to be cleared ahead of time, as the // subsequent check will ensure that either at least a full word of // return data is received (in which case it will be overwritten) or // that no data is received (in which case scratch space will be // ignored) on a successful call to the given token. let callStatus := call( gas(), token, 0, ERC20_transferFrom_sig_ptr, ERC20_transferFrom_length, 0, OneWord ) // Determine whether transfer was successful using status & result. let success := and( // Set success to whether the call reverted, if not check it // either returned exactly 1 (can't just be non-zero data), or // had no return data. or( and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize()) ), callStatus ) // Handle cases where either the transfer failed or no data was // returned. Group these, as most transfers will succeed with data. // Equivalent to `or(iszero(success), iszero(returndatasize()))` // but after it's inverted for JUMPI this expression is cheaper. if iszero(and(success, iszero(iszero(returndatasize())))) { // If the token has no code or the transfer failed: Equivalent // to `or(iszero(success), iszero(extcodesize(token)))` but // after it's inverted for JUMPI this expression is cheaper. if iszero(and(iszero(iszero(extcodesize(token))), success)) { // If the transfer failed: if iszero(success) { // If it was due to a revert: if iszero(callStatus) { // If it returned a message, bubble it up as long as // sufficient gas remains to do so: if returndatasize() { // Ensure that sufficient gas is available to // copy returndata while expanding memory where // necessary. Start by computing the word size // of returndata and allocated memory. Round up // to the nearest full word. let returnDataWords := shr( OneWordShift, add(returndatasize(), ThirtyOneBytes) ) // Note: use the free memory pointer in place of // msize() to work around a Yul warning that // prevents accessing msize directly when the IR // pipeline is activated. let msizeWords := shr(OneWordShift, memPointer) // Next, compute the cost of the returndatacopy. let cost := mul(CostPerWord, returnDataWords) // Then, compute cost of new memory allocation. if gt(returnDataWords, msizeWords) { cost := add( cost, add( mul( sub( returnDataWords, msizeWords ), CostPerWord ), shr( MemoryExpansionCoefficientShift, sub( mul( returnDataWords, returnDataWords ), mul(msizeWords, msizeWords) ) ) ) ) } // Finally, add a small constant and compare to // gas remaining; bubble up the revert data if // enough gas is still available. if lt(add(cost, ExtraGasBuffer), gas()) { // Copy returndata to memory; overwrite // existing memory. returndatacopy(0, 0, returndatasize()) // Revert, specifying memory region with // copied returndata. revert(0, returndatasize()) } } // Store left-padded selector with push4, mem[28:32] mstore( 0, TokenTransferGenericFailure_error_selector ) mstore( TokenTransferGenericFailure_error_token_ptr, token ) mstore( TokenTransferGenericFailure_error_from_ptr, from ) mstore(TokenTransferGenericFailure_error_to_ptr, to) mstore( TokenTransferGenericFailure_err_identifier_ptr, 0 ) mstore( TokenTransferGenericFailure_error_amount_ptr, amount ) // revert(abi.encodeWithSignature( // "TokenTransferGenericFailure( // address,address,address,uint256,uint256 // )", token, from, to, identifier, amount // )) revert( Generic_error_selector_offset, TokenTransferGenericFailure_error_length ) } // Otherwise revert with a message about the token // returning false or non-compliant return values. // Store left-padded selector with push4, mem[28:32] mstore( 0, BadReturnValueFromERC20OnTransfer_error_selector ) mstore( BadReturnValueFromERC20OnTransfer_error_token_ptr, token ) mstore( BadReturnValueFromERC20OnTransfer_error_from_ptr, from ) mstore( BadReturnValueFromERC20OnTransfer_error_to_ptr, to ) mstore( BadReturnValueFromERC20OnTransfer_error_amount_ptr, amount ) // revert(abi.encodeWithSignature( // "BadReturnValueFromERC20OnTransfer( // address,address,address,uint256 // )", token, from, to, amount // )) revert( Generic_error_selector_offset, BadReturnValueFromERC20OnTransfer_error_length ) } // Otherwise, revert with error about token not having code: // Store left-padded selector with push4, mem[28:32] mstore(0, NoContract_error_selector) mstore(NoContract_error_account_ptr, token) // revert(abi.encodeWithSignature( // "NoContract(address)", account // )) revert( Generic_error_selector_offset, NoContract_error_length ) } // Otherwise, the token just returned no data despite the call // having succeeded; no need to optimize for this as it's not // technically ERC20 compliant. } // Restore the original free memory pointer. mstore(FreeMemoryPointerSlot, memPointer) // Restore the zero slot to zero. mstore(ZeroSlot, 0) } } /** * @dev Internal function to transfer an ERC721 token from a given * originator to a given recipient. Sufficient approvals must be set on * the contract performing the transfer. Note that this function does * not check whether the receiver can accept the ERC721 token (i.e. it * does not use `safeTransferFrom`). * * @param token The ERC721 token to transfer. * @param from The originator of the transfer. * @param to The recipient of the transfer. * @param identifier The tokenId to transfer. */ function _performERC721Transfer( address token, address from, address to, uint256 identifier ) internal { // Utilize assembly to perform an optimized ERC721 token transfer. assembly { // If the token has no code, revert. if iszero(extcodesize(token)) { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, NoContract_error_selector) mstore(NoContract_error_account_ptr, token) // revert(abi.encodeWithSignature( // "NoContract(address)", account // )) revert(Generic_error_selector_offset, NoContract_error_length) } // The free memory pointer memory slot will be used when populating // call data for the transfer; read the value and restore it later. let memPointer := mload(FreeMemoryPointerSlot) // Write call data to memory starting with function selector. mstore(ERC721_transferFrom_sig_ptr, ERC721_transferFrom_signature) mstore(ERC721_transferFrom_from_ptr, from) mstore(ERC721_transferFrom_to_ptr, to) mstore(ERC721_transferFrom_id_ptr, identifier) // Perform the call, ignoring return data. let success := call( gas(), token, 0, ERC721_transferFrom_sig_ptr, ERC721_transferFrom_length, 0, 0 ) // If the transfer reverted: if iszero(success) { // If it returned a message, bubble it up as long as sufficient // gas remains to do so: if returndatasize() { // Ensure that sufficient gas is available to copy // returndata while expanding memory where necessary. Start // by computing word size of returndata & allocated memory. // Round up to the nearest full word. let returnDataWords := shr( OneWordShift, add(returndatasize(), ThirtyOneBytes) ) // Note: use the free memory pointer in place of msize() to // work around a Yul warning that prevents accessing msize // directly when the IR pipeline is activated. let msizeWords := shr(OneWordShift, memPointer) // Next, compute the cost of the returndatacopy. let cost := mul(CostPerWord, returnDataWords) // Then, compute cost of new memory allocation. if gt(returnDataWords, msizeWords) { cost := add( cost, add( mul( sub(returnDataWords, msizeWords), CostPerWord ), shr( MemoryExpansionCoefficientShift, sub( mul(returnDataWords, returnDataWords), mul(msizeWords, msizeWords) ) ) ) ) } // Finally, add a small constant and compare to gas // remaining; bubble up the revert data if enough gas is // still available. if lt(add(cost, ExtraGasBuffer), gas()) { // Copy returndata to memory; overwrite existing memory. returndatacopy(0, 0, returndatasize()) // Revert, giving memory region with copied returndata. revert(0, returndatasize()) } } // Otherwise revert with a generic error message. // Store left-padded selector with push4, mem[28:32] = selector mstore(0, TokenTransferGenericFailure_error_selector) mstore(TokenTransferGenericFailure_error_token_ptr, token) mstore(TokenTransferGenericFailure_error_from_ptr, from) mstore(TokenTransferGenericFailure_error_to_ptr, to) mstore( TokenTransferGenericFailure_error_identifier_ptr, identifier ) mstore(TokenTransferGenericFailure_error_amount_ptr, 1) // revert(abi.encodeWithSignature( // "TokenTransferGenericFailure( // address,address,address,uint256,uint256 // )", token, from, to, identifier, amount // )) revert( Generic_error_selector_offset, TokenTransferGenericFailure_error_length ) } // Restore the original free memory pointer. mstore(FreeMemoryPointerSlot, memPointer) // Restore the zero slot to zero. mstore(ZeroSlot, 0) } } /** * @dev Internal function to transfer ERC1155 tokens from a given * originator to a given recipient. Sufficient approvals must be set on * the contract performing the transfer and contract recipients must * implement the ERC1155TokenReceiver interface to indicate that they * are willing to accept the transfer. * * @param token The ERC1155 token to transfer. * @param from The originator of the transfer. * @param to The recipient of the transfer. * @param identifier The id to transfer. * @param amount The amount to transfer. */ function _performERC1155Transfer( address token, address from, address to, uint256 identifier, uint256 amount ) internal { // Utilize assembly to perform an optimized ERC1155 token transfer. assembly { // If the token has no code, revert. if iszero(extcodesize(token)) { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, NoContract_error_selector) mstore(NoContract_error_account_ptr, token) // revert(abi.encodeWithSignature( // "NoContract(address)", account // )) revert(Generic_error_selector_offset, NoContract_error_length) } // The following memory slots will be used when populating call data // for the transfer; read the values and restore them later. let memPointer := mload(FreeMemoryPointerSlot) let slot0x80 := mload(Slot0x80) let slot0xA0 := mload(Slot0xA0) let slot0xC0 := mload(Slot0xC0) // Write call data into memory, beginning with function selector. mstore( ERC1155_safeTransferFrom_sig_ptr, ERC1155_safeTransferFrom_signature ) mstore(ERC1155_safeTransferFrom_from_ptr, from) mstore(ERC1155_safeTransferFrom_to_ptr, to) mstore(ERC1155_safeTransferFrom_id_ptr, identifier) mstore(ERC1155_safeTransferFrom_amount_ptr, amount) mstore( ERC1155_safeTransferFrom_data_offset_ptr, ERC1155_safeTransferFrom_data_length_offset ) mstore(ERC1155_safeTransferFrom_data_length_ptr, 0) // Perform the call, ignoring return data. let success := call( gas(), token, 0, ERC1155_safeTransferFrom_sig_ptr, ERC1155_safeTransferFrom_length, 0, 0 ) // If the transfer reverted: if iszero(success) { // If it returned a message, bubble it up as long as sufficient // gas remains to do so: if returndatasize() { // Ensure that sufficient gas is available to copy // returndata while expanding memory where necessary. Start // by computing word size of returndata & allocated memory. // Round up to the nearest full word. let returnDataWords := shr( OneWordShift, add(returndatasize(), ThirtyOneBytes) ) // Note: use the free memory pointer in place of msize() to // work around a Yul warning that prevents accessing msize // directly when the IR pipeline is activated. let msizeWords := shr(OneWordShift, memPointer) // Next, compute the cost of the returndatacopy. let cost := mul(CostPerWord, returnDataWords) // Then, compute cost of new memory allocation. if gt(returnDataWords, msizeWords) { cost := add( cost, add( mul( sub(returnDataWords, msizeWords), CostPerWord ), shr( MemoryExpansionCoefficientShift, sub( mul(returnDataWords, returnDataWords), mul(msizeWords, msizeWords) ) ) ) ) } // Finally, add a small constant and compare to gas // remaining; bubble up the revert data if enough gas is // still available. if lt(add(cost, ExtraGasBuffer), gas()) { // Copy returndata to memory; overwrite existing memory. returndatacopy(0, 0, returndatasize()) // Revert, giving memory region with copied returndata. revert(0, returndatasize()) } } // Otherwise revert with a generic error message. // Store left-padded selector with push4, mem[28:32] = selector mstore(0, TokenTransferGenericFailure_error_selector) mstore(TokenTransferGenericFailure_error_token_ptr, token) mstore(TokenTransferGenericFailure_error_from_ptr, from) mstore(TokenTransferGenericFailure_error_to_ptr, to) mstore( TokenTransferGenericFailure_error_identifier_ptr, identifier ) mstore(TokenTransferGenericFailure_error_amount_ptr, amount) // revert(abi.encodeWithSignature( // "TokenTransferGenericFailure( // address,address,address,uint256,uint256 // )", token, from, to, identifier, amount // )) revert( Generic_error_selector_offset, TokenTransferGenericFailure_error_length ) } mstore(Slot0x80, slot0x80) // Restore slot 0x80. mstore(Slot0xA0, slot0xA0) // Restore slot 0xA0. mstore(Slot0xC0, slot0xC0) // Restore slot 0xC0. // Restore the original free memory pointer. mstore(FreeMemoryPointerSlot, memPointer) // Restore the zero slot to zero. mstore(ZeroSlot, 0) } } /** * @dev Internal function to transfer ERC1155 tokens from a given * originator to a given recipient. Sufficient approvals must be set on * the contract performing the transfer and contract recipients must * implement the ERC1155TokenReceiver interface to indicate that they * are willing to accept the transfer. NOTE: this function is not * memory-safe; it will overwrite existing memory, restore the free * memory pointer to the default value, and overwrite the zero slot. * This function should only be called once memory is no longer * required and when uninitialized arrays are not utilized, and memory * should be considered fully corrupted (aside from the existence of a * default-value free memory pointer) after calling this function. * * @param batchTransfers The group of 1155 batch transfers to perform. */ function _performERC1155BatchTransfers( ConduitBatch1155Transfer[] calldata batchTransfers ) internal { // Utilize assembly to perform optimized batch 1155 transfers. assembly { let len := batchTransfers.length // Pointer to first head in the array, which is offset to the struct // at each index. This gets incremented after each loop to avoid // multiplying by 32 to get the offset for each element. let nextElementHeadPtr := batchTransfers.offset // Pointer to beginning of the head of the array. This is the // reference position each offset references. It's held static to // let each loop calculate the data position for an element. let arrayHeadPtr := nextElementHeadPtr // Write the function selector, which will be reused for each call: // safeBatchTransferFrom(address,address,uint256[],uint256[],bytes) mstore( ConduitBatch1155Transfer_from_offset, ERC1155_safeBatchTransferFrom_signature ) // Iterate over each batch transfer. for { let i := 0 } lt(i, len) { i := add(i, 1) } { // Read the offset to the beginning of the element and add // it to pointer to the beginning of the array head to get // the absolute position of the element in calldata. let elementPtr := add( arrayHeadPtr, calldataload(nextElementHeadPtr) ) // Retrieve the token from calldata. let token := calldataload(elementPtr) // If the token has no code, revert. if iszero(extcodesize(token)) { // Store left-padded selector with push4, mem[28:32] mstore(0, NoContract_error_selector) mstore(NoContract_error_account_ptr, token) // revert(abi.encodeWithSignature( // "NoContract(address)", account // )) revert( Generic_error_selector_offset, NoContract_error_length ) } // Get the total number of supplied ids. let idsLength := calldataload( add(elementPtr, ConduitBatch1155Transfer_ids_length_offset) ) // Determine the expected offset for the amounts array. let expectedAmountsOffset := add( ConduitBatch1155Transfer_amounts_length_baseOffset, shl(OneWordShift, idsLength) ) // Validate struct encoding. let invalidEncoding := iszero( and( // ids.length == amounts.length eq( idsLength, calldataload(add(elementPtr, expectedAmountsOffset)) ), and( // ids_offset == 0xa0 eq( calldataload( add( elementPtr, ConduitBatch1155Transfer_ids_head_offset ) ), ConduitBatch1155Transfer_ids_length_offset ), // amounts_offset == 0xc0 + ids.length*32 eq( calldataload( add( elementPtr, ConduitBatchTransfer_amounts_head_offset ) ), expectedAmountsOffset ) ) ) ) // Revert with an error if the encoding is not valid. if invalidEncoding { // Store left-padded selector with push4, mem[28:32] mstore( Invalid1155BatchTransferEncoding_ptr, Invalid1155BatchTransferEncoding_selector ) // revert(abi.encodeWithSignature( // "Invalid1155BatchTransferEncoding()" // )) revert( Invalid1155BatchTransferEncoding_ptr, Invalid1155BatchTransferEncoding_length ) } // Update the offset position for the next loop nextElementHeadPtr := add(nextElementHeadPtr, OneWord) // Copy the first section of calldata (before dynamic values). calldatacopy( BatchTransfer1155Params_ptr, add(elementPtr, ConduitBatch1155Transfer_from_offset), ConduitBatch1155Transfer_usable_head_size ) // Determine size of calldata required for ids and amounts. Note // that the size includes both lengths as well as the data. let idsAndAmountsSize := add( TwoWords, shl(TwoWordsShift, idsLength) ) // Update the offset for the data array in memory. mstore( BatchTransfer1155Params_data_head_ptr, add( BatchTransfer1155Params_ids_length_offset, idsAndAmountsSize ) ) // Set the length of the data array in memory to zero. mstore( add( BatchTransfer1155Params_data_length_basePtr, idsAndAmountsSize ), 0 ) // Determine the total calldata size for the call to transfer. let transferDataSize := add( BatchTransfer1155Params_calldata_baseSize, idsAndAmountsSize ) // Copy second section of calldata (including dynamic values). calldatacopy( BatchTransfer1155Params_ids_length_ptr, add(elementPtr, ConduitBatch1155Transfer_ids_length_offset), idsAndAmountsSize ) // Perform the call to transfer 1155 tokens. let success := call( gas(), token, 0, ConduitBatch1155Transfer_from_offset, // Data portion start. transferDataSize, // Location of the length of callData. 0, 0 ) // If the transfer reverted: if iszero(success) { // If it returned a message, bubble it up as long as // sufficient gas remains to do so: if returndatasize() { // Ensure that sufficient gas is available to copy // returndata while expanding memory where necessary. // Start by computing word size of returndata and // allocated memory. Round up to the nearest full word. let returnDataWords := shr( OneWordShift, add(returndatasize(), ThirtyOneBytes) ) // Note: use transferDataSize in place of msize() to // work around a Yul warning that prevents accessing // msize directly when the IR pipeline is activated. // The free memory pointer is not used here because // this function does almost all memory management // manually and does not update it, and transferDataSize // should be the largest memory value used (unless a // previous batch was larger). let msizeWords := shr(OneWordShift, transferDataSize) // Next, compute the cost of the returndatacopy. let cost := mul(CostPerWord, returnDataWords) // Then, compute cost of new memory allocation. if gt(returnDataWords, msizeWords) { cost := add( cost, add( mul( sub(returnDataWords, msizeWords), CostPerWord ), shr( MemoryExpansionCoefficientShift, sub( mul( returnDataWords, returnDataWords ), mul(msizeWords, msizeWords) ) ) ) ) } // Finally, add a small constant and compare to gas // remaining; bubble up the revert data if enough gas is // still available. if lt(add(cost, ExtraGasBuffer), gas()) { // Copy returndata to memory; overwrite existing. returndatacopy(0, 0, returndatasize()) // Revert with memory region containing returndata. revert(0, returndatasize()) } } // Set the error signature. mstore( 0, ERC1155BatchTransferGenericFailure_error_signature ) // Write the token. mstore(ERC1155BatchTransferGenericFailure_token_ptr, token) // Increase the offset to ids by 32. mstore( BatchTransfer1155Params_ids_head_ptr, ERC1155BatchTransferGenericFailure_ids_offset ) // Increase the offset to amounts by 32. mstore( BatchTransfer1155Params_amounts_head_ptr, add( OneWord, mload(BatchTransfer1155Params_amounts_head_ptr) ) ) // Return modified region. The total size stays the same as // `token` uses the same number of bytes as `data.length`. revert(0, transferDataSize) } } // Reset the free memory pointer to the default value; memory must // be assumed to be dirtied and not reused from this point forward. // Also note that the zero slot is not reset to zero, meaning empty // arrays cannot be safely created or utilized until it is restored. mstore(FreeMemoryPointerSlot, DefaultFreeMemoryPointer) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ConduitItemType } from "./ConduitEnums.sol"; /** * @dev A ConduitTransfer is a struct that contains the information needed for a * conduit to transfer an item from one address to another. */ struct ConduitTransfer { ConduitItemType itemType; address token; address from; address to; uint256 identifier; uint256 amount; } /** * @dev A ConduitBatch1155Transfer is a struct that contains the information * needed for a conduit to transfer a batch of ERC-1155 tokens from one * address to another. */ struct ConduitBatch1155Transfer { address token; address from; address to; uint256[] ids; uint256[] amounts; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { OrderParameters } from "./ConsiderationStructs.sol"; import { GettersAndDerivers } from "./GettersAndDerivers.sol"; import { TokenTransferrerErrors } from "../interfaces/TokenTransferrerErrors.sol"; import { CounterManager } from "./CounterManager.sol"; import { AdditionalRecipient_size_shift, AddressDirtyUpperBitThreshold, BasicOrder_additionalRecipients_head_cdPtr, BasicOrder_additionalRecipients_head_ptr, BasicOrder_additionalRecipients_length_cdPtr, BasicOrder_basicOrderType_cdPtr, BasicOrder_basicOrderType_range, BasicOrder_considerationToken_cdPtr, BasicOrder_offerer_cdPtr, BasicOrder_offerToken_cdPtr, BasicOrder_parameters_cdPtr, BasicOrder_parameters_ptr, BasicOrder_signature_cdPtr, BasicOrder_signature_ptr, BasicOrder_zone_cdPtr } from "./ConsiderationConstants.sol"; import { Error_selector_offset, MissingItemAmount_error_length, MissingItemAmount_error_selector } from "./ConsiderationErrorConstants.sol"; import { _revertInvalidBasicOrderParameterEncoding, _revertMissingOriginalConsiderationItems } from "./ConsiderationErrors.sol"; /** * @title Assertions * @author 0age * @notice Assertions contains logic for making various assertions that do not * fit neatly within a dedicated semantic scope. */ contract Assertions is GettersAndDerivers, CounterManager, TokenTransferrerErrors { /** * @dev Derive and set hashes, reference chainId, and associated domain * separator during deployment. * * @param conduitController A contract that deploys conduits, or proxies * that may optionally be used to transfer approved * ERC20/721/1155 tokens. */ constructor( address conduitController ) GettersAndDerivers(conduitController) {} /** * @dev Internal view function to ensure that the supplied consideration * array length on a given set of order parameters is not less than the * original consideration array length for that order and to retrieve * the current counter for a given order's offerer and zone and use it * to derive the order hash. * * @param orderParameters The parameters of the order to hash. * * @return The hash. */ function _assertConsiderationLengthAndGetOrderHash( OrderParameters memory orderParameters ) internal view returns (bytes32) { // Ensure supplied consideration array length is not less than original. _assertConsiderationLengthIsNotLessThanOriginalConsiderationLength( orderParameters.consideration.length, orderParameters.totalOriginalConsiderationItems ); // Derive and return order hash using current counter for the offerer. return _deriveOrderHash( orderParameters, _getCounter(orderParameters.offerer) ); } /** * @dev Internal pure function to ensure that the supplied consideration * array length for an order to be fulfilled is not less than the * original consideration array length for that order. * * @param suppliedConsiderationItemTotal The number of consideration items * supplied when fulfilling the order. * @param originalConsiderationItemTotal The number of consideration items * supplied on initial order creation. */ function _assertConsiderationLengthIsNotLessThanOriginalConsiderationLength( uint256 suppliedConsiderationItemTotal, uint256 originalConsiderationItemTotal ) internal pure { // Ensure supplied consideration array length is not less than original. if (suppliedConsiderationItemTotal < originalConsiderationItemTotal) { _revertMissingOriginalConsiderationItems(); } } /** * @dev Internal pure function to ensure that a given item amount is not * zero. * * @param amount The amount to check. */ function _assertNonZeroAmount(uint256 amount) internal pure { assembly { if iszero(amount) { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, MissingItemAmount_error_selector) // revert(abi.encodeWithSignature("MissingItemAmount()")) revert(Error_selector_offset, MissingItemAmount_error_length) } } } /** * @dev Internal pure function to validate calldata offsets for dynamic * types in BasicOrderParameters and other parameters. This ensures * that functions using the calldata object normally will be using the * same data as the assembly functions and that values that are bound * to a given range are within that range. Note that no parameters are * supplied as all basic order functions use the same calldata * encoding. */ function _assertValidBasicOrderParameters() internal pure { // Declare a boolean designating basic order parameter offset validity. bool validOffsets; // Utilize assembly in order to read offset data directly from calldata. assembly { /* * Checks: * 1. Order parameters struct offset == 0x20 * 2. Additional recipients arr offset == 0x240 * 3. Signature offset == 0x260 + (recipients.length * 0x40) * 4. BasicOrderType between 0 and 23 (i.e. < 24) * 5. Offerer, zone, offer token, and consideration token have no * upper dirty bits — each argument is type(uint160).max or less */ validOffsets := and( and( and( // Order parameters at cd 0x04 must have offset of 0x20. eq( calldataload(BasicOrder_parameters_cdPtr), BasicOrder_parameters_ptr ), // Additional recipients (cd 0x224) arr offset == 0x240. eq( calldataload( BasicOrder_additionalRecipients_head_cdPtr ), BasicOrder_additionalRecipients_head_ptr ) ), // Signature offset == 0x260 + (recipients.length * 0x40). eq( // Load signature offset from calldata 0x244. calldataload(BasicOrder_signature_cdPtr), // Expected offset is start of recipients + len * 64. add( BasicOrder_signature_ptr, shl( // Each additional recipient has length of 0x40. AdditionalRecipient_size_shift, // Additional recipients length at cd 0x264. calldataload( BasicOrder_additionalRecipients_length_cdPtr ) ) ) ) ), and( // Ensure BasicOrderType parameter is less than 0x18. lt( // BasicOrderType parameter at calldata offset 0x124. calldataload(BasicOrder_basicOrderType_cdPtr), // Value should be less than 24. BasicOrder_basicOrderType_range ), // Ensure no dirty upper bits are present on offerer, zone, // offer token, or consideration token. lt( or( or( // Offerer parameter at calldata offset 0x84. calldataload(BasicOrder_offerer_cdPtr), // Zone parameter at calldata offset 0xa4. calldataload(BasicOrder_zone_cdPtr) ), or( // Offer token parameter at cd offset 0xc4. calldataload(BasicOrder_offerToken_cdPtr), // Consideration token parameter at offset 0x24. calldataload( BasicOrder_considerationToken_cdPtr ) ) ), AddressDirtyUpperBitThreshold ) ) ) } // Revert with an error if basic order parameter offsets are invalid. if (!validOffsets) { _revertInvalidBasicOrderParameterEncoding(); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { SignatureVerificationErrors } from "../interfaces/SignatureVerificationErrors.sol"; import { LowLevelHelpers } from "./LowLevelHelpers.sol"; import { ECDSA_MaxLength, ECDSA_signature_s_offset, ECDSA_signature_v_offset, ECDSA_twentySeventhAndTwentyEighthBytesSet, Ecrecover_args_size, Ecrecover_precompile, EIP1271_isValidSignature_calldata_baseLength, EIP1271_isValidSignature_digest_negativeOffset, EIP1271_isValidSignature_selector_negativeOffset, EIP1271_isValidSignature_selector, EIP1271_isValidSignature_signature_head_offset, EIP2098_allButHighestBitMask, MaxUint8, OneWord, Signature_lower_v } from "./ConsiderationConstants.sol"; import { BadContractSignature_error_length, BadContractSignature_error_selector, BadSignatureV_error_length, BadSignatureV_error_selector, BadSignatureV_error_v_ptr, Error_selector_offset, InvalidSignature_error_length, InvalidSignature_error_selector, InvalidSigner_error_length, InvalidSigner_error_selector } from "./ConsiderationErrorConstants.sol"; /** * @title SignatureVerification * @author 0age * @notice SignatureVerification contains logic for verifying signatures. */ contract SignatureVerification is SignatureVerificationErrors, LowLevelHelpers { /** * @dev Internal view function to verify the signature of an order. An * ERC-1271 fallback will be attempted if either the signature length * is not 64 or 65 bytes or if the recovered signer does not match the * supplied signer. * * @param signer The signer for the order. * @param digest The digest to verify signature against. * @param originalDigest The original digest to verify signature * against. * @param originalSignatureLength The original signature length. * @param signature A signature from the signer indicating * that the order has been approved. */ function _assertValidSignature( address signer, bytes32 digest, bytes32 originalDigest, uint256 originalSignatureLength, bytes memory signature ) internal view { // Declare value for ecrecover equality or 1271 call success status. bool success; // Utilize assembly to perform optimized signature verification check. assembly { // Ensure that first word of scratch space is empty. mstore(0, 0) // Get the length of the signature. let signatureLength := mload(signature) // Get the pointer to the value preceding the signature length. // This will be used for temporary memory overrides - either the // signature head for isValidSignature or the digest for ecrecover. let wordBeforeSignaturePtr := sub(signature, OneWord) // Cache the current value behind the signature to restore it later. let cachedWordBeforeSignature := mload(wordBeforeSignaturePtr) // Declare lenDiff + recoveredSigner scope to manage stack pressure. { // Take the difference between the max ECDSA signature length // and the actual signature length. Overflow desired for any // values > 65. If the diff is not 0 or 1, it is not a valid // ECDSA signature - move on to EIP1271 check. let lenDiff := sub(ECDSA_MaxLength, signatureLength) // Declare variable for recovered signer. let recoveredSigner // If diff is 0 or 1, it may be an ECDSA signature. // Try to recover signer. if iszero(gt(lenDiff, 1)) { // Read the signature `s` value. let originalSignatureS := mload( add(signature, ECDSA_signature_s_offset) ) // Read the first byte of the word after `s`. If the // signature is 65 bytes, this will be the real `v` value. // If not, it will need to be modified - doing it this way // saves an extra condition. let v := byte( 0, mload(add(signature, ECDSA_signature_v_offset)) ) // If lenDiff is 1, parse 64-byte signature as ECDSA. if lenDiff { // Extract yParity from highest bit of vs and add 27 to // get v. v := add( shr(MaxUint8, originalSignatureS), Signature_lower_v ) // Extract canonical s from vs, all but the highest bit. // Temporarily overwrite the original `s` value in the // signature. mstore( add(signature, ECDSA_signature_s_offset), and( originalSignatureS, EIP2098_allButHighestBitMask ) ) } // Temporarily overwrite the signature length with `v` to // conform to the expected input for ecrecover. mstore(signature, v) // Temporarily overwrite the word before the length with // `digest` to conform to the expected input for ecrecover. mstore(wordBeforeSignaturePtr, digest) // Attempt to recover the signer for the given signature. Do // not check the call status as ecrecover will return a null // address if the signature is invalid. pop( staticcall( gas(), Ecrecover_precompile, // Call ecrecover precompile. wordBeforeSignaturePtr, // Use data memory location. Ecrecover_args_size, // Size of digest, v, r, and s. 0, // Write result to scratch space. OneWord // Provide size of returned result. ) ) // Restore cached word before signature. mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature) // Restore cached signature length. mstore(signature, signatureLength) // Restore cached signature `s` value. mstore( add(signature, ECDSA_signature_s_offset), originalSignatureS ) // Read the recovered signer from the buffer given as return // space for ecrecover. recoveredSigner := mload(0) } // Set success to true if the signature provided was a valid // ECDSA signature and the signer is not the null address. Use // gt instead of direct as success is used outside of assembly. success := and(eq(signer, recoveredSigner), gt(signer, 0)) } // If the signature was not verified with ecrecover, try EIP1271. if iszero(success) { // Reset the original signature length. mstore(signature, originalSignatureLength) // Temporarily overwrite the word before the signature length // and use it as the head of the signature input to // `isValidSignature`, which has a value of 64. mstore( wordBeforeSignaturePtr, EIP1271_isValidSignature_signature_head_offset ) // Get pointer to use for the selector of `isValidSignature`. let selectorPtr := sub( signature, EIP1271_isValidSignature_selector_negativeOffset ) // Cache the value currently stored at the selector pointer. let cachedWordOverwrittenBySelector := mload(selectorPtr) // Cache the value currently stored at the digest pointer. let cachedWordOverwrittenByDigest := mload( sub( signature, EIP1271_isValidSignature_digest_negativeOffset ) ) // Write the selector first, since it overlaps the digest. mstore(selectorPtr, EIP1271_isValidSignature_selector) // Next, write the original digest. mstore( sub( signature, EIP1271_isValidSignature_digest_negativeOffset ), originalDigest ) // Call signer with `isValidSignature` to validate signature. success := staticcall( gas(), signer, selectorPtr, add( originalSignatureLength, EIP1271_isValidSignature_calldata_baseLength ), 0, OneWord ) // Determine if the signature is valid on successful calls. if success { // If first word of scratch space does not contain EIP-1271 // signature selector, revert. if iszero(eq(mload(0), EIP1271_isValidSignature_selector)) { // Revert with bad 1271 signature if signer has code. if extcodesize(signer) { // Bad contract signature. // Store left-padded selector with push4, mem[28:32] mstore(0, BadContractSignature_error_selector) // revert(abi.encodeWithSignature( // "BadContractSignature()" // )) revert( Error_selector_offset, BadContractSignature_error_length ) } // Check if signature length was invalid. if gt(sub(ECDSA_MaxLength, signatureLength), 1) { // Revert with generic invalid signature error. // Store left-padded selector with push4, mem[28:32] mstore(0, InvalidSignature_error_selector) // revert(abi.encodeWithSignature( // "InvalidSignature()" // )) revert( Error_selector_offset, InvalidSignature_error_length ) } // Check if v was invalid. if and( eq(signatureLength, ECDSA_MaxLength), iszero( byte( byte( 0, mload( add( signature, ECDSA_signature_v_offset ) ) ), ECDSA_twentySeventhAndTwentyEighthBytesSet ) ) ) { // Revert with invalid v value. // Store left-padded selector with push4, mem[28:32] mstore(0, BadSignatureV_error_selector) mstore( BadSignatureV_error_v_ptr, byte( 0, mload( add(signature, ECDSA_signature_v_offset) ) ) ) // revert(abi.encodeWithSignature( // "BadSignatureV(uint8)", v // )) revert( Error_selector_offset, BadSignatureV_error_length ) } // Revert with generic invalid signer error message. // Store left-padded selector with push4, mem[28:32] mstore(0, InvalidSigner_error_selector) // revert(abi.encodeWithSignature("InvalidSigner()")) revert( Error_selector_offset, InvalidSigner_error_length ) } } // Restore the cached values overwritten by selector, digest and // signature head. mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature) mstore(selectorPtr, cachedWordOverwrittenBySelector) mstore( sub( signature, EIP1271_isValidSignature_digest_negativeOffset ), cachedWordOverwrittenByDigest ) } } // If the call failed... if (!success) { // Revert and pass reason along if one was returned. _revertWithReasonIfOneIsReturned(); // Otherwise, revert with error indicating bad contract signature. assembly { // Store left-padded selector with push4, mem[28:32] = selector mstore(0, BadContractSignature_error_selector) // revert(abi.encodeWithSignature("BadContractSignature()")) revert(Error_selector_offset, BadContractSignature_error_length) } } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { OrderParameters } from "./ConsiderationStructs.sol"; import { ConsiderationBase } from "./ConsiderationBase.sol"; import { Create2AddressDerivation_length, Create2AddressDerivation_ptr, EIP_712_PREFIX, EIP712_ConsiderationItem_size, EIP712_DigestPayload_size, EIP712_DomainSeparator_offset, EIP712_OfferItem_size, EIP712_Order_size, EIP712_OrderHash_offset, FreeMemoryPointerSlot, information_conduitController_offset, information_domainSeparator_offset, information_length, information_version_cd_offset, information_version_offset, information_versionLengthPtr, information_versionWithLength, MaskOverByteTwelve, MaskOverLastTwentyBytes, OneWord, OneWordShift, OrderParameters_consideration_head_offset, OrderParameters_counter_offset, OrderParameters_offer_head_offset, TwoWords } from "./ConsiderationConstants.sol"; /** * @title GettersAndDerivers * @author 0age * @notice ConsiderationInternal contains pure and internal view functions * related to getting or deriving various values. */ contract GettersAndDerivers is ConsiderationBase { /** * @dev Derive and set hashes, reference chainId, and associated domain * separator during deployment. * * @param conduitController A contract that deploys conduits, or proxies * that may optionally be used to transfer approved * ERC20/721/1155 tokens. */ constructor( address conduitController ) ConsiderationBase(conduitController) {} /** * @dev Internal view function to derive the order hash for a given order. * Note that only the original consideration items are included in the * order hash, as additional consideration items may be supplied by the * caller. * * @param orderParameters The parameters of the order to hash. * @param counter The counter of the order to hash. * * @return orderHash The hash. */ function _deriveOrderHash( OrderParameters memory orderParameters, uint256 counter ) internal view returns (bytes32 orderHash) { // Get length of original consideration array and place it on the stack. uint256 originalConsiderationLength = ( orderParameters.totalOriginalConsiderationItems ); /* * Memory layout for an array of structs (dynamic or not) is similar * to ABI encoding of dynamic types, with a head segment followed by * a data segment. The main difference is that the head of an element * is a memory pointer rather than an offset. */ // Declare a variable for the derived hash of the offer array. bytes32 offerHash; // Read offer item EIP-712 typehash from runtime code & place on stack. bytes32 typeHash = _OFFER_ITEM_TYPEHASH; // Utilize assembly so that memory regions can be reused across hashes. assembly { // Retrieve the free memory pointer and place on the stack. let hashArrPtr := mload(FreeMemoryPointerSlot) // Get the pointer to the offers array. let offerArrPtr := mload( add(orderParameters, OrderParameters_offer_head_offset) ) // Load the length. let offerLength := mload(offerArrPtr) // Set the pointer to the first offer's head. offerArrPtr := add(offerArrPtr, OneWord) // Iterate over the offer items. for { let i := 0 } lt(i, offerLength) { i := add(i, 1) } { // Read the pointer to the offer data and subtract one word // to get typeHash pointer. let ptr := sub(mload(offerArrPtr), OneWord) // Read the current value before the offer data. let value := mload(ptr) // Write the type hash to the previous word. mstore(ptr, typeHash) // Take the EIP712 hash and store it in the hash array. mstore(hashArrPtr, keccak256(ptr, EIP712_OfferItem_size)) // Restore the previous word. mstore(ptr, value) // Increment the array pointers by one word. offerArrPtr := add(offerArrPtr, OneWord) hashArrPtr := add(hashArrPtr, OneWord) } // Derive the offer hash using the hashes of each item. offerHash := keccak256( mload(FreeMemoryPointerSlot), shl(OneWordShift, offerLength) ) } // Declare a variable for the derived hash of the consideration array. bytes32 considerationHash; // Read consideration item typehash from runtime code & place on stack. typeHash = _CONSIDERATION_ITEM_TYPEHASH; // Utilize assembly so that memory regions can be reused across hashes. assembly { // Retrieve the free memory pointer and place on the stack. let hashArrPtr := mload(FreeMemoryPointerSlot) // Get the pointer to the consideration array. let considerationArrPtr := add( mload( add( orderParameters, OrderParameters_consideration_head_offset ) ), OneWord ) // Iterate over the consideration items (not including tips). for { let i := 0 } lt(i, originalConsiderationLength) { i := add(i, 1) } { // Read the pointer to the consideration data and subtract one // word to get typeHash pointer. let ptr := sub(mload(considerationArrPtr), OneWord) // Read the current value before the consideration data. let value := mload(ptr) // Write the type hash to the previous word. mstore(ptr, typeHash) // Take the EIP712 hash and store it in the hash array. mstore( hashArrPtr, keccak256(ptr, EIP712_ConsiderationItem_size) ) // Restore the previous word. mstore(ptr, value) // Increment the array pointers by one word. considerationArrPtr := add(considerationArrPtr, OneWord) hashArrPtr := add(hashArrPtr, OneWord) } // Derive the consideration hash using the hashes of each item. considerationHash := keccak256( mload(FreeMemoryPointerSlot), shl(OneWordShift, originalConsiderationLength) ) } // Read order item EIP-712 typehash from runtime code & place on stack. typeHash = _ORDER_TYPEHASH; // Utilize assembly to access derived hashes & other arguments directly. assembly { // Retrieve pointer to the region located just behind parameters. let typeHashPtr := sub(orderParameters, OneWord) // Store the value at that pointer location to restore later. let previousValue := mload(typeHashPtr) // Store the order item EIP-712 typehash at the typehash location. mstore(typeHashPtr, typeHash) // Retrieve the pointer for the offer array head. let offerHeadPtr := add( orderParameters, OrderParameters_offer_head_offset ) // Retrieve the data pointer referenced by the offer head. let offerDataPtr := mload(offerHeadPtr) // Store the offer hash at the retrieved memory location. mstore(offerHeadPtr, offerHash) // Retrieve the pointer for the consideration array head. let considerationHeadPtr := add( orderParameters, OrderParameters_consideration_head_offset ) // Retrieve the data pointer referenced by the consideration head. let considerationDataPtr := mload(considerationHeadPtr) // Store the consideration hash at the retrieved memory location. mstore(considerationHeadPtr, considerationHash) // Retrieve the pointer for the counter. let counterPtr := add( orderParameters, OrderParameters_counter_offset ) // Store the counter at the retrieved memory location. mstore(counterPtr, counter) // Derive the order hash using the full range of order parameters. orderHash := keccak256(typeHashPtr, EIP712_Order_size) // Restore the value previously held at typehash pointer location. mstore(typeHashPtr, previousValue) // Restore offer data pointer at the offer head pointer location. mstore(offerHeadPtr, offerDataPtr) // Restore consideration data pointer at the consideration head ptr. mstore(considerationHeadPtr, considerationDataPtr) // Restore consideration item length at the counter pointer. mstore(counterPtr, originalConsiderationLength) } } /** * @dev Internal view function to derive the address of a given conduit * using a corresponding conduit key. * * @param conduitKey A bytes32 value indicating what corresponding conduit, * if any, to source token approvals from. This value is * the "salt" parameter supplied by the deployer (i.e. the * conduit controller) when deploying the given conduit. * * @return conduit The address of the conduit associated with the given * conduit key. */ function _deriveConduit( bytes32 conduitKey ) internal view returns (address conduit) { // Read conduit controller address from runtime and place on the stack. address conduitController = address(_CONDUIT_CONTROLLER); // Read conduit creation code hash from runtime and place on the stack. bytes32 conduitCreationCodeHash = _CONDUIT_CREATION_CODE_HASH; // Leverage scratch space to perform an efficient hash. assembly { // Retrieve the free memory pointer; it will be replaced afterwards. let freeMemoryPointer := mload(FreeMemoryPointerSlot) // Place the control character and the conduit controller in scratch // space; note that eleven bytes at the beginning are left unused. mstore(0, or(MaskOverByteTwelve, conduitController)) // Place the conduit key in the next region of scratch space. mstore(OneWord, conduitKey) // Place conduit creation code hash in free memory pointer location. mstore(TwoWords, conduitCreationCodeHash) // Derive conduit by hashing and applying a mask over last 20 bytes. conduit := and( // Hash the relevant region. keccak256( // The region starts at memory pointer 11. Create2AddressDerivation_ptr, // The region is 85 bytes long (1 + 20 + 32 + 32). Create2AddressDerivation_length ), // The address equals the last twenty bytes of the hash. MaskOverLastTwentyBytes ) // Restore the free memory pointer. mstore(FreeMemoryPointerSlot, freeMemoryPointer) } } /** * @dev Internal view function to get the EIP-712 domain separator. If the * chainId matches the chainId set on deployment, the cached domain * separator will be returned; otherwise, it will be derived from * scratch. * * @return The domain separator. */ function _domainSeparator() internal view returns (bytes32) { return block.chainid == _CHAIN_ID ? _DOMAIN_SEPARATOR : _deriveDomainSeparator(); } /** * @dev Internal view function to retrieve configuration information for * this contract. * * @return The contract version. * @return The domain separator for this contract. * @return The conduit Controller set for this contract. */ function _information() internal view returns ( string memory /* version */, bytes32 /* domainSeparator */, address /* conduitController */ ) { // Derive the domain separator. bytes32 domainSeparator = _domainSeparator(); // Declare variable as immutables cannot be accessed within assembly. address conduitController = address(_CONDUIT_CONTROLLER); // Return the version, domain separator, and conduit controller. assembly { mstore(information_version_offset, information_version_cd_offset) mstore(information_domainSeparator_offset, domainSeparator) mstore(information_conduitController_offset, conduitController) mstore(information_versionLengthPtr, information_versionWithLength) return(information_version_offset, information_length) } } /** * @dev Internal pure function to efficiently derive an digest to sign for * an order in accordance with EIP-712. * * @param domainSeparator The domain separator. * @param orderHash The order hash. * * @return value The hash. */ function _deriveEIP712Digest( bytes32 domainSeparator, bytes32 orderHash ) internal pure returns (bytes32 value) { // Leverage scratch space to perform an efficient hash. assembly { // Place the EIP-712 prefix at the start of scratch space. mstore(0, EIP_712_PREFIX) // Place the domain separator in the next region of scratch space. mstore(EIP712_DomainSeparator_offset, domainSeparator) // Place the order hash in scratch space, spilling into the first // two bytes of the free memory pointer — this should never be set // as memory cannot be expanded to that size, and will be zeroed out // after the hash is performed. mstore(EIP712_OrderHash_offset, orderHash) // Hash the relevant region (65 bytes). value := keccak256(0, EIP712_DigestPayload_size) // Clear out the dirtied bits in the memory pointer. mstore(EIP712_OrderHash_offset, 0) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @title TokenTransferrerErrors */ interface TokenTransferrerErrors { /** * @dev Revert with an error when an ERC721 transfer with amount other than * one is attempted. * * @param amount The amount of the ERC721 tokens to transfer. */ error InvalidERC721TransferAmount(uint256 amount); /** * @dev Revert with an error when attempting to fulfill an order where an * item has an amount of zero. */ error MissingItemAmount(); /** * @dev Revert with an error when attempting to fulfill an order where an * item has unused parameters. This includes both the token and the * identifier parameters for native transfers as well as the identifier * parameter for ERC20 transfers. Note that the conduit does not * perform this check, leaving it up to the calling channel to enforce * when desired. */ error UnusedItemParameters(); /** * @dev Revert with an error when an ERC20, ERC721, or ERC1155 token * transfer reverts. * * @param token The token for which the transfer was attempted. * @param from The source of the attempted transfer. * @param to The recipient of the attempted transfer. * @param identifier The identifier for the attempted transfer. * @param amount The amount for the attempted transfer. */ error TokenTransferGenericFailure( address token, address from, address to, uint256 identifier, uint256 amount ); /** * @dev Revert with an error when a batch ERC1155 token transfer reverts. * * @param token The token for which the transfer was attempted. * @param from The source of the attempted transfer. * @param to The recipient of the attempted transfer. * @param identifiers The identifiers for the attempted transfer. * @param amounts The amounts for the attempted transfer. */ error ERC1155BatchTransferGenericFailure( address token, address from, address to, uint256[] identifiers, uint256[] amounts ); /** * @dev Revert with an error when an ERC20 token transfer returns a falsey * value. * * @param token The token for which the ERC20 transfer was attempted. * @param from The source of the attempted ERC20 transfer. * @param to The recipient of the attempted ERC20 transfer. * @param amount The amount for the attempted ERC20 transfer. */ error BadReturnValueFromERC20OnTransfer( address token, address from, address to, uint256 amount ); /** * @dev Revert with an error when an account being called as an assumed * contract does not have code and returns no data. * * @param account The account that should contain code. */ error NoContract(address account); /** * @dev Revert with an error when attempting to execute an 1155 batch * transfer using calldata not produced by default ABI encoding or with * different lengths for ids and amounts arrays. */ error Invalid1155BatchTransferEncoding(); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { ConsiderationEventsAndErrors } from "../interfaces/ConsiderationEventsAndErrors.sol"; import { ReentrancyGuard } from "./ReentrancyGuard.sol"; import { Counter_blockhash_shift, OneWord, TwoWords } from "./ConsiderationConstants.sol"; /** * @title CounterManager * @author 0age * @notice CounterManager contains a storage mapping and related functionality * for retrieving and incrementing a per-offerer counter. */ contract CounterManager is ConsiderationEventsAndErrors, ReentrancyGuard { // Only orders signed using an offerer's current counter are fulfillable. mapping(address => uint256) private _counters; /** * @dev Internal function to cancel all orders from a given offerer in bulk * by incrementing a counter by a large, quasi-random interval. Note * that only the offerer may increment the counter. Note that the * counter is incremented by a large, quasi-random interval, which * makes it infeasible to "activate" signed orders by incrementing the * counter. This activation functionality can be achieved instead with * restricted orders or contract orders. * * @return newCounter The new counter. */ function _incrementCounter() internal returns (uint256 newCounter) { // Ensure that the reentrancy guard is not currently set. _assertNonReentrant(); // Utilize assembly to access counters storage mapping directly. Skip // overflow check as counter cannot be incremented that far. assembly { // Use second half of previous block hash as a quasi-random number. let quasiRandomNumber := shr( Counter_blockhash_shift, blockhash(sub(number(), 1)) ) // Write the caller to scratch space. mstore(0, caller()) // Write the storage slot for _counters to scratch space. mstore(OneWord, _counters.slot) // Derive the storage pointer for the counter value. let storagePointer := keccak256(0, TwoWords) // Derive new counter value using random number and original value. newCounter := add(quasiRandomNumber, sload(storagePointer)) // Store the updated counter value. sstore(storagePointer, newCounter) } // Emit an event containing the new counter. emit CounterIncremented(newCounter, msg.sender); } /** * @dev Internal view function to retrieve the current counter for a given * offerer. * * @param offerer The offerer in question. * * @return currentCounter The current counter. */ function _getCounter( address offerer ) internal view returns (uint256 currentCounter) { // Return the counter for the supplied offerer. currentCounter = _counters[offerer]; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { ConduitControllerInterface } from "../interfaces/ConduitControllerInterface.sol"; import { ConsiderationEventsAndErrors } from "../interfaces/ConsiderationEventsAndErrors.sol"; import { BulkOrder_Typehash_Height_One, BulkOrder_Typehash_Height_Two, BulkOrder_Typehash_Height_Three, BulkOrder_Typehash_Height_Four, BulkOrder_Typehash_Height_Five, BulkOrder_Typehash_Height_Six, BulkOrder_Typehash_Height_Seven, BulkOrder_Typehash_Height_Eight, BulkOrder_Typehash_Height_Nine, BulkOrder_Typehash_Height_Ten, BulkOrder_Typehash_Height_Eleven, BulkOrder_Typehash_Height_Twelve, BulkOrder_Typehash_Height_Thirteen, BulkOrder_Typehash_Height_Fourteen, BulkOrder_Typehash_Height_Fifteen, BulkOrder_Typehash_Height_Sixteen, BulkOrder_Typehash_Height_Seventeen, BulkOrder_Typehash_Height_Eighteen, BulkOrder_Typehash_Height_Nineteen, BulkOrder_Typehash_Height_Twenty, BulkOrder_Typehash_Height_TwentyOne, BulkOrder_Typehash_Height_TwentyTwo, BulkOrder_Typehash_Height_TwentyThree, BulkOrder_Typehash_Height_TwentyFour, EIP712_domainData_chainId_offset, EIP712_domainData_nameHash_offset, EIP712_domainData_size, EIP712_domainData_verifyingContract_offset, EIP712_domainData_versionHash_offset, FreeMemoryPointerSlot, NameLengthPtr, NameWithLength, OneWord, OneWordShift, Slot0x80, ThreeWords, ZeroSlot } from "./ConsiderationConstants.sol"; import { ConsiderationDecoder } from "./ConsiderationDecoder.sol"; import { ConsiderationEncoder } from "./ConsiderationEncoder.sol"; /** * @title ConsiderationBase * @author 0age * @notice ConsiderationBase contains immutable constants and constructor logic. */ contract ConsiderationBase is ConsiderationDecoder, ConsiderationEncoder, ConsiderationEventsAndErrors { // Precompute hashes, original chainId, and domain separator on deployment. bytes32 internal immutable _NAME_HASH; bytes32 internal immutable _VERSION_HASH; bytes32 internal immutable _EIP_712_DOMAIN_TYPEHASH; bytes32 internal immutable _OFFER_ITEM_TYPEHASH; bytes32 internal immutable _CONSIDERATION_ITEM_TYPEHASH; bytes32 internal immutable _ORDER_TYPEHASH; uint256 internal immutable _CHAIN_ID; bytes32 internal immutable _DOMAIN_SEPARATOR; // Allow for interaction with the conduit controller. ConduitControllerInterface internal immutable _CONDUIT_CONTROLLER; // Cache the conduit creation code hash used by the conduit controller. bytes32 internal immutable _CONDUIT_CREATION_CODE_HASH; /** * @dev Derive and set hashes, reference chainId, and associated domain * separator during deployment. * * @param conduitController A contract that deploys conduits, or proxies * that may optionally be used to transfer approved * ERC20/721/1155 tokens. */ constructor(address conduitController) { // Derive name and version hashes alongside required EIP-712 typehashes. ( _NAME_HASH, _VERSION_HASH, _EIP_712_DOMAIN_TYPEHASH, _OFFER_ITEM_TYPEHASH, _CONSIDERATION_ITEM_TYPEHASH, _ORDER_TYPEHASH ) = _deriveTypehashes(); // Store the current chainId and derive the current domain separator. _CHAIN_ID = block.chainid; _DOMAIN_SEPARATOR = _deriveDomainSeparator(); // Set the supplied conduit controller. _CONDUIT_CONTROLLER = ConduitControllerInterface(conduitController); // Retrieve the conduit creation code hash from the supplied controller. (_CONDUIT_CREATION_CODE_HASH, ) = ( _CONDUIT_CONTROLLER.getConduitCodeHashes() ); } /** * @dev Internal view function to derive the EIP-712 domain separator. * * @return domainSeparator The derived domain separator. */ function _deriveDomainSeparator() internal view returns (bytes32 domainSeparator) { bytes32 typehash = _EIP_712_DOMAIN_TYPEHASH; bytes32 nameHash = _NAME_HASH; bytes32 versionHash = _VERSION_HASH; // Leverage scratch space and other memory to perform an efficient hash. assembly { // Retrieve the free memory pointer; it will be replaced afterwards. let freeMemoryPointer := mload(FreeMemoryPointerSlot) // Retrieve value at 0x80; it will also be replaced afterwards. let slot0x80 := mload(Slot0x80) // Place typehash, name hash, and version hash at start of memory. mstore(0, typehash) mstore(EIP712_domainData_nameHash_offset, nameHash) mstore(EIP712_domainData_versionHash_offset, versionHash) // Place chainId in the next memory location. mstore(EIP712_domainData_chainId_offset, chainid()) // Place the address of this contract in the next memory location. mstore(EIP712_domainData_verifyingContract_offset, address()) // Hash relevant region of memory to derive the domain separator. domainSeparator := keccak256(0, EIP712_domainData_size) // Restore the free memory pointer. mstore(FreeMemoryPointerSlot, freeMemoryPointer) // Restore the zero slot to zero. mstore(ZeroSlot, 0) // Restore the value at 0x80. mstore(Slot0x80, slot0x80) } } /** * @dev Internal pure function to retrieve the default name of this * contract and return. * * @return The name of this contract. */ function _name() internal pure virtual returns (string memory) { // Return the name of the contract. assembly { // First element is the offset for the returned string. Offset the // value in memory by one word so that the free memory pointer will // be overwritten by the next write. mstore(OneWord, OneWord) // Name is right padded, so it touches the length which is left // padded. This enables writing both values at once. The free memory // pointer will be overwritten in the process. mstore(NameLengthPtr, NameWithLength) // Standard ABI encoding pads returned data to the nearest word. Use // the already empty zero slot memory region for this purpose and // return the final name string, offset by the original single word. return(OneWord, ThreeWords) } } /** * @dev Internal pure function to retrieve the default name of this contract * as a string that can be used internally. * * @return The name of this contract. */ function _nameString() internal pure virtual returns (string memory) { // Return the name of the contract. return "Consideration"; } /** * @dev Internal pure function to derive required EIP-712 typehashes and * other hashes during contract creation. * * @return nameHash The hash of the name of the contract. * @return versionHash The hash of the version string of the * contract. * @return eip712DomainTypehash The primary EIP-712 domain typehash. * @return offerItemTypehash The EIP-712 typehash for OfferItem * types. * @return considerationItemTypehash The EIP-712 typehash for * ConsiderationItem types. * @return orderTypehash The EIP-712 typehash for Order types. */ function _deriveTypehashes() internal pure returns ( bytes32 nameHash, bytes32 versionHash, bytes32 eip712DomainTypehash, bytes32 offerItemTypehash, bytes32 considerationItemTypehash, bytes32 orderTypehash ) { // Derive hash of the name of the contract. nameHash = keccak256(bytes(_nameString())); // Derive hash of the version string of the contract. versionHash = keccak256(bytes("1.4")); // Construct the OfferItem type string. bytes memory offerItemTypeString = bytes( "OfferItem(" "uint8 itemType," "address token," "uint256 identifierOrCriteria," "uint256 startAmount," "uint256 endAmount" ")" ); // Construct the ConsiderationItem type string. bytes memory considerationItemTypeString = bytes( "ConsiderationItem(" "uint8 itemType," "address token," "uint256 identifierOrCriteria," "uint256 startAmount," "uint256 endAmount," "address recipient" ")" ); // Construct the OrderComponents type string, not including the above. bytes memory orderComponentsPartialTypeString = bytes( "OrderComponents(" "address offerer," "address zone," "OfferItem[] offer," "ConsiderationItem[] consideration," "uint8 orderType," "uint256 startTime," "uint256 endTime," "bytes32 zoneHash," "uint256 salt," "bytes32 conduitKey," "uint256 counter" ")" ); // Construct the primary EIP-712 domain type string. eip712DomainTypehash = keccak256( bytes( "EIP712Domain(" "string name," "string version," "uint256 chainId," "address verifyingContract" ")" ) ); // Derive the OfferItem type hash using the corresponding type string. offerItemTypehash = keccak256(offerItemTypeString); // Derive ConsiderationItem type hash using corresponding type string. considerationItemTypehash = keccak256(considerationItemTypeString); bytes memory orderTypeString = bytes.concat( orderComponentsPartialTypeString, considerationItemTypeString, offerItemTypeString ); // Derive OrderItem type hash via combination of relevant type strings. orderTypehash = keccak256(orderTypeString); } /** * @dev Internal pure function to look up one of twenty-four potential bulk * order typehash constants based on the height of the bulk order tree. * Note that values between one and twenty-four are supported, which is * enforced by _isValidBulkOrderSize. * * @param _treeHeight The height of the bulk order tree. The value must be * between one and twenty-four. * * @return _typeHash The EIP-712 typehash for the bulk order type with the * given height. */ function _lookupBulkOrderTypehash( uint256 _treeHeight ) internal pure returns (bytes32 _typeHash) { // Utilize assembly to efficiently retrieve correct bulk order typehash. assembly { // Use a Yul function to enable use of the `leave` keyword // to stop searching once the appropriate type hash is found. function lookupTypeHash(treeHeight) -> typeHash { // Handle tree heights one through eight. if lt(treeHeight, 9) { // Handle tree heights one through four. if lt(treeHeight, 5) { // Handle tree heights one and two. if lt(treeHeight, 3) { // Utilize branchless logic to determine typehash. typeHash := ternary( eq(treeHeight, 1), BulkOrder_Typehash_Height_One, BulkOrder_Typehash_Height_Two ) // Exit the function once typehash has been located. leave } // Handle height three and four via branchless logic. typeHash := ternary( eq(treeHeight, 3), BulkOrder_Typehash_Height_Three, BulkOrder_Typehash_Height_Four ) // Exit the function once typehash has been located. leave } // Handle tree height five and six. if lt(treeHeight, 7) { // Utilize branchless logic to determine typehash. typeHash := ternary( eq(treeHeight, 5), BulkOrder_Typehash_Height_Five, BulkOrder_Typehash_Height_Six ) // Exit the function once typehash has been located. leave } // Handle height seven and eight via branchless logic. typeHash := ternary( eq(treeHeight, 7), BulkOrder_Typehash_Height_Seven, BulkOrder_Typehash_Height_Eight ) // Exit the function once typehash has been located. leave } // Handle tree height nine through sixteen. if lt(treeHeight, 17) { // Handle tree height nine through twelve. if lt(treeHeight, 13) { // Handle tree height nine and ten. if lt(treeHeight, 11) { // Utilize branchless logic to determine typehash. typeHash := ternary( eq(treeHeight, 9), BulkOrder_Typehash_Height_Nine, BulkOrder_Typehash_Height_Ten ) // Exit the function once typehash has been located. leave } // Handle height eleven and twelve via branchless logic. typeHash := ternary( eq(treeHeight, 11), BulkOrder_Typehash_Height_Eleven, BulkOrder_Typehash_Height_Twelve ) // Exit the function once typehash has been located. leave } // Handle tree height thirteen and fourteen. if lt(treeHeight, 15) { // Utilize branchless logic to determine typehash. typeHash := ternary( eq(treeHeight, 13), BulkOrder_Typehash_Height_Thirteen, BulkOrder_Typehash_Height_Fourteen ) // Exit the function once typehash has been located. leave } // Handle height fifteen and sixteen via branchless logic. typeHash := ternary( eq(treeHeight, 15), BulkOrder_Typehash_Height_Fifteen, BulkOrder_Typehash_Height_Sixteen ) // Exit the function once typehash has been located. leave } // Handle tree height seventeen through twenty. if lt(treeHeight, 21) { // Handle tree height seventeen and eighteen. if lt(treeHeight, 19) { // Utilize branchless logic to determine typehash. typeHash := ternary( eq(treeHeight, 17), BulkOrder_Typehash_Height_Seventeen, BulkOrder_Typehash_Height_Eighteen ) // Exit the function once typehash has been located. leave } // Handle height nineteen and twenty via branchless logic. typeHash := ternary( eq(treeHeight, 19), BulkOrder_Typehash_Height_Nineteen, BulkOrder_Typehash_Height_Twenty ) // Exit the function once typehash has been located. leave } // Handle tree height twenty-one and twenty-two. if lt(treeHeight, 23) { // Utilize branchless logic to determine typehash. typeHash := ternary( eq(treeHeight, 21), BulkOrder_Typehash_Height_TwentyOne, BulkOrder_Typehash_Height_TwentyTwo ) // Exit the function once typehash has been located. leave } // Handle height twenty-three & twenty-four w/ branchless logic. typeHash := ternary( eq(treeHeight, 23), BulkOrder_Typehash_Height_TwentyThree, BulkOrder_Typehash_Height_TwentyFour ) // Exit the function once typehash has been located. leave } // Implement ternary conditional using branchless logic. function ternary(cond, ifTrue, ifFalse) -> c { c := xor(ifFalse, mul(cond, xor(ifFalse, ifTrue))) } // Look up the typehash using the supplied tree height. _typeHash := lookupTypeHash(_treeHeight) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @title ConduitControllerInterface * @author 0age * @notice ConduitControllerInterface contains all external function interfaces, * structs, events, and errors for the conduit controller. */ interface ConduitControllerInterface { /** * @dev Track the conduit key, current owner, new potential owner, and open * channels for each deployed conduit. */ struct ConduitProperties { bytes32 key; address owner; address potentialOwner; address[] channels; mapping(address => uint256) channelIndexesPlusOne; } /** * @dev Emit an event whenever a new conduit is created. * * @param conduit The newly created conduit. * @param conduitKey The conduit key used to create the new conduit. */ event NewConduit(address conduit, bytes32 conduitKey); /** * @dev Emit an event whenever conduit ownership is transferred. * * @param conduit The conduit for which ownership has been * transferred. * @param previousOwner The previous owner of the conduit. * @param newOwner The new owner of the conduit. */ event OwnershipTransferred( address indexed conduit, address indexed previousOwner, address indexed newOwner ); /** * @dev Emit an event whenever a conduit owner registers a new potential * owner for that conduit. * * @param newPotentialOwner The new potential owner of the conduit. */ event PotentialOwnerUpdated(address indexed newPotentialOwner); /** * @dev Revert with an error when attempting to create a new conduit using a * conduit key where the first twenty bytes of the key do not match the * address of the caller. */ error InvalidCreator(); /** * @dev Revert with an error when attempting to create a new conduit when no * initial owner address is supplied. */ error InvalidInitialOwner(); /** * @dev Revert with an error when attempting to set a new potential owner * that is already set. */ error NewPotentialOwnerAlreadySet( address conduit, address newPotentialOwner ); /** * @dev Revert with an error when attempting to cancel ownership transfer * when no new potential owner is currently set. */ error NoPotentialOwnerCurrentlySet(address conduit); /** * @dev Revert with an error when attempting to interact with a conduit that * does not yet exist. */ error NoConduit(); /** * @dev Revert with an error when attempting to create a conduit that * already exists. */ error ConduitAlreadyExists(address conduit); /** * @dev Revert with an error when attempting to update channels or transfer * ownership of a conduit when the caller is not the owner of the * conduit in question. */ error CallerIsNotOwner(address conduit); /** * @dev Revert with an error when attempting to register a new potential * owner and supplying the null address. */ error NewPotentialOwnerIsZeroAddress(address conduit); /** * @dev Revert with an error when attempting to claim ownership of a conduit * with a caller that is not the current potential owner for the * conduit in question. */ error CallerIsNotNewPotentialOwner(address conduit); /** * @dev Revert with an error when attempting to retrieve a channel using an * index that is out of range. */ error ChannelOutOfRange(address conduit); /** * @notice Deploy a new conduit using a supplied conduit key and assigning * an initial owner for the deployed conduit. Note that the first * twenty bytes of the supplied conduit key must match the caller * and that a new conduit cannot be created if one has already been * deployed using the same conduit key. * * @param conduitKey The conduit key used to deploy the conduit. Note that * the first twenty bytes of the conduit key must match * the caller of this contract. * @param initialOwner The initial owner to set for the new conduit. * * @return conduit The address of the newly deployed conduit. */ function createConduit( bytes32 conduitKey, address initialOwner ) external returns (address conduit); /** * @notice Open or close a channel on a given conduit, thereby allowing the * specified account to execute transfers against that conduit. * Extreme care must be taken when updating channels, as malicious * or vulnerable channels can transfer any ERC20, ERC721 and ERC1155 * tokens where the token holder has granted the conduit approval. * Only the owner of the conduit in question may call this function. * * @param conduit The conduit for which to open or close the channel. * @param channel The channel to open or close on the conduit. * @param isOpen A boolean indicating whether to open or close the channel. */ function updateChannel( address conduit, address channel, bool isOpen ) external; /** * @notice Initiate conduit ownership transfer by assigning a new potential * owner for the given conduit. Once set, the new potential owner * may call `acceptOwnership` to claim ownership of the conduit. * Only the owner of the conduit in question may call this function. * * @param conduit The conduit for which to initiate ownership transfer. * @param newPotentialOwner The new potential owner of the conduit. */ function transferOwnership( address conduit, address newPotentialOwner ) external; /** * @notice Clear the currently set potential owner, if any, from a conduit. * Only the owner of the conduit in question may call this function. * * @param conduit The conduit for which to cancel ownership transfer. */ function cancelOwnershipTransfer(address conduit) external; /** * @notice Accept ownership of a supplied conduit. Only accounts that the * current owner has set as the new potential owner may call this * function. * * @param conduit The conduit for which to accept ownership. */ function acceptOwnership(address conduit) external; /** * @notice Retrieve the current owner of a deployed conduit. * * @param conduit The conduit for which to retrieve the associated owner. * * @return owner The owner of the supplied conduit. */ function ownerOf(address conduit) external view returns (address owner); /** * @notice Retrieve the conduit key for a deployed conduit via reverse * lookup. * * @param conduit The conduit for which to retrieve the associated conduit * key. * * @return conduitKey The conduit key used to deploy the supplied conduit. */ function getKey(address conduit) external view returns (bytes32 conduitKey); /** * @notice Derive the conduit associated with a given conduit key and * determine whether that conduit exists (i.e. whether it has been * deployed). * * @param conduitKey The conduit key used to derive the conduit. * * @return conduit The derived address of the conduit. * @return exists A boolean indicating whether the derived conduit has been * deployed or not. */ function getConduit( bytes32 conduitKey ) external view returns (address conduit, bool exists); /** * @notice Retrieve the potential owner, if any, for a given conduit. The * current owner may set a new potential owner via * `transferOwnership` and that owner may then accept ownership of * the conduit in question via `acceptOwnership`. * * @param conduit The conduit for which to retrieve the potential owner. * * @return potentialOwner The potential owner, if any, for the conduit. */ function getPotentialOwner( address conduit ) external view returns (address potentialOwner); /** * @notice Retrieve the status (either open or closed) of a given channel on * a conduit. * * @param conduit The conduit for which to retrieve the channel status. * @param channel The channel for which to retrieve the status. * * @return isOpen The status of the channel on the given conduit. */ function getChannelStatus( address conduit, address channel ) external view returns (bool isOpen); /** * @notice Retrieve the total number of open channels for a given conduit. * * @param conduit The conduit for which to retrieve the total channel count. * * @return totalChannels The total number of open channels for the conduit. */ function getTotalChannels( address conduit ) external view returns (uint256 totalChannels); /** * @notice Retrieve an open channel at a specific index for a given conduit. * Note that the index of a channel can change as a result of other * channels being closed on the conduit. * * @param conduit The conduit for which to retrieve the open channel. * @param channelIndex The index of the channel in question. * * @return channel The open channel, if any, at the specified channel index. */ function getChannel( address conduit, uint256 channelIndex ) external view returns (address channel); /** * @notice Retrieve all open channels for a given conduit. Note that calling * this function for a conduit with many channels will revert with * an out-of-gas error. * * @param conduit The conduit for which to retrieve open channels. * * @return channels An array of open channels on the given conduit. */ function getChannels( address conduit ) external view returns (address[] memory channels); /** * @dev Retrieve the conduit creation code and runtime code hashes. */ function getConduitCodeHashes() external view returns (bytes32 creationCodeHash, bytes32 runtimeCodeHash); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { OrderParameters, ReceivedItem, SpentItem } from "../lib/ConsiderationStructs.sol"; /** * @title ConsiderationEventsAndErrors * @author 0age * @notice ConsiderationEventsAndErrors contains all events and errors. */ interface ConsiderationEventsAndErrors { /** * @dev Emit an event whenever an order is successfully fulfilled. * * @param orderHash The hash of the fulfilled order. * @param offerer The offerer of the fulfilled order. * @param zone The zone of the fulfilled order. * @param recipient The recipient of each spent item on the fulfilled * order, or the null address if there is no specific * fulfiller (i.e. the order is part of a group of * orders). Defaults to the caller unless explicitly * specified otherwise by the fulfiller. * @param offer The offer items spent as part of the order. * @param consideration The consideration items received as part of the * order along with the recipients of each item. */ event OrderFulfilled( bytes32 orderHash, address indexed offerer, address indexed zone, address recipient, SpentItem[] offer, ReceivedItem[] consideration ); /** * @dev Emit an event whenever an order is successfully cancelled. * * @param orderHash The hash of the cancelled order. * @param offerer The offerer of the cancelled order. * @param zone The zone of the cancelled order. */ event OrderCancelled( bytes32 orderHash, address indexed offerer, address indexed zone ); /** * @dev Emit an event whenever an order is explicitly validated. Note that * this event will not be emitted on partial fills even though they do * validate the order as part of partial fulfillment. * * @param orderHash The hash of the validated order. * @param orderParameters The parameters of the validated order. */ event OrderValidated(bytes32 orderHash, OrderParameters orderParameters); /** * @dev Emit an event whenever one or more orders are matched using either * matchOrders or matchAdvancedOrders. * * @param orderHashes The order hashes of the matched orders. */ event OrdersMatched(bytes32[] orderHashes); /** * @dev Emit an event whenever a counter for a given offerer is incremented. * * @param newCounter The new counter for the offerer. * @param offerer The offerer in question. */ event CounterIncremented(uint256 newCounter, address indexed offerer); /** * @dev Revert with an error when attempting to fill an order that has * already been fully filled. * * @param orderHash The order hash on which a fill was attempted. */ error OrderAlreadyFilled(bytes32 orderHash); /** * @dev Revert with an error when attempting to fill an order outside the * specified start time and end time. * * @param startTime The time at which the order becomes active. * @param endTime The time at which the order becomes inactive. */ error InvalidTime(uint256 startTime, uint256 endTime); /** * @dev Revert with an error when attempting to fill an order referencing an * invalid conduit (i.e. one that has not been deployed). */ error InvalidConduit(bytes32 conduitKey, address conduit); /** * @dev Revert with an error when an order is supplied for fulfillment with * a consideration array that is shorter than the original array. */ error MissingOriginalConsiderationItems(); /** * @dev Revert with an error when an order is validated and the length of * the consideration array is not equal to the supplied total original * consideration items value. This error is also thrown when contract * orders supply a total original consideration items value that does * not match the supplied consideration array length. */ error ConsiderationLengthNotEqualToTotalOriginal(); /** * @dev Revert with an error when a call to a conduit fails with revert data * that is too expensive to return. */ error InvalidCallToConduit(address conduit); /** * @dev Revert with an error if a consideration amount has not been fully * zeroed out after applying all fulfillments. * * @param orderIndex The index of the order with the consideration * item with a shortfall. * @param considerationIndex The index of the consideration item on the * order. * @param shortfallAmount The unfulfilled consideration amount. */ error ConsiderationNotMet( uint256 orderIndex, uint256 considerationIndex, uint256 shortfallAmount ); /** * @dev Revert with an error when insufficient native tokens are supplied as * part of msg.value when fulfilling orders. */ error InsufficientNativeTokensSupplied(); /** * @dev Revert with an error when a native token transfer reverts. */ error NativeTokenTransferGenericFailure(address account, uint256 amount); /** * @dev Revert with an error when a partial fill is attempted on an order * that does not specify partial fill support in its order type. */ error PartialFillsNotEnabledForOrder(); /** * @dev Revert with an error when attempting to fill an order that has been * cancelled. * * @param orderHash The hash of the cancelled order. */ error OrderIsCancelled(bytes32 orderHash); /** * @dev Revert with an error when attempting to fill a basic order that has * been partially filled. * * @param orderHash The hash of the partially used order. */ error OrderPartiallyFilled(bytes32 orderHash); /** * @dev Revert with an error when attempting to cancel an order as a caller * other than the indicated offerer or zone or when attempting to * cancel a contract order. */ error CannotCancelOrder(); /** * @dev Revert with an error when supplying a fraction with a value of zero * for the numerator or denominator, or one where the numerator exceeds * the denominator. */ error BadFraction(); /** * @dev Revert with an error when a caller attempts to supply callvalue to a * non-payable basic order route or does not supply any callvalue to a * payable basic order route. */ error InvalidMsgValue(uint256 value); /** * @dev Revert with an error when attempting to fill a basic order using * calldata not produced by default ABI encoding. */ error InvalidBasicOrderParameterEncoding(); /** * @dev Revert with an error when attempting to fulfill any number of * available orders when none are fulfillable. */ error NoSpecifiedOrdersAvailable(); /** * @dev Revert with an error when attempting to fulfill an order with an * offer for a native token outside of matching orders. */ error InvalidNativeOfferItem(); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { AdvancedOrder, ConsiderationItem, CriteriaResolver, Fulfillment, FulfillmentComponent, OfferItem, Order, OrderParameters, ReceivedItem } from "./ConsiderationStructs.sol"; import { AdvancedOrder_denominator_offset, AdvancedOrder_extraData_offset, AdvancedOrder_fixed_segment_0, AdvancedOrder_head_size, AdvancedOrder_numerator_offset, AdvancedOrder_signature_offset, AdvancedOrderPlusOrderParameters_head_size, Common_amount_offset, Common_endAmount_offset, ConsiderationItem_size_with_length, ConsiderationItem_size, CriteriaResolver_criteriaProof_offset, CriteriaResolver_fixed_segment_0, CriteriaResolver_head_size, FourWords, FreeMemoryPointerSlot, Fulfillment_considerationComponents_offset, Fulfillment_head_size, FulfillmentComponent_mem_tail_size_shift, FulfillmentComponent_mem_tail_size, generateOrder_maximum_returndatasize, OfferItem_size_with_length, OfferItem_size, OneWord, OneWordShift, OnlyFullWordMask, Order_head_size, Order_signature_offset, OrderComponents_OrderParameters_common_head_size, OrderParameters_consideration_head_offset, OrderParameters_head_size, OrderParameters_offer_head_offset, OrderParameters_totalOriginalConsiderationItems_offset, ReceivedItem_recipient_offset, ReceivedItem_size, ReceivedItem_size_excluding_recipient, SpentItem_size_shift, SpentItem_size, ThirtyOneBytes, TwoWords } from "./ConsiderationConstants.sol"; import { CalldataPointer, malloc, MemoryPointer, OffsetOrLengthMask } from "../helpers/PointerLibraries.sol"; contract ConsiderationDecoder { /** * @dev Takes a bytes array from calldata and copies it into memory. * * @param cdPtrLength A calldata pointer to the start of the bytes array in * calldata which contains the length of the array. * * @return mPtrLength A memory pointer to the start of the bytes array in * memory which contains the length of the array. */ function _decodeBytes( CalldataPointer cdPtrLength ) internal pure returns (MemoryPointer mPtrLength) { assembly { // Get the current free memory pointer. mPtrLength := mload(FreeMemoryPointerSlot) // Derive the size of the bytes array, rounding up to nearest word // and adding a word for the length field. Note: masking // `calldataload(cdPtrLength)` is redundant here. let size := add( and( add(calldataload(cdPtrLength), ThirtyOneBytes), OnlyFullWordMask ), OneWord ) // Copy bytes from calldata into memory based on pointers and size. calldatacopy(mPtrLength, cdPtrLength, size) // Store the masked value in memory. Note: the value of `size` is at // least 32, meaning the calldatacopy above will at least write to // `[mPtrLength, mPtrLength + 32)`. mstore( mPtrLength, and(calldataload(cdPtrLength), OffsetOrLengthMask) ) // Update free memory pointer based on the size of the bytes array. mstore(FreeMemoryPointerSlot, add(mPtrLength, size)) } } /** * @dev Takes an offer array from calldata and copies it into memory. * * @param cdPtrLength A calldata pointer to the start of the offer array * in calldata which contains the length of the array. * * @return mPtrLength A memory pointer to the start of the offer array in * memory which contains the length of the array. */ function _decodeOffer( CalldataPointer cdPtrLength ) internal pure returns (MemoryPointer mPtrLength) { assembly { // Retrieve length of array, masking to prevent potential overflow. let arrLength := and(calldataload(cdPtrLength), OffsetOrLengthMask) // Get the current free memory pointer. mPtrLength := mload(FreeMemoryPointerSlot) // Write the array length to memory. mstore(mPtrLength, arrLength) // Derive the head by adding one word to the length pointer. let mPtrHead := add(mPtrLength, OneWord) // Derive the tail by adding one word per element (note that structs // are written to memory with an offset per struct element). let mPtrTail := add(mPtrHead, shl(OneWordShift, arrLength)) // Track the next tail, beginning with the initial tail value. let mPtrTailNext := mPtrTail // Copy all offer array data into memory at the tail pointer. calldatacopy( mPtrTail, add(cdPtrLength, OneWord), mul(arrLength, OfferItem_size) ) // Track the next head pointer, starting with initial head value. let mPtrHeadNext := mPtrHead // Iterate over each head pointer until it reaches the tail. for { } lt(mPtrHeadNext, mPtrTail) { } { // Write the next tail pointer to next head pointer in memory. mstore(mPtrHeadNext, mPtrTailNext) // Increment the next head pointer by one word. mPtrHeadNext := add(mPtrHeadNext, OneWord) // Increment the next tail pointer by the size of an offer item. mPtrTailNext := add(mPtrTailNext, OfferItem_size) } // Update free memory pointer to allocate memory up to end of tail. mstore(FreeMemoryPointerSlot, mPtrTailNext) } } /** * @dev Takes a consideration array from calldata and copies it into memory. * * @param cdPtrLength A calldata pointer to the start of the consideration * array in calldata which contains the length of the * array. * * @return mPtrLength A memory pointer to the start of the consideration * array in memory which contains the length of the * array. */ function _decodeConsideration( CalldataPointer cdPtrLength ) internal pure returns (MemoryPointer mPtrLength) { assembly { // Retrieve length of array, masking to prevent potential overflow. let arrLength := and(calldataload(cdPtrLength), OffsetOrLengthMask) // Get the current free memory pointer. mPtrLength := mload(FreeMemoryPointerSlot) // Write the array length to memory. mstore(mPtrLength, arrLength) // Derive the head by adding one word to the length pointer. let mPtrHead := add(mPtrLength, OneWord) // Derive the tail by adding one word per element (note that structs // are written to memory with an offset per struct element). let mPtrTail := add(mPtrHead, shl(OneWordShift, arrLength)) // Track the next tail, beginning with the initial tail value. let mPtrTailNext := mPtrTail // Copy all consideration array data into memory at tail pointer. calldatacopy( mPtrTail, add(cdPtrLength, OneWord), mul(arrLength, ConsiderationItem_size) ) // Track the next head pointer, starting with initial head value. let mPtrHeadNext := mPtrHead // Iterate over each head pointer until it reaches the tail. for { } lt(mPtrHeadNext, mPtrTail) { } { // Write the next tail pointer to next head pointer in memory. mstore(mPtrHeadNext, mPtrTailNext) // Increment the next head pointer by one word. mPtrHeadNext := add(mPtrHeadNext, OneWord) // Increment next tail pointer by size of a consideration item. mPtrTailNext := add(mPtrTailNext, ConsiderationItem_size) } // Update free memory pointer to allocate memory up to end of tail. mstore(FreeMemoryPointerSlot, mPtrTailNext) } } /** * @dev Takes a calldata pointer and memory pointer and copies a referenced * OrderParameters struct and associated offer and consideration data * to memory. * * @param cdPtr A calldata pointer for the OrderParameters struct. * @param mPtr A memory pointer to the OrderParameters struct head. */ function _decodeOrderParametersTo( CalldataPointer cdPtr, MemoryPointer mPtr ) internal pure { // Copy the full OrderParameters head from calldata to memory. cdPtr.copy(mPtr, OrderParameters_head_size); // Resolve the offer calldata offset, use that to decode and copy offer // from calldata, and write resultant memory offset to head in memory. mPtr.offset(OrderParameters_offer_head_offset).write( _decodeOffer(cdPtr.pptr(OrderParameters_offer_head_offset)) ); // Resolve consideration calldata offset, use that to copy consideration // from calldata, and write resultant memory offset to head in memory. mPtr.offset(OrderParameters_consideration_head_offset).write( _decodeConsideration( cdPtr.pptr(OrderParameters_consideration_head_offset) ) ); } /** * @dev Takes a calldata pointer to an OrderParameters struct and copies the * decoded struct to memory. * * @param cdPtr A calldata pointer for the OrderParameters struct. * * @return mPtr A memory pointer to the OrderParameters struct head. */ function _decodeOrderParameters( CalldataPointer cdPtr ) internal pure returns (MemoryPointer mPtr) { // Allocate required memory for the OrderParameters head (offer and // consideration are allocated independently). mPtr = malloc(OrderParameters_head_size); // Decode and copy the order parameters to the newly allocated memory. _decodeOrderParametersTo(cdPtr, mPtr); } /** * @dev Takes a calldata pointer to an Order struct and copies the decoded * struct to memory. * * @param cdPtr A calldata pointer for the Order struct. * * @return mPtr A memory pointer to the Order struct head. */ function _decodeOrder( CalldataPointer cdPtr ) internal pure returns (MemoryPointer mPtr) { // Allocate required memory for the Order head (OrderParameters and // signature are allocated independently). mPtr = malloc(Order_head_size); // Resolve OrderParameters calldata offset, use it to decode and copy // from calldata, and write resultant memory offset to head in memory. mPtr.write(_decodeOrderParameters(cdPtr.pptr())); // Resolve signature calldata offset, use that to decode and copy from // calldata, and write resultant memory offset to head in memory. mPtr.offset(Order_signature_offset).write( _decodeBytes(cdPtr.pptr(Order_signature_offset)) ); } /** * @dev Takes a calldata pointer to an AdvancedOrder struct and copies the * decoded struct to memory. * * @param cdPtr A calldata pointer for the AdvancedOrder struct. * * @return mPtr A memory pointer to the AdvancedOrder struct head. */ function _decodeAdvancedOrder( CalldataPointer cdPtr ) internal pure returns (MemoryPointer mPtr) { // Allocate memory for AdvancedOrder head and OrderParameters head. mPtr = malloc(AdvancedOrderPlusOrderParameters_head_size); // Use numerator + denominator calldata offset to decode and copy // from calldata and write resultant memory offset to head in memory. cdPtr.offset(AdvancedOrder_numerator_offset).copy( mPtr.offset(AdvancedOrder_numerator_offset), AdvancedOrder_fixed_segment_0 ); // Get pointer to memory immediately after advanced order. MemoryPointer mPtrParameters = mPtr.offset(AdvancedOrder_head_size); // Write pptr for advanced order parameters to memory. mPtr.write(mPtrParameters); // Resolve OrderParameters calldata pointer & write to allocated region. _decodeOrderParametersTo(cdPtr.pptr(), mPtrParameters); // Resolve signature calldata offset, use that to decode and copy from // calldata, and write resultant memory offset to head in memory. mPtr.offset(AdvancedOrder_signature_offset).write( _decodeBytes(cdPtr.pptr(AdvancedOrder_signature_offset)) ); // Resolve extraData calldata offset, use that to decode and copy from // calldata, and write resultant memory offset to head in memory. mPtr.offset(AdvancedOrder_extraData_offset).write( _decodeBytes(cdPtr.pptr(AdvancedOrder_extraData_offset)) ); } /** * @dev Allocates a single word of empty bytes in memory and returns the * pointer to that memory region. * * @return mPtr The memory pointer to the new empty word in memory. */ function _getEmptyBytesOrArray() internal pure returns (MemoryPointer mPtr) { mPtr = malloc(OneWord); mPtr.write(0); } /** * @dev Takes a calldata pointer to an Order struct and copies the decoded * struct to memory as an AdvancedOrder. * * @param cdPtr A calldata pointer for the Order struct. * * @return mPtr A memory pointer to the AdvancedOrder struct head. */ function _decodeOrderAsAdvancedOrder( CalldataPointer cdPtr ) internal pure returns (MemoryPointer mPtr) { // Allocate memory for AdvancedOrder head and OrderParameters head. mPtr = malloc(AdvancedOrderPlusOrderParameters_head_size); // Get pointer to memory immediately after advanced order. MemoryPointer mPtrParameters = mPtr.offset(AdvancedOrder_head_size); // Write pptr for advanced order parameters. mPtr.write(mPtrParameters); // Resolve OrderParameters calldata pointer & write to allocated region. _decodeOrderParametersTo(cdPtr.pptr(), mPtrParameters); // Write default Order numerator and denominator values (i.e. 1/1). mPtr.offset(AdvancedOrder_numerator_offset).write(1); mPtr.offset(AdvancedOrder_denominator_offset).write(1); // Resolve signature calldata offset, use that to decode and copy from // calldata, and write resultant memory offset to head in memory. mPtr.offset(AdvancedOrder_signature_offset).write( _decodeBytes(cdPtr.pptr(Order_signature_offset)) ); // Resolve extraData calldata offset, use that to decode and copy from // calldata, and write resultant memory offset to head in memory. mPtr.offset(AdvancedOrder_extraData_offset).write( _getEmptyBytesOrArray() ); } /** * @dev Takes a calldata pointer to an array of Order structs and copies the * decoded array to memory as an array of AdvancedOrder structs. * * @param cdPtrLength A calldata pointer to the start of the orders array in * calldata which contains the length of the array. * * @return mPtrLength A memory pointer to the start of the array of advanced * orders in memory which contains length of the array. */ function _decodeOrdersAsAdvancedOrders( CalldataPointer cdPtrLength ) internal pure returns (MemoryPointer mPtrLength) { // Retrieve length of array, masking to prevent potential overflow. uint256 arrLength = cdPtrLength.readMaskedUint256(); unchecked { // Derive offset to the tail based on one word per array element. uint256 tailOffset = arrLength << OneWordShift; // Add one additional word for the length and allocate memory. mPtrLength = malloc(tailOffset + OneWord); // Write the length of the array to memory. mPtrLength.write(arrLength); // Advance to first memory & calldata pointers (e.g. after length). MemoryPointer mPtrHead = mPtrLength.next(); CalldataPointer cdPtrHead = cdPtrLength.next(); // Iterate over each pointer, word by word, until tail is reached. for (uint256 offset = 0; offset < tailOffset; offset += OneWord) { // Resolve Order calldata offset, use it to decode and copy from // calldata, and write resultant AdvancedOrder offset to memory. mPtrHead.offset(offset).write( _decodeOrderAsAdvancedOrder(cdPtrHead.pptr(offset)) ); } } } /** * @dev Takes a calldata pointer to a criteria proof, or an array bytes32 * types, and copies the decoded proof to memory. * * @param cdPtrLength A calldata pointer to the start of the criteria proof * in calldata which contains the length of the array. * * @return mPtrLength A memory pointer to the start of the criteria proof * in memory which contains length of the array. */ function _decodeCriteriaProof( CalldataPointer cdPtrLength ) internal pure returns (MemoryPointer mPtrLength) { // Retrieve length of array, masking to prevent potential overflow. uint256 arrLength = cdPtrLength.readMaskedUint256(); unchecked { // Derive array size based on one word per array element and length. uint256 arrSize = (arrLength + 1) << OneWordShift; // Allocate memory equal to the array size. mPtrLength = malloc(arrSize); // Copy the array from calldata into memory. cdPtrLength.copy(mPtrLength, arrSize); } } /** * @dev Takes a calldata pointer to a CriteriaResolver struct and copies the * decoded struct to memory. * * @param cdPtr A calldata pointer for the CriteriaResolver struct. * * @return mPtr A memory pointer to the CriteriaResolver struct head. */ function _decodeCriteriaResolver( CalldataPointer cdPtr ) internal pure returns (MemoryPointer mPtr) { // Allocate required memory for the CriteriaResolver head (the criteria // proof bytes32 array is allocated independently). mPtr = malloc(CriteriaResolver_head_size); // Decode and copy order index, side, index, and identifier from // calldata and write resultant memory offset to head in memory. cdPtr.copy(mPtr, CriteriaResolver_fixed_segment_0); // Resolve criteria proof calldata offset, use it to decode and copy // from calldata, and write resultant memory offset to head in memory. mPtr.offset(CriteriaResolver_criteriaProof_offset).write( _decodeCriteriaProof( cdPtr.pptr(CriteriaResolver_criteriaProof_offset) ) ); } /** * @dev Takes an array of criteria resolvers from calldata and copies it * into memory. * * @param cdPtrLength A calldata pointer to the start of the criteria * resolver array in calldata which contains the length * of the array. * * @return mPtrLength A memory pointer to the start of the criteria resolver * array in memory which contains the length of the * array. */ function _decodeCriteriaResolvers( CalldataPointer cdPtrLength ) internal pure returns (MemoryPointer mPtrLength) { // Retrieve length of array, masking to prevent potential overflow. uint256 arrLength = cdPtrLength.readMaskedUint256(); unchecked { // Derive offset to the tail based on one word per array element. uint256 tailOffset = arrLength << OneWordShift; // Add one additional word for the length and allocate memory. mPtrLength = malloc(tailOffset + OneWord); // Write the length of the array to memory. mPtrLength.write(arrLength); // Advance to first memory & calldata pointers (e.g. after length). MemoryPointer mPtrHead = mPtrLength.next(); CalldataPointer cdPtrHead = cdPtrLength.next(); // Iterate over each pointer, word by word, until tail is reached. for (uint256 offset = 0; offset < tailOffset; offset += OneWord) { // Resolve CriteriaResolver calldata offset, use it to decode // and copy from calldata, and write resultant memory offset. mPtrHead.offset(offset).write( _decodeCriteriaResolver(cdPtrHead.pptr(offset)) ); } } } /** * @dev Takes an array of orders from calldata and copies it into memory. * * @param cdPtrLength A calldata pointer to the start of the orders array in * calldata which contains the length of the array. * * @return mPtrLength A memory pointer to the start of the orders array * in memory which contains the length of the array. */ function _decodeOrders( CalldataPointer cdPtrLength ) internal pure returns (MemoryPointer mPtrLength) { // Retrieve length of array, masking to prevent potential overflow. uint256 arrLength = cdPtrLength.readMaskedUint256(); unchecked { // Derive offset to the tail based on one word per array element. uint256 tailOffset = arrLength << OneWordShift; // Add one additional word for the length and allocate memory. mPtrLength = malloc(tailOffset + OneWord); // Write the length of the array to memory. mPtrLength.write(arrLength); // Advance to first memory & calldata pointers (e.g. after length). MemoryPointer mPtrHead = mPtrLength.next(); CalldataPointer cdPtrHead = cdPtrLength.next(); // Iterate over each pointer, word by word, until tail is reached. for (uint256 offset = 0; offset < tailOffset; offset += OneWord) { // Resolve Order calldata offset, use it to decode and copy // from calldata, and write resultant memory offset. mPtrHead.offset(offset).write( _decodeOrder(cdPtrHead.pptr(offset)) ); } } } /** * @dev Takes an array of fulfillment components from calldata and copies it * into memory. * * @param cdPtrLength A calldata pointer to the start of the fulfillment * components array in calldata which contains the length * of the array. * * @return mPtrLength A memory pointer to the start of the fulfillment * components array in memory which contains the length * of the array. */ function _decodeFulfillmentComponents( CalldataPointer cdPtrLength ) internal pure returns (MemoryPointer mPtrLength) { assembly { let arrLength := and(calldataload(cdPtrLength), OffsetOrLengthMask) // Get the current free memory pointer. mPtrLength := mload(FreeMemoryPointerSlot) mstore(mPtrLength, arrLength) let mPtrHead := add(mPtrLength, OneWord) let mPtrTail := add(mPtrHead, shl(OneWordShift, arrLength)) let mPtrTailNext := mPtrTail calldatacopy( mPtrTail, add(cdPtrLength, OneWord), shl(FulfillmentComponent_mem_tail_size_shift, arrLength) ) let mPtrHeadNext := mPtrHead for { } lt(mPtrHeadNext, mPtrTail) { } { mstore(mPtrHeadNext, mPtrTailNext) mPtrHeadNext := add(mPtrHeadNext, OneWord) mPtrTailNext := add( mPtrTailNext, FulfillmentComponent_mem_tail_size ) } // Update the free memory pointer. mstore(FreeMemoryPointerSlot, mPtrTailNext) } } /** * @dev Takes a nested array of fulfillment components from calldata and * copies it into memory. * * @param cdPtrLength A calldata pointer to the start of the nested * fulfillment components array in calldata which * contains the length of the array. * * @return mPtrLength A memory pointer to the start of the nested * fulfillment components array in memory which * contains the length of the array. */ function _decodeNestedFulfillmentComponents( CalldataPointer cdPtrLength ) internal pure returns (MemoryPointer mPtrLength) { // Retrieve length of array, masking to prevent potential overflow. uint256 arrLength = cdPtrLength.readMaskedUint256(); unchecked { // Derive offset to the tail based on one word per array element. uint256 tailOffset = arrLength << OneWordShift; // Add one additional word for the length and allocate memory. mPtrLength = malloc(tailOffset + OneWord); // Write the length of the array to memory. mPtrLength.write(arrLength); // Advance to first memory & calldata pointers (e.g. after length). MemoryPointer mPtrHead = mPtrLength.next(); CalldataPointer cdPtrHead = cdPtrLength.next(); // Iterate over each pointer, word by word, until tail is reached. for (uint256 offset = 0; offset < tailOffset; offset += OneWord) { // Resolve FulfillmentComponents array calldata offset, use it // to decode and copy from calldata, and write memory offset. mPtrHead.offset(offset).write( _decodeFulfillmentComponents(cdPtrHead.pptr(offset)) ); } } } /** * @dev Takes an array of advanced orders from calldata and copies it into * memory. * * @param cdPtrLength A calldata pointer to the start of the advanced orders * array in calldata which contains the length of the * array. * * @return mPtrLength A memory pointer to the start of the advanced orders * array in memory which contains the length of the * array. */ function _decodeAdvancedOrders( CalldataPointer cdPtrLength ) internal pure returns (MemoryPointer mPtrLength) { // Retrieve length of array, masking to prevent potential overflow. uint256 arrLength = cdPtrLength.readMaskedUint256(); unchecked { // Derive offset to the tail based on one word per array element. uint256 tailOffset = arrLength << OneWordShift; // Add one additional word for the length and allocate memory. mPtrLength = malloc(tailOffset + OneWord); // Write the length of the array to memory. mPtrLength.write(arrLength); // Advance to first memory & calldata pointers (e.g. after length). MemoryPointer mPtrHead = mPtrLength.next(); CalldataPointer cdPtrHead = cdPtrLength.next(); // Iterate over each pointer, word by word, until tail is reached. for (uint256 offset = 0; offset < tailOffset; offset += OneWord) { // Resolve AdvancedOrder calldata offset, use it to decode and // copy from calldata, and write resultant memory offset. mPtrHead.offset(offset).write( _decodeAdvancedOrder(cdPtrHead.pptr(offset)) ); } } } /** * @dev Takes a calldata pointer to a Fulfillment struct and copies the * decoded struct to memory. * * @param cdPtr A calldata pointer for the Fulfillment struct. * * @return mPtr A memory pointer to the Fulfillment struct head. */ function _decodeFulfillment( CalldataPointer cdPtr ) internal pure returns (MemoryPointer mPtr) { // Allocate required memory for the Fulfillment head (the fulfillment // components arrays are allocated independently). mPtr = malloc(Fulfillment_head_size); // Resolve offerComponents calldata offset, use it to decode and copy // from calldata, and write resultant memory offset to head in memory. mPtr.write(_decodeFulfillmentComponents(cdPtr.pptr())); // Resolve considerationComponents calldata offset, use it to decode and // copy from calldata, and write resultant memory offset to memory head. mPtr.offset(Fulfillment_considerationComponents_offset).write( _decodeFulfillmentComponents( cdPtr.pptr(Fulfillment_considerationComponents_offset) ) ); } /** * @dev Takes an array of fulfillments from calldata and copies it into * memory. * * @param cdPtrLength A calldata pointer to the start of the fulfillments * array in calldata which contains the length of the * array. * * @return mPtrLength A memory pointer to the start of the fulfillments * array in memory which contains the length of the * array. */ function _decodeFulfillments( CalldataPointer cdPtrLength ) internal pure returns (MemoryPointer mPtrLength) { // Retrieve length of array, masking to prevent potential overflow. uint256 arrLength = cdPtrLength.readMaskedUint256(); unchecked { // Derive offset to the tail based on one word per array element. uint256 tailOffset = arrLength << OneWordShift; // Add one additional word for the length and allocate memory. mPtrLength = malloc(tailOffset + OneWord); // Write the length of the array to memory. mPtrLength.write(arrLength); // Advance to first memory & calldata pointers (e.g. after length). MemoryPointer mPtrHead = mPtrLength.next(); CalldataPointer cdPtrHead = cdPtrLength.next(); // Iterate over each pointer, word by word, until tail is reached. for (uint256 offset = 0; offset < tailOffset; offset += OneWord) { // Resolve Fulfillment calldata offset, use it to decode and // copy from calldata, and write resultant memory offset. mPtrHead.offset(offset).write( _decodeFulfillment(cdPtrHead.pptr(offset)) ); } } } /** * @dev Takes a calldata pointer to an OrderComponents struct and copies the * decoded struct to memory as an OrderParameters struct (with the * totalOriginalConsiderationItems value set equal to the length of the * supplied consideration array). * * @param cdPtr A calldata pointer for the OrderComponents struct. * * @return mPtr A memory pointer to the OrderParameters struct head. */ function _decodeOrderComponentsAsOrderParameters( CalldataPointer cdPtr ) internal pure returns (MemoryPointer mPtr) { // Allocate memory for the OrderParameters head. mPtr = malloc(OrderParameters_head_size); // Copy the full OrderComponents head from calldata to memory. cdPtr.copy(mPtr, OrderComponents_OrderParameters_common_head_size); // Resolve the offer calldata offset, use that to decode and copy offer // from calldata, and write resultant memory offset to head in memory. mPtr.offset(OrderParameters_offer_head_offset).write( _decodeOffer(cdPtr.pptr(OrderParameters_offer_head_offset)) ); // Resolve consideration calldata offset, use that to copy consideration // from calldata, and write resultant memory offset to head in memory. MemoryPointer consideration = _decodeConsideration( cdPtr.pptr(OrderParameters_consideration_head_offset) ); mPtr.offset(OrderParameters_consideration_head_offset).write( consideration ); // Write masked consideration length to totalOriginalConsiderationItems. mPtr .offset(OrderParameters_totalOriginalConsiderationItems_offset) .write(consideration.readUint256()); } /** * @dev Decodes the returndata from a call to generateOrder, or returns * empty arrays and a boolean signifying that the returndata does not * adhere to a valid encoding scheme if it cannot be decoded. * * @return invalidEncoding A boolean signifying whether the returndata has * an invalid encoding. * @return offer The decoded offer array. * @return consideration The decoded consideration array. */ function _decodeGenerateOrderReturndata() internal pure returns ( uint256 invalidEncoding, MemoryPointer offer, MemoryPointer consideration ) { assembly { // Check that returndatasize is at least four words: offerOffset, // considerationOffset, offerLength, & considerationLength invalidEncoding := lt(returndatasize(), FourWords) let offsetOffer let offsetConsideration let offerLength let considerationLength // Proceed if enough returndata is present to continue evaluation. if iszero(invalidEncoding) { // Copy first two words of returndata (the offsets to offer and // consideration array lengths) to scratch space. returndatacopy(0, 0, TwoWords) offsetOffer := mload(0) offsetConsideration := mload(OneWord) // If valid length, check that offsets are within returndata. let invalidOfferOffset := gt(offsetOffer, returndatasize()) let invalidConsiderationOffset := gt( offsetConsideration, returndatasize() ) // Only proceed if length (and thus encoding) is valid so far. invalidEncoding := or( invalidOfferOffset, invalidConsiderationOffset ) if iszero(invalidEncoding) { // Copy length of offer array to scratch space. returndatacopy(0, offsetOffer, OneWord) offerLength := mload(0) // Copy length of consideration array to scratch space. returndatacopy(OneWord, offsetConsideration, OneWord) considerationLength := mload(OneWord) { // Calculate total size of offer & consideration arrays. let totalOfferSize := shl( SpentItem_size_shift, offerLength ) let totalConsiderationSize := mul( ReceivedItem_size, considerationLength ) // Add 4 words to total size to cover the offset and // length fields of the two arrays. let totalSize := add( FourWords, add(totalOfferSize, totalConsiderationSize) ) // Don't continue if returndatasize exceeds 65535 bytes // or is greater than the calculated size. invalidEncoding := or( gt( or(offerLength, considerationLength), generateOrder_maximum_returndatasize ), gt(totalSize, returndatasize()) ) // Set first word of scratch space to 0 so length of // offer/consideration are set to 0 on invalid encoding. mstore(0, 0) } } } if iszero(invalidEncoding) { offer := copySpentItemsAsOfferItems( add(offsetOffer, OneWord), offerLength ) consideration := copyReceivedItemsAsConsiderationItems( add(offsetConsideration, OneWord), considerationLength ) } function copySpentItemsAsOfferItems(rdPtrHead, length) -> mPtrLength { // Retrieve the current free memory pointer. mPtrLength := mload(FreeMemoryPointerSlot) // Allocate memory for the array. mstore( FreeMemoryPointerSlot, add( mPtrLength, add(OneWord, mul(length, OfferItem_size_with_length)) ) ) // Write the length of the array to the start of free memory. mstore(mPtrLength, length) // Use offset from length to minimize stack depth. let headOffsetFromLength := OneWord let headSizeWithLength := shl(OneWordShift, add(1, length)) let mPtrTailNext := add(mPtrLength, headSizeWithLength) // Iterate over each element. for { } lt(headOffsetFromLength, headSizeWithLength) { } { // Write the memory pointer to the accompanying head offset. mstore(add(mPtrLength, headOffsetFromLength), mPtrTailNext) // Copy itemType, token, identifier and amount. returndatacopy(mPtrTailNext, rdPtrHead, SpentItem_size) // Copy amount to endAmount. mstore( add(mPtrTailNext, Common_endAmount_offset), mload(add(mPtrTailNext, Common_amount_offset)) ) // Update read pointer, next tail pointer, and head offset. rdPtrHead := add(rdPtrHead, SpentItem_size) mPtrTailNext := add(mPtrTailNext, OfferItem_size) headOffsetFromLength := add(headOffsetFromLength, OneWord) } } function copyReceivedItemsAsConsiderationItems(rdPtrHead, length) -> mPtrLength { // Retrieve the current free memory pointer. mPtrLength := mload(FreeMemoryPointerSlot) // Allocate memory for the array. mstore( FreeMemoryPointerSlot, add( mPtrLength, add( OneWord, mul(length, ConsiderationItem_size_with_length) ) ) ) // Write the length of the array to the start of free memory. mstore(mPtrLength, length) // Use offset from length to minimize stack depth. let headOffsetFromLength := OneWord let headSizeWithLength := shl(OneWordShift, add(1, length)) let mPtrTailNext := add(mPtrLength, headSizeWithLength) // Iterate over each element. for { } lt(headOffsetFromLength, headSizeWithLength) { } { // Write the memory pointer to the accompanying head offset. mstore(add(mPtrLength, headOffsetFromLength), mPtrTailNext) // Copy itemType, token, identifier and amount. returndatacopy( mPtrTailNext, rdPtrHead, ReceivedItem_size_excluding_recipient ) // Copy amount and recipient. returndatacopy( add(mPtrTailNext, Common_endAmount_offset), add(rdPtrHead, Common_amount_offset), TwoWords ) // Update read pointer, next tail pointer, and head offset. rdPtrHead := add(rdPtrHead, ReceivedItem_size) mPtrTailNext := add(mPtrTailNext, ConsiderationItem_size) headOffsetFromLength := add(headOffsetFromLength, OneWord) } } } } /** * @dev Converts a function returning _decodeGenerateOrderReturndata types * into a function returning offer and consideration types. * * @param inFn The input function, taking no arguments and returning an * error buffer, spent item array, and received item array. * * @return outFn The output function, taking no arguments and returning an * error buffer, offer array, and consideration array. */ function _convertGetGeneratedOrderResult( function() internal pure returns (uint256, MemoryPointer, MemoryPointer) inFn ) internal pure returns ( function() internal pure returns ( uint256, OfferItem[] memory, ConsiderationItem[] memory ) outFn ) { assembly { outFn := inFn } } /** * @dev Converts a function taking ReceivedItem, address, bytes32, and bytes * types (e.g. the _transfer function) into a function taking * OfferItem, address, bytes32, and bytes types. * * @param inFn The input function, taking ReceivedItem, address, bytes32, * and bytes types (e.g. the _transfer function). * * @return outFn The output function, taking OfferItem, address, bytes32, * and bytes types. */ function _toOfferItemInput( function(ReceivedItem memory, address, bytes32, bytes memory) internal inFn ) internal pure returns ( function(OfferItem memory, address, bytes32, bytes memory) internal outFn ) { assembly { outFn := inFn } } /** * @dev Converts a function taking ReceivedItem, address, bytes32, and bytes * types (e.g. the _transfer function) into a function taking * ConsiderationItem, address, bytes32, and bytes types. * * @param inFn The input function, taking ReceivedItem, address, bytes32, * and bytes types (e.g. the _transfer function). * * @return outFn The output function, taking ConsiderationItem, address, * bytes32, and bytes types. */ function _toConsiderationItemInput( function(ReceivedItem memory, address, bytes32, bytes memory) internal inFn ) internal pure returns ( function(ConsiderationItem memory, address, bytes32, bytes memory) internal outFn ) { assembly { outFn := inFn } } /** * @dev Converts a function taking a calldata pointer and returning a memory * pointer into a function taking that calldata pointer and returning * an OrderParameters type. * * @param inFn The input function, taking an arbitrary calldata pointer and * returning an arbitrary memory pointer. * * @return outFn The output function, taking an arbitrary calldata pointer * and returning an OrderParameters type. */ function _toOrderParametersReturnType( function(CalldataPointer) internal pure returns (MemoryPointer) inFn ) internal pure returns ( function(CalldataPointer) internal pure returns (OrderParameters memory) outFn ) { assembly { outFn := inFn } } /** * @dev Converts a function taking a calldata pointer and returning a memory * pointer into a function taking that calldata pointer and returning * an AdvancedOrder type. * * @param inFn The input function, taking an arbitrary calldata pointer and * returning an arbitrary memory pointer. * * @return outFn The output function, taking an arbitrary calldata pointer * and returning an AdvancedOrder type. */ function _toAdvancedOrderReturnType( function(CalldataPointer) internal pure returns (MemoryPointer) inFn ) internal pure returns ( function(CalldataPointer) internal pure returns (AdvancedOrder memory) outFn ) { assembly { outFn := inFn } } /** * @dev Converts a function taking a calldata pointer and returning a memory * pointer into a function taking that calldata pointer and returning * a dynamic array of CriteriaResolver types. * * @param inFn The input function, taking an arbitrary calldata pointer and * returning an arbitrary memory pointer. * * @return outFn The output function, taking an arbitrary calldata pointer * and returning a dynamic array of CriteriaResolver types. */ function _toCriteriaResolversReturnType( function(CalldataPointer) internal pure returns (MemoryPointer) inFn ) internal pure returns ( function(CalldataPointer) internal pure returns (CriteriaResolver[] memory) outFn ) { assembly { outFn := inFn } } /** * @dev Converts a function taking a calldata pointer and returning a memory * pointer into a function taking that calldata pointer and returning * a dynamic array of Order types. * * @param inFn The input function, taking an arbitrary calldata pointer and * returning an arbitrary memory pointer. * * @return outFn The output function, taking an arbitrary calldata pointer * and returning a dynamic array of Order types. */ function _toOrdersReturnType( function(CalldataPointer) internal pure returns (MemoryPointer) inFn ) internal pure returns ( function(CalldataPointer) internal pure returns (Order[] memory) outFn ) { assembly { outFn := inFn } } /** * @dev Converts a function taking a calldata pointer and returning a memory * pointer into a function taking that calldata pointer and returning * a nested dynamic array of dynamic arrays of FulfillmentComponent * types. * * @param inFn The input function, taking an arbitrary calldata pointer and * returning an arbitrary memory pointer. * * @return outFn The output function, taking an arbitrary calldata pointer * and returning a nested dynamic array of dynamic arrays of * FulfillmentComponent types. */ function _toNestedFulfillmentComponentsReturnType( function(CalldataPointer) internal pure returns (MemoryPointer) inFn ) internal pure returns ( function(CalldataPointer) internal pure returns (FulfillmentComponent[][] memory) outFn ) { assembly { outFn := inFn } } /** * @dev Converts a function taking a calldata pointer and returning a memory * pointer into a function taking that calldata pointer and returning * a dynamic array of AdvancedOrder types. * * @param inFn The input function, taking an arbitrary calldata pointer and * returning an arbitrary memory pointer. * * @return outFn The output function, taking an arbitrary calldata pointer * and returning a dynamic array of AdvancedOrder types. */ function _toAdvancedOrdersReturnType( function(CalldataPointer) internal pure returns (MemoryPointer) inFn ) internal pure returns ( function(CalldataPointer) internal pure returns (AdvancedOrder[] memory) outFn ) { assembly { outFn := inFn } } /** * @dev Converts a function taking a calldata pointer and returning a memory * pointer into a function taking that calldata pointer and returning * a dynamic array of Fulfillment types. * * @param inFn The input function, taking an arbitrary calldata pointer and * returning an arbitrary memory pointer. * * @return outFn The output function, taking an arbitrary calldata pointer * and returning a dynamic array of Fulfillment types. */ function _toFulfillmentsReturnType( function(CalldataPointer) internal pure returns (MemoryPointer) inFn ) internal pure returns ( function(CalldataPointer) internal pure returns (Fulfillment[] memory) outFn ) { assembly { outFn := inFn } } /** * @dev Converts an offer item into a received item, applying a given * recipient. * * @param offerItem The offer item. * @param recipient The recipient. * * @return receivedItem The received item. */ function _fromOfferItemToReceivedItemWithRecipient( OfferItem memory offerItem, address recipient ) internal pure returns (ReceivedItem memory receivedItem) { assembly { receivedItem := offerItem mstore(add(receivedItem, ReceivedItem_recipient_offset), recipient) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { BasicOrder_additionalRecipients_length_cdPtr, BasicOrder_common_params_size, BasicOrder_startTime_cdPtr, BasicOrder_startTimeThroughZoneHash_size, Common_amount_offset, Common_identifier_offset, Common_token_offset, generateOrder_base_tail_offset, generateOrder_context_head_offset, generateOrder_head_offset, generateOrder_maximumSpent_head_offset, generateOrder_minimumReceived_head_offset, generateOrder_selector_offset, generateOrder_selector, OneWord, OneWordShift, OnlyFullWordMask, OrderFulfilled_baseDataSize, OrderFulfilled_offer_length_baseOffset, OrderParameters_consideration_head_offset, OrderParameters_endTime_offset, OrderParameters_offer_head_offset, OrderParameters_startTime_offset, OrderParameters_zoneHash_offset, ratifyOrder_base_tail_offset, ratifyOrder_consideration_head_offset, ratifyOrder_context_head_offset, ratifyOrder_contractNonce_offset, ratifyOrder_head_offset, ratifyOrder_orderHashes_head_offset, ratifyOrder_selector_offset, ratifyOrder_selector, ReceivedItem_size, Selector_length, SixtyThreeBytes, SpentItem_size_shift, SpentItem_size, validateOrder_head_offset, validateOrder_selector_offset, validateOrder_selector, validateOrder_zoneParameters_offset, ZoneParameters_base_tail_offset, ZoneParameters_basicOrderFixedElements_length, ZoneParameters_consideration_head_offset, ZoneParameters_endTime_offset, ZoneParameters_extraData_head_offset, ZoneParameters_fulfiller_offset, ZoneParameters_offer_head_offset, ZoneParameters_offerer_offset, ZoneParameters_orderHashes_head_offset, ZoneParameters_selectorAndPointer_length, ZoneParameters_startTime_offset, ZoneParameters_zoneHash_offset } from "./ConsiderationConstants.sol"; import { BasicOrderParameters, OrderParameters } from "./ConsiderationStructs.sol"; import { CalldataPointer, getFreeMemoryPointer, MemoryPointer } from "../helpers/PointerLibraries.sol"; contract ConsiderationEncoder { /** * @dev Takes a bytes array and casts it to a memory pointer. * * @param obj A bytes array in memory. * * @return ptr A memory pointer to the start of the bytes array in memory. */ function toMemoryPointer( bytes memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Takes an array of bytes32 types and casts it to a memory pointer. * * @param obj An array of bytes32 types in memory. * * @return ptr A memory pointer to the start of the array of bytes32 types * in memory. */ function toMemoryPointer( bytes32[] memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Takes a bytes array in memory and copies it to a new location in * memory. * * @param src A memory pointer referencing the bytes array to be copied (and * pointing to the length of the bytes array). * @param src A memory pointer referencing the location in memory to copy * the bytes array to (and pointing to the length of the copied * bytes array). * * @return size The size of the bytes array. */ function _encodeBytes( MemoryPointer src, MemoryPointer dst ) internal view returns (uint256 size) { unchecked { // Mask the length of the bytes array to protect against overflow // and round up to the nearest word. // Note: `size` also includes the 1 word that stores the length. size = (src.readUint256() + SixtyThreeBytes) & OnlyFullWordMask; // Copy the bytes array to the new memory location. src.copy(dst, size); } } /** * @dev Takes an OrderParameters struct and a context bytes array in memory * and encodes it as `generateOrder` calldata. * * @param orderParameters The OrderParameters struct used to construct the * encoded `generateOrder` calldata. * @param context The context bytes array used to construct the * encoded `generateOrder` calldata. * * @return dst A memory pointer referencing the encoded `generateOrder` * calldata. * @return size The size of the bytes array. */ function _encodeGenerateOrder( OrderParameters memory orderParameters, bytes memory context ) internal view returns (MemoryPointer dst, uint256 size) { // Get the memory pointer for the OrderParameters struct. MemoryPointer src = orderParameters.toMemoryPointer(); // Get free memory pointer to write calldata to. dst = getFreeMemoryPointer(); // Write generateOrder selector and get pointer to start of calldata. dst.write(generateOrder_selector); dst = dst.offset(generateOrder_selector_offset); // Get pointer to the beginning of the encoded data. MemoryPointer dstHead = dst.offset(generateOrder_head_offset); // Write `fulfiller` to calldata. dstHead.write(msg.sender); // Initialize tail offset, used to populate the minimumReceived array. uint256 tailOffset = generateOrder_base_tail_offset; // Write offset to minimumReceived. dstHead.offset(generateOrder_minimumReceived_head_offset).write( tailOffset ); // Get memory pointer to `orderParameters.offer.length`. MemoryPointer srcOfferPointer = src .offset(OrderParameters_offer_head_offset) .readMemoryPointer(); // Encode the offer array as a `SpentItem[]`. uint256 minimumReceivedSize = _encodeSpentItems( srcOfferPointer, dstHead.offset(tailOffset) ); unchecked { // Increment tail offset, now used to populate maximumSpent array. tailOffset += minimumReceivedSize; } // Write offset to maximumSpent. dstHead.offset(generateOrder_maximumSpent_head_offset).write( tailOffset ); // Get memory pointer to `orderParameters.consideration.length`. MemoryPointer srcConsiderationPointer = src .offset(OrderParameters_consideration_head_offset) .readMemoryPointer(); // Encode the consideration array as a `SpentItem[]`. uint256 maximumSpentSize = _encodeSpentItems( srcConsiderationPointer, dstHead.offset(tailOffset) ); unchecked { // Increment tail offset, now used to populate context array. tailOffset += maximumSpentSize; } // Write offset to context. dstHead.offset(generateOrder_context_head_offset).write(tailOffset); // Get memory pointer to context. MemoryPointer srcContext = toMemoryPointer(context); // Encode context as a bytes array. uint256 contextSize = _encodeBytes( srcContext, dstHead.offset(tailOffset) ); unchecked { // Increment the tail offset, now used to determine final size. tailOffset += contextSize; // Derive the final size by including the selector. size = Selector_length + tailOffset; } } /** * @dev Takes an order hash (e.g. offerer shifted 96 bits to the left XOR'd * with the contract nonce in the case of contract orders), an * OrderParameters struct, context bytes array, and an array of order * hashes for each order included as part of the current fulfillment * and encodes it as `ratifyOrder` calldata. * * @param orderHash The order hash (e.g. shl(0x60, offerer) ^ nonce). * @param orderParameters The OrderParameters struct used to construct the * encoded `ratifyOrder` calldata. * @param context The context bytes array used to construct the * encoded `ratifyOrder` calldata. * @param orderHashes An array of bytes32 values representing the order * hashes of all orders included as part of the * current fulfillment. * @param shiftedOfferer The offerer for the order, shifted 96 bits to the * left. * * @return dst A memory pointer referencing the encoded `ratifyOrder` * calldata. * @return size The size of the bytes array. */ function _encodeRatifyOrder( bytes32 orderHash, // e.g. shl(0x60, offerer) ^ contract nonce OrderParameters memory orderParameters, bytes memory context, // encoded based on the schemaID bytes32[] memory orderHashes, uint256 shiftedOfferer ) internal view returns (MemoryPointer dst, uint256 size) { // Get free memory pointer to write calldata to. This isn't allocated as // it is only used for a single function call. dst = getFreeMemoryPointer(); // Write ratifyOrder selector and get pointer to start of calldata. dst.write(ratifyOrder_selector); dst = dst.offset(ratifyOrder_selector_offset); // Get pointer to the beginning of the encoded data. MemoryPointer dstHead = dst.offset(ratifyOrder_head_offset); // Write contractNonce to calldata via xor(orderHash, shiftedOfferer). dstHead.offset(ratifyOrder_contractNonce_offset).write( uint256(orderHash) ^ shiftedOfferer ); // Initialize tail offset, used to populate the offer array. uint256 tailOffset = ratifyOrder_base_tail_offset; MemoryPointer src = orderParameters.toMemoryPointer(); // Write offset to `offer`. dstHead.write(tailOffset); // Get memory pointer to `orderParameters.offer.length`. MemoryPointer srcOfferPointer = src .offset(OrderParameters_offer_head_offset) .readMemoryPointer(); // Encode the offer array as a `SpentItem[]`. uint256 offerSize = _encodeSpentItems( srcOfferPointer, dstHead.offset(tailOffset) ); unchecked { // Increment tail offset, now used to populate consideration array. tailOffset += offerSize; } // Write offset to consideration. dstHead.offset(ratifyOrder_consideration_head_offset).write(tailOffset); // Get pointer to `orderParameters.consideration.length`. MemoryPointer srcConsiderationPointer = src .offset(OrderParameters_consideration_head_offset) .readMemoryPointer(); // Encode the consideration array as a `ReceivedItem[]`. uint256 considerationSize = _encodeConsiderationAsReceivedItems( srcConsiderationPointer, dstHead.offset(tailOffset) ); unchecked { // Increment tail offset, now used to populate context array. tailOffset += considerationSize; } // Write offset to context. dstHead.offset(ratifyOrder_context_head_offset).write(tailOffset); // Encode context. uint256 contextSize = _encodeBytes( toMemoryPointer(context), dstHead.offset(tailOffset) ); unchecked { // Increment tail offset, now used to populate orderHashes array. tailOffset += contextSize; } // Write offset to orderHashes. dstHead.offset(ratifyOrder_orderHashes_head_offset).write(tailOffset); // Encode orderHashes. uint256 orderHashesSize = _encodeOrderHashes( toMemoryPointer(orderHashes), dstHead.offset(tailOffset) ); unchecked { // Increment the tail offset, now used to determine final size. tailOffset += orderHashesSize; // Derive the final size by including the selector. size = Selector_length + tailOffset; } } /** * @dev Takes an order hash, OrderParameters struct, extraData bytes array, * and array of order hashes for each order included as part of the * current fulfillment and encodes it as `validateOrder` calldata. * Note that future, new versions of this contract may end up writing * to a memory region that might have been potentially dirtied by the * accumulator. Since the book-keeping for the accumulator does not * update the free memory pointer, it will be necessary to ensure that * all bytes in the memory in the range [dst, dst+size) are fully * updated/written to in this function. * * @param orderHash The order hash. * @param orderParameters The OrderParameters struct used to construct the * encoded `validateOrder` calldata. * @param extraData The extraData bytes array used to construct the * encoded `validateOrder` calldata. * @param orderHashes An array of bytes32 values representing the order * hashes of all orders included as part of the * current fulfillment. * * @return dst A memory pointer referencing the encoded `validateOrder` * calldata. * @return size The size of the bytes array. */ function _encodeValidateOrder( bytes32 orderHash, OrderParameters memory orderParameters, bytes memory extraData, bytes32[] memory orderHashes ) internal view returns (MemoryPointer dst, uint256 size) { // Get free memory pointer to write calldata to. This isn't allocated as // it is only used for a single function call. dst = getFreeMemoryPointer(); // Write validateOrder selector and get pointer to start of calldata. dst.write(validateOrder_selector); dst = dst.offset(validateOrder_selector_offset); // Get pointer to the beginning of the encoded data. MemoryPointer dstHead = dst.offset(validateOrder_head_offset); // Write offset to zoneParameters to start of calldata. dstHead.write(validateOrder_zoneParameters_offset); // Reuse `dstHead` as pointer to zoneParameters. dstHead = dstHead.offset(validateOrder_zoneParameters_offset); // Write orderHash and fulfiller to zoneParameters. dstHead.writeBytes32(orderHash); dstHead.offset(ZoneParameters_fulfiller_offset).write(msg.sender); // Get the memory pointer to the order parameters struct. MemoryPointer src = orderParameters.toMemoryPointer(); // Copy offerer, startTime, endTime and zoneHash to zoneParameters. dstHead.offset(ZoneParameters_offerer_offset).write(src.readUint256()); dstHead.offset(ZoneParameters_startTime_offset).write( src.offset(OrderParameters_startTime_offset).readUint256() ); dstHead.offset(ZoneParameters_endTime_offset).write( src.offset(OrderParameters_endTime_offset).readUint256() ); dstHead.offset(ZoneParameters_zoneHash_offset).write( src.offset(OrderParameters_zoneHash_offset).readUint256() ); // Initialize tail offset, used to populate the offer array. uint256 tailOffset = ZoneParameters_base_tail_offset; // Write offset to `offer`. dstHead.offset(ZoneParameters_offer_head_offset).write(tailOffset); // Get pointer to `orderParameters.offer.length`. MemoryPointer srcOfferPointer = src .offset(OrderParameters_offer_head_offset) .readMemoryPointer(); // Encode the offer array as a `SpentItem[]`. uint256 offerSize = _encodeSpentItems( srcOfferPointer, dstHead.offset(tailOffset) ); unchecked { // Increment tail offset, now used to populate consideration array. tailOffset += offerSize; } // Write offset to consideration. dstHead.offset(ZoneParameters_consideration_head_offset).write( tailOffset ); // Get pointer to `orderParameters.consideration.length`. MemoryPointer srcConsiderationPointer = src .offset(OrderParameters_consideration_head_offset) .readMemoryPointer(); // Encode the consideration array as a `ReceivedItem[]`. uint256 considerationSize = _encodeConsiderationAsReceivedItems( srcConsiderationPointer, dstHead.offset(tailOffset) ); unchecked { // Increment tail offset, now used to populate extraData array. tailOffset += considerationSize; } // Write offset to extraData. dstHead.offset(ZoneParameters_extraData_head_offset).write(tailOffset); // Copy extraData. uint256 extraDataSize = _encodeBytes( toMemoryPointer(extraData), dstHead.offset(tailOffset) ); unchecked { // Increment tail offset, now used to populate orderHashes array. tailOffset += extraDataSize; } // Write offset to orderHashes. dstHead.offset(ZoneParameters_orderHashes_head_offset).write( tailOffset ); // Encode the order hashes array. uint256 orderHashesSize = _encodeOrderHashes( toMemoryPointer(orderHashes), dstHead.offset(tailOffset) ); unchecked { // Increment the tail offset, now used to determine final size. tailOffset += orderHashesSize; // Derive final size including selector and ZoneParameters pointer. size = ZoneParameters_selectorAndPointer_length + tailOffset; } } /** * @dev Takes an order hash and BasicOrderParameters struct (from calldata) * and encodes it as `validateOrder` calldata. * * @param orderHash The order hash. * @param parameters The BasicOrderParameters struct used to construct the * encoded `validateOrder` calldata. * * @return dst A memory pointer referencing the encoded `validateOrder` * calldata. * @return size The size of the bytes array. */ function _encodeValidateBasicOrder( bytes32 orderHash, BasicOrderParameters calldata parameters ) internal view returns (MemoryPointer dst, uint256 size) { // Get free memory pointer to write calldata to. This isn't allocated as // it is only used for a single function call. dst = getFreeMemoryPointer(); // Write validateOrder selector and get pointer to start of calldata. dst.write(validateOrder_selector); dst = dst.offset(validateOrder_selector_offset); // Get pointer to the beginning of the encoded data. MemoryPointer dstHead = dst.offset(validateOrder_head_offset); // Write offset to zoneParameters to start of calldata. dstHead.write(validateOrder_zoneParameters_offset); // Reuse `dstHead` as pointer to zoneParameters. dstHead = dstHead.offset(validateOrder_zoneParameters_offset); // Write offerer, orderHash and fulfiller to zoneParameters. dstHead.writeBytes32(orderHash); dstHead.offset(ZoneParameters_fulfiller_offset).write(msg.sender); dstHead.offset(ZoneParameters_offerer_offset).write(parameters.offerer); // Copy startTime, endTime and zoneHash to zoneParameters. CalldataPointer.wrap(BasicOrder_startTime_cdPtr).copy( dstHead.offset(ZoneParameters_startTime_offset), BasicOrder_startTimeThroughZoneHash_size ); // Initialize tail offset, used for the offer + consideration arrays. uint256 tailOffset = ZoneParameters_base_tail_offset; // Write offset to offer from event data into target calldata. dstHead.offset(ZoneParameters_offer_head_offset).write(tailOffset); unchecked { // Write consideration offset next (located 5 words after offer). dstHead.offset(ZoneParameters_consideration_head_offset).write( tailOffset + BasicOrder_common_params_size ); // Retrieve the offset to the length of additional recipients. uint256 additionalRecipientsLength = CalldataPointer .wrap(BasicOrder_additionalRecipients_length_cdPtr) .readUint256(); // Derive offset to event data using base offset & total recipients. uint256 offerDataOffset = OrderFulfilled_offer_length_baseOffset + additionalRecipientsLength * OneWord; // Derive size of offer and consideration data. // 2 words (lengths) + 4 (offer data) + 5 (consideration 1) + 5 * ar uint256 offerAndConsiderationSize = OrderFulfilled_baseDataSize + (additionalRecipientsLength * ReceivedItem_size); // Copy offer and consideration data from event data to calldata. MemoryPointer.wrap(offerDataOffset).copy( dstHead.offset(tailOffset), offerAndConsiderationSize ); // Increment tail offset, now used to populate extraData array. tailOffset += offerAndConsiderationSize; } // Write empty bytes for extraData. dstHead.offset(ZoneParameters_extraData_head_offset).write(tailOffset); dstHead.offset(tailOffset).write(0); unchecked { // Increment tail offset, now used to populate orderHashes array. tailOffset += OneWord; } // Write offset to orderHashes. dstHead.offset(ZoneParameters_orderHashes_head_offset).write( tailOffset ); // Write length = 1 to the orderHashes array. dstHead.offset(tailOffset).write(1); unchecked { // Write the single order hash to the orderHashes array. dstHead.offset(tailOffset + OneWord).writeBytes32(orderHash); // Final size: selector, ZoneParameters pointer, orderHashes & tail. size = ZoneParameters_basicOrderFixedElements_length + tailOffset; } } /** * @dev Takes a memory pointer to an array of bytes32 values representing * the order hashes included as part of the fulfillment and a memory * pointer to a location to copy it to, and copies the source data to * the destination in memory. * * @param srcLength A memory pointer referencing the order hashes array to * be copied (and pointing to the length of the array). * @param dstLength A memory pointer referencing the location in memory to * copy the orderHashes array to (and pointing to the * length of the copied array). * * @return size The size of the order hashes array (including the length). */ function _encodeOrderHashes( MemoryPointer srcLength, MemoryPointer dstLength ) internal view returns (uint256 size) { // Read length of the array from source and write to destination. uint256 length = srcLength.readUint256(); dstLength.write(length); unchecked { // Determine head & tail size as one word per element in the array. uint256 headAndTailSize = length << OneWordShift; // Copy the tail starting from the next element of the source to the // next element of the destination. srcLength.next().copy(dstLength.next(), headAndTailSize); // Set size to the length of the tail plus one word for length. size = headAndTailSize + OneWord; } } /** * @dev Takes a memory pointer to an offer or consideration array and a * memory pointer to a location to copy it to, and copies the source * data to the destination in memory as a SpentItem array. * * @param srcLength A memory pointer referencing the offer or consideration * array to be copied as a SpentItem array (and pointing to * the length of the original array). * @param dstLength A memory pointer referencing the location in memory to * copy the offer array to (and pointing to the length of * the copied array). * * @return size The size of the SpentItem array (including the length). */ function _encodeSpentItems( MemoryPointer srcLength, MemoryPointer dstLength ) internal pure returns (uint256 size) { assembly { // Read length of the array from source and write to destination. let length := mload(srcLength) mstore(dstLength, length) // Get pointer to first item's head position in the array, // containing the item's pointer in memory. The head pointer will be // incremented until it reaches the tail position (start of the // array data). let mPtrHead := add(srcLength, OneWord) // Position in memory to write next item for calldata. Since // SpentItem has a fixed length, the array elements do not contain // head elements in calldata, they are concatenated together after // the array length. let cdPtrData := add(dstLength, OneWord) // Pointer to end of array head in memory. let mPtrHeadEnd := add(mPtrHead, shl(OneWordShift, length)) for { } lt(mPtrHead, mPtrHeadEnd) { } { // Read pointer to data for array element from head position. let mPtrTail := mload(mPtrHead) // Copy itemType, token, identifier, amount to calldata. mstore(cdPtrData, mload(mPtrTail)) mstore( add(cdPtrData, Common_token_offset), mload(add(mPtrTail, Common_token_offset)) ) mstore( add(cdPtrData, Common_identifier_offset), mload(add(mPtrTail, Common_identifier_offset)) ) mstore( add(cdPtrData, Common_amount_offset), mload(add(mPtrTail, Common_amount_offset)) ) mPtrHead := add(mPtrHead, OneWord) cdPtrData := add(cdPtrData, SpentItem_size) } size := add(OneWord, shl(SpentItem_size_shift, length)) } } /** * @dev Takes a memory pointer to an consideration array and a memory * pointer to a location to copy it to, and copies the source data to * the destination in memory as a ReceivedItem array. * * @param srcLength A memory pointer referencing the consideration array to * be copied as a ReceivedItem array (and pointing to the * length of the original array). * @param dstLength A memory pointer referencing the location in memory to * copy the consideration array to as a ReceivedItem array * (and pointing to the length of the new array). * * @return size The size of the ReceivedItem array (including the length). */ function _encodeConsiderationAsReceivedItems( MemoryPointer srcLength, MemoryPointer dstLength ) internal view returns (uint256 size) { unchecked { // Read length of the array from source and write to destination. uint256 length = srcLength.readUint256(); dstLength.write(length); // Get pointer to first item's head position in the array, // containing the item's pointer in memory. The head pointer will be // incremented until it reaches the tail position (start of the // array data). MemoryPointer srcHead = srcLength.next(); MemoryPointer srcHeadEnd = srcHead.offset(length << OneWordShift); // Position in memory to write next item for calldata. Since // ReceivedItem has a fixed length, the array elements do not // contain offsets in calldata, they are concatenated together after // the array length. MemoryPointer dstHead = dstLength.next(); while (srcHead.lt(srcHeadEnd)) { MemoryPointer srcTail = srcHead.pptr(); srcTail.copy(dstHead, ReceivedItem_size); srcHead = srcHead.next(); dstHead = dstHead.offset(ReceivedItem_size); } size = OneWord + (length * ReceivedItem_size); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { ReentrancyErrors } from "../interfaces/ReentrancyErrors.sol"; import { LowLevelHelpers } from "./LowLevelHelpers.sol"; import { _revertInvalidMsgValue, _revertNoReentrantCalls } from "./ConsiderationErrors.sol"; import { _ENTERED_AND_ACCEPTING_NATIVE_TOKENS, _ENTERED, _NOT_ENTERED } from "./ConsiderationConstants.sol"; /** * @title ReentrancyGuard * @author 0age * @notice ReentrancyGuard contains a storage variable and related functionality * for protecting against reentrancy. */ contract ReentrancyGuard is ReentrancyErrors, LowLevelHelpers { // Prevent reentrant calls on protected functions. uint256 private _reentrancyGuard; /** * @dev Initialize the reentrancy guard during deployment. */ constructor() { // Initialize the reentrancy guard in a cleared state. _reentrancyGuard = _NOT_ENTERED; } /** * @dev Internal function to ensure that a sentinel value for the reentrancy * guard is not currently set and, if not, to set a sentinel value for * the reentrancy guard based on whether or not native tokens may be * received during execution or not. * * @param acceptNativeTokens A boolean indicating whether native tokens may * be received during execution or not. */ function _setReentrancyGuard(bool acceptNativeTokens) internal { // Ensure that the reentrancy guard is not already set. _assertNonReentrant(); // Set the reentrancy guard. A value of 2 indicates that native tokens // may not be accepted during execution, whereas a value of 3 indicates // that they will be accepted (with any remaining native tokens returned // to the caller). unchecked { _reentrancyGuard = _ENTERED + _cast(acceptNativeTokens); } } /** * @dev Internal function to unset the reentrancy guard sentinel value. */ function _clearReentrancyGuard() internal { // Clear the reentrancy guard. _reentrancyGuard = _NOT_ENTERED; } /** * @dev Internal view function to ensure that a sentinel value for the reentrancy guard is not currently set. */ function _assertNonReentrant() internal view { // Ensure that the reentrancy guard is not currently set. if (_reentrancyGuard != _NOT_ENTERED) { _revertNoReentrantCalls(); } } /** * @dev Internal view function to ensure that the sentinel value indicating * native tokens may be received during execution is currently set. */ function _assertAcceptingNativeTokens() internal view { // Ensure that the reentrancy guard is not currently set. if (_reentrancyGuard != _ENTERED_AND_ACCEPTING_NATIVE_TOKENS) { _revertInvalidMsgValue(msg.value); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @title ReentrancyErrors * @author 0age * @notice ReentrancyErrors contains errors related to reentrancy. */ interface ReentrancyErrors { /** * @dev Revert with an error when a caller attempts to reenter a protected * function. */ error NoReentrantCalls(); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { CostPerWord, ExtraGasBuffer, FreeMemoryPointerSlot, MemoryExpansionCoefficientShift, OneWord, OneWordShift, ThirtyOneBytes } from "./ConsiderationConstants.sol"; /** * @title LowLevelHelpers * @author 0age * @notice LowLevelHelpers contains logic for performing various low-level * operations. */ contract LowLevelHelpers { /** * @dev Internal view function to revert and pass along the revert reason if * data was returned by the last call and that the size of that data * does not exceed the currently allocated memory size. */ function _revertWithReasonIfOneIsReturned() internal view { assembly { // If it returned a message, bubble it up as long as sufficient gas // remains to do so: if returndatasize() { // Ensure that sufficient gas is available to copy returndata // while expanding memory where necessary. Start by computing // the word size of returndata and allocated memory. let returnDataWords := shr( OneWordShift, add(returndatasize(), ThirtyOneBytes) ) // Note: use the free memory pointer in place of msize() to work // around a Yul warning that prevents accessing msize directly // when the IR pipeline is activated. let msizeWords := shr( OneWordShift, mload(FreeMemoryPointerSlot) ) // Next, compute the cost of the returndatacopy. let cost := mul(CostPerWord, returnDataWords) // Then, compute cost of new memory allocation. if gt(returnDataWords, msizeWords) { cost := add( cost, add( mul(sub(returnDataWords, msizeWords), CostPerWord), shr( MemoryExpansionCoefficientShift, sub( mul(returnDataWords, returnDataWords), mul(msizeWords, msizeWords) ) ) ) ) } // Finally, add a small constant and compare to gas remaining; // bubble up the revert data if enough gas is still available. if lt(add(cost, ExtraGasBuffer), gas()) { // Copy returndata to memory; overwrite existing memory. returndatacopy(0, 0, returndatasize()) // Revert, specifying memory region with copied returndata. revert(0, returndatasize()) } } } } /** * @dev Internal view function to branchlessly select either the caller (if * a supplied recipient is equal to zero) or the supplied recipient (if * that recipient is a nonzero value). * * @param recipient The supplied recipient. * * @return updatedRecipient The updated recipient. */ function _substituteCallerForEmptyRecipient( address recipient ) internal view returns (address updatedRecipient) { // Utilize assembly to perform a branchless operation on the recipient. assembly { // Add caller to recipient if recipient equals 0; otherwise add 0. updatedRecipient := add(recipient, mul(iszero(recipient), caller())) } } /** * @dev Internal pure function to cast a `bool` value to a `uint256` value. * * @param b The `bool` value to cast. * * @return u The `uint256` value. */ function _cast(bool b) internal pure returns (uint256 u) { assembly { u := b } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @title SignatureVerificationErrors * @author 0age * @notice SignatureVerificationErrors contains all errors related to signature * verification. */ interface SignatureVerificationErrors { /** * @dev Revert with an error when a signature that does not contain a v * value of 27 or 28 has been supplied. * * @param v The invalid v value. */ error BadSignatureV(uint8 v); /** * @dev Revert with an error when the signer recovered by the supplied * signature does not match the offerer or an allowed EIP-1271 signer * as specified by the offerer in the event they are a contract. */ error InvalidSigner(); /** * @dev Revert with an error when a signer cannot be recovered from the * supplied signature. */ error InvalidSignature(); /** * @dev Revert with an error when an EIP-1271 call to an account fails. */ error BadContractSignature(); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /* * -------------------------- Disambiguation & Other Notes --------------------- * - The term "head" is used as it is in the documentation for ABI encoding, * but only in reference to dynamic types, i.e. it always refers to the * offset or pointer to the body of a dynamic type. In calldata, the head * is always an offset (relative to the parent object), while in memory, * the head is always the pointer to the body. More information found here: * https://docs.soliditylang.org/en/v0.8.17/abi-spec.html#argument-encoding * - Note that the length of an array is separate from and precedes the * head of the array. * * - The term "body" is used in place of the term "head" used in the ABI * documentation. It refers to the start of the data for a dynamic type, * e.g. the first word of a struct or the first word of the first element * in an array. * * - The term "pointer" is used to describe the absolute position of a value * and never an offset relative to another value. * - The suffix "_ptr" refers to a memory pointer. * - The suffix "_cdPtr" refers to a calldata pointer. * * - The term "offset" is used to describe the position of a value relative * to some parent value. For example, OrderParameters_conduit_offset is the * offset to the "conduit" value in the OrderParameters struct relative to * the start of the body. * - Note: Offsets are used to derive pointers. * * - Some structs have pointers defined for all of their fields in this file. * Lines which are commented out are fields that are not used in the * codebase but have been left in for readability. */ uint256 constant ThirtyOneBytes = 0x1f; uint256 constant OneWord = 0x20; uint256 constant TwoWords = 0x40; uint256 constant ThreeWords = 0x60; uint256 constant OneWordShift = 0x5; uint256 constant TwoWordsShift = 0x6; uint256 constant FreeMemoryPointerSlot = 0x40; uint256 constant ZeroSlot = 0x60; uint256 constant DefaultFreeMemoryPointer = 0x80; uint256 constant Slot0x80 = 0x80; uint256 constant Slot0xA0 = 0xa0; uint256 constant Slot0xC0 = 0xc0; uint256 constant Generic_error_selector_offset = 0x1c; // abi.encodeWithSignature("transferFrom(address,address,uint256)") uint256 constant ERC20_transferFrom_signature = ( 0x23b872dd00000000000000000000000000000000000000000000000000000000 ); uint256 constant ERC20_transferFrom_sig_ptr = 0x0; uint256 constant ERC20_transferFrom_from_ptr = 0x04; uint256 constant ERC20_transferFrom_to_ptr = 0x24; uint256 constant ERC20_transferFrom_amount_ptr = 0x44; uint256 constant ERC20_transferFrom_length = 0x64; // 4 + 32 * 3 == 100 // abi.encodeWithSignature( // "safeTransferFrom(address,address,uint256,uint256,bytes)" // ) uint256 constant ERC1155_safeTransferFrom_signature = ( 0xf242432a00000000000000000000000000000000000000000000000000000000 ); uint256 constant ERC1155_safeTransferFrom_sig_ptr = 0x0; uint256 constant ERC1155_safeTransferFrom_from_ptr = 0x04; uint256 constant ERC1155_safeTransferFrom_to_ptr = 0x24; uint256 constant ERC1155_safeTransferFrom_id_ptr = 0x44; uint256 constant ERC1155_safeTransferFrom_amount_ptr = 0x64; uint256 constant ERC1155_safeTransferFrom_data_offset_ptr = 0x84; uint256 constant ERC1155_safeTransferFrom_data_length_ptr = 0xa4; uint256 constant ERC1155_safeTransferFrom_length = 0xc4; // 4 + 32 * 6 == 196 uint256 constant ERC1155_safeTransferFrom_data_length_offset = 0xa0; // abi.encodeWithSignature( // "safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)" // ) uint256 constant ERC1155_safeBatchTransferFrom_signature = ( 0x2eb2c2d600000000000000000000000000000000000000000000000000000000 ); // bytes4 constant ERC1155_safeBatchTransferFrom_selector = bytes4( // bytes32(ERC1155_safeBatchTransferFrom_signature) // ); uint256 constant ERC721_transferFrom_signature = ( 0x23b872dd00000000000000000000000000000000000000000000000000000000 ); uint256 constant ERC721_transferFrom_sig_ptr = 0x0; uint256 constant ERC721_transferFrom_from_ptr = 0x04; uint256 constant ERC721_transferFrom_to_ptr = 0x24; uint256 constant ERC721_transferFrom_id_ptr = 0x44; uint256 constant ERC721_transferFrom_length = 0x64; // 4 + 32 * 3 == 100 /* * error NoContract(address account) * - Defined in TokenTransferrerErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x00: account * Revert buffer is memory[0x1c:0x40] */ uint256 constant NoContract_error_selector = 0x5f15d672; uint256 constant NoContract_error_account_ptr = 0x20; uint256 constant NoContract_error_length = 0x24; /* * error TokenTransferGenericFailure( * address token, * address from, * address to, * uint256 identifier, * uint256 amount * ) * - Defined in TokenTransferrerErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x20: token * - 0x40: from * - 0x60: to * - 0x80: identifier * - 0xa0: amount * Revert buffer is memory[0x1c:0xc0] */ uint256 constant TokenTransferGenericFailure_error_selector = 0xf486bc87; uint256 constant TokenTransferGenericFailure_error_token_ptr = 0x20; uint256 constant TokenTransferGenericFailure_error_from_ptr = 0x40; uint256 constant TokenTransferGenericFailure_error_to_ptr = 0x60; uint256 constant TokenTransferGenericFailure_error_identifier_ptr = 0x80; uint256 constant TokenTransferGenericFailure_err_identifier_ptr = 0x80; uint256 constant TokenTransferGenericFailure_error_amount_ptr = 0xa0; uint256 constant TokenTransferGenericFailure_error_length = 0xa4; uint256 constant ExtraGasBuffer = 0x20; uint256 constant CostPerWord = 0x3; uint256 constant MemoryExpansionCoefficientShift = 0x9; // Values are offset by 32 bytes in order to write the token to the beginning // in the event of a revert uint256 constant BatchTransfer1155Params_ptr = 0x24; uint256 constant BatchTransfer1155Params_ids_head_ptr = 0x64; uint256 constant BatchTransfer1155Params_amounts_head_ptr = 0x84; uint256 constant BatchTransfer1155Params_data_head_ptr = 0xa4; uint256 constant BatchTransfer1155Params_data_length_basePtr = 0xc4; uint256 constant BatchTransfer1155Params_calldata_baseSize = 0xc4; uint256 constant BatchTransfer1155Params_ids_length_ptr = 0xc4; uint256 constant BatchTransfer1155Params_ids_length_offset = 0xa0; // uint256 constant BatchTransfer1155Params_amounts_length_baseOffset = 0xc0; // uint256 constant BatchTransfer1155Params_data_length_baseOffset = 0xe0; uint256 constant ConduitBatch1155Transfer_usable_head_size = 0x80; uint256 constant ConduitBatch1155Transfer_from_offset = 0x20; uint256 constant ConduitBatch1155Transfer_ids_head_offset = 0x60; // uint256 constant ConduitBatch1155Transfer_amounts_head_offset = 0x80; uint256 constant ConduitBatch1155Transfer_ids_length_offset = 0xa0; uint256 constant ConduitBatch1155Transfer_amounts_length_baseOffset = 0xc0; // uint256 constant ConduitBatch1155Transfer_calldata_baseSize = 0xc0; // Note: abbreviated version of above constant to adhere to line length limit. uint256 constant ConduitBatchTransfer_amounts_head_offset = 0x80; uint256 constant Invalid1155BatchTransferEncoding_ptr = 0x00; uint256 constant Invalid1155BatchTransferEncoding_length = 0x04; uint256 constant Invalid1155BatchTransferEncoding_selector = ( 0xeba2084c00000000000000000000000000000000000000000000000000000000 ); uint256 constant ERC1155BatchTransferGenericFailure_error_signature = ( 0xafc445e200000000000000000000000000000000000000000000000000000000 ); uint256 constant ERC1155BatchTransferGenericFailure_token_ptr = 0x04; uint256 constant ERC1155BatchTransferGenericFailure_ids_offset = 0xc0; /* * error BadReturnValueFromERC20OnTransfer( * address token, address from, address to, uint256 amount * ) * - Defined in TokenTransferrerErrors.sol * Memory layout: * - 0x00: Left-padded selector (data begins at 0x1c) * - 0x00: token * - 0x20: from * - 0x40: to * - 0x60: amount * Revert buffer is memory[0x1c:0xa0] */ uint256 constant BadReturnValueFromERC20OnTransfer_error_selector = 0x98891923; uint256 constant BadReturnValueFromERC20OnTransfer_error_token_ptr = 0x20; uint256 constant BadReturnValueFromERC20OnTransfer_error_from_ptr = 0x40; uint256 constant BadReturnValueFromERC20OnTransfer_error_to_ptr = 0x60; uint256 constant BadReturnValueFromERC20OnTransfer_error_amount_ptr = 0x80; uint256 constant BadReturnValueFromERC20OnTransfer_error_length = 0x84;
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @title ZoneInteractionErrors * @author 0age * @notice ZoneInteractionErrors contains errors related to zone interaction. */ interface ZoneInteractionErrors { /** * @dev Revert with an error when attempting to fill an order that specifies * a restricted submitter as its order type when not submitted by * either the offerer or the order's zone or approved as valid by the * zone in question via a call to `isValidOrder`. * * @param orderHash The order hash for the invalid restricted order. */ error InvalidRestrictedOrder(bytes32 orderHash); /** * @dev Revert with an error when attempting to fill a contract order that * fails to generate an order successfully, that does not adhere to the * requirements for minimum spent or maximum received supplied by the * fulfiller, or that fails the post-execution `ratifyOrder` check.. * * @param orderHash The order hash for the invalid contract order. */ error InvalidContractOrder(bytes32 orderHash); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { Side } from "../lib/ConsiderationEnums.sol"; /** * @title CriteriaResolutionErrors * @author 0age * @notice CriteriaResolutionErrors contains all errors related to criteria * resolution. */ interface CriteriaResolutionErrors { /** * @dev Revert with an error when providing a criteria resolver that refers * to an order that has not been supplied. * * @param side The side of the order that was not supplied. */ error OrderCriteriaResolverOutOfRange(Side side); /** * @dev Revert with an error if an offer item still has unresolved criteria * after applying all criteria resolvers. * * @param orderIndex The index of the order that contains the offer item. * @param offerIndex The index of the offer item that still has unresolved * criteria. */ error UnresolvedOfferCriteria(uint256 orderIndex, uint256 offerIndex); /** * @dev Revert with an error if a consideration item still has unresolved * criteria after applying all criteria resolvers. * * @param orderIndex The index of the order that contains the * consideration item. * @param considerationIndex The index of the consideration item that still * has unresolved criteria. */ error UnresolvedConsiderationCriteria( uint256 orderIndex, uint256 considerationIndex ); /** * @dev Revert with an error when providing a criteria resolver that refers * to an order with an offer item that has not been supplied. */ error OfferCriteriaResolverOutOfRange(); /** * @dev Revert with an error when providing a criteria resolver that refers * to an order with a consideration item that has not been supplied. */ error ConsiderationCriteriaResolverOutOfRange(); /** * @dev Revert with an error when providing a criteria resolver that refers * to an order with an item that does not expect a criteria to be * resolved. */ error CriteriaNotEnabledForItem(); /** * @dev Revert with an error when providing a criteria resolver that * contains an invalid proof with respect to the given item and * chosen identifier. */ error InvalidProof(); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @title AmountDerivationErrors * @author 0age * @notice AmountDerivationErrors contains errors related to amount derivation. */ interface AmountDerivationErrors { /** * @dev Revert with an error when attempting to apply a fraction as part of * a partial fill that does not divide the target amount cleanly. */ error InexactFraction(); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { Side } from "../lib/ConsiderationEnums.sol"; /** * @title FulfillmentApplicationErrors * @author 0age * @notice FulfillmentApplicationErrors contains errors related to fulfillment * application and aggregation. */ interface FulfillmentApplicationErrors { /** * @dev Revert with an error when a fulfillment is provided that does not * declare at least one component as part of a call to fulfill * available orders. */ error MissingFulfillmentComponentOnAggregation(Side side); /** * @dev Revert with an error when a fulfillment is provided that does not * declare at least one offer component and at least one consideration * component. */ error OfferAndConsiderationRequiredOnFulfillment(); /** * @dev Revert with an error when the initial offer item named by a * fulfillment component does not match the type, token, identifier, * or conduit preference of the initial consideration item. * * @param fulfillmentIndex The index of the fulfillment component that * does not match the initial offer item. */ error MismatchedFulfillmentOfferAndConsiderationComponents( uint256 fulfillmentIndex ); /** * @dev Revert with an error when an order or item index are out of range * or a fulfillment component does not match the type, token, * identifier, or conduit preference of the initial consideration item. */ error InvalidFulfillmentComponentData(); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import { FreeMemoryPointerSlot, OneWord, OneWordShift, ThirtyOneBytes } from "../lib/ConsiderationConstants.sol"; /** * @title TypehashDirectory * @notice The typehash directory contains 24 bulk order EIP-712 typehashes, * depending on the height of the tree in each bulk order payload, as * its runtime code (with an invalid opcode prefix so that the contract * cannot be called normally). This runtime code is designed to be read * from by Seaport using `extcodecopy` while verifying bulk signatures. */ contract TypehashDirectory { // Encodes "[2]" for use in deriving typehashes. bytes3 internal constant twoSubstring = 0x5B325D; uint256 internal constant twoSubstringLength = 0x3; // Dictates maximum bulk order group size; 24 => 2^24 => 16,777,216 orders. uint256 internal constant MaxTreeHeight = 0x18; uint256 internal constant InvalidOpcode = 0xfe; /** * @dev Derive 24 bulk order EIP-712 typehashes, one for each supported * tree height from 1 to 24, and write them to runtime code. */ constructor() { // Declare an array where each type hash will be written. bytes32[] memory typeHashes = new bytes32[](MaxTreeHeight); // Derive a string of 24 "[2]" substrings. bytes memory brackets = getMaxTreeBrackets(MaxTreeHeight); // Derive a string of subtypes for the order parameters. bytes memory subTypes = getTreeSubTypes(); // Cache memory pointer before each loop so memory doesn't expand by the // full string size on each loop. uint256 freeMemoryPointer; assembly { freeMemoryPointer := mload(FreeMemoryPointerSlot) } // Iterate over each tree height. for (uint256 i = 0; i < MaxTreeHeight; ) { // The actual height is one greater than its respective index. uint256 height = i + 1; // Slice brackets length to size needed for `height`. assembly { mstore(brackets, mul(twoSubstringLength, height)) } // Encode the type string for the BulkOrder struct. bytes memory bulkOrderTypeString = bytes.concat( "BulkOrder(OrderComponents", brackets, " tree)", subTypes ); // Derive EIP712 type hash. bytes32 typeHash = keccak256(bulkOrderTypeString); typeHashes[i] = typeHash; // Reset the free memory pointer. assembly { mstore(FreeMemoryPointerSlot, freeMemoryPointer) } unchecked { ++i; } } assembly { // Overwrite length with zero to give the contract an INVALID prefix // and deploy the type hashes array as a contract. mstore(typeHashes, InvalidOpcode) return( add(typeHashes, ThirtyOneBytes), add(shl(OneWordShift, MaxTreeHeight), 1) ) } } /** * @dev Internal pure function that returns a string of "[2]" substrings, * with a number of substrings equal to the provided height. * * @param maxHeight The number of "[2]" substrings to include. * * @return A bytes array representing the string. */ function getMaxTreeBrackets( uint256 maxHeight ) internal pure returns (bytes memory) { bytes memory suffixes = new bytes(twoSubstringLength * maxHeight); assembly { // Retrieve the pointer to the array head. let ptr := add(suffixes, OneWord) // Derive the terminal pointer. let endPtr := add(ptr, mul(maxHeight, twoSubstringLength)) // Iterate over each pointer until terminal pointer is reached. for { } lt(ptr, endPtr) { ptr := add(ptr, twoSubstringLength) } { // Insert "[2]" substring directly at current pointer location. mstore(ptr, twoSubstring) } } // Return the fully populated array of substrings. return suffixes; } /** * @dev Internal pure function that returns a string of subtypes used in * generating bulk order EIP-712 typehashes. * * @return A bytes array representing the string. */ function getTreeSubTypes() internal pure returns (bytes memory) { // Construct the OfferItem type string. bytes memory offerItemTypeString = bytes( "OfferItem(" "uint8 itemType," "address token," "uint256 identifierOrCriteria," "uint256 startAmount," "uint256 endAmount" ")" ); // Construct the ConsiderationItem type string. bytes memory considerationItemTypeString = bytes( "ConsiderationItem(" "uint8 itemType," "address token," "uint256 identifierOrCriteria," "uint256 startAmount," "uint256 endAmount," "address recipient" ")" ); // Construct the OrderComponents type string, not including the above. bytes memory orderComponentsPartialTypeString = bytes( "OrderComponents(" "address offerer," "address zone," "OfferItem[] offer," "ConsiderationItem[] consideration," "uint8 orderType," "uint256 startTime," "uint256 endTime," "bytes32 zoneHash," "uint256 salt," "bytes32 conduitKey," "uint256 counter" ")" ); // Return the combined string. return bytes.concat( considerationItemTypeString, offerItemTypeString, orderComponentsPartialTypeString ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { SeaportInterface } from "../../interfaces/SeaportInterface.sol"; import { AdvancedOrder, CriteriaResolver, Execution, Fulfillment, Order, OrderComponents } from "../../lib/ConsiderationStructs.sol"; /** * @title PausableZone * @author cupOJoseph, BCLeFevre, ryanio * @notice PausableZone is a simple zone implementation that approves every * order. It can be self-destructed by its controller to pause * restricted orders that have it set as their zone. */ interface PausableZoneInterface { /** * @notice Cancel an arbitrary number of orders that have agreed to use the * contract as their zone. * * @param seaport The Seaport address. * @param orders The orders to cancel. * * @return cancelled A boolean indicating whether the supplied orders have * been successfully cancelled. */ function cancelOrders( SeaportInterface seaport, OrderComponents[] calldata orders ) external returns (bool cancelled); /** * @notice Execute an arbitrary number of matched orders, each with * an arbitrary number of items for offer and consideration * along with a set of fulfillments allocating offer components * to consideration components. * * @param seaport The Seaport address. * @param orders The orders to match. * @param fulfillments An array of elements allocating offer components * to consideration components. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function executeMatchOrders( SeaportInterface seaport, Order[] calldata orders, Fulfillment[] calldata fulfillments ) external payable returns (Execution[] memory executions); /** * @notice Execute an arbitrary number of matched advanced orders, * each with an arbitrary number of items for offer and * consideration along with a set of fulfillments allocating * offer components to consideration components. * * @param seaport The Seaport address. * @param orders The orders to match. * @param criteriaResolvers An array where each element contains a reference * to a specific order as well as that order's * offer or consideration, a token identifier, and * a proof that the supplied token identifier is * contained in the order's merkle root. * @param fulfillments An array of elements allocating offer components * to consideration components. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function executeMatchAdvancedOrders( SeaportInterface seaport, AdvancedOrder[] calldata orders, CriteriaResolver[] calldata criteriaResolvers, Fulfillment[] calldata fulfillments ) external payable returns (Execution[] memory executions); /** * @notice Pause this contract, safely stopping orders from using * the contract as a zone. Restricted orders with this address as a * zone will not be fulfillable unless the zone is redeployed to the * same address. */ function pause(address payee) external; /** * @notice Assign the given address with the ability to operate the zone. * * @param operatorToAssign The address to assign as the operator. */ function assignOperator(address operatorToAssign) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { AdvancedOrder, BasicOrderParameters, CriteriaResolver, Execution, Fulfillment, FulfillmentComponent, Order, OrderComponents } from "../lib/ConsiderationStructs.sol"; /** * @title SeaportInterface * @author 0age * @custom:version 1.4 * @notice Seaport is a generalized native token/ERC20/ERC721/ERC1155 * marketplace. It minimizes external calls to the greatest extent * possible and provides lightweight methods for common routes as well * as more flexible methods for composing advanced orders. * * @dev SeaportInterface contains all external function interfaces for Seaport. */ interface SeaportInterface { /** * @notice Fulfill an order offering an ERC721 token by supplying Ether (or * the native token for the given chain) as consideration for the * order. An arbitrary number of "additional recipients" may also be * supplied which will each receive native tokens from the fulfiller * as consideration. * * @param parameters Additional information on the fulfilled order. Note * that the offerer must first approve this contract (or * their preferred conduit if indicated by the order) for * their offered ERC721 token to be transferred. * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillBasicOrder( BasicOrderParameters calldata parameters ) external payable returns (bool fulfilled); /** * @notice Fulfill an order with an arbitrary number of items for offer and * consideration. Note that this function does not support * criteria-based orders or partial filling of orders (though * filling the remainder of a partially-filled order is supported). * * @param order The order to fulfill. Note that both the * offerer and the fulfiller must first approve * this contract (or the corresponding conduit if * indicated) to transfer any relevant tokens on * their behalf and that contracts must implement * `onERC1155Received` to receive ERC1155 tokens * as consideration. * @param fulfillerConduitKey A bytes32 value indicating what conduit, if * any, to source the fulfiller's token approvals * from. The zero hash signifies that no conduit * should be used, with direct approvals set on * Seaport. * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillOrder( Order calldata order, bytes32 fulfillerConduitKey ) external payable returns (bool fulfilled); /** * @notice Fill an order, fully or partially, with an arbitrary number of * items for offer and consideration alongside criteria resolvers * containing specific token identifiers and associated proofs. * * @param advancedOrder The order to fulfill along with the fraction * of the order to attempt to fill. Note that * both the offerer and the fulfiller must first * approve this contract (or their preferred * conduit if indicated by the order) to transfer * any relevant tokens on their behalf and that * contracts must implement `onERC1155Received` * to receive ERC1155 tokens as consideration. * Also note that all offer and consideration * components must have no remainder after * multiplication of the respective amount with * the supplied fraction for the partial fill to * be considered valid. * @param criteriaResolvers An array where each element contains a * reference to a specific offer or * consideration, a token identifier, and a proof * that the supplied token identifier is * contained in the merkle root held by the item * in question's criteria element. Note that an * empty criteria indicates that any * (transferable) token identifier on the token * in question is valid and that no associated * proof needs to be supplied. * @param fulfillerConduitKey A bytes32 value indicating what conduit, if * any, to source the fulfiller's token approvals * from. The zero hash signifies that no conduit * should be used, with direct approvals set on * Seaport. * @param recipient The intended recipient for all received items, * with `address(0)` indicating that the caller * should receive the items. * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillAdvancedOrder( AdvancedOrder calldata advancedOrder, CriteriaResolver[] calldata criteriaResolvers, bytes32 fulfillerConduitKey, address recipient ) external payable returns (bool fulfilled); /** * @notice Attempt to fill a group of orders, each with an arbitrary number * of items for offer and consideration. Any order that is not * currently active, has already been fully filled, or has been * cancelled will be omitted. Remaining offer and consideration * items will then be aggregated where possible as indicated by the * supplied offer and consideration component arrays and aggregated * items will be transferred to the fulfiller or to each intended * recipient, respectively. Note that a failing item transfer or an * issue with order formatting will cause the entire batch to fail. * Note that this function does not support criteria-based orders or * partial filling of orders (though filling the remainder of a * partially-filled order is supported). * * @param orders The orders to fulfill. Note that both * the offerer and the fulfiller must first * approve this contract (or the * corresponding conduit if indicated) to * transfer any relevant tokens on their * behalf and that contracts must implement * `onERC1155Received` to receive ERC1155 * tokens as consideration. * @param offerFulfillments An array of FulfillmentComponent arrays * indicating which offer items to attempt * to aggregate when preparing executions. * @param considerationFulfillments An array of FulfillmentComponent arrays * indicating which consideration items to * attempt to aggregate when preparing * executions. * @param fulfillerConduitKey A bytes32 value indicating what conduit, * if any, to source the fulfiller's token * approvals from. The zero hash signifies * that no conduit should be used, with * direct approvals set on this contract. * @param maximumFulfilled The maximum number of orders to fulfill. * * @return availableOrders An array of booleans indicating if each order * with an index corresponding to the index of the * returned boolean was fulfillable or not. * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. Note that unspent offer item amounts or * native tokens will not be reflected as part of * this array. */ function fulfillAvailableOrders( Order[] calldata orders, FulfillmentComponent[][] calldata offerFulfillments, FulfillmentComponent[][] calldata considerationFulfillments, bytes32 fulfillerConduitKey, uint256 maximumFulfilled ) external payable returns (bool[] memory availableOrders, Execution[] memory executions); /** * @notice Attempt to fill a group of orders, fully or partially, with an * arbitrary number of items for offer and consideration per order * alongside criteria resolvers containing specific token * identifiers and associated proofs. Any order that is not * currently active, has already been fully filled, or has been * cancelled will be omitted. Remaining offer and consideration * items will then be aggregated where possible as indicated by the * supplied offer and consideration component arrays and aggregated * items will be transferred to the fulfiller or to each intended * recipient, respectively. Note that a failing item transfer or an * issue with order formatting will cause the entire batch to fail. * * @param advancedOrders The orders to fulfill along with the * fraction of those orders to attempt to * fill. Note that both the offerer and the * fulfiller must first approve this * contract (or their preferred conduit if * indicated by the order) to transfer any * relevant tokens on their behalf and that * contracts must implement * `onERC1155Received` to enable receipt of * ERC1155 tokens as consideration. Also * note that all offer and consideration * components must have no remainder after * multiplication of the respective amount * with the supplied fraction for an * order's partial fill amount to be * considered valid. * @param criteriaResolvers An array where each element contains a * reference to a specific offer or * consideration, a token identifier, and a * proof that the supplied token identifier * is contained in the merkle root held by * the item in question's criteria element. * Note that an empty criteria indicates * that any (transferable) token * identifier on the token in question is * valid and that no associated proof needs * to be supplied. * @param offerFulfillments An array of FulfillmentComponent arrays * indicating which offer items to attempt * to aggregate when preparing executions. * @param considerationFulfillments An array of FulfillmentComponent arrays * indicating which consideration items to * attempt to aggregate when preparing * executions. * @param fulfillerConduitKey A bytes32 value indicating what conduit, * if any, to source the fulfiller's token * approvals from. The zero hash signifies * that no conduit should be used, with * direct approvals set on this contract. * @param recipient The intended recipient for all received * items, with `address(0)` indicating that * the caller should receive the items. * @param maximumFulfilled The maximum number of orders to fulfill. * * @return availableOrders An array of booleans indicating if each order * with an index corresponding to the index of the * returned boolean was fulfillable or not. * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. Note that unspent offer item amounts or * native tokens will not be reflected as part of * this array. */ function fulfillAvailableAdvancedOrders( AdvancedOrder[] calldata advancedOrders, CriteriaResolver[] calldata criteriaResolvers, FulfillmentComponent[][] calldata offerFulfillments, FulfillmentComponent[][] calldata considerationFulfillments, bytes32 fulfillerConduitKey, address recipient, uint256 maximumFulfilled ) external payable returns (bool[] memory availableOrders, Execution[] memory executions); /** * @notice Match an arbitrary number of orders, each with an arbitrary * number of items for offer and consideration along with a set of * fulfillments allocating offer components to consideration * components. Note that this function does not support * criteria-based or partial filling of orders (though filling the * remainder of a partially-filled order is supported). Any unspent * offer item amounts or native tokens will be transferred to the * caller. * * @param orders The orders to match. Note that both the offerer and * fulfiller on each order must first approve this * contract (or their conduit if indicated by the order) * to transfer any relevant tokens on their behalf and * each consideration recipient must implement * `onERC1155Received` to enable ERC1155 token receipt. * @param fulfillments An array of elements allocating offer components to * consideration components. Note that each * consideration component must be fully met for the * match operation to be valid. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. Note that unspent offer item amounts or * native tokens will not be reflected as part of this * array. */ function matchOrders( Order[] calldata orders, Fulfillment[] calldata fulfillments ) external payable returns (Execution[] memory executions); /** * @notice Match an arbitrary number of full or partial orders, each with an * arbitrary number of items for offer and consideration, supplying * criteria resolvers containing specific token identifiers and * associated proofs as well as fulfillments allocating offer * components to consideration components. Any unspent offer item * amounts will be transferred to the designated recipient (with the * null address signifying to use the caller) and any unspent native * tokens will be returned to the caller. * * @param orders The advanced orders to match. Note that both the * offerer and fulfiller on each order must first * approve this contract (or a preferred conduit if * indicated by the order) to transfer any relevant * tokens on their behalf and each consideration * recipient must implement `onERC1155Received` in * order to receive ERC1155 tokens. Also note that * the offer and consideration components for each * order must have no remainder after multiplying * the respective amount with the supplied fraction * in order for the group of partial fills to be * considered valid. * @param criteriaResolvers An array where each element contains a reference * to a specific order as well as that order's * offer or consideration, a token identifier, and * a proof that the supplied token identifier is * contained in the order's merkle root. Note that * an empty root indicates that any (transferable) * token identifier is valid and that no associated * proof needs to be supplied. * @param fulfillments An array of elements allocating offer components * to consideration components. Note that each * consideration component must be fully met in * order for the match operation to be valid. * @param recipient The intended recipient for all unspent offer * item amounts, or the caller if the null address * is supplied. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. Note that unspent offer item amounts or native * tokens will not be reflected as part of this array. */ function matchAdvancedOrders( AdvancedOrder[] calldata orders, CriteriaResolver[] calldata criteriaResolvers, Fulfillment[] calldata fulfillments, address recipient ) external payable returns (Execution[] memory executions); /** * @notice Cancel an arbitrary number of orders. Note that only the offerer * or the zone of a given order may cancel it. Callers should ensure * that the intended order was cancelled by calling `getOrderStatus` * and confirming that `isCancelled` returns `true`. * * @param orders The orders to cancel. * * @return cancelled A boolean indicating whether the supplied orders have * been successfully cancelled. */ function cancel( OrderComponents[] calldata orders ) external returns (bool cancelled); /** * @notice Validate an arbitrary number of orders, thereby registering their * signatures as valid and allowing the fulfiller to skip signature * verification on fulfillment. Note that validated orders may still * be unfulfillable due to invalid item amounts or other factors; * callers should determine whether validated orders are fulfillable * by simulating the fulfillment call prior to execution. Also note * that anyone can validate a signed order, but only the offerer can * validate an order without supplying a signature. * * @param orders The orders to validate. * * @return validated A boolean indicating whether the supplied orders have * been successfully validated. */ function validate( Order[] calldata orders ) external returns (bool validated); /** * @notice Cancel all orders from a given offerer with a given zone in bulk * by incrementing a counter. Note that only the offerer may * increment the counter. * * @return newCounter The new counter. */ function incrementCounter() external returns (uint256 newCounter); /** * @notice Fulfill an order offering an ERC721 token by supplying Ether (or * the native token for the given chain) as consideration for the * order. An arbitrary number of "additional recipients" may also be * supplied which will each receive native tokens from the fulfiller * as consideration. Note that this function costs less gas than * `fulfillBasicOrder` due to the zero bytes in the function * selector (0x00000000) which also results in earlier function * dispatch. * * @param parameters Additional information on the fulfilled order. Note * that the offerer must first approve this contract (or * their preferred conduit if indicated by the order) for * their offered ERC721 token to be transferred. * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillBasicOrder_efficient_6GL6yc( BasicOrderParameters calldata parameters ) external payable returns (bool fulfilled); /** * @notice Retrieve the order hash for a given order. * * @param order The components of the order. * * @return orderHash The order hash. */ function getOrderHash( OrderComponents calldata order ) external view returns (bytes32 orderHash); /** * @notice Retrieve the status of a given order by hash, including whether * the order has been cancelled or validated and the fraction of the * order that has been filled. * * @param orderHash The order hash in question. * * @return isValidated A boolean indicating whether the order in question * has been validated (i.e. previously approved or * partially filled). * @return isCancelled A boolean indicating whether the order in question * has been cancelled. * @return totalFilled The total portion of the order that has been filled * (i.e. the "numerator"). * @return totalSize The total size of the order that is either filled or * unfilled (i.e. the "denominator"). */ function getOrderStatus( bytes32 orderHash ) external view returns ( bool isValidated, bool isCancelled, uint256 totalFilled, uint256 totalSize ); /** * @notice Retrieve the current counter for a given offerer. * * @param offerer The offerer in question. * * @return counter The current counter. */ function getCounter( address offerer ) external view returns (uint256 counter); /** * @notice Retrieve configuration information for this contract. * * @return version The contract version. * @return domainSeparator The domain separator for this contract. * @return conduitController The conduit Controller set for this contract. */ function information() external view returns ( string memory version, bytes32 domainSeparator, address conduitController ); function getContractOffererNonce( address contractOfferer ) external view returns (uint256 nonce); /** * @notice Retrieve the name of this contract. * * @return contractName The name of this contract. */ function name() external view returns (string memory contractName); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { AdvancedOrder, CriteriaResolver, Execution, Fulfillment, Order, OrderComponents } from "../../lib/ConsiderationStructs.sol"; import { SeaportInterface } from "../../interfaces/SeaportInterface.sol"; /** * @title PausableZoneController * @author cupOJoseph, BCLeFevre, stuckinaboot * @notice PausableZoneController enables deploying, pausing and executing * orders on PausableZones. This deployer is designed to be owned * by a gnosis safe, DAO, or trusted party. */ interface PausableZoneControllerInterface { /** * @notice Deploy a PausableZone to a precomputed address. * * @param salt The salt to be used to derive the zone address * * @return derivedAddress The derived address for the zone. */ function createZone(bytes32 salt) external returns (address derivedAddress); /** * @notice Pause orders on a given zone. * * @param zone The address of the zone to be paused. * * @return success A boolean indicating the zone has been paused. */ function pause(address zone) external returns (bool success); /** * @notice Cancel Seaport offers on a given zone. * * @param pausableZoneAddress The zone that manages the orders to be * cancelled. * @param seaportAddress The Seaport address. * @param orders The orders to cancel. */ function cancelOrders( address pausableZoneAddress, SeaportInterface seaportAddress, OrderComponents[] calldata orders ) external; /** * @notice Execute an arbitrary number of matched orders on a given zone. * * @param pausableZoneAddress The zone that manages the orders to be * cancelled. * @param seaportAddress The Seaport address. * @param orders The orders to match. * @param fulfillments An array of elements allocating offer * components to consideration components. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function executeMatchOrders( address pausableZoneAddress, SeaportInterface seaportAddress, Order[] calldata orders, Fulfillment[] calldata fulfillments ) external payable returns (Execution[] memory executions); /** * @notice Execute an arbitrary number of matched advanced orders on a * given zone. * * @param pausableZoneAddress The zone that manages the orders to be * cancelled. * @param seaportAddress The Seaport address. * @param orders The orders to match. * @param criteriaResolvers An array where each element contains a * reference to a specific order as well as * that order's offer or consideration, * a token identifier, and a proof that * the supplied token identifier is * contained in the order's merkle root. * @param fulfillments An array of elements allocating offer * components to consideration components. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function executeMatchAdvancedOrders( address pausableZoneAddress, SeaportInterface seaportAddress, AdvancedOrder[] calldata orders, CriteriaResolver[] calldata criteriaResolvers, Fulfillment[] calldata fulfillments ) external payable returns (Execution[] memory executions); /** * @notice Initiate Zone ownership transfer by assigning a new potential * owner this contract. Once set, the new potential owner * may call `acceptOwnership` to claim ownership. * Only the owner in question may call this function. * * @param newPotentialOwner The address for which to initiate ownership * transfer to. */ function transferOwnership(address newPotentialOwner) external; /** * @notice Clear the currently set potential owner, if any. * Only the owner of this contract may call this function. */ function cancelOwnershipTransfer() external; /** * @notice Accept ownership of this contract. Only the account that the * current owner has set as the new potential owner may call this * function. */ function acceptOwnership() external; /** * @notice Assign the given address with the ability to pause the zone. * * @param pauserToAssign The address to assign the pauser role. */ function assignPauser(address pauserToAssign) external; /** * @notice Assign the given address with the ability to operate the * given zone. * * @param pausableZoneAddress The zone address to assign operator role. * @param operatorToAssign The address to assign as operator. */ function assignOperator( address pausableZoneAddress, address operatorToAssign ) external; /** * @notice An external view function that returns the owner. * * @return The address of the owner. */ function owner() external view returns (address); /** * @notice An external view function that return the potential owner. * * @return The address of the potential owner. */ function potentialOwner() external view returns (address); /** * @notice An external view function that returns the pauser. * * @return The address of the pauser. */ function pauser() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { PausableZone } from "./PausableZone.sol"; import { PausableZoneControllerInterface } from "./interfaces/PausableZoneControllerInterface.sol"; import { PausableZoneEventsAndErrors } from "./interfaces/PausableZoneEventsAndErrors.sol"; import { AdvancedOrder, CriteriaResolver, Execution, Fulfillment, Order, OrderComponents } from "../lib/ConsiderationStructs.sol"; import { SeaportInterface } from "../interfaces/SeaportInterface.sol"; /** * @title PausableZoneController * @author cupOJoseph, BCLeFevre, stuckinaboot, stephankmin * @notice PausableZoneController enables deploying, pausing and executing * orders on PausableZones. This deployer is designed to be owned * by a gnosis safe, DAO, or trusted party. */ contract PausableZoneController is PausableZoneControllerInterface, PausableZoneEventsAndErrors { // Set the owner that can deploy, pause and execute orders on PausableZones. address internal _owner; // Set the address of the new potential owner of the zone. address private _potentialOwner; // Set the address with the ability to pause the zone. address internal _pauser; // Set the immutable zone creation code hash. bytes32 public immutable zoneCreationCode; /** * @dev Throws if called by any account other than the owner or pauser. */ modifier isPauser() { if (msg.sender != _pauser && msg.sender != _owner) { revert InvalidPauser(); } _; } /** * @notice Set the owner of the controller and store * the zone creation code. * * @param ownerAddress The deployer to be set as the owner. */ constructor(address ownerAddress) { // Set the owner address as the owner. _owner = ownerAddress; // Hash and store the zone creation code. zoneCreationCode = keccak256(type(PausableZone).creationCode); } /** * @notice Deploy a PausableZone to a precomputed address. * * @param salt The salt to be used to derive the zone address * * @return derivedAddress The derived address for the zone. */ function createZone( bytes32 salt ) external override returns (address derivedAddress) { // Ensure the caller is the owner. if (msg.sender != _owner) { revert CallerIsNotOwner(); } // Derive the PausableZone address. // This expression demonstrates address computation but is not required. derivedAddress = address( uint160( uint256( keccak256( abi.encodePacked( bytes1(0xff), address(this), salt, zoneCreationCode ) ) ) ) ); // Revert if a zone is currently deployed to the derived address. if (derivedAddress.code.length != 0) { revert ZoneAlreadyExists(derivedAddress); } // Deploy the zone using the supplied salt. new PausableZone{ salt: salt }(); // Emit an event signifying that the zone was created. emit ZoneCreated(derivedAddress, salt); } /** * @notice Pause orders on a given zone. * * @param zone The address of the zone to be paused. * * @return success A boolean indicating the zone has been paused. */ function pause( address zone ) external override isPauser returns (bool success) { // Call pause on the given zone. PausableZone(zone).pause(msg.sender); // Return a boolean indicating the pause was successful. success = true; } /** * @notice Cancel Seaport orders on a given zone. * * @param pausableZoneAddress The zone that manages the * orders to be cancelled. * @param seaportAddress The Seaport address. * @param orders The orders to cancel. */ function cancelOrders( address pausableZoneAddress, SeaportInterface seaportAddress, OrderComponents[] calldata orders ) external override { // Ensure the caller is the owner. if (msg.sender != _owner) { revert CallerIsNotOwner(); } // Create a zone object from the zone address. PausableZone zone = PausableZone(pausableZoneAddress); // Call cancelOrders on the given zone. zone.cancelOrders(seaportAddress, orders); } /** * @notice Execute an arbitrary number of matched orders on a given zone. * * @param pausableZoneAddress The zone that manages the orders * to be cancelled. * @param seaportAddress The Seaport address. * @param orders The orders to match. * @param fulfillments An array of elements allocating offer * components to consideration components. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function executeMatchOrders( address pausableZoneAddress, SeaportInterface seaportAddress, Order[] calldata orders, Fulfillment[] calldata fulfillments ) external payable override returns (Execution[] memory executions) { // Ensure the caller is the owner. if (msg.sender != _owner) { revert CallerIsNotOwner(); } // Create a zone object from the zone address. PausableZone zone = PausableZone(pausableZoneAddress); // Call executeMatchOrders on the given zone and return the sequence // of transfers performed as part of matching the given orders. executions = zone.executeMatchOrders{ value: msg.value }( seaportAddress, orders, fulfillments ); } /** * @notice Execute an arbitrary number of matched advanced orders on a given * zone. * * @param pausableZoneAddress The zone that manages the orders to be * cancelled. * @param seaportAddress The Seaport address. * @param orders The orders to match. * @param criteriaResolvers An array where each element contains a * reference to a specific order as well as that * order's offer or consideration, a token * identifier, and a proof that the supplied * token identifier is contained in the * order's merkle root. * @param fulfillments An array of elements allocating offer * components to consideration components. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function executeMatchAdvancedOrders( address pausableZoneAddress, SeaportInterface seaportAddress, AdvancedOrder[] calldata orders, CriteriaResolver[] calldata criteriaResolvers, Fulfillment[] calldata fulfillments ) external payable override returns (Execution[] memory executions) { // Ensure the caller is the owner. if (msg.sender != _owner) { revert CallerIsNotOwner(); } // Create a zone object from the zone address. PausableZone zone = PausableZone(pausableZoneAddress); // Call executeMatchOrders on the given zone and return the sequence // of transfers performed as part of matching the given orders. executions = zone.executeMatchAdvancedOrders{ value: msg.value }( seaportAddress, orders, criteriaResolvers, fulfillments ); } /** * @notice Initiate Zone ownership transfer by assigning a new potential * owner this contract. Once set, the new potential owner * may call `acceptOwnership` to claim ownership. * Only the owner in question may call this function. * * @param newPotentialOwner The address for which to initiate ownership * transfer to. */ function transferOwnership(address newPotentialOwner) external override { // Ensure the caller is the owner. if (msg.sender != _owner) { revert CallerIsNotOwner(); } // Ensure the new potential owner is not an invalid address. if (newPotentialOwner == address(0)) { revert OwnerCanNotBeSetAsZero(); } // Emit an event indicating that the potential owner has been updated. emit PotentialOwnerUpdated(newPotentialOwner); // Set the new potential owner as the potential owner. _potentialOwner = newPotentialOwner; } /** * @notice Clear the currently set potential owner, if any. * Only the owner of this contract may call this function. */ function cancelOwnershipTransfer() external override { // Ensure the caller is the current owner. if (msg.sender != _owner) { revert CallerIsNotOwner(); } // Emit an event indicating that the potential owner has been cleared. emit PotentialOwnerUpdated(address(0)); // Clear the current new potential owner. delete _potentialOwner; } /** * @notice Accept ownership of this contract. Only the account that the * current owner has set as the new potential owner may call this * function. */ function acceptOwnership() external override { // Ensure the caller is the potential owner. if (msg.sender != _potentialOwner) { revert CallerIsNotPotentialOwner(); } // Emit an event indicating that the potential owner has been cleared. emit PotentialOwnerUpdated(address(0)); // Clear the current new potential owner delete _potentialOwner; // Emit an event indicating ownership has been transferred. emit OwnershipTransferred(_owner, msg.sender); // Set the caller as the owner of this contract. _owner = msg.sender; } /** * @notice Assign the given address with the ability to pause the zone. * * @param pauserToAssign The address to assign the pauser role. */ function assignPauser(address pauserToAssign) external override { // Ensure the caller is the owner. if (msg.sender != _owner) { revert CallerIsNotOwner(); } // Ensure the pauser to assign is not an invalid address. if (pauserToAssign == address(0)) { revert PauserCanNotBeSetAsZero(); } // Set the given account as the pauser. _pauser = pauserToAssign; // Emit an event indicating the pauser has been assigned. emit PauserUpdated(pauserToAssign); } /** * @notice Assign the given address with the ability to operate the * given zone. * * @param pausableZoneAddress The zone address to assign operator role. * @param operatorToAssign The address to assign as operator. */ function assignOperator( address pausableZoneAddress, address operatorToAssign ) external override { // Ensure the caller is the owner. if (msg.sender != _owner) { revert CallerIsNotOwner(); } // Create a zone object from the zone address. PausableZone zone = PausableZone(pausableZoneAddress); // Call assignOperator on the zone by passing in the given // operator address. zone.assignOperator(operatorToAssign); } /** * @notice An external view function that returns the owner. * * @return The address of the owner. */ function owner() external view override returns (address) { return _owner; } /** * @notice An external view function that return the potential owner. * * @return The address of the potential owner. */ function potentialOwner() external view override returns (address) { return _potentialOwner; } /** * @notice An external view function that returns the pauser. * * @return The address of the pauser. */ function pauser() external view override returns (address) { return _pauser; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ZoneInterface } from "../interfaces/ZoneInterface.sol"; import { PausableZoneEventsAndErrors } from "./interfaces/PausableZoneEventsAndErrors.sol"; import { SeaportInterface } from "../interfaces/SeaportInterface.sol"; import { AdvancedOrder, CriteriaResolver, Execution, Fulfillment, Order, OrderComponents, Schema, ZoneParameters } from "../lib/ConsiderationStructs.sol"; import { PausableZoneInterface } from "./interfaces/PausableZoneInterface.sol"; /** * @title PausableZone * @author cupOJoseph, BCLeFevre, ryanio * @notice PausableZone is a simple zone implementation that approves every * order. It can be self-destructed by its controller to pause * restricted orders that have it set as their zone. Note that this zone * cannot execute orders that return native tokens to the fulfiller. */ contract PausableZone is PausableZoneEventsAndErrors, ZoneInterface, PausableZoneInterface { // Set an immutable controller that can pause the zone & update an operator. address internal immutable _controller; // Set an operator that can instruct the zone to cancel or execute orders. address public operator; /** * @dev Ensure that the caller is either the operator or controller. */ modifier isOperator() { // Ensure that the caller is either the operator or the controller. if (msg.sender != operator && msg.sender != _controller) { revert InvalidOperator(); } // Continue with function execution. _; } /** * @dev Ensure that the caller is the controller. */ modifier isController() { // Ensure that the caller is the controller. if (msg.sender != _controller) { revert InvalidController(); } // Continue with function execution. _; } /** * @notice Set the deployer as the controller of the zone. */ constructor() { // Set the controller to the deployer. _controller = msg.sender; // Emit an event signifying that the zone is unpaused. emit Unpaused(); } /** * @notice Cancel an arbitrary number of orders that have agreed to use the * contract as their zone. * * @param seaport The Seaport address. * @param orders The orders to cancel. * * @return cancelled A boolean indicating whether the supplied orders have * been successfully cancelled. */ function cancelOrders( SeaportInterface seaport, OrderComponents[] calldata orders ) external override isOperator returns (bool cancelled) { // Call cancel on Seaport and return its boolean value. cancelled = seaport.cancel(orders); } /** * @notice Pause this contract, safely stopping orders from using * the contract as a zone. Restricted orders with this address as a * zone will not be fulfillable unless the zone is redeployed to the * same address. */ function pause(address payee) external override isController { // Emit an event signifying that the zone is paused. emit Paused(); // Destroy the zone, sending any native tokens to the transaction // submitter. selfdestruct(payable(payee)); } /** * @notice Assign the given address with the ability to operate the zone. * * @param operatorToAssign The address to assign as the operator. */ function assignOperator( address operatorToAssign ) external override isController { // Ensure the operator being assigned is not the null address. if (operatorToAssign == address(0)) { revert PauserCanNotBeSetAsZero(); } // Set the given address as the new operator. operator = operatorToAssign; // Emit an event indicating the operator has been updated. emit OperatorUpdated(operatorToAssign); } /** * @notice Execute an arbitrary number of matched orders, each with * an arbitrary number of items for offer and consideration * along with a set of fulfillments allocating offer components * to consideration components. Note that this call will revert if * excess native tokens are returned by Seaport. * * @param seaport The Seaport address. * @param orders The orders to match. * @param fulfillments An array of elements allocating offer components * to consideration components. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function executeMatchOrders( SeaportInterface seaport, Order[] calldata orders, Fulfillment[] calldata fulfillments ) external payable override isOperator returns (Execution[] memory executions) { // Call matchOrders on Seaport and return the sequence of transfers // performed as part of matching the given orders. executions = seaport.matchOrders{ value: msg.value }( orders, fulfillments ); } /** * @notice Execute an arbitrary number of matched advanced orders, * each with an arbitrary number of items for offer and * consideration along with a set of fulfillments allocating * offer components to consideration components. Note that this call * will revert if excess native tokens are returned by Seaport. * * @param seaport The Seaport address. * @param orders The orders to match. * @param criteriaResolvers An array where each element contains a reference * to a specific order as well as that order's * offer or consideration, a token identifier, and * a proof that the supplied token identifier is * contained in the order's merkle root. * @param fulfillments An array of elements allocating offer components * to consideration components. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function executeMatchAdvancedOrders( SeaportInterface seaport, AdvancedOrder[] calldata orders, CriteriaResolver[] calldata criteriaResolvers, Fulfillment[] calldata fulfillments ) external payable override isOperator returns (Execution[] memory executions) { // Call matchAdvancedOrders on Seaport and return the sequence of // transfers performed as part of matching the given orders. executions = seaport.matchAdvancedOrders{ value: msg.value }( orders, criteriaResolvers, fulfillments, msg.sender ); } /** * @notice Check if a given order including extraData is currently valid. * * @dev This function is called by Seaport whenever any extraData is * provided by the caller. * * @custom:param zoneParameters A struct that 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. * * @return validOrderMagicValue A magic value indicating if the order is * currently valid. */ function validateOrder( /** * @custom:name zoneParameters */ ZoneParameters calldata ) external pure override returns (bytes4 validOrderMagicValue) { // Return the selector of isValidOrder as the magic value. validOrderMagicValue = ZoneInterface.validateOrder.selector; } /** * @dev Returns the metadata for this zone. */ function getSeaportMetadata() external pure override returns ( string memory name, Schema[] memory schemas // map to Seaport Improvement Proposal IDs ) { schemas = new Schema[](1); schemas[0].id = 3003; schemas[0].metadata = new bytes(0); return ("PausableZone", schemas); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @notice PausableZoneEventsAndErrors contains errors and events * related to zone interaction. */ interface PausableZoneEventsAndErrors { /** * @dev Emit an event whenever a zone is successfully paused. */ event Paused(); /** * @dev Emit an event whenever a zone is successfully unpaused (created). */ event Unpaused(); /** * @dev Emit an event whenever a zone owner registers a new potential * owner for that zone. * * @param newPotentialOwner The new potential owner of the zone. */ event PotentialOwnerUpdated(address newPotentialOwner); /** * @dev Emit an event whenever zone ownership is transferred. * * @param previousOwner The previous owner of the zone. * @param newOwner The new owner of the zone. */ event OwnershipTransferred(address previousOwner, address newOwner); /** * @dev Emit an event whenever a new zone is created. * * @param zone The address of the zone. * @param salt The salt used to deploy the zone. */ event ZoneCreated(address zone, bytes32 salt); /** * @dev Emit an event whenever a zone owner assigns a new pauser * * @param newPauser The new pausear of the zone. */ event PauserUpdated(address newPauser); /** * @dev Emit an event whenever a zone owner assigns a new operator * * @param newOperator The new operator of the zone. */ event OperatorUpdated(address newOperator); /** * @dev Revert with an error when attempting to pause the zone * while the caller is not the owner or pauser of the zone. */ error InvalidPauser(); /** * @dev Revert with an error when attempting to call an operation * while the caller is not the controller or operator of the zone. */ error InvalidOperator(); /** * @dev Revert with an error when attempting to pause the zone or update the * operator while the caller is not the controller of the zone. */ error InvalidController(); /** * @dev Revert with an error when attempting to deploy a zone that is * currently deployed. */ error ZoneAlreadyExists(address zone); /** * @dev Revert with an error when the caller does not have the _owner role * */ error CallerIsNotOwner(); /** * @dev Revert with an error when the caller does not have the operator role * */ error CallerIsNotOperator(); /** * @dev Revert with an error when attempting to set the new potential owner * as the 0 address. * */ error OwnerCanNotBeSetAsZero(); /** * @dev Revert with an error when attempting to set the new potential pauser * as the 0 address. * */ error PauserCanNotBeSetAsZero(); /** * @dev Revert with an error when the caller does not have * the potentialOwner role. */ error CallerIsNotPotentialOwner(); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ZoneParameters, Schema } from "../lib/ConsiderationStructs.sol"; /** * @title ZoneInterface * @notice Contains functions exposed by a zone. */ interface ZoneInterface { /** * @dev Validates an order. * * @param zoneParameters The context about the order fulfillment and any * supplied extraData. * * @return validOrderMagicValue The magic value that indicates a valid * order. */ function validateOrder( ZoneParameters calldata zoneParameters ) external returns (bytes4 validOrderMagicValue); /** * @dev Returns the metadata for this zone. * * @return name The name of the zone. * @return schemas The schemas that the zone implements. */ function getSeaportMetadata() external view returns ( string memory name, Schema[] memory schemas // map to Seaport Improvement Proposal IDs ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ZoneInterface } from "../interfaces/ZoneInterface.sol"; import { Schema, ZoneParameters } from "../lib/ConsiderationStructs.sol"; contract TestZone is ZoneInterface { function validateOrder( ZoneParameters calldata zoneParameters ) external pure override returns (bytes4 validOrderMagicValue) { if (zoneParameters.extraData.length == 0) { if (zoneParameters.zoneHash == bytes32(uint256(1))) { revert("Revert on zone hash 1"); } else if (zoneParameters.zoneHash == bytes32(uint256(2))) { assembly { revert(0, 0) } } } else if (zoneParameters.extraData.length == 4) { revert("Revert on extraData length 4"); } else if (zoneParameters.extraData.length == 5) { assembly { revert(0, 0) } } else if ( zoneParameters.extraData.length > 32 && zoneParameters.extraData.length % 32 == 0 ) { bytes32[] memory expectedOrderHashes = abi.decode( zoneParameters.extraData, (bytes32[]) ); uint256 expectedLength = expectedOrderHashes.length; if (expectedLength != zoneParameters.orderHashes.length) { revert("Revert on unexpected order hashes length"); } for (uint256 i = 0; i < expectedLength; ++i) { if (expectedOrderHashes[i] != zoneParameters.orderHashes[i]) { revert("Revert on unexpected order hash"); } } } validOrderMagicValue = zoneParameters.zoneHash != bytes32(uint256(3)) ? ZoneInterface.validateOrder.selector : bytes4(0xffffffff); } /** * @dev Returns the metadata for this zone. */ function getSeaportMetadata() external pure override returns ( string memory name, Schema[] memory schemas // map to Seaport Improvement Proposal IDs ) { schemas = new Schema[](1); schemas[0].id = 3003; schemas[0].metadata = new bytes(0); return ("TestZone", schemas); } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ERC20Interface, ERC721Interface, ERC1155Interface } from "../interfaces/AbridgedTokenInterfaces.sol"; import { ReceivedItem, Schema, SpentItem, ZoneParameters } from "../lib/ConsiderationStructs.sol"; import { ItemType } from "../lib/ConsiderationEnums.sol"; import { ContractOffererInterface } from "../interfaces/ContractOffererInterface.sol"; import { ZoneInterface } from "../interfaces/ZoneInterface.sol"; contract TestTransferValidationZoneOfferer is ContractOffererInterface, ZoneInterface { error InvalidBalance(); error InvalidOwner(); constructor() {} /** * @dev Validates that the parties have received the correct items. * * @param zoneParameters The zone parameters, including the SpentItem and * ReceivedItem arrays. * * @return validOrderMagicValue The magic value to indicate things are OK. */ function validateOrder( ZoneParameters calldata zoneParameters ) external view override returns (bytes4 validOrderMagicValue) { // Validate the order. // Currently assumes that the balances of all tokens of addresses are // zero at the start of the transaction. // Check if all consideration items have been received. _assertValidReceivedItems(zoneParameters.consideration); // Check if all offer items have been spent. _assertValidSpentItems(zoneParameters.fulfiller, zoneParameters.offer); // Return the selector of validateOrder as the magic value. validOrderMagicValue = ZoneInterface.validateOrder.selector; } /** * @dev Generates an order with the specified minimum and maximum spent * items. */ function generateOrder( address, SpentItem[] calldata a, SpentItem[] calldata b, bytes calldata c ) external virtual override returns (SpentItem[] memory offer, ReceivedItem[] memory consideration) { return previewOrder(address(this), address(this), a, b, c); } /** * @dev View function to preview an order generated in response to a minimum * set of received items, maximum set of spent items, and context * (supplied as extraData). */ function previewOrder( address, address, SpentItem[] calldata a, SpentItem[] calldata b, bytes calldata ) public view override returns (SpentItem[] memory offer, ReceivedItem[] memory consideration) { return (a, _convertSpentToReceived(b)); } /** * @dev Ratifies that the parties have received the correct items. * * @param minimumReceived The minimum items that the caller was willing to * receive. * @param maximumSpent The maximum items that the caller was willing to * spend. * @param context The context of the order. * @ param orderHashes The order hashes, unused here. * @ param contractNonce The contract nonce, unused here. * * @return ratifyOrderMagicValue The magic value to indicate things are OK. */ function ratifyOrder( SpentItem[] calldata minimumReceived /* offer */, ReceivedItem[] calldata maximumSpent /* consideration */, bytes calldata context /* context */, bytes32[] calldata /* orderHashes */, uint256 /* contractNonce */ ) external view override returns (bytes4 /* ratifyOrderMagicValue */) { // Ratify the order. // Ensure that the offerer or recipient has received all consideration // items. _assertValidReceivedItems(maximumSpent); // Get the fulfiller address from the context. address fulfiller = address(bytes20(context[0:20])); // Ensure that the fulfiller has received all offer items. _assertValidSpentItems(fulfiller, minimumReceived); return this.ratifyOrder.selector; } function getSeaportMetadata() external pure override(ContractOffererInterface, ZoneInterface) returns (string memory name, Schema[] memory schemas) { // Return the metadata. name = "TestTransferValidationZoneOfferer"; schemas = new Schema[](1); schemas[0].id = 1337; schemas[0].metadata = new bytes(0); } function _convertSpentToReceived( SpentItem[] calldata spentItems ) internal view returns (ReceivedItem[] memory) { ReceivedItem[] memory receivedItems = new ReceivedItem[]( spentItems.length ); for (uint256 i = 0; i < spentItems.length; ++i) { receivedItems[i] = _convertSpentToReceived(spentItems[i]); } return receivedItems; } function _convertSpentToReceived( SpentItem calldata spentItem ) internal view returns (ReceivedItem memory) { return ReceivedItem({ itemType: spentItem.itemType, token: spentItem.token, identifier: spentItem.identifier, amount: spentItem.amount, recipient: payable(address(this)) }); } function _assertValidReceivedItems( ReceivedItem[] calldata receivedItems ) internal view { address recipient; ItemType itemType; ReceivedItem memory receivedItem; // Check if all consideration items have been received. for (uint256 i = 0; i < receivedItems.length; i++) { // Check if the consideration item has been received. receivedItem = receivedItems[i]; // Get the recipient of the consideration item. recipient = receivedItem.recipient; // Get item type. itemType = receivedItem.itemType; // Check balance/ownerOf depending on item type. if (itemType == ItemType.NATIVE) { // NATIVE Token _assertNativeTokenTransfer(receivedItem.amount, recipient); } else if (itemType == ItemType.ERC20) { // ERC20 Token _assertERC20Transfer( receivedItem.amount, receivedItem.token, recipient ); } else if (itemType == ItemType.ERC721) { // ERC721 Token _assertERC721Transfer( receivedItem.identifier, receivedItem.token, recipient ); } else if (itemType == ItemType.ERC1155) { // ERC1155 Token _assertERC1155Transfer( receivedItem.amount, receivedItem.identifier, receivedItem.token, recipient ); } } } function _assertValidSpentItems( address fulfiller, SpentItem[] calldata spentItems ) internal view { SpentItem memory spentItem; ItemType itemType; // Check if all offer items have been spent. for (uint256 i = 0; i < spentItems.length; i++) { // Check if the offer item has been spent. spentItem = spentItems[i]; // Get item type. itemType = spentItem.itemType; // Check balance/ownerOf depending on item type. if (itemType == ItemType.NATIVE) { // NATIVE Token _assertNativeTokenTransfer(spentItem.amount, fulfiller); } else if (itemType == ItemType.ERC20) { // ERC20 Token _assertERC20Transfer( spentItem.amount, spentItem.token, fulfiller ); } else if (itemType == ItemType.ERC721) { // ERC721 Token _assertERC721Transfer( spentItem.identifier, spentItem.token, fulfiller ); } else if (itemType == ItemType.ERC1155) { // ERC1155 Token _assertERC1155Transfer( spentItem.amount, spentItem.identifier, spentItem.token, fulfiller ); } } } function _assertNativeTokenTransfer( uint256 amount, address recipient ) internal view { if (amount > address(recipient).balance) { revert InvalidBalance(); } } function _assertERC20Transfer( uint256 amount, address token, address recipient ) internal view { if (amount > ERC20Interface(token).balanceOf(recipient)) { revert InvalidBalance(); } } function _assertERC721Transfer( uint256 identifier, address token, address recipient ) internal view { if (recipient != ERC721Interface(token).ownerOf(identifier)) { revert InvalidOwner(); } } function _assertERC1155Transfer( uint256 amount, uint256 identifier, address token, address recipient ) internal view { if (amount > ERC1155Interface(token).balanceOf(recipient, identifier)) { revert InvalidBalance(); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @title ERC20Interface * @notice Contains the minimum interfaces needed to interact with ERC20s. */ interface ERC20Interface { /** * @dev Allows an operator to transfer tokens on behalf of an owner. * * @param from The address of the owner. * @param to The address of the recipient. * @param value The amount of tokens to transfer. * * @return success True if the transfer was successful. */ function transferFrom( address from, address to, uint256 value ) external returns (bool success); /** * @dev Allows an operator to approve a spender to transfer tokens on behalf * of a user. * * @param spender The address of the spender. * @param value The amount of tokens to approve. * * @return success True if the approval was successful. */ function approve( address spender, uint256 value ) external returns (bool success); /** * @dev Returns the amount of tokens owned by `account`. * * @param account The address of the account to check the balance of. * * @return balance The amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); } /** * @title ERC721Interface * @notice Contains the minimum interfaces needed to interact with ERC721s. */ interface ERC721Interface { /** * @dev Allows an operator to transfer tokens on behalf of an owner. * * @param from The address of the owner. * @param to The address of the recipient. * @param tokenId The ID of the token to transfer. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Allows an owner to approve an operator to transfer all tokens on a * contract on behalf of the owner. * * @param to The address of the operator. * @param approved Whether the operator is approved. */ function setApprovalForAll(address to, bool approved) external; /** * @dev Returns the owner of a given token ID. * * @param tokenId The token ID. * * @return owner The owner of the token. */ function ownerOf(uint256 tokenId) external view returns (address owner); } /** * @title ERC1155Interface * @notice Contains the minimum interfaces needed to interact with ERC1155s. */ interface ERC1155Interface { /** * @dev Allows an operator to transfer tokens on behalf of an owner. * * @param from The address of the owner. * @param to The address of the recipient. * @param id The ID of the token(s) to transfer. * @param amount The amount of tokens to transfer. * @param data Additional data. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) external; /** * @dev Allows an operator to transfer tokens on behalf of an owner. * * @param from The address of the owner. * @param to The address of the recipient. * @param ids The IDs of the token(s) to transfer. * @param amounts The amounts of tokens to transfer. * @param data Additional data. */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; /** * @dev Allows an owner to approve an operator to transfer all tokens on a * contract on behalf of the owner. * * @param to The address of the operator. * @param approved Whether the operator is approved. */ function setApprovalForAll(address to, bool approved) external; /** * @dev Returns the owner of a given token ID. * * @param account The address of the account to check the balance of. * @param id The token ID. * * @return balance The balance of the token. */ function balanceOf( address account, uint256 id ) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ReceivedItem, Schema, SpentItem } from "../lib/ConsiderationStructs.sol"; /** * @title ContractOffererInterface * @notice Contains the minimum interfaces needed to interact with a contract * offerer. */ interface ContractOffererInterface { /** * @dev Generates an order with the specified minimum and maximum spent * items, and optional context (supplied as extraData). * * @param fulfiller The address of the fulfiller. * @param minimumReceived The minimum items that the caller is willing to * receive. * @param maximumSpent The maximum items the caller is willing to spend. * @param context Additional context of the order. * * @return offer A tuple containing the offer items. * @return consideration A tuple containing the consideration items. */ function generateOrder( address fulfiller, SpentItem[] calldata minimumReceived, SpentItem[] calldata maximumSpent, bytes calldata context // encoded based on the schemaID ) external returns (SpentItem[] memory offer, ReceivedItem[] memory consideration); /** * @dev Ratifies an order with the specified offer, consideration, and * optional context (supplied as extraData). * * @param offer The offer items. * @param consideration The consideration items. * @param context Additional context of the order. * @param orderHashes The hashes to ratify. * @param contractNonce The nonce of the contract. * * @return ratifyOrderMagicValue The magic value returned by the contract * offerer. */ function ratifyOrder( SpentItem[] calldata offer, ReceivedItem[] calldata consideration, bytes calldata context, // encoded based on the schemaID bytes32[] calldata orderHashes, uint256 contractNonce ) external returns (bytes4 ratifyOrderMagicValue); /** * @dev View function to preview an order generated in response to a minimum * set of received items, maximum set of spent items, and context * (supplied as extraData). * * @param caller The address of the caller (e.g. Seaport). * @param fulfiller The address of the fulfiller (e.g. the account * calling Seaport). * @param minimumReceived The minimum items that the caller is willing to * receive. * @param maximumSpent The maximum items the caller is willing to spend. * @param context Additional context of the order. * * @return offer A tuple containing the offer items. * @return consideration A tuple containing the consideration items. */ function previewOrder( address caller, address fulfiller, SpentItem[] calldata minimumReceived, SpentItem[] calldata maximumSpent, bytes calldata context // encoded based on the schemaID ) external view returns (SpentItem[] memory offer, ReceivedItem[] memory consideration); /** * @dev Gets the metadata for this contract offerer. * * @return name The name of the contract offerer. * @return schemas The schemas supported by the contract offerer. */ function getSeaportMetadata() external view returns ( string memory name, Schema[] memory schemas // map to Seaport Improvement Proposal IDs ); // Additional functions and/or events based on implemented schemaIDs }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ERC721Interface, ERC1155Interface } from "../interfaces/AbridgedTokenInterfaces.sol"; import { ContractOffererInterface } from "../interfaces/ContractOffererInterface.sol"; import { ItemType } from "../lib/ConsiderationEnums.sol"; import { ReceivedItem, Schema, SpentItem } from "../lib/ConsiderationStructs.sol"; /** * @title TestContractOffererNativeToken */ contract TestContractOffererNativeToken is ContractOffererInterface { error OrderUnavailable(); address private immutable _SEAPORT; SpentItem private _available; SpentItem private _required; bool public ready; bool public fulfilled; uint256 public extraAvailable; uint256 public extraRequired; constructor(address seaport) { // Set immutable values and storage variables. _SEAPORT = seaport; fulfilled = false; ready = false; extraAvailable = 0; extraRequired = 0; } receive() external payable {} function activate( SpentItem memory available, SpentItem memory required ) public payable { if (ready || fulfilled) { revert OrderUnavailable(); } // Set storage variables. _available = available; _required = required; ready = true; } /// In case of criteria based orders and non-wildcard items, the member /// `available.identifier` would correspond to the `identifierOrCriteria` /// i.e., the merkle-root. /// @param identifier corresponds to the actual token-id that gets transferred. function activateWithCriteria( SpentItem memory available, SpentItem memory required, uint256 identifier ) public { if (ready || fulfilled) { revert OrderUnavailable(); } if (available.itemType == ItemType.ERC721_WITH_CRITERIA) { ERC721Interface token = ERC721Interface(available.token); token.transferFrom(msg.sender, address(this), identifier); token.setApprovalForAll(_SEAPORT, true); } else if (available.itemType == ItemType.ERC1155_WITH_CRITERIA) { ERC1155Interface token = ERC1155Interface(available.token); token.safeTransferFrom( msg.sender, address(this), identifier, available.amount, "" ); token.setApprovalForAll(_SEAPORT, true); } // Set storage variables. _available = available; _required = required; ready = true; } function extendAvailable() public { if (!ready || fulfilled) { revert OrderUnavailable(); } extraAvailable++; _available.amount /= 2; } function extendRequired() public { if (!ready || fulfilled) { revert OrderUnavailable(); } extraRequired++; } function generateOrder( address, SpentItem[] calldata minimumReceived, SpentItem[] calldata maximumSpent, bytes calldata /* context */ ) external virtual override returns (SpentItem[] memory offer, ReceivedItem[] memory consideration) { // Set the offer and consideration that were supplied during deployment. offer = new SpentItem[](1); consideration = new ReceivedItem[](1); // Send eth to Seaport. (bool success, ) = _SEAPORT.call{ value: minimumReceived[0].amount }( "" ); // Revert if transaction fails. if (!success) { assembly { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } // Set the offer item as the _available item in storage. offer[0] = minimumReceived[0]; // Set the erc721 consideration item. consideration[0] = ReceivedItem({ itemType: ItemType.ERC721, token: maximumSpent[0].token, identifier: maximumSpent[0].identifier, amount: maximumSpent[0].amount, recipient: payable(address(this)) }); // Update storage to reflect that the order has been fulfilled. fulfilled = true; } function previewOrder( address caller, address, SpentItem[] calldata, SpentItem[] calldata, bytes calldata context ) external view override returns (SpentItem[] memory offer, ReceivedItem[] memory consideration) { // Ensure the caller is Seaport & the order has not yet been fulfilled. if (!ready || fulfilled || caller != _SEAPORT || context.length != 0) { revert OrderUnavailable(); } // Set the offer and consideration that were supplied during deployment. offer = new SpentItem[](1 + extraAvailable); consideration = new ReceivedItem[](1 + extraRequired); for (uint256 i = 0; i < 1 + extraAvailable; ++i) { offer[i] = _available; } for (uint256 i = 0; i < 1 + extraRequired; ++i) { consideration[i] = ReceivedItem({ itemType: _required.itemType, token: _required.token, identifier: _required.identifier, amount: _required.amount, recipient: payable(address(this)) }); } } function getInventory() external view returns (SpentItem[] memory offerable, SpentItem[] memory receivable) { // Set offerable and receivable supplied at deployment if unfulfilled. if (!ready || fulfilled) { offerable = new SpentItem[](0); receivable = new SpentItem[](0); } else { offerable = new SpentItem[](1 + extraAvailable); for (uint256 i = 0; i < 1 + extraAvailable; ++i) { offerable[i] = _available; } receivable = new SpentItem[](1 + extraRequired); for (uint256 i = 0; i < 1 + extraRequired; ++i) { receivable[i] = _required; } } } function ratifyOrder( SpentItem[] calldata /* offer */, ReceivedItem[] calldata /* consideration */, bytes calldata /* context */, bytes32[] calldata /* orderHashes */, uint256 /* contractNonce */ ) external pure virtual override returns (bytes4 /* ratifyOrderMagicValue */) { return ContractOffererInterface.ratifyOrder.selector; } function onERC1155Received( address, address, uint256, uint256, bytes calldata ) external pure returns (bytes4) { return bytes4(0xf23a6e61); } /** * @dev Returns the metadata for this contract offerer. */ function getSeaportMetadata() external pure override returns ( string memory name, Schema[] memory schemas // map to Seaport Improvement Proposal IDs ) { schemas = new Schema[](1); schemas[0].id = 1337; schemas[0].metadata = new bytes(0); return ("TestContractOffererNativeToken", schemas); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ZoneInterface } from "../interfaces/ZoneInterface.sol"; import { ERC721Interface } from "../interfaces/AbridgedTokenInterfaces.sol"; import { ItemType } from "../lib/ConsiderationEnums.sol"; import { ReceivedItem, Schema, ZoneParameters } from "../lib/ConsiderationStructs.sol"; contract TestPostExecution is ZoneInterface { function validateOrder( ZoneParameters calldata zoneParameters ) external view override returns (bytes4 validOrderMagicValue) { if (zoneParameters.consideration.length == 0) { revert("No consideration items supplied"); } ReceivedItem memory receivedItem = zoneParameters.consideration[0]; address currentOwner; try ERC721Interface(receivedItem.token).ownerOf(receivedItem.identifier) returns (address owner) { currentOwner = owner; } catch { revert("Unsupported consideration token type (must implement 721)"); } if (receivedItem.itemType != ItemType.ERC721) { revert("Validity check performed with unsupported item type"); } // Note that endAmount has been repurposed as recipient; this interface // still needs to be modified to return spent / received items. if (receivedItem.amount != 1) { // Note that this is currently failing in the matchOrder case. revert("Returned item amount incorrectly modified"); } if (currentOwner != receivedItem.recipient) { revert("Validity check performed prior to execution"); } validOrderMagicValue = ZoneInterface.validateOrder.selector; } /** * @dev Returns the metadata for this zone. */ function getSeaportMetadata() external pure override returns ( string memory name, Schema[] memory schemas // map to Seaport Improvement Proposal IDs ) { schemas = new Schema[](1); schemas[0].id = 3003; schemas[0].metadata = new bytes(0); return ("TestPostExecution", schemas); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ERC20Interface, ERC721Interface, ERC1155Interface } from "../interfaces/AbridgedTokenInterfaces.sol"; import { ContractOffererInterface } from "../interfaces/ContractOffererInterface.sol"; import { ItemType } from "../lib/ConsiderationEnums.sol"; import { ReceivedItem, Schema, SpentItem } from "../lib/ConsiderationStructs.sol"; /** * @title TestContractOfferer * @author 0age * @notice TestContractOfferer is a maximally simple contract offerer. It offers * a single item and expects to receive back another single item, and * ignores all parameters supplied to it when previewing or generating * an order. The offered item is placed into this contract as part of * deployment and the corresponding token approvals are set for Seaport. */ contract TestContractOfferer is ContractOffererInterface { error OrderUnavailable(); address private immutable _SEAPORT; SpentItem private _available; SpentItem private _required; bool public ready; bool public fulfilled; uint256 public extraAvailable; uint256 public extraRequired; constructor(address seaport) { // Set immutable values and storage variables. _SEAPORT = seaport; fulfilled = false; ready = false; extraAvailable = 0; extraRequired = 0; } receive() external payable {} /// In case of criteria based orders and non-wildcard items, the member /// `available.identifier` would correspond to the `identifierOrCriteria` /// i.e., the merkle-root. /// @param identifier corresponds to the actual token-id that gets transferred. function activateWithCriteria( SpentItem memory available, SpentItem memory required, uint256 identifier ) public { if (ready || fulfilled) { revert OrderUnavailable(); } if (available.itemType == ItemType.ERC721_WITH_CRITERIA) { ERC721Interface token = ERC721Interface(available.token); token.transferFrom(msg.sender, address(this), identifier); token.setApprovalForAll(_SEAPORT, true); } else if (available.itemType == ItemType.ERC1155_WITH_CRITERIA) { ERC1155Interface token = ERC1155Interface(available.token); token.safeTransferFrom( msg.sender, address(this), identifier, available.amount, "" ); token.setApprovalForAll(_SEAPORT, true); } // Set storage variables. _available = available; _required = required; ready = true; } function activate( SpentItem memory available, SpentItem memory required ) public payable { if (ready || fulfilled) { revert OrderUnavailable(); } // Retrieve the offered item and set associated approvals. if (available.itemType == ItemType.NATIVE) { available.amount = address(this).balance; } else if (available.itemType == ItemType.ERC20) { ERC20Interface token = ERC20Interface(available.token); token.transferFrom(msg.sender, address(this), available.amount); token.approve(_SEAPORT, available.amount); } else if (available.itemType == ItemType.ERC721) { ERC721Interface token = ERC721Interface(available.token); token.transferFrom(msg.sender, address(this), available.identifier); token.setApprovalForAll(_SEAPORT, true); } else if (available.itemType == ItemType.ERC1155) { ERC1155Interface token = ERC1155Interface(available.token); token.safeTransferFrom( msg.sender, address(this), available.identifier, available.amount, "" ); token.setApprovalForAll(_SEAPORT, true); } // Set storage variables. _available = available; _required = required; ready = true; } function extendAvailable() public { if (!ready || fulfilled) { revert OrderUnavailable(); } extraAvailable++; _available.amount /= 2; } function extendRequired() public { if (!ready || fulfilled) { revert OrderUnavailable(); } extraRequired++; } function generateOrder( address, SpentItem[] calldata, SpentItem[] calldata, bytes calldata context ) external virtual override returns (SpentItem[] memory offer, ReceivedItem[] memory consideration) { // Ensure the caller is Seaport & the order has not yet been fulfilled. if ( !ready || fulfilled || msg.sender != _SEAPORT || context.length % 32 != 0 ) { revert OrderUnavailable(); } // Set the offer and consideration that were supplied during deployment. offer = new SpentItem[](1 + extraAvailable); consideration = new ReceivedItem[](1 + extraRequired); for (uint256 i = 0; i < 1 + extraAvailable; ++i) { offer[i] = _available; } for (uint256 i = 0; i < 1 + extraRequired; ++i) { consideration[i] = ReceivedItem({ itemType: _required.itemType, token: _required.token, identifier: _required.identifier, amount: _required.amount, recipient: payable(address(this)) }); } // Update storage to reflect that the order has been fulfilled. fulfilled = true; } function previewOrder( address caller, address, SpentItem[] calldata, SpentItem[] calldata, bytes calldata context ) external view override returns (SpentItem[] memory offer, ReceivedItem[] memory consideration) { // Ensure the caller is Seaport & the order has not yet been fulfilled. if ( !ready || fulfilled || caller != _SEAPORT || context.length % 32 != 0 ) { revert OrderUnavailable(); } // Set the offer and consideration that were supplied during deployment. offer = new SpentItem[](1 + extraAvailable); consideration = new ReceivedItem[](1 + extraRequired); for (uint256 i = 0; i < 1 + extraAvailable; ++i) { offer[i] = _available; } for (uint256 i = 0; i < 1 + extraRequired; ++i) { consideration[i] = ReceivedItem({ itemType: _required.itemType, token: _required.token, identifier: _required.identifier, amount: _required.amount, recipient: payable(address(this)) }); } } function getInventory() external view returns (SpentItem[] memory offerable, SpentItem[] memory receivable) { // Set offerable and receivable supplied at deployment if unfulfilled. if (!ready || fulfilled) { offerable = new SpentItem[](0); receivable = new SpentItem[](0); } else { offerable = new SpentItem[](1 + extraAvailable); for (uint256 i = 0; i < 1 + extraAvailable; ++i) { offerable[i] = _available; } receivable = new SpentItem[](1 + extraRequired); for (uint256 i = 0; i < 1 + extraRequired; ++i) { receivable[i] = _required; } } } function ratifyOrder( SpentItem[] calldata /* offer */, ReceivedItem[] calldata /* consideration */, bytes calldata context, bytes32[] calldata orderHashes, uint256 /* contractNonce */ ) external pure virtual override returns (bytes4 /* ratifyOrderMagicValue */) { if (context.length > 32 && context.length % 32 == 0) { bytes32[] memory expectedOrderHashes = abi.decode( context, (bytes32[]) ); uint256 expectedLength = expectedOrderHashes.length; if (expectedLength != orderHashes.length) { revert("Revert on unexpected order hashes length"); } for (uint256 i = 0; i < expectedLength; ++i) { if (expectedOrderHashes[i] != orderHashes[i]) { revert("Revert on unexpected order hash"); } } } return ContractOffererInterface.ratifyOrder.selector; } function onERC1155Received( address, address, uint256, uint256, bytes calldata ) external pure returns (bytes4) { return bytes4(0xf23a6e61); } /** * @dev Returns the metadata for this contract offerer. */ function getSeaportMetadata() external pure override returns ( string memory name, Schema[] memory schemas // map to Seaport Improvement Proposal IDs ) { schemas = new Schema[](1); schemas[0].id = 1337; schemas[0].metadata = new bytes(0); return ("TestContractOfferer", schemas); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ReceivedItem, SpentItem } from "../lib/ConsiderationStructs.sol"; import { TestContractOfferer } from "./TestContractOfferer.sol"; contract TestInvalidContractOffererRatifyOrder is TestContractOfferer { constructor(address seaport) TestContractOfferer(seaport) {} function ratifyOrder( SpentItem[] calldata, ReceivedItem[] calldata, bytes calldata, bytes32[] calldata, uint256 ) external pure override returns (bytes4) { return bytes4(keccak256("throw")); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ReceivedItem, SpentItem } from "../lib/ConsiderationStructs.sol"; import { TestContractOfferer } from "./TestContractOfferer.sol"; contract TestInvalidContractOfferer is TestContractOfferer { error RevertWithData(bytes revertData); constructor(address seaport) TestContractOfferer(seaport) {} function generateOrder( address, SpentItem[] calldata, SpentItem[] calldata, bytes calldata context ) external pure override returns (SpentItem[] memory, ReceivedItem[] memory) { revert RevertWithData(context); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ERC721Interface } from "../interfaces/AbridgedTokenInterfaces.sol"; import { ContractOffererInterface } from "../interfaces/ContractOffererInterface.sol"; import { ItemType } from "../lib/ConsiderationEnums.sol"; import { ReceivedItem, Schema, SpentItem } from "../lib/ConsiderationStructs.sol"; contract TestBadContractOfferer is ContractOffererInterface { error IntentionalRevert(); address private immutable seaport; ERC721Interface token; constructor(address _seaport, ERC721Interface _token) { seaport = _seaport; token = _token; ERC721Interface(token).setApprovalForAll(seaport, true); } receive() external payable {} /** * @dev Generates an order with the specified minimum and maximum spent items, * and the optional extra data. * * @param a Fulfiller, unused here. * @param b The minimum items that the caller is willing to * receive. * @param c maximumSent, unused here. * @param d context, unused here. * * @return offer A tuple containing the offer items. * @return consideration A tuple containing the consideration items. */ function generateOrder( address a, SpentItem[] calldata b, SpentItem[] calldata c, bytes calldata d ) external virtual override returns (SpentItem[] memory offer, ReceivedItem[] memory consideration) { return previewOrder(a, a, b, c, d); } /** * @dev View function to preview an order generated in response to a minimum * set of received items, maximum set of spent items, and context * (supplied as extraData). * * @param - caller, unused here. * @param - fulfiller, unused here. * @param minimumReceived The minimum received set. * @param - maximumSpent, unused here. * @param - context, unused here. * * @return offer The offer for the order. * @return consideration The consideration for the order. */ function previewOrder( address, address, SpentItem[] calldata minimumReceived, SpentItem[] calldata maximumSpent, bytes calldata ) public view override returns (SpentItem[] memory offer, ReceivedItem[] memory consideration) { if (minimumReceived[0].identifier == 1) { offer = minimumReceived; consideration = new ReceivedItem[](1); consideration[0] = ReceivedItem({ itemType: ItemType.NATIVE, token: address(0), identifier: 0, amount: 100, recipient: payable(address(this)) }); return (offer, consideration); } else if (minimumReceived[0].identifier == 2) { // return nothing assembly { return(0, 0) } } else if (minimumReceived[0].identifier == 3) { revert IntentionalRevert(); } else { // return garbage bytes32 h1 = keccak256(abi.encode(minimumReceived)); bytes32 h2 = keccak256(abi.encode(maximumSpent)); assembly { mstore(0x00, h1) mstore(0x20, h2) return(0, 0x100) } } } function ratifyOrder( SpentItem[] calldata /* offer */, ReceivedItem[] calldata /* consideration */, bytes calldata /* context */, bytes32[] calldata /* orderHashes */, uint256 /* contractNonce */ ) external pure override returns (bytes4 /* ratifyOrderMagicValue */) { return TestBadContractOfferer.ratifyOrder.selector; } /** * @dev Returns the metadata for this contract offerer. */ function getSeaportMetadata() external pure override returns ( string memory name, Schema[] memory schemas // map to Seaport Improvement Proposal IDs ) { schemas = new Schema[](1); schemas[0].id = 1337; schemas[0].metadata = new bytes(0); return ("TestBadContractOfferer", schemas); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ConduitInterface } from "../interfaces/ConduitInterface.sol"; import { ConduitBatch1155Transfer, ConduitTransfer } from "../conduit/lib/ConduitStructs.sol"; contract ConduitMockRevertNoReason is ConduitInterface { constructor() {} function execute( ConduitTransfer[] calldata /* transfers */ ) external pure override returns (bytes4) { // Revert without reason string. revert(); } function executeBatch1155( ConduitBatch1155Transfer[] calldata /* batch1155Transfers */ ) external view override returns (bytes4 magicValue) {} function executeWithBatch1155( ConduitTransfer[] calldata /* standardTransfers */, ConduitBatch1155Transfer[] calldata /* batch1155Transfers */ ) external view override returns (bytes4 magicValue) {} function updateChannel(address channel, bool isOpen) external override {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ConduitInterface } from "../interfaces/ConduitInterface.sol"; import { ConduitBatch1155Transfer, ConduitTransfer } from "../conduit/lib/ConduitStructs.sol"; contract ConduitMockRevertBytes is ConduitInterface { constructor() {} error CustomError(); function execute( ConduitTransfer[] calldata /* transfers */ ) external pure override returns (bytes4) { revert CustomError(); } function executeBatch1155( ConduitBatch1155Transfer[] calldata /* batch1155Transfers */ ) external view override returns (bytes4 magicValue) {} function executeWithBatch1155( ConduitTransfer[] calldata /* standardTransfers */, ConduitBatch1155Transfer[] calldata /* batch1155Transfers */ ) external view override returns (bytes4 magicValue) {} function updateChannel(address channel, bool isOpen) external override {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ConduitControllerInterface } from "../interfaces/ConduitControllerInterface.sol"; import { ConduitInterface } from "../interfaces/ConduitInterface.sol"; import { ConduitMock } from "../test/ConduitMock.sol"; import { ConduitMockInvalidMagic } from "../test/ConduitMockInvalidMagic.sol"; import { ConduitMockRevertNoReason } from "../test/ConduitMockRevertNoReason.sol"; import { ConduitMockRevertBytes } from "../test/ConduitMockRevertBytes.sol"; contract ConduitControllerMock is ConduitControllerInterface { // Register keys, owners, new potential owners, and channels by conduit. mapping(address => ConduitProperties) internal _conduits; // Set conduit creation code and runtime code hashes as immutable arguments. bytes32 internal immutable _CONDUIT_CREATION_CODE_HASH; bytes32 internal immutable _CONDUIT_RUNTIME_CODE_HASH; uint256 private conduitNum; /** * @dev Initialize contract by deploying a conduit and setting the creation * code and runtime code hashes as immutable arguments. */ constructor(uint256 _conduitNum) { conduitNum = _conduitNum; bytes32 creationCodeHash; bytes32 runtimeCodeHash; if (conduitNum == 0) { creationCodeHash = keccak256(type(ConduitMock).creationCode); ConduitMock zeroConduit = new ConduitMock{ salt: bytes32(0) }(); runtimeCodeHash = address(zeroConduit).codehash; } else if (conduitNum == 1) { creationCodeHash = keccak256( type(ConduitMockRevertNoReason).creationCode ); ConduitMockRevertNoReason zeroConduit = new ConduitMockRevertNoReason{ salt: bytes32(0) }(); runtimeCodeHash = address(zeroConduit).codehash; } else if (conduitNum == 2) { creationCodeHash = keccak256( type(ConduitMockInvalidMagic).creationCode ); ConduitMockInvalidMagic zeroConduit = new ConduitMockInvalidMagic{ salt: bytes32(0) }(); runtimeCodeHash = address(zeroConduit).codehash; } else if (conduitNum == 3) { creationCodeHash = keccak256( type(ConduitMockRevertBytes).creationCode ); ConduitMockRevertBytes zeroConduit = new ConduitMockRevertBytes{ salt: bytes32(0) }(); runtimeCodeHash = address(zeroConduit).codehash; } _CONDUIT_CREATION_CODE_HASH = creationCodeHash; _CONDUIT_RUNTIME_CODE_HASH = runtimeCodeHash; } /** * @notice Deploy a new conduit using a supplied conduit key and assigning * an initial owner for the deployed conduit. Note that the first * twenty bytes of the supplied conduit key must match the caller * and that a new conduit cannot be created if one has already been * deployed using the same conduit key. * * @param conduitKey The conduit key used to deploy the conduit. Note that * the first twenty bytes of the conduit key must match * the caller of this contract. * @param initialOwner The initial owner to set for the new conduit. * * @return conduit The address of the newly deployed conduit. */ function createConduit( bytes32 conduitKey, address initialOwner ) external override returns (address conduit) { // Ensure that an initial owner has been supplied. if (initialOwner == address(0)) { revert InvalidInitialOwner(); } // If the first 20 bytes of the conduit key do not match the caller... if (address(uint160(bytes20(conduitKey))) != msg.sender) { // Revert with an error indicating that the creator is invalid. revert InvalidCreator(); } // Derive address from deployer, conduit key and creation code hash. conduit = address( uint160( uint256( keccak256( abi.encodePacked( bytes1(0xff), address(this), conduitKey, _CONDUIT_CREATION_CODE_HASH ) ) ) ) ); // If derived conduit exists, as evidenced by comparing runtime code... if (conduit.codehash == _CONDUIT_RUNTIME_CODE_HASH) { // Revert with an error indicating that the conduit already exists. revert ConduitAlreadyExists(conduit); } // Deploy the conduit via CREATE2 using the conduit key as the salt. if (conduitNum == 0) { new ConduitMock{ salt: conduitKey }(); } else if (conduitNum == 1) { new ConduitMockRevertNoReason{ salt: conduitKey }(); } else if (conduitNum == 2) { new ConduitMockInvalidMagic{ salt: conduitKey }(); } else if (conduitNum == 3) { new ConduitMockRevertBytes{ salt: conduitKey }(); } // Initialize storage variable referencing conduit properties. ConduitProperties storage conduitProperties = _conduits[conduit]; // Set the supplied initial owner as the owner of the conduit. conduitProperties.owner = initialOwner; // Set conduit key used to deploy the conduit to enable reverse lookup. conduitProperties.key = conduitKey; // Emit an event indicating that the conduit has been deployed. emit NewConduit(conduit, conduitKey); // Emit an event indicating that conduit ownership has been assigned. emit OwnershipTransferred(conduit, address(0), initialOwner); } /** * @notice Open or close a channel on a given conduit, thereby allowing the * specified account to execute transfers against that conduit. * Extreme care must be taken when updating channels, as malicious * or vulnerable channels can transfer any ERC20, ERC721 and ERC1155 * tokens where the token holder has granted the conduit approval. * Only the owner of the conduit in question may call this function. * * @param conduit The conduit for which to open or close the channel. * @param channel The channel to open or close on the conduit. * @param isOpen A boolean indicating whether to open or close the channel. */ function updateChannel( address conduit, address channel, bool isOpen ) external override { // Ensure the caller is the current owner of the conduit in question. _assertCallerIsConduitOwner(conduit); // Call the conduit, updating the channel. ConduitInterface(conduit).updateChannel(channel, isOpen); // Retrieve storage region where channels for the conduit are tracked. ConduitProperties storage conduitProperties = _conduits[conduit]; // Retrieve the index, if one currently exists, for the updated channel. uint256 channelIndexPlusOne = ( conduitProperties.channelIndexesPlusOne[channel] ); // Determine whether the updated channel is already tracked as open. bool channelPreviouslyOpen = channelIndexPlusOne != 0; // If the channel has been set to open and was previously closed... if (isOpen && !channelPreviouslyOpen) { // Add the channel to the channels array for the conduit. conduitProperties.channels.push(channel); // Add new open channel length to associated mapping as index + 1. conduitProperties.channelIndexesPlusOne[channel] = ( conduitProperties.channels.length ); } else if (!isOpen && channelPreviouslyOpen) { // Set a previously open channel as closed via "swap & pop" method. // Decrement located index to get the index of the closed channel. uint256 removedChannelIndex; // Skip underflow check as channelPreviouslyOpen being true ensures // that channelIndexPlusOne is nonzero. unchecked { removedChannelIndex = channelIndexPlusOne - 1; } // Use length of channels array to determine index of last channel. uint256 finalChannelIndex = conduitProperties.channels.length - 1; // If closed channel is not last channel in the channels array... if (finalChannelIndex != removedChannelIndex) { // Retrieve the final channel and place the value on the stack. address finalChannel = ( conduitProperties.channels[finalChannelIndex] ); // Overwrite the removed channel using the final channel value. conduitProperties.channels[removedChannelIndex] = finalChannel; // Update final index in associated mapping to removed index. conduitProperties.channelIndexesPlusOne[finalChannel] = ( channelIndexPlusOne ); } // Remove the last channel from the channels array for the conduit. conduitProperties.channels.pop(); // Remove the closed channel from associated mapping of indexes. delete conduitProperties.channelIndexesPlusOne[channel]; } } /** * @notice Initiate conduit ownership transfer by assigning a new potential * owner for the given conduit. Once set, the new potential owner * may call `acceptOwnership` to claim ownership of the conduit. * Only the owner of the conduit in question may call this function. * * @param conduit The conduit for which to initiate ownership transfer. * @param newPotentialOwner The new potential owner of the conduit. */ function transferOwnership( address conduit, address newPotentialOwner ) external override { // Ensure the caller is the current owner of the conduit in question. _assertCallerIsConduitOwner(conduit); // Ensure the new potential owner is not an invalid address. if (newPotentialOwner == address(0)) { revert NewPotentialOwnerIsZeroAddress(conduit); } // Ensure the new potential owner is not already set. if (newPotentialOwner == _conduits[conduit].potentialOwner) { revert NewPotentialOwnerAlreadySet(conduit, newPotentialOwner); } // Emit an event indicating that the potential owner has been updated. emit PotentialOwnerUpdated(newPotentialOwner); // Set the new potential owner as the potential owner of the conduit. _conduits[conduit].potentialOwner = newPotentialOwner; } /** * @notice Clear the currently set potential owner, if any, from a conduit. * Only the owner of the conduit in question may call this function. * * @param conduit The conduit for which to cancel ownership transfer. */ function cancelOwnershipTransfer(address conduit) external override { // Ensure the caller is the current owner of the conduit in question. _assertCallerIsConduitOwner(conduit); // Ensure that ownership transfer is currently possible. if (_conduits[conduit].potentialOwner == address(0)) { revert NoPotentialOwnerCurrentlySet(conduit); } // Emit an event indicating that the potential owner has been cleared. emit PotentialOwnerUpdated(address(0)); // Clear the current new potential owner from the conduit. _conduits[conduit].potentialOwner = address(0); } /** * @notice Accept ownership of a supplied conduit. Only accounts that the * current owner has set as the new potential owner may call this * function. * * @param conduit The conduit for which to accept ownership. */ function acceptOwnership(address conduit) external override { // Ensure that the conduit in question exists. _assertConduitExists(conduit); // If caller does not match current potential owner of the conduit... if (msg.sender != _conduits[conduit].potentialOwner) { // Revert, indicating that caller is not current potential owner. revert CallerIsNotNewPotentialOwner(conduit); } // Emit an event indicating that the potential owner has been cleared. emit PotentialOwnerUpdated(address(0)); // Clear the current new potential owner from the conduit. _conduits[conduit].potentialOwner = address(0); // Emit an event indicating conduit ownership has been transferred. emit OwnershipTransferred( conduit, _conduits[conduit].owner, msg.sender ); // Set the caller as the owner of the conduit. _conduits[conduit].owner = msg.sender; } /** * @notice Retrieve the current owner of a deployed conduit. * * @param conduit The conduit for which to retrieve the associated owner. * * @return owner The owner of the supplied conduit. */ function ownerOf( address conduit ) external view override returns (address owner) { // Ensure that the conduit in question exists. _assertConduitExists(conduit); // Retrieve the current owner of the conduit in question. owner = _conduits[conduit].owner; } /** * @notice Retrieve the conduit key for a deployed conduit via reverse * lookup. * * @param conduit The conduit for which to retrieve the associated conduit * key. * * @return conduitKey The conduit key used to deploy the supplied conduit. */ function getKey( address conduit ) external view override returns (bytes32 conduitKey) { // Attempt to retrieve a conduit key for the conduit in question. conduitKey = _conduits[conduit].key; // Revert if no conduit key was located. if (conduitKey == bytes32(0)) { revert NoConduit(); } } /** * @notice Derive the conduit associated with a given conduit key and * determine whether that conduit exists (i.e. whether it has been * deployed). * * @param conduitKey The conduit key used to derive the conduit. * * @return conduit The derived address of the conduit. * @return exists A boolean indicating whether the derived conduit has been * deployed or not. */ function getConduit( bytes32 conduitKey ) external view override returns (address conduit, bool exists) { // Derive address from deployer, conduit key and creation code hash. conduit = address( uint160( uint256( keccak256( abi.encodePacked( bytes1(0xff), address(this), conduitKey, _CONDUIT_CREATION_CODE_HASH ) ) ) ) ); // Determine whether conduit exists by retrieving its runtime code. exists = (conduit.codehash == _CONDUIT_RUNTIME_CODE_HASH); } /** * @notice Retrieve the potential owner, if any, for a given conduit. The * current owner may set a new potential owner via * `transferOwnership` and that owner may then accept ownership of * the conduit in question via `acceptOwnership`. * * @param conduit The conduit for which to retrieve the potential owner. * * @return potentialOwner The potential owner, if any, for the conduit. */ function getPotentialOwner( address conduit ) external view override returns (address potentialOwner) { // Ensure that the conduit in question exists. _assertConduitExists(conduit); // Retrieve the current potential owner of the conduit in question. potentialOwner = _conduits[conduit].potentialOwner; } /** * @notice Retrieve the status (either open or closed) of a given channel on * a conduit. * * @param conduit The conduit for which to retrieve the channel status. * @param channel The channel for which to retrieve the status. * * @return isOpen The status of the channel on the given conduit. */ function getChannelStatus( address conduit, address channel ) external view override returns (bool isOpen) { // Ensure that the conduit in question exists. _assertConduitExists(conduit); // Retrieve the current channel status for the conduit in question. isOpen = _conduits[conduit].channelIndexesPlusOne[channel] != 0; } /** * @notice Retrieve the total number of open channels for a given conduit. * * @param conduit The conduit for which to retrieve the total channel count. * * @return totalChannels The total number of open channels for the conduit. */ function getTotalChannels( address conduit ) external view override returns (uint256 totalChannels) { // Ensure that the conduit in question exists. _assertConduitExists(conduit); // Retrieve the total open channel count for the conduit in question. totalChannels = _conduits[conduit].channels.length; } /** * @notice Retrieve an open channel at a specific index for a given conduit. * Note that the index of a channel can change as a result of other * channels being closed on the conduit. * * @param conduit The conduit for which to retrieve the open channel. * @param channelIndex The index of the channel in question. * * @return channel The open channel, if any, at the specified channel index. */ function getChannel( address conduit, uint256 channelIndex ) external view override returns (address channel) { // Ensure that the conduit in question exists. _assertConduitExists(conduit); // Retrieve the total open channel count for the conduit in question. uint256 totalChannels = _conduits[conduit].channels.length; // Ensure that the supplied index is within range. if (channelIndex >= totalChannels) { revert ChannelOutOfRange(conduit); } // Retrieve the channel at the given index. channel = _conduits[conduit].channels[channelIndex]; } /** * @notice Retrieve all open channels for a given conduit. Note that calling * this function for a conduit with many channels will revert with * an out-of-gas error. * * @param conduit The conduit for which to retrieve open channels. * * @return channels An array of open channels on the given conduit. */ function getChannels( address conduit ) external view override returns (address[] memory channels) { // Ensure that the conduit in question exists. _assertConduitExists(conduit); // Retrieve all of the open channels on the conduit in question. channels = _conduits[conduit].channels; } /** * @dev Retrieve the conduit creation code and runtime code hashes. */ function getConduitCodeHashes() external view override returns (bytes32 creationCodeHash, bytes32 runtimeCodeHash) { // Retrieve the conduit creation code hash from runtime. creationCodeHash = _CONDUIT_CREATION_CODE_HASH; // Retrieve the conduit runtime code hash from runtime. runtimeCodeHash = _CONDUIT_RUNTIME_CODE_HASH; } /** * @dev Private view function to revert if the caller is not the owner of a * given conduit. * * @param conduit The conduit for which to assert ownership. */ function _assertCallerIsConduitOwner(address conduit) private view { // Ensure that the conduit in question exists. _assertConduitExists(conduit); // If the caller does not match the current owner of the conduit... if (msg.sender != _conduits[conduit].owner) { // Revert, indicating that the caller is not the owner. revert CallerIsNotOwner(conduit); } } /** * @dev Private view function to revert if a given conduit does not exist. * * @param conduit The conduit for which to assert existence. */ function _assertConduitExists(address conduit) private view { // Attempt to retrieve a conduit key for the conduit in question. if (_conduits[conduit].key == bytes32(0)) { // Revert if no conduit key was located. revert NoConduit(); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ConduitInterface } from "../interfaces/ConduitInterface.sol"; import { ConduitBatch1155Transfer, ConduitTransfer } from "../conduit/lib/ConduitStructs.sol"; contract ConduitMock is ConduitInterface { constructor() {} function execute( ConduitTransfer[] calldata /* transfers */ ) external pure override returns (bytes4) { // Return the valid magic value. return 0x4ce34aa2; } function executeBatch1155( ConduitBatch1155Transfer[] calldata /* batch1155Transfers */ ) external view override returns (bytes4 magicValue) {} function executeWithBatch1155( ConduitTransfer[] calldata /* standardTransfers */, ConduitBatch1155Transfer[] calldata /* batch1155Transfers */ ) external view override returns (bytes4 magicValue) {} function updateChannel(address channel, bool isOpen) external override {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ConduitInterface } from "../interfaces/ConduitInterface.sol"; import { ConduitBatch1155Transfer, ConduitTransfer } from "../conduit/lib/ConduitStructs.sol"; contract ConduitMockInvalidMagic is ConduitInterface { constructor() {} function execute( ConduitTransfer[] calldata /* transfers */ ) external pure override returns (bytes4) { return 0xabcd0000; } function executeBatch1155( ConduitBatch1155Transfer[] calldata /* batch1155Transfers */ ) external view override returns (bytes4 magicValue) {} function executeWithBatch1155( ConduitTransfer[] calldata /* standardTransfers */, ConduitBatch1155Transfer[] calldata /* batch1155Transfers */ ) external view override returns (bytes4 magicValue) {} function updateChannel(address channel, bool isOpen) external override {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { IERC721Receiver } from "../interfaces/IERC721Receiver.sol"; import { TransferHelperItem, TransferHelperItemsWithRecipient } from "./TransferHelperStructs.sol"; import { ConduitItemType } from "../conduit/lib/ConduitEnums.sol"; import { ConduitInterface } from "../interfaces/ConduitInterface.sol"; import { ConduitControllerInterface } from "../interfaces/ConduitControllerInterface.sol"; import { ConduitTransfer } from "../conduit/lib/ConduitStructs.sol"; import { TransferHelperInterface } from "../interfaces/TransferHelperInterface.sol"; import { TransferHelperErrors } from "../interfaces/TransferHelperErrors.sol"; /** * @title TransferHelper * @author stephankmin, stuckinaboot, ryanio * @notice TransferHelper is a utility contract for transferring * ERC20/ERC721/ERC1155 items in bulk to specific recipients. */ contract TransferHelper is TransferHelperInterface, TransferHelperErrors { // Allow for interaction with the conduit controller. ConduitControllerInterface internal immutable _CONDUIT_CONTROLLER; // Set conduit creation code and runtime code hashes as immutable arguments. bytes32 internal immutable _CONDUIT_CREATION_CODE_HASH; bytes32 internal immutable _CONDUIT_RUNTIME_CODE_HASH; /** * @dev Set the supplied conduit controller and retrieve its * conduit creation code hash. * * * @param conduitController A contract that deploys conduits, or proxies * that may optionally be used to transfer approved * ERC20/721/1155 tokens. */ constructor(address conduitController) { // Get the conduit creation code and runtime code hashes from the // supplied conduit controller and set them as an immutable. ConduitControllerInterface controller = ConduitControllerInterface( conduitController ); (_CONDUIT_CREATION_CODE_HASH, _CONDUIT_RUNTIME_CODE_HASH) = controller .getConduitCodeHashes(); // Set the supplied conduit controller as an immutable. _CONDUIT_CONTROLLER = controller; } /** * @notice Transfer multiple ERC20/ERC721/ERC1155 items to * specified recipients. * * @param items The items to transfer to an intended recipient. * @param conduitKey A mandatory conduit key referring to a conduit through * which the bulk transfer should occur. * * @return magicValue A value indicating that the transfers were successful. */ function bulkTransfer( TransferHelperItemsWithRecipient[] calldata items, bytes32 conduitKey ) external override returns (bytes4 magicValue) { // Ensure that a conduit key has been supplied. if (conduitKey == bytes32(0)) { revert InvalidConduit(conduitKey, address(0)); } // Use conduit derived from supplied conduit key to perform transfers. _performTransfersWithConduit(items, conduitKey); // Return a magic value indicating that the transfers were performed. magicValue = this.bulkTransfer.selector; } /** * @notice Perform multiple transfers to specified recipients via the * conduit derived from the provided conduit key. * * @param transfers The items to transfer. * @param conduitKey The conduit key referring to the conduit through * which the bulk transfer should occur. */ function _performTransfersWithConduit( TransferHelperItemsWithRecipient[] calldata transfers, bytes32 conduitKey ) internal { // Retrieve total number of transfers and place on stack. uint256 numTransfers = transfers.length; // Derive the conduit address from the deployer, conduit key // and creation code hash. address conduit = address( uint160( uint256( keccak256( abi.encodePacked( bytes1(0xff), address(_CONDUIT_CONTROLLER), conduitKey, _CONDUIT_CREATION_CODE_HASH ) ) ) ) ); // Declare a variable to store the sum of all items across transfers. uint256 sumOfItemsAcrossAllTransfers; // Skip overflow checks: all for loops are indexed starting at zero. unchecked { // Iterate over each transfer. for (uint256 i = 0; i < numTransfers; ++i) { // Retrieve the transfer in question. TransferHelperItemsWithRecipient calldata transfer = transfers[ i ]; // Increment totalItems by the number of items in the transfer. sumOfItemsAcrossAllTransfers += transfer.items.length; } } // Declare a new array in memory with length totalItems to populate with // each conduit transfer. ConduitTransfer[] memory conduitTransfers = new ConduitTransfer[]( sumOfItemsAcrossAllTransfers ); // Declare an index for storing ConduitTransfers in conduitTransfers. uint256 itemIndex; // Skip overflow checks: all for loops are indexed starting at zero. unchecked { // Iterate over each transfer. for (uint256 i = 0; i < numTransfers; ++i) { // Retrieve the transfer in question. TransferHelperItemsWithRecipient calldata transfer = transfers[ i ]; // Retrieve the items of the transfer in question. TransferHelperItem[] calldata transferItems = transfer.items; // Ensure recipient is not the zero address. _checkRecipientIsNotZeroAddress(transfer.recipient); // Create a boolean indicating whether validateERC721Receiver // is true and recipient is a contract. bool callERC721Receiver = transfer.validateERC721Receiver && transfer.recipient.code.length != 0; // Retrieve the total number of items in the transfer and // place on stack. uint256 numItemsInTransfer = transferItems.length; // Iterate over each item in the transfer to create a // corresponding ConduitTransfer. for (uint256 j = 0; j < numItemsInTransfer; ++j) { // Retrieve the item from the transfer. TransferHelperItem calldata item = transferItems[j]; if (item.itemType == ConduitItemType.ERC20) { // Ensure that the identifier of an ERC20 token is 0. if (item.identifier != 0) { revert InvalidERC20Identifier(); } } // If the item is an ERC721 token and // callERC721Receiver is true... if (item.itemType == ConduitItemType.ERC721) { if (callERC721Receiver) { // Check if the recipient implements // onERC721Received for the given tokenId. _checkERC721Receiver( conduit, transfer.recipient, item.identifier ); } } // Create a ConduitTransfer corresponding to each // TransferHelperItem. conduitTransfers[itemIndex] = ConduitTransfer( item.itemType, item.token, msg.sender, transfer.recipient, item.identifier, item.amount ); // Increment the index for storing ConduitTransfers. ++itemIndex; } } } // Attempt the external call to transfer tokens via the derived conduit. try ConduitInterface(conduit).execute(conduitTransfers) returns ( bytes4 conduitMagicValue ) { // Check if the value returned from the external call matches // the conduit `execute` selector. if (conduitMagicValue != ConduitInterface.execute.selector) { // If the external call fails, revert with the conduit key // and conduit address. revert InvalidConduit(conduitKey, conduit); } } catch Error(string memory reason) { // Catch reverts with a provided reason string and // revert with the reason, conduit key and conduit address. revert ConduitErrorRevertString(reason, conduitKey, conduit); } catch (bytes memory data) { // Conduits will throw a custom error when attempting to transfer // native token item types or an ERC721 item amount other than 1. // Bubble up these custom errors when encountered. Note that the // conduit itself will bubble up revert reasons from transfers as // well, meaning that these errors are not necessarily indicative of // an issue with the item type or amount in cases where the same // custom error signature is encountered during a conduit transfer. // Set initial value of first four bytes of revert data to the mask. bytes4 customErrorSelector = bytes4(0xffffffff); // Utilize assembly to read first four bytes (if present) directly. assembly { // Combine original mask with first four bytes of revert data. customErrorSelector := and( mload(add(data, 0x20)), // Data begins after length offset. customErrorSelector ) } // Pass through the custom error in question if the revert data is // the correct length and matches an expected custom error selector. if ( data.length == 4 && customErrorSelector == InvalidItemType.selector ) { // "Bubble up" the revert reason. assembly { revert(add(data, 0x20), 0x04) } } else if ( data.length == 36 && customErrorSelector == InvalidERC721TransferAmount.selector ) { // "Bubble up" the revert reason. assembly { revert(add(data, 0x20), 0x24) } } // Catch all other reverts from the external call to the conduit and // include the conduit's raw revert reason as a data argument to a // new custom error. revert ConduitErrorRevertBytes(data, conduitKey, conduit); } } /** * @notice An internal function to check if a recipient address implements * onERC721Received for a given tokenId. Note that this check does * not adhere to the safe transfer specification and is only meant * to provide an additional layer of assurance that the recipient * can receive the tokens — any hooks or post-transfer checks will * fail and the caller will be the transfer helper rather than the * ERC721 contract. Note that the conduit is set as the operator, as * it will be the caller once the transfer is performed. * * @param conduit The conduit to provide as the operator when calling * onERC721Received. * @param recipient The ERC721 recipient on which to call onERC721Received. * @param tokenId The ERC721 tokenId of the token being transferred. */ function _checkERC721Receiver( address conduit, address recipient, uint256 tokenId ) internal { // Check if recipient can receive ERC721 tokens. try IERC721Receiver(recipient).onERC721Received( conduit, msg.sender, tokenId, "" ) returns (bytes4 selector) { // Check if onERC721Received selector is valid. if (selector != IERC721Receiver.onERC721Received.selector) { // Revert if recipient cannot accept // ERC721 tokens. revert InvalidERC721Recipient(recipient); } } catch (bytes memory data) { // "Bubble up" recipient's revert reason. revert ERC721ReceiverErrorRevertBytes( data, recipient, msg.sender, tokenId ); } catch Error(string memory reason) { // "Bubble up" recipient's revert reason. revert ERC721ReceiverErrorRevertString( reason, recipient, msg.sender, tokenId ); } } /** * @notice An internal function that reverts if the passed-in recipient * is the zero address. * * @param recipient The recipient on which to perform the check. */ function _checkRecipientIsNotZeroAddress(address recipient) internal pure { // Revert if the recipient is the zero address. if (recipient == address(0x0)) { revert RecipientCannotBeZeroAddress(); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an ERC721 token is transferred to this contract via * safeTransferFrom, this function is called. * * @param operator The address of the operator. * @param from The address of the sender. * @param tokenId The ID of the ERC721. * @param data Additional data. * * @return bytes4 The magic value, unless throwing. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ConduitItemType } from "../conduit/lib/ConduitEnums.sol"; /** * @dev A TransferHelperItem specifies the itemType (ERC20/ERC721/ERC1155), * token address, token identifier, and amount of the token to be * transferred via the TransferHelper. For ERC20 tokens, identifier * must be 0. For ERC721 tokens, amount must be 1. */ struct TransferHelperItem { ConduitItemType itemType; address token; uint256 identifier; uint256 amount; } /** * @dev A TransferHelperItemsWithRecipient specifies the tokens to transfer * via the TransferHelper, their intended recipient, and a boolean flag * indicating whether onERC721Received should be called on a recipient * contract. */ struct TransferHelperItemsWithRecipient { TransferHelperItem[] items; address recipient; bool validateERC721Receiver; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { TransferHelperItemsWithRecipient } from "../helpers/TransferHelperStructs.sol"; interface TransferHelperInterface { /** * @notice Transfer multiple items to a single recipient. * * @param items The items to transfer. * @param conduitKey The key of the conduit performing the bulk transfer. */ function bulkTransfer( TransferHelperItemsWithRecipient[] calldata items, bytes32 conduitKey ) external returns (bytes4); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @title TransferHelperErrors */ interface TransferHelperErrors { /** * @dev Revert with an error when attempting to execute transfers with a * NATIVE itemType. */ error InvalidItemType(); /** * @dev Revert with an error when an ERC721 transfer with amount other than * one is attempted. * * @param amount The amount of the ERC721 tokens to transfer. */ error InvalidERC721TransferAmount(uint256 amount); /** * @dev Revert with an error when attempting to execute an ERC721 transfer * to an invalid recipient. */ error InvalidERC721Recipient(address recipient); /** * @dev Revert with an error when a call to an ERC721 receiver reverts with * bytes data. */ error ERC721ReceiverErrorRevertBytes( bytes reason, address receiver, address sender, uint256 identifier ); /** * @dev Revert with an error when a call to an ERC721 receiver reverts with * string reason. */ error ERC721ReceiverErrorRevertString( string reason, address receiver, address sender, uint256 identifier ); /** * @dev Revert with an error when an ERC20 token has an invalid identifier. */ error InvalidERC20Identifier(); /** * @dev Revert with an error if the recipient is the zero address. */ error RecipientCannotBeZeroAddress(); /** * @dev Revert with an error when attempting to fill an order referencing an * invalid conduit (i.e. one that has not been deployed). */ error InvalidConduit(bytes32 conduitKey, address conduit); /** * @dev Revert with an error when a call to a conduit reverts with a * reason string. */ error ConduitErrorRevertString( string reason, bytes32 conduitKey, address conduit ); /** * @dev Revert with an error when a call to a conduit reverts with bytes * data. */ error ConduitErrorRevertBytes( bytes reason, bytes32 conduitKey, address conduit ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; // error ChannelClosed(address channel) uint256 constant ChannelClosed_error_signature = ( 0x93daadf200000000000000000000000000000000000000000000000000000000 ); uint256 constant ChannelClosed_error_ptr = 0x00; uint256 constant ChannelClosed_channel_ptr = 0x4; uint256 constant ChannelClosed_error_length = 0x24; // For the mapping: // mapping(address => bool) channels // The position in storage for a particular account is: // keccak256(abi.encode(account, channels.slot)) uint256 constant ChannelKey_channel_ptr = 0x00; uint256 constant ChannelKey_slot_ptr = 0x20; uint256 constant ChannelKey_length = 0x40;
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { IERC721Receiver } from "../interfaces/IERC721Receiver.sol"; contract ERC721ReceiverMock is IERC721Receiver { enum Error { None, RevertWithMessage, RevertWithoutMessage, Panic } bytes4 private immutable _retval; Error private immutable _error; event Received( address operator, address from, uint256 tokenId, bytes data, uint256 gas ); constructor(bytes4 retval, Error error) { _retval = retval; _error = error; } function onERC721Received( address operator, address from, uint256 tokenId, bytes memory data ) public override returns (bytes4) { if (_error == Error.RevertWithMessage) { revert("ERC721ReceiverMock: reverting"); } else if (_error == Error.RevertWithoutMessage) { revert(); } else if (_error == Error.Panic) { uint256 a = uint256(0) / uint256(0); a; } emit Received(operator, from, tokenId, data, gasleft()); return _retval; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { SpentItem, OfferItem } from "../../../lib/ConsiderationStructs.sol"; import { ItemType } from "../../../lib/ConsiderationEnums.sol"; import { StructCopier } from "./StructCopier.sol"; library SpentItemLib { bytes32 private constant SPENT_ITEM_MAP_POSITION = keccak256("seaport.SpentItemDefaults"); bytes32 private constant SPENT_ITEMS_MAP_POSITION = keccak256("seaport.SpentItemsDefaults"); function empty() internal pure returns (SpentItem memory) { return SpentItem(ItemType(0), address(0), 0, 0); } function clear(SpentItem storage item) internal { // clear all fields item.itemType = ItemType(0); item.token = address(0); item.identifier = 0; item.amount = 0; } function clearMany(SpentItem[] storage items) internal { while (items.length > 0) { clear(items[items.length - 1]); items.pop(); } } /** * @notice clears a default SpentItem from storage * @param defaultName the name of the default to clear */ function clear(string memory defaultName) internal { mapping(string => SpentItem) storage spentItemMap = _spentItemMap(); SpentItem storage item = spentItemMap[defaultName]; clear(item); } function clearMany(string memory defaultsName) internal { mapping(string => SpentItem[]) storage spentItemsMap = _spentItemsMap(); SpentItem[] storage items = spentItemsMap[defaultsName]; clearMany(items); } /** * @notice gets a default SpentItem from storage * @param defaultName the name of the default for retrieval */ function fromDefault( string memory defaultName ) internal view returns (SpentItem memory item) { mapping(string => SpentItem) storage spentItemMap = _spentItemMap(); item = spentItemMap[defaultName]; } function fromDefaultMany( string memory defaultsName ) internal view returns (SpentItem[] memory items) { mapping(string => SpentItem[]) storage spentItemsMap = _spentItemsMap(); items = spentItemsMap[defaultsName]; } /** * @notice saves an SpentItem as a named default * @param spentItem the SpentItem to save as a default * @param defaultName the name of the default for retrieval */ function saveDefault( SpentItem memory spentItem, string memory defaultName ) internal returns (SpentItem memory _spentItem) { mapping(string => SpentItem) storage spentItemMap = _spentItemMap(); spentItemMap[defaultName] = spentItem; return spentItem; } function saveDefaultMany( SpentItem[] memory spentItems, string memory defaultsName ) internal returns (SpentItem[] memory _spentItems) { mapping(string => SpentItem[]) storage spentItemsMap = _spentItemsMap(); SpentItem[] storage items = spentItemsMap[defaultsName]; setSpentItems(items, spentItems); return spentItems; } function setSpentItems( SpentItem[] storage items, SpentItem[] memory newItems ) internal { clearMany(items); for (uint256 i = 0; i < newItems.length; i++) { items.push(newItems[i]); } } /** * @notice makes a copy of an SpentItem in-memory * @param item the SpentItem to make a copy of in-memory */ function copy( SpentItem memory item ) internal pure returns (SpentItem memory) { return SpentItem({ itemType: item.itemType, token: item.token, identifier: item.identifier, amount: item.amount }); } function copy( SpentItem[] memory items ) internal pure returns (SpentItem[] memory) { SpentItem[] memory copiedItems = new SpentItem[](items.length); for (uint256 i = 0; i < items.length; i++) { copiedItems[i] = copy(items[i]); } return copiedItems; } /** * @notice gets the storage position of the default SpentItem map */ function _spentItemMap() private pure returns (mapping(string => SpentItem) storage spentItemMap) { bytes32 position = SPENT_ITEM_MAP_POSITION; assembly { spentItemMap.slot := position } } function _spentItemsMap() private pure returns (mapping(string => SpentItem[]) storage spentItemsMap) { bytes32 position = SPENT_ITEMS_MAP_POSITION; assembly { spentItemsMap.slot := position } } // methods for configuring a single of each of an SpentItem's fields, which modifies the SpentItem in-place and // returns it /** * @notice sets the item type * @param item the SpentItem to modify * @param itemType the item type to set * @return the modified SpentItem */ function withItemType( SpentItem memory item, ItemType itemType ) internal pure returns (SpentItem memory) { item.itemType = itemType; return item; } /** * @notice sets the token address * @param item the SpentItem to modify * @param token the token address to set * @return the modified SpentItem */ function withToken( SpentItem memory item, address token ) internal pure returns (SpentItem memory) { item.token = token; return item; } /** * @notice sets the identifier or criteria * @param item the SpentItem to modify * @param identifier the identifier or criteria to set * @return the modified SpentItem */ function withIdentifier( SpentItem memory item, uint256 identifier ) internal pure returns (SpentItem memory) { item.identifier = identifier; return item; } /** * @notice sets the start amount * @param item the SpentItem to modify * @param amount the start amount to set * @return the modified SpentItem */ function withAmount( SpentItem memory item, uint256 amount ) internal pure returns (SpentItem memory) { item.amount = amount; return item; } function toOfferItem( SpentItem memory item ) internal pure returns (OfferItem memory) { return OfferItem({ itemType: item.itemType, token: item.token, identifierOrCriteria: item.identifier, startAmount: item.amount, endAmount: item.amount }); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { BasicOrderParameters, CriteriaResolver, AdvancedOrder, AdditionalRecipient, OfferItem, Order, ConsiderationItem, Fulfillment, FulfillmentComponent, OrderParameters, OrderComponents, Execution } from "../../../lib/ConsiderationStructs.sol"; import { ConsiderationInterface } from "../../../interfaces/ConsiderationInterface.sol"; import { ArrayLib } from "./ArrayLib.sol"; library StructCopier { function _basicOrderParameters() private pure returns (BasicOrderParameters storage empty) { bytes32 position = keccak256("StructCopier.EmptyBasicOrderParameters"); assembly { empty.slot := position } return empty; } function _criteriaResolver() private pure returns (CriteriaResolver storage empty) { bytes32 position = keccak256("StructCopier.EmptyCriteriaResolver"); assembly { empty.slot := position } return empty; } function _fulfillment() private pure returns (Fulfillment storage empty) { bytes32 position = keccak256("StructCopier.EmptyFulfillment"); assembly { empty.slot := position } return empty; } function _orderComponents() private pure returns (OrderComponents storage empty) { bytes32 position = keccak256("StructCopier.EmptyOrderComponents"); assembly { empty.slot := position } return empty; } function _orderParameters() private pure returns (OrderParameters storage empty) { bytes32 position = keccak256("StructCopier.EmptyOrderParameters"); assembly { empty.slot := position } return empty; } function _order() private pure returns (Order storage empty) { bytes32 position = keccak256("StructCopier.EmptyOrder"); assembly { empty.slot := position } return empty; } function setBasicOrderParameters( BasicOrderParameters storage dest, BasicOrderParameters memory src ) internal { dest.considerationToken = src.considerationToken; dest.considerationIdentifier = src.considerationIdentifier; dest.considerationAmount = src.considerationAmount; dest.offerer = src.offerer; dest.zone = src.zone; dest.offerToken = src.offerToken; dest.offerIdentifier = src.offerIdentifier; dest.offerAmount = src.offerAmount; dest.basicOrderType = src.basicOrderType; dest.startTime = src.startTime; dest.endTime = src.endTime; dest.zoneHash = src.zoneHash; dest.salt = src.salt; dest.offererConduitKey = src.offererConduitKey; dest.fulfillerConduitKey = src.fulfillerConduitKey; dest.totalOriginalAdditionalRecipients = src .totalOriginalAdditionalRecipients; setAdditionalRecipients( dest.additionalRecipients, src.additionalRecipients ); dest.signature = src.signature; } function setOrderComponents( OrderComponents storage dest, OrderComponents memory src ) internal { dest.offerer = src.offerer; dest.zone = src.zone; setOfferItems(dest.offer, src.offer); setConsiderationItems(dest.consideration, src.consideration); dest.orderType = src.orderType; dest.startTime = src.startTime; dest.endTime = src.endTime; dest.zoneHash = src.zoneHash; dest.salt = src.salt; dest.conduitKey = src.conduitKey; dest.counter = src.counter; } function setOrderComponents( OrderComponents[] storage dest, OrderComponents[] memory src ) internal { while (dest.length != 0) { dest.pop(); } OrderComponents storage empty = _orderComponents(); for (uint256 i = 0; i < src.length; ++i) { dest.push(empty); setOrderComponents(dest[i], src[i]); } } function setBasicOrderParameters( BasicOrderParameters[] storage dest, BasicOrderParameters[] memory src ) internal { while (dest.length != 0) { dest.pop(); } BasicOrderParameters storage empty = _basicOrderParameters(); for (uint256 i = 0; i < src.length; ++i) { dest.push(empty); setBasicOrderParameters(dest[i], src[i]); } } function setAdditionalRecipients( AdditionalRecipient[] storage dest, AdditionalRecipient[] memory src ) internal { while (dest.length != 0) { dest.pop(); } for (uint256 i = 0; i < src.length; ++i) { dest.push(src[i]); } } function setCriteriaResolver( CriteriaResolver storage dest, CriteriaResolver memory src ) internal { dest.orderIndex = src.orderIndex; dest.side = src.side; dest.index = src.index; dest.identifier = src.identifier; ArrayLib.setBytes32s(dest.criteriaProof, src.criteriaProof); } function setCriteriaResolvers( CriteriaResolver[] storage dest, CriteriaResolver[] memory src ) internal { while (dest.length != 0) { dest.pop(); } CriteriaResolver storage empty = _criteriaResolver(); for (uint256 i = 0; i < src.length; ++i) { dest.push(empty); setCriteriaResolver(dest[i], src[i]); } } function setOrder(Order storage dest, Order memory src) internal { setOrderParameters(dest.parameters, src.parameters); dest.signature = src.signature; } bytes32 constant TEMP_ORDER = keccak256("seaport-sol.temp.Order"); bytes32 constant TEMP_COUNTER_SLOT = keccak256("seaport-sol.temp.Counter"); /** * @notice Get a counter used to derive a temporary storage slot. * @dev Solidity does not allow copying dynamic types from memory to storage. * We need a "clean" (empty) temp pointer to make an exact copy of a struct with dynamic members, but * Solidity does not allow calling "delete" on a storage pointer either. * By hashing a struct's temp slot with a monotonically increasing counter, we can derive a new temp slot * that is basically "guaranteed" to have all successive storage slots empty. * TODO: We can revisit adding "clear" methods that definitively wipe all dynamic components of a struct, * but that will require an equal amount of SSTOREs; this is obviously more expensive gas-wise, but may not * make a difference performance-wise when running simiulations locally (though this needs to be tested) */ function _getAndIncrementTempCounter() internal returns (uint256 counter) { // get counter slot bytes32 counterSlot = TEMP_COUNTER_SLOT; assembly { // load current value counter := sload(counterSlot) // store incremented value sstore(counterSlot, add(counter, 1)) } // return original value return counter; } function _deriveTempSlotWithCounter( bytes32 libSlot ) internal returns (uint256 derivedSlot) { uint256 counter = _getAndIncrementTempCounter(); assembly { // store lib slot in first mem position mstore(0x0, libSlot) // store temp counter in second position mstore(0x20, counter) // hash original slot with counter to get new temp slot, which has a low probability of being dirty // (~1/2**256) derivedSlot := keccak256(0x0, 0x40) } } function _getTempOrder() internal returns (Order storage _tempOrder) { uint256 position = _deriveTempSlotWithCounter(TEMP_ORDER); assembly { _tempOrder.slot := position } } function setOrders(Order[] storage dest, Order[] memory src) internal { while (dest.length != 0) { dest.pop(); } Order storage empty = _order(); for (uint256 i = 0; i < src.length; ++i) { dest.push(empty); setOrder(dest[i], src[i]); } } function setAdvancedOrder( AdvancedOrder storage dest, AdvancedOrder memory src ) internal { setOrderParameters(dest.parameters, src.parameters); dest.numerator = src.numerator; dest.denominator = src.denominator; dest.signature = src.signature; dest.extraData = src.extraData; } bytes32 constant TEMP_ADVANCED_ORDER = keccak256("seaport-sol.temp.AdvancedOrder"); function _getTempAdvancedOrder() internal returns (AdvancedOrder storage _tempAdvancedOrder) { uint256 position = _deriveTempSlotWithCounter(TEMP_ADVANCED_ORDER); assembly { _tempAdvancedOrder.slot := position } } function setAdvancedOrders( AdvancedOrder[] storage dest, AdvancedOrder[] memory src ) internal { AdvancedOrder storage _tempAdvancedOrder = _getTempAdvancedOrder(); while (dest.length != 0) { dest.pop(); } for (uint256 i = 0; i < src.length; ++i) { setAdvancedOrder(_tempAdvancedOrder, src[i]); dest.push(_tempAdvancedOrder); } } function setOrderParameters( OrderParameters storage dest, OrderParameters memory src ) internal { dest.offerer = src.offerer; dest.zone = src.zone; setOfferItems(dest.offer, src.offer); setConsiderationItems(dest.consideration, src.consideration); dest.orderType = src.orderType; dest.startTime = src.startTime; dest.endTime = src.endTime; dest.zoneHash = src.zoneHash; dest.salt = src.salt; dest.conduitKey = src.conduitKey; dest.totalOriginalConsiderationItems = src .totalOriginalConsiderationItems; } function setOfferItems( OfferItem[] storage dest, OfferItem[] memory src ) internal { while (dest.length != 0) { dest.pop(); } for (uint256 i = 0; i < src.length; ++i) { dest.push(src[i]); } } function setConsiderationItems( ConsiderationItem[] storage dest, ConsiderationItem[] memory src ) internal { while (dest.length != 0) { dest.pop(); } for (uint256 i = 0; i < src.length; ++i) { dest.push(src[i]); } } function setFulfillment( Fulfillment storage dest, Fulfillment memory src ) internal { setFulfillmentComponents(dest.offerComponents, src.offerComponents); setFulfillmentComponents( dest.considerationComponents, src.considerationComponents ); } function setFulfillments( Fulfillment[] storage dest, Fulfillment[] memory src ) internal { while (dest.length != 0) { dest.pop(); } Fulfillment storage empty = _fulfillment(); for (uint256 i = 0; i < src.length; ++i) { dest.push(empty); setFulfillment(dest[i], src[i]); } } function setFulfillmentComponents( FulfillmentComponent[] storage dest, FulfillmentComponent[] memory src ) internal { while (dest.length != 0) { dest.pop(); } for (uint256 i = 0; i < src.length; ++i) { dest.push(src[i]); } } bytes32 constant TEMP_FULFILLMENT_COMPONENTS = keccak256("seaport-sol.temp.FulfillmentComponents"); function _getTempFulfillmentComponents() internal pure returns (FulfillmentComponent[] storage _tempFulfillmentComponents) { bytes32 position = TEMP_FULFILLMENT_COMPONENTS; assembly { _tempFulfillmentComponents.slot := position } } function pushFulFillmentComponents( FulfillmentComponent[][] storage dest, FulfillmentComponent[] memory src ) internal { FulfillmentComponent[] storage _tempFulfillmentComponents = _getTempFulfillmentComponents(); setFulfillmentComponents(_tempFulfillmentComponents, src); dest.push(_tempFulfillmentComponents); } function setFulfillmentComponentsArray( FulfillmentComponent[][] storage dest, FulfillmentComponent[][] memory src ) internal { while (dest.length != 0) { dest.pop(); } for (uint256 i = 0; i < src.length; ++i) { pushFulFillmentComponents(dest, src[i]); } } function toConsiderationItems( OfferItem[] memory _offerItems, address payable receiver ) internal pure returns (ConsiderationItem[] memory) { ConsiderationItem[] memory considerationItems = new ConsiderationItem[]( _offerItems.length ); for (uint256 i = 0; i < _offerItems.length; ++i) { considerationItems[i] = ConsiderationItem( _offerItems[i].itemType, _offerItems[i].token, _offerItems[i].identifierOrCriteria, _offerItems[i].startAmount, _offerItems[i].endAmount, receiver ); } return considerationItems; } function toOfferItems( ConsiderationItem[] memory _considerationItems ) internal pure returns (OfferItem[] memory) { OfferItem[] memory _offerItems = new OfferItem[]( _considerationItems.length ); for (uint256 i = 0; i < _offerItems.length; i++) { _offerItems[i] = OfferItem( _considerationItems[i].itemType, _considerationItems[i].token, _considerationItems[i].identifierOrCriteria, _considerationItems[i].startAmount, _considerationItems[i].endAmount ); } return _offerItems; } function createMirrorOrderParameters( OrderParameters memory orderParameters, address payable offerer, address zone, bytes32 conduitKey ) public pure returns (OrderParameters memory) { OfferItem[] memory _offerItems = toOfferItems( orderParameters.consideration ); ConsiderationItem[] memory _considerationItems = toConsiderationItems( orderParameters.offer, offerer ); OrderParameters memory _mirrorOrderParameters = OrderParameters( offerer, zone, _offerItems, _considerationItems, orderParameters.orderType, orderParameters.startTime, orderParameters.endTime, orderParameters.zoneHash, orderParameters.salt, conduitKey, _considerationItems.length ); return _mirrorOrderParameters; } function setExecutions( Execution[] storage dest, Execution[] memory src ) internal { while (dest.length != 0) { dest.pop(); } for (uint256 i = 0; i < src.length; ++i) { dest.push(src[i]); } } function setOrderParameters( OrderParameters[] storage dest, OrderParameters[] memory src ) internal { while (dest.length != 0) { dest.pop(); } OrderParameters storage empty = _orderParameters(); for (uint256 i = 0; i < src.length; ++i) { dest.push(empty); setOrderParameters(dest[i], src[i]); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; library ArrayLib { function setBytes32s( bytes32[] storage array, bytes32[] memory values ) internal { while (array.length > 0) { array.pop(); } for (uint256 i = 0; i < values.length; i++) { array.push(values[i]); } } function copy( bytes32[] memory array ) internal pure returns (bytes32[] memory) { bytes32[] memory copiedArray = new bytes32[](array.length); for (uint256 i = 0; i < array.length; i++) { copiedArray[i] = array[i]; } return copiedArray; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { AdditionalRecipientLib } from "./AdditionalRecipientLib.sol"; import { AdvancedOrderLib } from "./AdvancedOrderLib.sol"; import { ArrayLib } from "./ArrayLib.sol"; import { BasicOrderParametersLib } from "./BasicOrderParametersLib.sol"; import { ConsiderationItemLib } from "./ConsiderationItemLib.sol"; import { CriteriaResolverLib } from "./CriteriaResolverLib.sol"; import { ExecutionLib } from "./ExecutionLib.sol"; import { FulfillmentComponentLib } from "./FulfillmentComponentLib.sol"; import { FulfillmentLib } from "./FulfillmentLib.sol"; import { OfferItemLib } from "./OfferItemLib.sol"; import { OrderComponentsLib } from "./OrderComponentsLib.sol"; import { OrderLib } from "./OrderLib.sol"; import { OrderParametersLib } from "./OrderParametersLib.sol"; import { ReceivedItemLib } from "./ReceivedItemLib.sol"; import { SpentItemLib } from "./SpentItemLib.sol"; import { StructCopier } from "./StructCopier.sol"; import { SeaportArrays } from "./SeaportArrays.sol";
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { AdditionalRecipient } from "../../../lib/ConsiderationStructs.sol"; import { StructCopier } from "./StructCopier.sol"; library AdditionalRecipientLib { bytes32 private constant ADDITIONAL_RECIPIENT_MAP_POSITION = keccak256("seaport.AdditionalRecipientDefaults"); bytes32 private constant ADDITIONAL_RECIPIENTS_MAP_POSITION = keccak256("seaport.AdditionalRecipientsDefaults"); /** * @notice clears a default AdditionalRecipient from storage * @param defaultName the name of the default to clear */ function clear(string memory defaultName) internal { mapping(string => AdditionalRecipient) storage additionalRecipientMap = _additionalRecipientMap(); AdditionalRecipient storage item = additionalRecipientMap[defaultName]; clear(item); } function clear(AdditionalRecipient storage item) internal { // clear all fields item.amount = 0; item.recipient = payable(address(0)); } function clear(AdditionalRecipient[] storage item) internal { while (item.length > 0) { clear(item[item.length - 1]); item.pop(); } } /** * @notice gets a default AdditionalRecipient from storage * @param defaultName the name of the default for retrieval */ function fromDefault( string memory defaultName ) internal view returns (AdditionalRecipient memory item) { mapping(string => AdditionalRecipient) storage additionalRecipientMap = _additionalRecipientMap(); item = additionalRecipientMap[defaultName]; } function fromDefaultMany( string memory defaultName ) internal view returns (AdditionalRecipient[] memory items) { mapping(string => AdditionalRecipient[]) storage additionalRecipientsMap = _additionalRecipientsMap(); items = additionalRecipientsMap[defaultName]; } /** * @notice saves an AdditionalRecipient as a named default * @param additionalRecipient the AdditionalRecipient to save as a default * @param defaultName the name of the default for retrieval */ function saveDefault( AdditionalRecipient memory additionalRecipient, string memory defaultName ) internal returns (AdditionalRecipient memory _additionalRecipient) { mapping(string => AdditionalRecipient) storage additionalRecipientMap = _additionalRecipientMap(); additionalRecipientMap[defaultName] = additionalRecipient; return additionalRecipient; } function saveDefaultMany( AdditionalRecipient[] memory additionalRecipients, string memory defaultName ) internal returns (AdditionalRecipient[] memory _additionalRecipients) { mapping(string => AdditionalRecipient[]) storage additionalRecipientsMap = _additionalRecipientsMap(); StructCopier.setAdditionalRecipients( additionalRecipientsMap[defaultName], additionalRecipients ); return additionalRecipients; } /** * @notice makes a copy of an AdditionalRecipient in-memory * @param item the AdditionalRecipient to make a copy of in-memory */ function copy( AdditionalRecipient memory item ) internal pure returns (AdditionalRecipient memory) { return AdditionalRecipient({ amount: item.amount, recipient: item.recipient }); } function copy( AdditionalRecipient[] memory items ) internal pure returns (AdditionalRecipient[] memory) { AdditionalRecipient[] memory copiedItems = new AdditionalRecipient[]( items.length ); for (uint256 i = 0; i < items.length; i++) { copiedItems[i] = copy(items[i]); } return copiedItems; } function empty() internal pure returns (AdditionalRecipient memory) { return AdditionalRecipient({ amount: 0, recipient: payable(address(0)) }); } /** * @notice gets the storage position of the default AdditionalRecipient map */ function _additionalRecipientMap() private pure returns ( mapping(string => AdditionalRecipient) storage additionalRecipientMap ) { bytes32 position = ADDITIONAL_RECIPIENT_MAP_POSITION; assembly { additionalRecipientMap.slot := position } } function _additionalRecipientsMap() private pure returns ( mapping(string => AdditionalRecipient[]) storage additionalRecipientsMap ) { bytes32 position = ADDITIONAL_RECIPIENTS_MAP_POSITION; assembly { additionalRecipientsMap.slot := position } } // methods for configuring a single of each of an AdditionalRecipient's fields, which modifies the // AdditionalRecipient in-place and // returns it function withAmount( AdditionalRecipient memory item, uint256 amount ) internal pure returns (AdditionalRecipient memory) { item.amount = amount; return item; } function withRecipient( AdditionalRecipient memory item, address recipient ) internal pure returns (AdditionalRecipient memory) { item.recipient = payable(recipient); return item; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { AdvancedOrder, Order, OrderParameters } from "../../../lib/ConsiderationStructs.sol"; import { OrderParametersLib } from "./OrderParametersLib.sol"; import { StructCopier } from "./StructCopier.sol"; library AdvancedOrderLib { bytes32 private constant ADVANCED_ORDER_MAP_POSITION = keccak256("seaport.AdvancedOrderDefaults"); bytes32 private constant ADVANCED_ORDERS_MAP_POSITION = keccak256("seaport.AdvancedOrdersDefaults"); using OrderParametersLib for OrderParameters; /** * @notice clears a default AdvancedOrder from storage * @param defaultName the name of the default to clear */ function clear(string memory defaultName) internal { mapping(string => AdvancedOrder) storage advancedOrderMap = _advancedOrderMap(); AdvancedOrder storage item = advancedOrderMap[defaultName]; clear(item); } function clear(AdvancedOrder storage item) internal { // clear all fields item.parameters.clear(); item.signature = ""; item.numerator = 0; item.denominator = 0; item.extraData = ""; } function clear(AdvancedOrder[] storage items) internal { while (items.length > 0) { clear(items[items.length - 1]); items.pop(); } } /** * @notice gets a default AdvancedOrder from storage * @param defaultName the name of the default for retrieval */ function fromDefault( string memory defaultName ) internal view returns (AdvancedOrder memory item) { mapping(string => AdvancedOrder) storage advancedOrderMap = _advancedOrderMap(); item = advancedOrderMap[defaultName]; } function fromDefaultMany( string memory defaultName ) internal view returns (AdvancedOrder[] memory items) { mapping(string => AdvancedOrder[]) storage advancedOrdersMap = _advancedOrdersMap(); items = advancedOrdersMap[defaultName]; } function empty() internal pure returns (AdvancedOrder memory) { return AdvancedOrder(OrderParametersLib.empty(), 0, 0, "", ""); } /** * @notice saves an AdvancedOrder as a named default * @param advancedOrder the AdvancedOrder to save as a default * @param defaultName the name of the default for retrieval */ function saveDefault( AdvancedOrder memory advancedOrder, string memory defaultName ) internal returns (AdvancedOrder memory _advancedOrder) { mapping(string => AdvancedOrder) storage advancedOrderMap = _advancedOrderMap(); StructCopier.setAdvancedOrder( advancedOrderMap[defaultName], advancedOrder ); return advancedOrder; } function saveDefaultMany( AdvancedOrder[] memory advancedOrders, string memory defaultName ) internal returns (AdvancedOrder[] memory _advancedOrders) { mapping(string => AdvancedOrder[]) storage advancedOrdersMap = _advancedOrdersMap(); StructCopier.setAdvancedOrders( advancedOrdersMap[defaultName], advancedOrders ); return advancedOrders; } /** * @notice makes a copy of an AdvancedOrder in-memory * @param item the AdvancedOrder to make a copy of in-memory */ function copy( AdvancedOrder memory item ) internal pure returns (AdvancedOrder memory) { return AdvancedOrder({ parameters: item.parameters.copy(), numerator: item.numerator, denominator: item.denominator, signature: item.signature, extraData: item.extraData }); } function copy( AdvancedOrder[] memory items ) internal pure returns (AdvancedOrder[] memory) { AdvancedOrder[] memory copiedItems = new AdvancedOrder[](items.length); for (uint256 i = 0; i < items.length; i++) { copiedItems[i] = copy(items[i]); } return copiedItems; } /** * @notice gets the storage position of the default AdvancedOrder map */ function _advancedOrderMap() private pure returns (mapping(string => AdvancedOrder) storage advancedOrderMap) { bytes32 position = ADVANCED_ORDER_MAP_POSITION; assembly { advancedOrderMap.slot := position } } function _advancedOrdersMap() private pure returns (mapping(string => AdvancedOrder[]) storage advancedOrdersMap) { bytes32 position = ADVANCED_ORDERS_MAP_POSITION; assembly { advancedOrdersMap.slot := position } } // methods for configuring a single of each of an AdvancedOrder's fields, which modifies the AdvancedOrder in-place // and // returns it function withParameters( AdvancedOrder memory advancedOrder, OrderParameters memory parameters ) internal pure returns (AdvancedOrder memory) { advancedOrder.parameters = parameters.copy(); return advancedOrder; } function withNumerator( AdvancedOrder memory advancedOrder, uint120 numerator ) internal pure returns (AdvancedOrder memory) { advancedOrder.numerator = numerator; return advancedOrder; } function withDenominator( AdvancedOrder memory advancedOrder, uint120 denominator ) internal pure returns (AdvancedOrder memory) { advancedOrder.denominator = denominator; return advancedOrder; } function withSignature( AdvancedOrder memory advancedOrder, bytes memory signature ) internal pure returns (AdvancedOrder memory) { advancedOrder.signature = signature; return advancedOrder; } function withExtraData( AdvancedOrder memory advancedOrder, bytes memory extraData ) internal pure returns (AdvancedOrder memory) { advancedOrder.extraData = extraData; return advancedOrder; } function toOrder( AdvancedOrder memory advancedOrder ) internal pure returns (Order memory order) { order.parameters = advancedOrder.parameters.copy(); order.signature = advancedOrder.signature; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { BasicOrderParameters, OrderComponents, OrderParameters, ConsiderationItem, OrderParameters, OfferItem, AdditionalRecipient } from "../../../lib/ConsiderationStructs.sol"; import { OrderType, ItemType, BasicOrderType } from "../../../lib/ConsiderationEnums.sol"; import { StructCopier } from "./StructCopier.sol"; import { AdditionalRecipientLib } from "./AdditionalRecipientLib.sol"; library BasicOrderParametersLib { using BasicOrderParametersLib for BasicOrderParameters; using AdditionalRecipientLib for AdditionalRecipient[]; bytes32 private constant BASIC_ORDER_PARAMETERS_MAP_POSITION = keccak256("seaport.BasicOrderParametersDefaults"); bytes32 private constant BASIC_ORDER_PARAMETERS_ARRAY_MAP_POSITION = keccak256("seaport.BasicOrderParametersArrayDefaults"); function clear(BasicOrderParameters storage basicParameters) internal { // uninitialized pointers take up no new memory (versus one word for initializing length-0) AdditionalRecipient[] memory additionalRecipients; basicParameters.considerationToken = address(0); basicParameters.considerationIdentifier = 0; basicParameters.considerationAmount = 0; basicParameters.offerer = payable(address(0)); basicParameters.zone = address(0); basicParameters.offerToken = address(0); basicParameters.offerIdentifier = 0; basicParameters.offerAmount = 0; basicParameters.basicOrderType = BasicOrderType(0); basicParameters.startTime = 0; basicParameters.endTime = 0; basicParameters.zoneHash = bytes32(0); basicParameters.salt = 0; basicParameters.offererConduitKey = bytes32(0); basicParameters.fulfillerConduitKey = bytes32(0); basicParameters.totalOriginalAdditionalRecipients = 0; StructCopier.setAdditionalRecipients( basicParameters.additionalRecipients, additionalRecipients ); basicParameters.signature = new bytes(0); } function clear( BasicOrderParameters[] storage basicParametersArray ) internal { while (basicParametersArray.length > 0) { basicParametersArray[basicParametersArray.length - 1].clear(); basicParametersArray.pop(); } } /** * @notice clears a default BasicOrderParameters from storage * @param defaultName the name of the default to clear */ function clear(string memory defaultName) internal { mapping(string => BasicOrderParameters) storage orderComponentsMap = _orderComponentsMap(); BasicOrderParameters storage basicParameters = orderComponentsMap[ defaultName ]; basicParameters.clear(); } function empty() internal pure returns (BasicOrderParameters memory item) { AdditionalRecipient[] memory additionalRecipients; item = BasicOrderParameters({ considerationToken: address(0), considerationIdentifier: 0, considerationAmount: 0, offerer: payable(address(0)), zone: address(0), offerToken: address(0), offerIdentifier: 0, offerAmount: 0, basicOrderType: BasicOrderType(0), startTime: 0, endTime: 0, zoneHash: bytes32(0), salt: 0, offererConduitKey: bytes32(0), fulfillerConduitKey: bytes32(0), totalOriginalAdditionalRecipients: 0, additionalRecipients: additionalRecipients, signature: new bytes(0) }); } /** * @notice gets a default BasicOrderParameters from storage * @param defaultName the name of the default for retrieval */ function fromDefault( string memory defaultName ) internal view returns (BasicOrderParameters memory item) { mapping(string => BasicOrderParameters) storage orderComponentsMap = _orderComponentsMap(); item = orderComponentsMap[defaultName]; } function fromDefaultMany( string memory defaultName ) internal view returns (BasicOrderParameters[] memory items) { mapping(string => BasicOrderParameters[]) storage orderComponentsArrayMap = _orderComponentsArrayMap(); items = orderComponentsArrayMap[defaultName]; } /** * @notice saves an BasicOrderParameters as a named default * @param orderComponents the BasicOrderParameters to save as a default * @param defaultName the name of the default for retrieval */ function saveDefault( BasicOrderParameters memory orderComponents, string memory defaultName ) internal returns (BasicOrderParameters memory _orderComponents) { mapping(string => BasicOrderParameters) storage orderComponentsMap = _orderComponentsMap(); BasicOrderParameters storage destination = orderComponentsMap[ defaultName ]; StructCopier.setBasicOrderParameters(destination, orderComponents); return orderComponents; } function saveDefaultMany( BasicOrderParameters[] memory orderComponents, string memory defaultName ) internal returns (BasicOrderParameters[] memory _orderComponents) { mapping(string => BasicOrderParameters[]) storage orderComponentsArrayMap = _orderComponentsArrayMap(); BasicOrderParameters[] storage destination = orderComponentsArrayMap[ defaultName ]; StructCopier.setBasicOrderParameters(destination, orderComponents); return orderComponents; } /** * @notice makes a copy of an BasicOrderParameters in-memory * @param item the BasicOrderParameters to make a copy of in-memory */ function copy( BasicOrderParameters memory item ) internal pure returns (BasicOrderParameters memory) { return BasicOrderParameters({ considerationToken: item.considerationToken, considerationIdentifier: item.considerationIdentifier, considerationAmount: item.considerationAmount, offerer: item.offerer, zone: item.zone, offerToken: item.offerToken, offerIdentifier: item.offerIdentifier, offerAmount: item.offerAmount, basicOrderType: item.basicOrderType, startTime: item.startTime, endTime: item.endTime, zoneHash: item.zoneHash, salt: item.salt, offererConduitKey: item.offererConduitKey, fulfillerConduitKey: item.fulfillerConduitKey, totalOriginalAdditionalRecipients: item .totalOriginalAdditionalRecipients, additionalRecipients: item.additionalRecipients.copy(), signature: item.signature }); } /** * @notice gets the storage position of the default BasicOrderParameters map */ function _orderComponentsMap() private pure returns ( mapping(string => BasicOrderParameters) storage orderComponentsMap ) { bytes32 position = BASIC_ORDER_PARAMETERS_MAP_POSITION; assembly { orderComponentsMap.slot := position } } function _orderComponentsArrayMap() private pure returns ( mapping(string => BasicOrderParameters[]) storage orderComponentsArrayMap ) { bytes32 position = BASIC_ORDER_PARAMETERS_ARRAY_MAP_POSITION; assembly { orderComponentsArrayMap.slot := position } } // methods for configuring a single of each of an in-memory BasicOrderParameters's fields, which modifies the // BasicOrderParameters in-memory and returns it function withConsiderationToken( BasicOrderParameters memory item, address value ) internal pure returns (BasicOrderParameters memory) { item.considerationToken = value; return item; } function withConsiderationIdentifier( BasicOrderParameters memory item, uint256 value ) internal pure returns (BasicOrderParameters memory) { item.considerationIdentifier = value; return item; } function withConsiderationAmount( BasicOrderParameters memory item, uint256 value ) internal pure returns (BasicOrderParameters memory) { item.considerationAmount = value; return item; } function withOfferer( BasicOrderParameters memory item, address value ) internal pure returns (BasicOrderParameters memory) { item.offerer = payable(value); return item; } function withZone( BasicOrderParameters memory item, address value ) internal pure returns (BasicOrderParameters memory) { item.zone = value; return item; } function withOfferToken( BasicOrderParameters memory item, address value ) internal pure returns (BasicOrderParameters memory) { item.offerToken = value; return item; } function withOfferIdentifier( BasicOrderParameters memory item, uint256 value ) internal pure returns (BasicOrderParameters memory) { item.offerIdentifier = value; return item; } function withOfferAmount( BasicOrderParameters memory item, uint256 value ) internal pure returns (BasicOrderParameters memory) { item.offerAmount = value; return item; } function withBasicOrderType( BasicOrderParameters memory item, BasicOrderType value ) internal pure returns (BasicOrderParameters memory) { item.basicOrderType = value; return item; } function withStartTime( BasicOrderParameters memory item, uint256 value ) internal pure returns (BasicOrderParameters memory) { item.startTime = value; return item; } function withEndTime( BasicOrderParameters memory item, uint256 value ) internal pure returns (BasicOrderParameters memory) { item.endTime = value; return item; } function withZoneHash( BasicOrderParameters memory item, bytes32 value ) internal pure returns (BasicOrderParameters memory) { item.zoneHash = value; return item; } function withSalt( BasicOrderParameters memory item, uint256 value ) internal pure returns (BasicOrderParameters memory) { item.salt = value; return item; } function withOffererConduitKey( BasicOrderParameters memory item, bytes32 value ) internal pure returns (BasicOrderParameters memory) { item.offererConduitKey = value; return item; } function withFulfillerConduitKey( BasicOrderParameters memory item, bytes32 value ) internal pure returns (BasicOrderParameters memory) { item.fulfillerConduitKey = value; return item; } function withTotalOriginalAdditionalRecipients( BasicOrderParameters memory item, uint256 value ) internal pure returns (BasicOrderParameters memory) { item.totalOriginalAdditionalRecipients = value; return item; } function withAdditionalRecipients( BasicOrderParameters memory item, AdditionalRecipient[] memory value ) internal pure returns (BasicOrderParameters memory) { item.additionalRecipients = value; return item; } function withSignature( BasicOrderParameters memory item, bytes memory value ) internal pure returns (BasicOrderParameters memory) { item.signature = value; return item; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { ConsiderationItem, ReceivedItem } from "../../../lib/ConsiderationStructs.sol"; import { ItemType } from "../../../lib/ConsiderationEnums.sol"; import { StructCopier } from "./StructCopier.sol"; library ConsiderationItemLib { bytes32 private constant CONSIDERATION_ITEM_MAP_POSITION = keccak256("seaport.ConsiderationItemDefaults"); bytes32 private constant CONSIDERATION_ITEMS_MAP_POSITION = keccak256("seaport.ConsiderationItemsDefaults"); function _clear(ConsiderationItem storage item) internal { // clear all fields item.itemType = ItemType.NATIVE; item.token = address(0); item.identifierOrCriteria = 0; item.startAmount = 0; item.endAmount = 0; item.recipient = payable(address(0)); } /** * @notice clears a default ConsiderationItem from storage * @param defaultName the name of the default to clear */ function clear(string memory defaultName) internal { mapping(string => ConsiderationItem) storage considerationItemMap = _considerationItemMap(); ConsiderationItem storage item = considerationItemMap[defaultName]; _clear(item); } function clearMany(string memory defaultsName) internal { mapping(string => ConsiderationItem[]) storage considerationItemsMap = _considerationItemsMap(); ConsiderationItem[] storage items = considerationItemsMap[defaultsName]; while (items.length > 0) { _clear(items[items.length - 1]); items.pop(); } } /** * @notice gets a default ConsiderationItem from storage * @param defaultName the name of the default for retrieval */ function fromDefault( string memory defaultName ) internal view returns (ConsiderationItem memory item) { mapping(string => ConsiderationItem) storage considerationItemMap = _considerationItemMap(); item = considerationItemMap[defaultName]; } function fromDefaultMany( string memory defaultsName ) internal view returns (ConsiderationItem[] memory items) { mapping(string => ConsiderationItem[]) storage considerationItemsMap = _considerationItemsMap(); items = considerationItemsMap[defaultsName]; } function empty() internal pure returns (ConsiderationItem memory) { return ConsiderationItem({ itemType: ItemType(0), token: address(0), identifierOrCriteria: 0, startAmount: 0, endAmount: 0, recipient: payable(address(0)) }); } /** * @notice saves an ConsiderationItem as a named default * @param considerationItem the ConsiderationItem to save as a default * @param defaultName the name of the default for retrieval */ function saveDefault( ConsiderationItem memory considerationItem, string memory defaultName ) internal returns (ConsiderationItem memory _considerationItem) { mapping(string => ConsiderationItem) storage considerationItemMap = _considerationItemMap(); considerationItemMap[defaultName] = considerationItem; return considerationItem; } function saveDefaultMany( ConsiderationItem[] memory considerationItems, string memory defaultsName ) internal returns (ConsiderationItem[] memory _considerationItems) { mapping(string => ConsiderationItem[]) storage considerationItemsMap = _considerationItemsMap(); ConsiderationItem[] storage items = considerationItemsMap[defaultsName]; clearMany(defaultsName); StructCopier.setConsiderationItems(items, considerationItems); return considerationItems; } /** * @notice makes a copy of an ConsiderationItem in-memory * @param item the ConsiderationItem to make a copy of in-memory */ function copy( ConsiderationItem memory item ) internal pure returns (ConsiderationItem memory) { return ConsiderationItem({ itemType: item.itemType, token: item.token, identifierOrCriteria: item.identifierOrCriteria, startAmount: item.startAmount, endAmount: item.endAmount, recipient: item.recipient }); } function copy( ConsiderationItem[] memory item ) internal pure returns (ConsiderationItem[] memory) { ConsiderationItem[] memory copies = new ConsiderationItem[]( item.length ); for (uint256 i = 0; i < item.length; i++) { copies[i] = ConsiderationItem({ itemType: item[i].itemType, token: item[i].token, identifierOrCriteria: item[i].identifierOrCriteria, startAmount: item[i].startAmount, endAmount: item[i].endAmount, recipient: item[i].recipient }); } return copies; } /** * @notice gets the storage position of the default ConsiderationItem map */ function _considerationItemMap() private pure returns ( mapping(string => ConsiderationItem) storage considerationItemMap ) { bytes32 position = CONSIDERATION_ITEM_MAP_POSITION; assembly { considerationItemMap.slot := position } } function _considerationItemsMap() private pure returns ( mapping(string => ConsiderationItem[]) storage considerationItemsMap ) { bytes32 position = CONSIDERATION_ITEMS_MAP_POSITION; assembly { considerationItemsMap.slot := position } } // methods for configuring a single of each of an ConsiderationItem's fields, which modifies the ConsiderationItem // in-place and // returns it /** * @notice sets the item type * @param item the ConsiderationItem to modify * @param itemType the item type to set * @return the modified ConsiderationItem */ function withItemType( ConsiderationItem memory item, ItemType itemType ) internal pure returns (ConsiderationItem memory) { item.itemType = itemType; return item; } /** * @notice sets the token address * @param item the ConsiderationItem to modify * @param token the token address to set * @return the modified ConsiderationItem */ function withToken( ConsiderationItem memory item, address token ) internal pure returns (ConsiderationItem memory) { item.token = token; return item; } /** * @notice sets the identifier or criteria * @param item the ConsiderationItem to modify * @param identifierOrCriteria the identifier or criteria to set * @return the modified ConsiderationItem */ function withIdentifierOrCriteria( ConsiderationItem memory item, uint256 identifierOrCriteria ) internal pure returns (ConsiderationItem memory) { item.identifierOrCriteria = identifierOrCriteria; return item; } /** * @notice sets the start amount * @param item the ConsiderationItem to modify * @param startAmount the start amount to set * @return the modified ConsiderationItem */ function withStartAmount( ConsiderationItem memory item, uint256 startAmount ) internal pure returns (ConsiderationItem memory) { item.startAmount = startAmount; return item; } /** * @notice sets the end amount * @param item the ConsiderationItem to modify * @param endAmount the end amount to set * @return the modified ConsiderationItem */ function withEndAmount( ConsiderationItem memory item, uint256 endAmount ) internal pure returns (ConsiderationItem memory) { item.endAmount = endAmount; return item; } /** * @notice sets the recipient * @param item the ConsiderationItem to modify * @param recipient the recipient to set * @return the modified ConsiderationItem */ function withRecipient( ConsiderationItem memory item, address recipient ) internal pure returns (ConsiderationItem memory) { item.recipient = payable(recipient); return item; } function toReceivedItem( ConsiderationItem memory item ) internal pure returns (ReceivedItem memory) { return ReceivedItem({ itemType: item.itemType, token: item.token, identifier: item.identifierOrCriteria, amount: item.startAmount, recipient: item.recipient }); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { CriteriaResolver, OfferItem } from "../../../lib/ConsiderationStructs.sol"; import { Side } from "../../../lib/ConsiderationEnums.sol"; import { ArrayLib } from "./ArrayLib.sol"; import { StructCopier } from "./StructCopier.sol"; library CriteriaResolverLib { bytes32 private constant CRITERIA_RESOLVER_MAP_POSITION = keccak256("seaport.CriteriaResolverDefaults"); bytes32 private constant CRITERIA_RESOLVERS_MAP_POSITION = keccak256("seaport.CriteriaResolversDefaults"); using ArrayLib for bytes32[]; /** * @notice clears a default CriteriaResolver from storage * @param defaultName the name of the default to clear */ function clear(string memory defaultName) internal { mapping(string => CriteriaResolver) storage criteriaResolverMap = _criteriaResolverMap(); CriteriaResolver storage resolver = criteriaResolverMap[defaultName]; // clear all fields clear(resolver); } function clear(CriteriaResolver storage resolver) internal { bytes32[] memory criteriaProof; resolver.orderIndex = 0; resolver.side = Side(0); resolver.index = 0; resolver.identifier = 0; ArrayLib.setBytes32s(resolver.criteriaProof, criteriaProof); } function clear(CriteriaResolver[] storage resolvers) internal { while (resolvers.length > 0) { clear(resolvers[resolvers.length - 1]); resolvers.pop(); } } /** * @notice gets a default CriteriaResolver from storage * @param defaultName the name of the default for retrieval */ function fromDefault( string memory defaultName ) internal view returns (CriteriaResolver memory resolver) { mapping(string => CriteriaResolver) storage criteriaResolverMap = _criteriaResolverMap(); resolver = criteriaResolverMap[defaultName]; } function fromDefaultMany( string memory defaultsName ) internal view returns (CriteriaResolver[] memory resolvers) { mapping(string => CriteriaResolver[]) storage criteriaResolversMap = _criteriaResolversMap(); resolvers = criteriaResolversMap[defaultsName]; } /** * @notice saves an CriteriaResolver as a named default * @param criteriaResolver the CriteriaResolver to save as a default * @param defaultName the name of the default for retrieval */ function saveDefault( CriteriaResolver memory criteriaResolver, string memory defaultName ) internal returns (CriteriaResolver memory _criteriaResolver) { mapping(string => CriteriaResolver) storage criteriaResolverMap = _criteriaResolverMap(); CriteriaResolver storage resolver = criteriaResolverMap[defaultName]; resolver.orderIndex = criteriaResolver.orderIndex; resolver.side = criteriaResolver.side; resolver.index = criteriaResolver.index; resolver.identifier = criteriaResolver.identifier; ArrayLib.setBytes32s( resolver.criteriaProof, criteriaResolver.criteriaProof ); return criteriaResolver; } function saveDefaultMany( CriteriaResolver[] memory criteriaResolvers, string memory defaultName ) internal returns (CriteriaResolver[] memory _criteriaResolvers) { mapping(string => CriteriaResolver[]) storage criteriaResolversMap = _criteriaResolversMap(); CriteriaResolver[] storage resolvers = criteriaResolversMap[ defaultName ]; // todo: make sure we do this elsewhere clear(resolvers); StructCopier.setCriteriaResolvers(resolvers, criteriaResolvers); return criteriaResolvers; } /** * @notice makes a copy of an CriteriaResolver in-memory * @param resolver the CriteriaResolver to make a copy of in-memory */ function copy( CriteriaResolver memory resolver ) internal pure returns (CriteriaResolver memory) { return CriteriaResolver({ orderIndex: resolver.orderIndex, side: resolver.side, index: resolver.index, identifier: resolver.identifier, criteriaProof: resolver.criteriaProof.copy() }); } function copy( CriteriaResolver[] memory resolvers ) internal pure returns (CriteriaResolver[] memory) { CriteriaResolver[] memory copiedItems = new CriteriaResolver[]( resolvers.length ); for (uint256 i = 0; i < resolvers.length; i++) { copiedItems[i] = copy(resolvers[i]); } return copiedItems; } function empty() internal pure returns (CriteriaResolver memory) { bytes32[] memory proof; return CriteriaResolver({ orderIndex: 0, side: Side(0), index: 0, identifier: 0, criteriaProof: proof }); } /** * @notice gets the storage position of the default CriteriaResolver map */ function _criteriaResolverMap() private pure returns ( mapping(string => CriteriaResolver) storage criteriaResolverMap ) { bytes32 position = CRITERIA_RESOLVER_MAP_POSITION; assembly { criteriaResolverMap.slot := position } } function _criteriaResolversMap() private pure returns ( mapping(string => CriteriaResolver[]) storage criteriaResolversMap ) { bytes32 position = CRITERIA_RESOLVERS_MAP_POSITION; assembly { criteriaResolversMap.slot := position } } // methods for configuring a single of each of an CriteriaResolver's fields, which modifies the CriteriaResolver // in-place and // returns it function withOrderIndex( CriteriaResolver memory resolver, uint256 orderIndex ) internal pure returns (CriteriaResolver memory) { resolver.orderIndex = orderIndex; return resolver; } function withSide( CriteriaResolver memory resolver, Side side ) internal pure returns (CriteriaResolver memory) { resolver.side = side; return resolver; } function withIndex( CriteriaResolver memory resolver, uint256 index ) internal pure returns (CriteriaResolver memory) { resolver.index = index; return resolver; } function withIdentifier( CriteriaResolver memory resolver, uint256 identifier ) internal pure returns (CriteriaResolver memory) { resolver.identifier = identifier; return resolver; } function withCriteriaProof( CriteriaResolver memory resolver, bytes32[] memory criteriaProof ) internal pure returns (CriteriaResolver memory) { // todo: consider copying? resolver.criteriaProof = criteriaProof; return resolver; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { Execution, ReceivedItem } from "../../../lib/ConsiderationStructs.sol"; import { ReceivedItemLib } from "./ReceivedItemLib.sol"; import { StructCopier } from "./StructCopier.sol"; library ExecutionLib { bytes32 private constant EXECUTION_MAP_POSITION = keccak256("seaport.ExecutionDefaults"); bytes32 private constant EXECUTIONS_MAP_POSITION = keccak256("seaport.ExecutionsDefaults"); using ReceivedItemLib for ReceivedItem; using ReceivedItemLib for ReceivedItem[]; /** * @notice clears a default Execution from storage * @param defaultName the name of the default to clear */ function clear(string memory defaultName) internal { mapping(string => Execution) storage executionMap = _executionMap(); Execution storage item = executionMap[defaultName]; clear(item); } function clear(Execution storage execution) internal { // clear all fields execution.item = ReceivedItemLib.empty(); execution.offerer = address(0); execution.conduitKey = bytes32(0); } function clear(Execution[] storage executions) internal { while (executions.length > 0) { clear(executions[executions.length - 1]); executions.pop(); } } /** * @notice gets a default Execution from storage * @param defaultName the name of the default for retrieval */ function fromDefault( string memory defaultName ) internal view returns (Execution memory item) { mapping(string => Execution) storage executionMap = _executionMap(); item = executionMap[defaultName]; } function fromDefaultMany( string memory defaultName ) internal view returns (Execution[] memory items) { mapping(string => Execution[]) storage executionsMap = _executionsMap(); items = executionsMap[defaultName]; } /** * @notice saves an Execution as a named default * @param execution the Execution to save as a default * @param defaultName the name of the default for retrieval */ function saveDefault( Execution memory execution, string memory defaultName ) internal returns (Execution memory _execution) { mapping(string => Execution) storage executionMap = _executionMap(); executionMap[defaultName] = execution; return execution; } function saveDefaultMany( Execution[] memory executions, string memory defaultName ) internal returns (Execution[] memory _executions) { mapping(string => Execution[]) storage executionsMap = _executionsMap(); StructCopier.setExecutions(executionsMap[defaultName], executions); return executions; } /** * @notice makes a copy of an Execution in-memory * @param item the Execution to make a copy of in-memory */ function copy( Execution memory item ) internal pure returns (Execution memory) { return Execution({ item: item.item.copy(), offerer: item.offerer, conduitKey: item.conduitKey }); } function copy( Execution[] memory item ) internal pure returns (Execution[] memory) { Execution[] memory copies = new Execution[](item.length); for (uint256 i = 0; i < item.length; i++) { copies[i] = copy(item[i]); } return copies; } function empty() internal pure returns (Execution memory) { return Execution({ item: ReceivedItemLib.empty(), offerer: address(0), conduitKey: bytes32(0) }); } /** * @notice gets the storage position of the default Execution map */ function _executionMap() private pure returns (mapping(string => Execution) storage executionMap) { bytes32 position = EXECUTION_MAP_POSITION; assembly { executionMap.slot := position } } function _executionsMap() private pure returns (mapping(string => Execution[]) storage executionsMap) { bytes32 position = EXECUTIONS_MAP_POSITION; assembly { executionsMap.slot := position } } // methods for configuring a single of each of an Execution's fields, which modifies the Execution // in-place and // returns it function withItem( Execution memory execution, ReceivedItem memory item ) internal pure returns (Execution memory) { execution.item = item.copy(); return execution; } function withOfferer( Execution memory execution, address offerer ) internal pure returns (Execution memory) { execution.offerer = offerer; return execution; } function withConduitKey( Execution memory execution, bytes32 conduitKey ) internal pure returns (Execution memory) { execution.conduitKey = conduitKey; return execution; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { FulfillmentComponent, OfferItem } from "../../../lib/ConsiderationStructs.sol"; import { Side } from "../../../lib/ConsiderationEnums.sol"; import { ArrayLib } from "./ArrayLib.sol"; import { StructCopier } from "./StructCopier.sol"; library FulfillmentComponentLib { bytes32 private constant FULFILLMENT_COMPONENT_MAP_POSITION = keccak256("seaport.FulfillmentComponentDefaults"); bytes32 private constant FULFILLMENT_COMPONENTS_MAP_POSITION = keccak256("seaport.FulfillmentComponentsDefaults"); using ArrayLib for bytes32[]; /** * @notice clears a default FulfillmentComponent from storage * @param defaultName the name of the default to clear */ function clear(string memory defaultName) internal { mapping(string => FulfillmentComponent) storage fulfillmentComponentMap = _fulfillmentComponentMap(); FulfillmentComponent storage component = fulfillmentComponentMap[ defaultName ]; clear(component); } function clear(FulfillmentComponent storage component) internal { component.orderIndex = 0; component.itemIndex = 0; } function clear(FulfillmentComponent[] storage components) internal { while (components.length > 0) { clear(components[components.length - 1]); components.pop(); } } /** * @notice gets a default FulfillmentComponent from storage * @param defaultName the name of the default for retrieval */ function fromDefault( string memory defaultName ) internal view returns (FulfillmentComponent memory component) { mapping(string => FulfillmentComponent) storage fulfillmentComponentMap = _fulfillmentComponentMap(); component = fulfillmentComponentMap[defaultName]; } function fromDefaultMany( string memory defaultName ) internal view returns (FulfillmentComponent[] memory components) { mapping(string => FulfillmentComponent[]) storage fulfillmentComponentMap = _fulfillmentComponentsMap(); components = fulfillmentComponentMap[defaultName]; } /** * @notice saves an FulfillmentComponent as a named default * @param fulfillmentComponent the FulfillmentComponent to save as a default * @param defaultName the name of the default for retrieval */ function saveDefault( FulfillmentComponent memory fulfillmentComponent, string memory defaultName ) internal returns (FulfillmentComponent memory _fulfillmentComponent) { mapping(string => FulfillmentComponent) storage fulfillmentComponentMap = _fulfillmentComponentMap(); FulfillmentComponent storage component = fulfillmentComponentMap[ defaultName ]; component.orderIndex = fulfillmentComponent.orderIndex; component.itemIndex = fulfillmentComponent.itemIndex; return fulfillmentComponent; } function saveDefaultMany( FulfillmentComponent[] memory fulfillmentComponents, string memory defaultName ) internal returns (FulfillmentComponent[] memory _fulfillmentComponents) { mapping(string => FulfillmentComponent[]) storage fulfillmentComponentsMap = _fulfillmentComponentsMap(); FulfillmentComponent[] storage components = fulfillmentComponentsMap[ defaultName ]; clear(components); StructCopier.setFulfillmentComponents( components, fulfillmentComponents ); return fulfillmentComponents; } /** * @notice makes a copy of an FulfillmentComponent in-memory * @param component the FulfillmentComponent to make a copy of in-memory */ function copy( FulfillmentComponent memory component ) internal pure returns (FulfillmentComponent memory) { return FulfillmentComponent({ orderIndex: component.orderIndex, itemIndex: component.itemIndex }); } function copy( FulfillmentComponent[] memory components ) internal pure returns (FulfillmentComponent[] memory) { FulfillmentComponent[] memory copiedItems = new FulfillmentComponent[]( components.length ); for (uint256 i = 0; i < components.length; i++) { copiedItems[i] = copy(components[i]); } return copiedItems; } function empty() internal pure returns (FulfillmentComponent memory) { return FulfillmentComponent({ orderIndex: 0, itemIndex: 0 }); } /** * @notice gets the storage position of the default FulfillmentComponent map */ function _fulfillmentComponentMap() private pure returns ( mapping(string => FulfillmentComponent) storage fulfillmentComponentMap ) { bytes32 position = FULFILLMENT_COMPONENT_MAP_POSITION; assembly { fulfillmentComponentMap.slot := position } } function _fulfillmentComponentsMap() private pure returns ( mapping(string => FulfillmentComponent[]) storage fulfillmentComponentsMap ) { bytes32 position = FULFILLMENT_COMPONENTS_MAP_POSITION; assembly { fulfillmentComponentsMap.slot := position } } // methods for configuring a single of each of an FulfillmentComponent's fields, which modifies the // FulfillmentComponent // in-place and // returns it function withOrderIndex( FulfillmentComponent memory component, uint256 orderIndex ) internal pure returns (FulfillmentComponent memory) { component.orderIndex = orderIndex; return component; } function withItemIndex( FulfillmentComponent memory component, uint256 itemIndex ) internal pure returns (FulfillmentComponent memory) { component.itemIndex = itemIndex; return component; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { Fulfillment, FulfillmentComponent } from "../../../lib/ConsiderationStructs.sol"; import { Side } from "../../../lib/ConsiderationEnums.sol"; import { ArrayLib } from "./ArrayLib.sol"; import { FulfillmentComponentLib } from "./FulfillmentComponentLib.sol"; import { StructCopier } from "./StructCopier.sol"; library FulfillmentLib { bytes32 private constant FULFILLMENT_MAP_POSITION = keccak256("seaport.FulfillmentDefaults"); bytes32 private constant FULFILLMENTS_MAP_POSITION = keccak256("seaport.FulfillmentsDefaults"); using FulfillmentComponentLib for FulfillmentComponent[]; using StructCopier for FulfillmentComponent[]; /** * @notice clears a default Fulfillment from storage * @param defaultName the name of the default to clear */ function clear(string memory defaultName) internal { mapping(string => Fulfillment) storage fulfillmentMap = _fulfillmentMap(); Fulfillment storage _fulfillment = fulfillmentMap[defaultName]; // clear all fields FulfillmentComponent[] memory components; _fulfillment.offerComponents.setFulfillmentComponents(components); _fulfillment.considerationComponents.setFulfillmentComponents( components ); } /** * @notice gets a default Fulfillment from storage * @param defaultName the name of the default for retrieval */ function fromDefault( string memory defaultName ) internal view returns (Fulfillment memory _fulfillment) { mapping(string => Fulfillment) storage fulfillmentMap = _fulfillmentMap(); _fulfillment = fulfillmentMap[defaultName]; } function fromDefaultMany( string memory defaultName ) internal view returns (Fulfillment[] memory _fulfillments) { mapping(string => Fulfillment[]) storage fulfillmentsMap = _fulfillmentsMap(); _fulfillments = fulfillmentsMap[defaultName]; } /** * @notice saves an Fulfillment as a named default * @param fulfillment the Fulfillment to save as a default * @param defaultName the name of the default for retrieval */ function saveDefault( Fulfillment memory fulfillment, string memory defaultName ) internal returns (Fulfillment memory _fulfillment) { mapping(string => Fulfillment) storage fulfillmentMap = _fulfillmentMap(); StructCopier.setFulfillment(fulfillmentMap[defaultName], fulfillment); return fulfillment; } function saveDefaultMany( Fulfillment[] memory fulfillments, string memory defaultName ) internal returns (Fulfillment[] memory _fulfillments) { mapping(string => Fulfillment[]) storage fulfillmentsMap = _fulfillmentsMap(); StructCopier.setFulfillments( fulfillmentsMap[defaultName], fulfillments ); return fulfillments; } /** * @notice makes a copy of an Fulfillment in-memory * @param _fulfillment the Fulfillment to make a copy of in-memory */ function copy( Fulfillment memory _fulfillment ) internal pure returns (Fulfillment memory) { return Fulfillment({ offerComponents: _fulfillment.offerComponents.copy(), considerationComponents: _fulfillment .considerationComponents .copy() }); } function copy( Fulfillment[] memory _fulfillments ) internal pure returns (Fulfillment[] memory) { Fulfillment[] memory copiedItems = new Fulfillment[]( _fulfillments.length ); for (uint256 i = 0; i < _fulfillments.length; i++) { copiedItems[i] = copy(_fulfillments[i]); } return copiedItems; } function empty() internal pure returns (Fulfillment memory) { FulfillmentComponent[] memory components; return Fulfillment({ offerComponents: components, considerationComponents: components }); } /** * @notice gets the storage position of the default Fulfillment map */ function _fulfillmentMap() private pure returns (mapping(string => Fulfillment) storage fulfillmentMap) { bytes32 position = FULFILLMENT_MAP_POSITION; assembly { fulfillmentMap.slot := position } } function _fulfillmentsMap() private pure returns (mapping(string => Fulfillment[]) storage fulfillmentsMap) { bytes32 position = FULFILLMENTS_MAP_POSITION; assembly { fulfillmentsMap.slot := position } } // methods for configuring a single of each of an Fulfillment's fields, which modifies the // Fulfillment // in-place and // returns it function withOfferComponents( Fulfillment memory _fulfillment, FulfillmentComponent[] memory components ) internal pure returns (Fulfillment memory) { _fulfillment.offerComponents = components.copy(); return _fulfillment; } function withConsiderationComponents( Fulfillment memory _fulfillment, FulfillmentComponent[] memory components ) internal pure returns (Fulfillment memory) { _fulfillment.considerationComponents = components.copy(); return _fulfillment; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { OfferItem, SpentItem } from "../../../lib/ConsiderationStructs.sol"; import { ItemType } from "../../../lib/ConsiderationEnums.sol"; import { StructCopier } from "./StructCopier.sol"; library OfferItemLib { bytes32 private constant OFFER_ITEM_MAP_POSITION = keccak256("seaport.OfferItemDefaults"); bytes32 private constant OFFER_ITEMS_MAP_POSITION = keccak256("seaport.OfferItemsDefaults"); function _clear(OfferItem storage item) internal { // clear all fields item.itemType = ItemType.NATIVE; item.token = address(0); item.identifierOrCriteria = 0; item.startAmount = 0; item.endAmount = 0; } /** * @notice clears a default OfferItem from storage * @param defaultName the name of the default to clear */ function clear(string memory defaultName) internal { mapping(string => OfferItem) storage offerItemMap = _offerItemMap(); OfferItem storage item = offerItemMap[defaultName]; _clear(item); } function clearMany(string memory defaultsName) internal { mapping(string => OfferItem[]) storage offerItemsMap = _offerItemsMap(); OfferItem[] storage items = offerItemsMap[defaultsName]; while (items.length > 0) { _clear(items[items.length - 1]); items.pop(); } } /** * @notice gets a default OfferItem from storage * @param defaultName the name of the default for retrieval */ function fromDefault( string memory defaultName ) internal view returns (OfferItem memory item) { mapping(string => OfferItem) storage offerItemMap = _offerItemMap(); item = offerItemMap[defaultName]; } function fromDefaultMany( string memory defaultsName ) internal view returns (OfferItem[] memory items) { mapping(string => OfferItem[]) storage offerItemsMap = _offerItemsMap(); items = offerItemsMap[defaultsName]; } /** * @notice saves an OfferItem as a named default * @param offerItem the OfferItem to save as a default * @param defaultName the name of the default for retrieval */ function saveDefault( OfferItem memory offerItem, string memory defaultName ) internal returns (OfferItem memory _offerItem) { mapping(string => OfferItem) storage offerItemMap = _offerItemMap(); offerItemMap[defaultName] = offerItem; return offerItem; } function saveDefaultMany( OfferItem[] memory offerItems, string memory defaultsName ) internal returns (OfferItem[] memory _offerItems) { mapping(string => OfferItem[]) storage offerItemsMap = _offerItemsMap(); OfferItem[] storage items = offerItemsMap[defaultsName]; clearMany(defaultsName); StructCopier.setOfferItems(items, offerItems); return offerItems; } /** * @notice makes a copy of an OfferItem in-memory * @param item the OfferItem to make a copy of in-memory */ function copy( OfferItem memory item ) internal pure returns (OfferItem memory) { return OfferItem({ itemType: item.itemType, token: item.token, identifierOrCriteria: item.identifierOrCriteria, startAmount: item.startAmount, endAmount: item.endAmount }); } function copy( OfferItem[] memory items ) internal pure returns (OfferItem[] memory) { OfferItem[] memory copiedItems = new OfferItem[](items.length); for (uint256 i = 0; i < items.length; i++) { copiedItems[i] = copy(items[i]); } return copiedItems; } function empty() internal pure returns (OfferItem memory) { return OfferItem({ itemType: ItemType.NATIVE, token: address(0), identifierOrCriteria: 0, startAmount: 0, endAmount: 0 }); } /** * @notice gets the storage position of the default OfferItem map */ function _offerItemMap() private pure returns (mapping(string => OfferItem) storage offerItemMap) { bytes32 position = OFFER_ITEM_MAP_POSITION; assembly { offerItemMap.slot := position } } /** * @notice gets the storage position of the default OfferItem[] map */ function _offerItemsMap() private pure returns (mapping(string => OfferItem[]) storage offerItemMap) { bytes32 position = OFFER_ITEMS_MAP_POSITION; assembly { offerItemMap.slot := position } } // methods for configuring a single of each of an OfferItem's fields, which modifies the OfferItem in-place and // returns it /** * @notice sets the item type * @param item the OfferItem to modify * @param itemType the item type to set * @return the modified OfferItem */ function withItemType( OfferItem memory item, ItemType itemType ) internal pure returns (OfferItem memory) { item.itemType = itemType; return item; } /** * @notice sets the token address * @param item the OfferItem to modify * @param token the token address to set * @return the modified OfferItem */ function withToken( OfferItem memory item, address token ) internal pure returns (OfferItem memory) { item.token = token; return item; } /** * @notice sets the identifier or criteria * @param item the OfferItem to modify * @param identifierOrCriteria the identifier or criteria to set * @return the modified OfferItem */ function withIdentifierOrCriteria( OfferItem memory item, uint256 identifierOrCriteria ) internal pure returns (OfferItem memory) { item.identifierOrCriteria = identifierOrCriteria; return item; } /** * @notice sets the start amount * @param item the OfferItem to modify * @param startAmount the start amount to set * @return the modified OfferItem */ function withStartAmount( OfferItem memory item, uint256 startAmount ) internal pure returns (OfferItem memory) { item.startAmount = startAmount; return item; } /** * @notice sets the end amount * @param item the OfferItem to modify * @param endAmount the end amount to set * @return the modified OfferItem */ function withEndAmount( OfferItem memory item, uint256 endAmount ) internal pure returns (OfferItem memory) { item.endAmount = endAmount; return item; } function toSpentItem( OfferItem memory item ) internal pure returns (SpentItem memory) { return SpentItem({ itemType: item.itemType, token: item.token, identifier: item.identifierOrCriteria, amount: item.startAmount }); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { BasicOrderParameters, OrderComponents, ConsiderationItem, OrderParameters, OfferItem, AdditionalRecipient } from "../../../lib/ConsiderationStructs.sol"; import { OrderType, ItemType, BasicOrderType } from "../../../lib/ConsiderationEnums.sol"; import { StructCopier } from "./StructCopier.sol"; import { OfferItemLib } from "./OfferItemLib.sol"; import { ConsiderationItemLib } from "./ConsiderationItemLib.sol"; library OrderComponentsLib { using OrderComponentsLib for OrderComponents; using OfferItemLib for OfferItem[]; using ConsiderationItemLib for ConsiderationItem[]; bytes32 private constant ORDER_COMPONENTS_MAP_POSITION = keccak256("seaport.OrderComponentsDefaults"); bytes32 private constant ORDER_COMPONENTS_ARRAY_MAP_POSITION = keccak256("seaport.OrderComponentsArrayDefaults"); function clear(OrderComponents storage components) internal { // uninitialized pointers take up no new memory (versus one word for initializing length-0) OfferItem[] memory offer; ConsiderationItem[] memory consideration; // clear all fields components.offerer = address(0); components.zone = address(0); StructCopier.setOfferItems(components.offer, offer); StructCopier.setConsiderationItems( components.consideration, consideration ); components.orderType = OrderType(0); components.startTime = 0; components.endTime = 0; components.zoneHash = bytes32(0); components.salt = 0; components.conduitKey = bytes32(0); components.counter = 0; } function clear(OrderComponents[] storage components) internal { while (components.length > 0) { clear(components[components.length - 1]); components.pop(); } } /** * @notice clears a default OrderComponents from storage * @param defaultName the name of the default to clear */ function clear(string memory defaultName) internal { mapping(string => OrderComponents) storage orderComponentsMap = _orderComponentsMap(); OrderComponents storage components = orderComponentsMap[defaultName]; components.clear(); } function empty() internal pure returns (OrderComponents memory item) { OfferItem[] memory offer; ConsiderationItem[] memory consideration; item = OrderComponents({ offerer: address(0), zone: address(0), offer: offer, consideration: consideration, orderType: OrderType(0), startTime: 0, endTime: 0, zoneHash: bytes32(0), salt: 0, conduitKey: bytes32(0), counter: 0 }); } /** * @notice gets a default OrderComponents from storage * @param defaultName the name of the default for retrieval */ function fromDefault( string memory defaultName ) internal view returns (OrderComponents memory item) { mapping(string => OrderComponents) storage orderComponentsMap = _orderComponentsMap(); item = orderComponentsMap[defaultName]; } function fromDefaultMany( string memory defaultName ) internal view returns (OrderComponents[] memory items) { mapping(string => OrderComponents[]) storage orderComponentsArrayMap = _orderComponentsArrayMap(); items = orderComponentsArrayMap[defaultName]; } /** * @notice saves an OrderComponents as a named default * @param orderComponents the OrderComponents to save as a default * @param defaultName the name of the default for retrieval */ function saveDefault( OrderComponents memory orderComponents, string memory defaultName ) internal returns (OrderComponents memory _orderComponents) { mapping(string => OrderComponents) storage orderComponentsMap = _orderComponentsMap(); OrderComponents storage destination = orderComponentsMap[defaultName]; StructCopier.setOrderComponents(destination, orderComponents); return orderComponents; } function saveDefaultMany( OrderComponents[] memory orderComponents, string memory defaultName ) internal returns (OrderComponents[] memory _orderComponents) { mapping(string => OrderComponents[]) storage orderComponentsArrayMap = _orderComponentsArrayMap(); OrderComponents[] storage destination = orderComponentsArrayMap[ defaultName ]; StructCopier.setOrderComponents(destination, orderComponents); return orderComponents; } /** * @notice makes a copy of an OrderComponents in-memory * @param item the OrderComponents to make a copy of in-memory */ function copy( OrderComponents memory item ) internal pure returns (OrderComponents memory) { return OrderComponents({ offerer: item.offerer, zone: item.zone, offer: item.offer.copy(), consideration: item.consideration.copy(), orderType: item.orderType, startTime: item.startTime, endTime: item.endTime, zoneHash: item.zoneHash, salt: item.salt, conduitKey: item.conduitKey, counter: item.counter }); } /** * @notice gets the storage position of the default OrderComponents map */ function _orderComponentsMap() private pure returns (mapping(string => OrderComponents) storage orderComponentsMap) { bytes32 position = ORDER_COMPONENTS_MAP_POSITION; assembly { orderComponentsMap.slot := position } } function _orderComponentsArrayMap() private pure returns ( mapping(string => OrderComponents[]) storage orderComponentsArrayMap ) { bytes32 position = ORDER_COMPONENTS_ARRAY_MAP_POSITION; assembly { orderComponentsArrayMap.slot := position } } // methods for configuring a single of each of an in-memory OrderComponents's fields, which modifies the // OrderComponents in-memory and returns it function withOfferer( OrderComponents memory components, address offerer ) internal pure returns (OrderComponents memory) { components.offerer = offerer; return components; } function withZone( OrderComponents memory components, address zone ) internal pure returns (OrderComponents memory) { components.zone = zone; return components; } function withOffer( OrderComponents memory components, OfferItem[] memory offer ) internal pure returns (OrderComponents memory) { components.offer = offer; return components; } function withConsideration( OrderComponents memory components, ConsiderationItem[] memory consideration ) internal pure returns (OrderComponents memory) { components.consideration = consideration; return components; } function withOrderType( OrderComponents memory components, OrderType orderType ) internal pure returns (OrderComponents memory) { components.orderType = orderType; return components; } function withStartTime( OrderComponents memory components, uint256 startTime ) internal pure returns (OrderComponents memory) { components.startTime = startTime; return components; } function withEndTime( OrderComponents memory components, uint256 endTime ) internal pure returns (OrderComponents memory) { components.endTime = endTime; return components; } function withZoneHash( OrderComponents memory components, bytes32 zoneHash ) internal pure returns (OrderComponents memory) { components.zoneHash = zoneHash; return components; } function withSalt( OrderComponents memory components, uint256 salt ) internal pure returns (OrderComponents memory) { components.salt = salt; return components; } function withConduitKey( OrderComponents memory components, bytes32 conduitKey ) internal pure returns (OrderComponents memory) { components.conduitKey = conduitKey; return components; } function withCounter( OrderComponents memory components, uint256 counter ) internal pure returns (OrderComponents memory) { components.counter = counter; return components; } function toOrderParameters( OrderComponents memory components ) internal pure returns (OrderParameters memory parameters) { parameters.offerer = components.offerer; parameters.zone = components.zone; parameters.offer = components.offer.copy(); parameters.consideration = components.consideration.copy(); parameters.orderType = components.orderType; parameters.startTime = components.startTime; parameters.endTime = components.endTime; parameters.zoneHash = components.zoneHash; parameters.salt = components.salt; parameters.conduitKey = components.conduitKey; parameters.totalOriginalConsiderationItems = components .consideration .length; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { Order, AdvancedOrder, OrderParameters } from "../../../lib/ConsiderationStructs.sol"; import { OrderParametersLib } from "./OrderParametersLib.sol"; import { StructCopier } from "./StructCopier.sol"; library OrderLib { bytes32 private constant ORDER_MAP_POSITION = keccak256("seaport.OrderDefaults"); bytes32 private constant ORDERS_MAP_POSITION = keccak256("seaport.OrdersDefaults"); using OrderParametersLib for OrderParameters; /** * @notice clears a default Order from storage * @param defaultName the name of the default to clear */ function clear(string memory defaultName) internal { mapping(string => Order) storage orderMap = _orderMap(); Order storage item = orderMap[defaultName]; clear(item); } function clear(Order storage order) internal { // clear all fields order.parameters.clear(); order.signature = ""; } function clear(Order[] storage order) internal { while (order.length > 0) { clear(order[order.length - 1]); order.pop(); } } /** * @notice gets a default Order from storage * @param defaultName the name of the default for retrieval */ function fromDefault( string memory defaultName ) internal view returns (Order memory item) { mapping(string => Order) storage orderMap = _orderMap(); item = orderMap[defaultName]; } function fromDefaultMany( string memory defaultName ) internal view returns (Order[] memory) { mapping(string => Order[]) storage ordersMap = _ordersMap(); Order[] memory items = ordersMap[defaultName]; return items; } /** * @notice saves an Order as a named default * @param order the Order to save as a default * @param defaultName the name of the default for retrieval */ function saveDefault( Order memory order, string memory defaultName ) internal returns (Order memory _order) { mapping(string => Order) storage orderMap = _orderMap(); StructCopier.setOrder(orderMap[defaultName], order); return order; } function saveDefaultMany( Order[] memory orders, string memory defaultName ) internal returns (Order[] memory _orders) { mapping(string => Order[]) storage ordersMap = _ordersMap(); StructCopier.setOrders(ordersMap[defaultName], orders); return orders; } /** * @notice makes a copy of an Order in-memory * @param item the Order to make a copy of in-memory */ function copy(Order memory item) internal pure returns (Order memory) { return Order({ parameters: item.parameters.copy(), signature: item.signature }); } function copy(Order[] memory items) internal pure returns (Order[] memory) { Order[] memory copiedItems = new Order[](items.length); for (uint256 i = 0; i < items.length; i++) { copiedItems[i] = copy(items[i]); } return copiedItems; } function empty() internal pure returns (Order memory) { return Order({ parameters: OrderParametersLib.empty(), signature: "" }); } /** * @notice gets the storage position of the default Order map */ function _orderMap() private pure returns (mapping(string => Order) storage orderMap) { bytes32 position = ORDER_MAP_POSITION; assembly { orderMap.slot := position } } function _ordersMap() private pure returns (mapping(string => Order[]) storage ordersMap) { bytes32 position = ORDERS_MAP_POSITION; assembly { ordersMap.slot := position } } // methods for configuring a single of each of an Order's fields, which modifies the Order in-place and // returns it function withParameters( Order memory order, OrderParameters memory parameters ) internal pure returns (Order memory) { order.parameters = parameters.copy(); return order; } function withSignature( Order memory order, bytes memory signature ) internal pure returns (Order memory) { order.signature = signature; return order; } function toAdvancedOrder( Order memory order, uint120 numerator, uint120 denominator, bytes memory extraData ) internal pure returns (AdvancedOrder memory advancedOrder) { advancedOrder.parameters = order.parameters.copy(); advancedOrder.numerator = numerator; advancedOrder.denominator = denominator; advancedOrder.signature = order.signature; advancedOrder.extraData = extraData; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { BasicOrderParameters, OrderComponents, ConsiderationItem, OrderParameters, OfferItem, AdditionalRecipient } from "../../../lib/ConsiderationStructs.sol"; import { OrderType, ItemType, BasicOrderType } from "../../../lib/ConsiderationEnums.sol"; import { StructCopier } from "./StructCopier.sol"; import { OfferItemLib } from "./OfferItemLib.sol"; import { ConsiderationItemLib } from "./ConsiderationItemLib.sol"; library OrderParametersLib { using OrderParametersLib for OrderParameters; using OfferItemLib for OfferItem[]; using ConsiderationItemLib for ConsiderationItem[]; using ConsiderationItemLib for ConsiderationItem; using OfferItemLib for OfferItem; bytes32 private constant ORDER_PARAMETERS_MAP_POSITION = keccak256("seaport.OrderParametersDefaults"); bytes32 private constant ORDER_PARAMETERS_ARRAY_MAP_POSITION = keccak256("seaport.OrderParametersArrayDefaults"); function clear(OrderParameters storage parameters) internal { // uninitialized pointers take up no new memory (versus one word for initializing length-0) OfferItem[] memory offer; ConsiderationItem[] memory consideration; // clear all fields parameters.offerer = address(0); parameters.zone = address(0); StructCopier.setOfferItems(parameters.offer, offer); StructCopier.setConsiderationItems( parameters.consideration, consideration ); parameters.orderType = OrderType(0); parameters.startTime = 0; parameters.endTime = 0; parameters.zoneHash = bytes32(0); parameters.salt = 0; parameters.conduitKey = bytes32(0); parameters.totalOriginalConsiderationItems = 0; } function clear(OrderParameters[] storage parameters) internal { while (parameters.length > 0) { clear(parameters[parameters.length - 1]); parameters.pop(); } } /** * @notice clears a default OrderParameters from storage * @param defaultName the name of the default to clear */ function clear(string memory defaultName) internal { mapping(string => OrderParameters) storage orderParametersMap = _orderParametersMap(); OrderParameters storage parameters = orderParametersMap[defaultName]; parameters.clear(); } function empty() internal pure returns (OrderParameters memory item) { OfferItem[] memory offer; ConsiderationItem[] memory consideration; item = OrderParameters({ offerer: address(0), zone: address(0), offer: offer, consideration: consideration, orderType: OrderType(0), startTime: 0, endTime: 0, zoneHash: bytes32(0), salt: 0, conduitKey: bytes32(0), totalOriginalConsiderationItems: 0 }); } /** * @notice gets a default OrderParameters from storage * @param defaultName the name of the default for retrieval */ function fromDefault( string memory defaultName ) internal view returns (OrderParameters memory item) { mapping(string => OrderParameters) storage orderParametersMap = _orderParametersMap(); item = orderParametersMap[defaultName]; } function fromDefaultMany( string memory defaultName ) internal view returns (OrderParameters[] memory items) { mapping(string => OrderParameters[]) storage orderParametersArrayMap = _orderParametersArrayMap(); items = orderParametersArrayMap[defaultName]; } /** * @notice saves an OrderParameters as a named default * @param orderParameters the OrderParameters to save as a default * @param defaultName the name of the default for retrieval */ function saveDefault( OrderParameters memory orderParameters, string memory defaultName ) internal returns (OrderParameters memory _orderParameters) { mapping(string => OrderParameters) storage orderParametersMap = _orderParametersMap(); OrderParameters storage destination = orderParametersMap[defaultName]; StructCopier.setOrderParameters(destination, orderParameters); return orderParameters; } function saveDefaultMany( OrderParameters[] memory orderParameters, string memory defaultName ) internal returns (OrderParameters[] memory _orderParameters) { mapping(string => OrderParameters[]) storage orderParametersArrayMap = _orderParametersArrayMap(); OrderParameters[] storage destination = orderParametersArrayMap[ defaultName ]; StructCopier.setOrderParameters(destination, orderParameters); return orderParameters; } /** * @notice makes a copy of an OrderParameters in-memory * @param item the OrderParameters to make a copy of in-memory */ function copy( OrderParameters memory item ) internal pure returns (OrderParameters memory) { return OrderParameters({ offerer: item.offerer, zone: item.zone, offer: item.offer.copy(), consideration: item.consideration.copy(), orderType: item.orderType, startTime: item.startTime, endTime: item.endTime, zoneHash: item.zoneHash, salt: item.salt, conduitKey: item.conduitKey, totalOriginalConsiderationItems: item .totalOriginalConsiderationItems }); } /** * @notice gets the storage position of the default OrderParameters map */ function _orderParametersMap() private pure returns (mapping(string => OrderParameters) storage orderParametersMap) { bytes32 position = ORDER_PARAMETERS_MAP_POSITION; assembly { orderParametersMap.slot := position } } function _orderParametersArrayMap() private pure returns ( mapping(string => OrderParameters[]) storage orderParametersArrayMap ) { bytes32 position = ORDER_PARAMETERS_ARRAY_MAP_POSITION; assembly { orderParametersArrayMap.slot := position } } // methods for configuring a single of each of an in-memory OrderParameters's fields, which modifies the // OrderParameters in-memory and returns it function withOfferer( OrderParameters memory parameters, address offerer ) internal pure returns (OrderParameters memory) { parameters.offerer = offerer; return parameters; } function withZone( OrderParameters memory parameters, address zone ) internal pure returns (OrderParameters memory) { parameters.zone = zone; return parameters; } function withOffer( OrderParameters memory parameters, OfferItem[] memory offer ) internal pure returns (OrderParameters memory) { parameters.offer = offer; return parameters; } function withConsideration( OrderParameters memory parameters, ConsiderationItem[] memory consideration ) internal pure returns (OrderParameters memory) { parameters.consideration = consideration; return parameters; } function withOrderType( OrderParameters memory parameters, OrderType orderType ) internal pure returns (OrderParameters memory) { parameters.orderType = orderType; return parameters; } function withStartTime( OrderParameters memory parameters, uint256 startTime ) internal pure returns (OrderParameters memory) { parameters.startTime = startTime; return parameters; } function withEndTime( OrderParameters memory parameters, uint256 endTime ) internal pure returns (OrderParameters memory) { parameters.endTime = endTime; return parameters; } function withZoneHash( OrderParameters memory parameters, bytes32 zoneHash ) internal pure returns (OrderParameters memory) { parameters.zoneHash = zoneHash; return parameters; } function withSalt( OrderParameters memory parameters, uint256 salt ) internal pure returns (OrderParameters memory) { parameters.salt = salt; return parameters; } function withConduitKey( OrderParameters memory parameters, bytes32 conduitKey ) internal pure returns (OrderParameters memory) { parameters.conduitKey = conduitKey; return parameters; } function withTotalOriginalConsiderationItems( OrderParameters memory parameters, uint256 totalOriginalConsiderationItems ) internal pure returns (OrderParameters memory) { parameters .totalOriginalConsiderationItems = totalOriginalConsiderationItems; return parameters; } function toOrderComponents( OrderParameters memory parameters, uint256 counter ) internal pure returns (OrderComponents memory components) { components.offerer = parameters.offerer; components.zone = parameters.zone; components.offer = parameters.offer.copy(); components.consideration = parameters.consideration.copy(); components.orderType = parameters.orderType; components.startTime = parameters.startTime; components.endTime = parameters.endTime; components.zoneHash = parameters.zoneHash; components.salt = parameters.salt; components.conduitKey = parameters.conduitKey; components.counter = counter; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { ReceivedItem, ConsiderationItem } from "../../../lib/ConsiderationStructs.sol"; import { ItemType } from "../../../lib/ConsiderationEnums.sol"; import { StructCopier } from "./StructCopier.sol"; library ReceivedItemLib { bytes32 private constant RECEIVED_ITEM_MAP_POSITION = keccak256("seaport.ReceivedItemDefaults"); bytes32 private constant RECEIVED_ITEMS_MAP_POSITION = keccak256("seaport.ReceivedItemsDefaults"); /** * @notice clears a default ReceivedItem from storage * @param defaultName the name of the default to clear */ function clear(string memory defaultName) internal { mapping(string => ReceivedItem) storage receivedItemMap = _receivedItemMap(); ReceivedItem storage item = receivedItemMap[defaultName]; clear(item); } function clear(ReceivedItem storage item) internal { // clear all fields item.itemType = ItemType.NATIVE; item.token = address(0); item.identifier = 0; item.amount = 0; item.recipient = payable(address(0)); } function clearMany(string memory defaultsName) internal { mapping(string => ReceivedItem[]) storage receivedItemsMap = _receivedItemsMap(); ReceivedItem[] storage items = receivedItemsMap[defaultsName]; clearMany(items); } function clearMany(ReceivedItem[] storage items) internal { while (items.length > 0) { clear(items[items.length - 1]); items.pop(); } } function empty() internal pure returns (ReceivedItem memory) { return ReceivedItem({ itemType: ItemType(0), token: address(0), identifier: 0, amount: 0, recipient: payable(address(0)) }); } /** * @notice gets a default ReceivedItem from storage * @param defaultName the name of the default for retrieval */ function fromDefault( string memory defaultName ) internal view returns (ReceivedItem memory item) { mapping(string => ReceivedItem) storage receivedItemMap = _receivedItemMap(); item = receivedItemMap[defaultName]; } function fromDefaultMany( string memory defaultsName ) internal view returns (ReceivedItem[] memory items) { mapping(string => ReceivedItem[]) storage receivedItemsMap = _receivedItemsMap(); items = receivedItemsMap[defaultsName]; } /** * @notice saves an ReceivedItem as a named default * @param receivedItem the ReceivedItem to save as a default * @param defaultName the name of the default for retrieval */ function saveDefault( ReceivedItem memory receivedItem, string memory defaultName ) internal returns (ReceivedItem memory _receivedItem) { mapping(string => ReceivedItem) storage receivedItemMap = _receivedItemMap(); receivedItemMap[defaultName] = receivedItem; return receivedItem; } function saveDefaultMany( ReceivedItem[] memory receivedItems, string memory defaultsName ) internal returns (ReceivedItem[] memory _receivedItems) { mapping(string => ReceivedItem[]) storage receivedItemsMap = _receivedItemsMap(); ReceivedItem[] storage items = receivedItemsMap[defaultsName]; setReceivedItems(items, receivedItems); return receivedItems; } function setReceivedItems( ReceivedItem[] storage items, ReceivedItem[] memory newItems ) internal { clearMany(items); for (uint256 i = 0; i < newItems.length; i++) { items.push(newItems[i]); } } /** * @notice makes a copy of an ReceivedItem in-memory * @param item the ReceivedItem to make a copy of in-memory */ function copy( ReceivedItem memory item ) internal pure returns (ReceivedItem memory) { return ReceivedItem({ itemType: item.itemType, token: item.token, identifier: item.identifier, amount: item.amount, recipient: item.recipient }); } function copy( ReceivedItem[] memory item ) internal pure returns (ReceivedItem[] memory) { ReceivedItem[] memory copies = new ReceivedItem[](item.length); for (uint256 i = 0; i < item.length; i++) { copies[i] = ReceivedItemLib.copy(item[i]); } return copies; } /** * @notice gets the storage position of the default ReceivedItem map */ function _receivedItemMap() private pure returns (mapping(string => ReceivedItem) storage receivedItemMap) { bytes32 position = RECEIVED_ITEM_MAP_POSITION; assembly { receivedItemMap.slot := position } } /** * @notice gets the storage position of the default ReceivedItem map */ function _receivedItemsMap() private pure returns (mapping(string => ReceivedItem[]) storage receivedItemsMap) { bytes32 position = RECEIVED_ITEMS_MAP_POSITION; assembly { receivedItemsMap.slot := position } } // methods for configuring a single of each of an ReceivedItem's fields, which modifies the ReceivedItem // in-place and // returns it /** * @notice sets the item type * @param item the ReceivedItem to modify * @param itemType the item type to set * @return the modified ReceivedItem */ function withItemType( ReceivedItem memory item, ItemType itemType ) internal pure returns (ReceivedItem memory) { item.itemType = itemType; return item; } /** * @notice sets the token address * @param item the ReceivedItem to modify * @param token the token address to set * @return the modified ReceivedItem */ function withToken( ReceivedItem memory item, address token ) internal pure returns (ReceivedItem memory) { item.token = token; return item; } /** * @notice sets the identifier or criteria * @param item the ReceivedItem to modify * @param identifier the identifier or criteria to set * @return the modified ReceivedItem */ function withIdentifier( ReceivedItem memory item, uint256 identifier ) internal pure returns (ReceivedItem memory) { item.identifier = identifier; return item; } /** * @notice sets the start amount * @param item the ReceivedItem to modify * @param amount the start amount to set * @return the modified ReceivedItem */ function withAmount( ReceivedItem memory item, uint256 amount ) internal pure returns (ReceivedItem memory) { item.amount = amount; return item; } /** * @notice sets the recipient * @param item the ReceivedItem to modify * @param recipient the recipient to set * @return the modified ReceivedItem */ function withRecipient( ReceivedItem memory item, address recipient ) internal pure returns (ReceivedItem memory) { item.recipient = payable(recipient); return item; } function toConsiderationItem( ReceivedItem memory item ) internal pure returns (ConsiderationItem memory) { return ConsiderationItem({ itemType: item.itemType, token: item.token, identifierOrCriteria: item.identifier, startAmount: item.amount, endAmount: item.amount, recipient: item.recipient }); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { OrderComponents, OfferItem, ConsiderationItem, SpentItem, ReceivedItem, BasicOrderParameters, AdditionalRecipient, OrderParameters, Order, AdvancedOrder, CriteriaResolver, Fulfillment, FulfillmentComponent } from "../../../lib/ConsiderationStructs.sol"; library SeaportArrays { function Orders(Order memory a) internal pure returns (Order[] memory) { Order[] memory arr = new Order[](1); arr[0] = a; return arr; } function Orders( Order memory a, Order memory b ) internal pure returns (Order[] memory) { Order[] memory arr = new Order[](2); arr[0] = a; arr[1] = b; return arr; } function Orders( Order memory a, Order memory b, Order memory c ) internal pure returns (Order[] memory) { Order[] memory arr = new Order[](3); arr[0] = a; arr[1] = b; arr[2] = c; return arr; } function Orders( Order memory a, Order memory b, Order memory c, Order memory d ) internal pure returns (Order[] memory) { Order[] memory arr = new Order[](4); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; return arr; } function Orders( Order memory a, Order memory b, Order memory c, Order memory d, Order memory e ) internal pure returns (Order[] memory) { Order[] memory arr = new Order[](5); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; return arr; } function Orders( Order memory a, Order memory b, Order memory c, Order memory d, Order memory e, Order memory f ) internal pure returns (Order[] memory) { Order[] memory arr = new Order[](6); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; return arr; } function Orders( Order memory a, Order memory b, Order memory c, Order memory d, Order memory e, Order memory f, Order memory g ) internal pure returns (Order[] memory) { Order[] memory arr = new Order[](7); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; arr[6] = g; return arr; } function AdvancedOrders( AdvancedOrder memory a ) internal pure returns (AdvancedOrder[] memory) { AdvancedOrder[] memory arr = new AdvancedOrder[](1); arr[0] = a; return arr; } function AdvancedOrders( AdvancedOrder memory a, AdvancedOrder memory b ) internal pure returns (AdvancedOrder[] memory) { AdvancedOrder[] memory arr = new AdvancedOrder[](2); arr[0] = a; arr[1] = b; return arr; } function AdvancedOrders( AdvancedOrder memory a, AdvancedOrder memory b, AdvancedOrder memory c ) internal pure returns (AdvancedOrder[] memory) { AdvancedOrder[] memory arr = new AdvancedOrder[](3); arr[0] = a; arr[1] = b; arr[2] = c; return arr; } function AdvancedOrders( AdvancedOrder memory a, AdvancedOrder memory b, AdvancedOrder memory c, AdvancedOrder memory d ) internal pure returns (AdvancedOrder[] memory) { AdvancedOrder[] memory arr = new AdvancedOrder[](4); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; return arr; } function AdvancedOrders( AdvancedOrder memory a, AdvancedOrder memory b, AdvancedOrder memory c, AdvancedOrder memory d, AdvancedOrder memory e ) internal pure returns (AdvancedOrder[] memory) { AdvancedOrder[] memory arr = new AdvancedOrder[](5); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; return arr; } function AdvancedOrders( AdvancedOrder memory a, AdvancedOrder memory b, AdvancedOrder memory c, AdvancedOrder memory d, AdvancedOrder memory e, AdvancedOrder memory f ) internal pure returns (AdvancedOrder[] memory) { AdvancedOrder[] memory arr = new AdvancedOrder[](6); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; return arr; } function AdvancedOrders( AdvancedOrder memory a, AdvancedOrder memory b, AdvancedOrder memory c, AdvancedOrder memory d, AdvancedOrder memory e, AdvancedOrder memory f, AdvancedOrder memory g ) internal pure returns (AdvancedOrder[] memory) { AdvancedOrder[] memory arr = new AdvancedOrder[](7); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; arr[6] = g; return arr; } function OrderComponentsArray( OrderComponents memory a ) internal pure returns (OrderComponents[] memory) { OrderComponents[] memory arr = new OrderComponents[](1); arr[0] = a; return arr; } function OrderComponentsArray( OrderComponents memory a, OrderComponents memory b ) internal pure returns (OrderComponents[] memory) { OrderComponents[] memory arr = new OrderComponents[](2); arr[0] = a; arr[1] = b; return arr; } function OrderComponentsArray( OrderComponents memory a, OrderComponents memory b, OrderComponents memory c ) internal pure returns (OrderComponents[] memory) { OrderComponents[] memory arr = new OrderComponents[](3); arr[0] = a; arr[1] = b; arr[2] = c; return arr; } function OrderComponentsArray( OrderComponents memory a, OrderComponents memory b, OrderComponents memory c, OrderComponents memory d ) internal pure returns (OrderComponents[] memory) { OrderComponents[] memory arr = new OrderComponents[](4); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; return arr; } function OrderComponentsArray( OrderComponents memory a, OrderComponents memory b, OrderComponents memory c, OrderComponents memory d, OrderComponents memory e ) internal pure returns (OrderComponents[] memory) { OrderComponents[] memory arr = new OrderComponents[](5); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; return arr; } function OrderComponentsArray( OrderComponents memory a, OrderComponents memory b, OrderComponents memory c, OrderComponents memory d, OrderComponents memory e, OrderComponents memory f ) internal pure returns (OrderComponents[] memory) { OrderComponents[] memory arr = new OrderComponents[](6); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; return arr; } function OrderComponentsArray( OrderComponents memory a, OrderComponents memory b, OrderComponents memory c, OrderComponents memory d, OrderComponents memory e, OrderComponents memory f, OrderComponents memory g ) internal pure returns (OrderComponents[] memory) { OrderComponents[] memory arr = new OrderComponents[](7); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; arr[6] = g; return arr; } function OrderParametersArray( OrderParameters memory a ) internal pure returns (OrderParameters[] memory) { OrderParameters[] memory arr = new OrderParameters[](1); arr[0] = a; return arr; } function OrderParametersArray( OrderParameters memory a, OrderParameters memory b ) internal pure returns (OrderParameters[] memory) { OrderParameters[] memory arr = new OrderParameters[](2); arr[0] = a; arr[1] = b; return arr; } function OrderParametersArray( OrderParameters memory a, OrderParameters memory b, OrderParameters memory c ) internal pure returns (OrderParameters[] memory) { OrderParameters[] memory arr = new OrderParameters[](3); arr[0] = a; arr[1] = b; arr[2] = c; return arr; } function OrderParametersArray( OrderParameters memory a, OrderParameters memory b, OrderParameters memory c, OrderParameters memory d ) internal pure returns (OrderParameters[] memory) { OrderParameters[] memory arr = new OrderParameters[](4); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; return arr; } function OrderParametersArray( OrderParameters memory a, OrderParameters memory b, OrderParameters memory c, OrderParameters memory d, OrderParameters memory e ) internal pure returns (OrderParameters[] memory) { OrderParameters[] memory arr = new OrderParameters[](5); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; return arr; } function OrderParametersArray( OrderParameters memory a, OrderParameters memory b, OrderParameters memory c, OrderParameters memory d, OrderParameters memory e, OrderParameters memory f ) internal pure returns (OrderParameters[] memory) { OrderParameters[] memory arr = new OrderParameters[](6); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; return arr; } function OrderParametersArray( OrderParameters memory a, OrderParameters memory b, OrderParameters memory c, OrderParameters memory d, OrderParameters memory e, OrderParameters memory f, OrderParameters memory g ) internal pure returns (OrderParameters[] memory) { OrderParameters[] memory arr = new OrderParameters[](7); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; arr[6] = g; return arr; } function OfferItems( OfferItem memory a ) internal pure returns (OfferItem[] memory) { OfferItem[] memory arr = new OfferItem[](1); arr[0] = a; return arr; } function OfferItems( OfferItem memory a, OfferItem memory b ) internal pure returns (OfferItem[] memory) { OfferItem[] memory arr = new OfferItem[](2); arr[0] = a; arr[1] = b; return arr; } function OfferItems( OfferItem memory a, OfferItem memory b, OfferItem memory c ) internal pure returns (OfferItem[] memory) { OfferItem[] memory arr = new OfferItem[](3); arr[0] = a; arr[1] = b; arr[2] = c; return arr; } function OfferItems( OfferItem memory a, OfferItem memory b, OfferItem memory c, OfferItem memory d ) internal pure returns (OfferItem[] memory) { OfferItem[] memory arr = new OfferItem[](4); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; return arr; } function OfferItems( OfferItem memory a, OfferItem memory b, OfferItem memory c, OfferItem memory d, OfferItem memory e ) internal pure returns (OfferItem[] memory) { OfferItem[] memory arr = new OfferItem[](5); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; return arr; } function OfferItems( OfferItem memory a, OfferItem memory b, OfferItem memory c, OfferItem memory d, OfferItem memory e, OfferItem memory f ) internal pure returns (OfferItem[] memory) { OfferItem[] memory arr = new OfferItem[](6); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; return arr; } function OfferItems( OfferItem memory a, OfferItem memory b, OfferItem memory c, OfferItem memory d, OfferItem memory e, OfferItem memory f, OfferItem memory g ) internal pure returns (OfferItem[] memory) { OfferItem[] memory arr = new OfferItem[](7); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; arr[6] = g; return arr; } function ConsiderationItems( ConsiderationItem memory a ) internal pure returns (ConsiderationItem[] memory) { ConsiderationItem[] memory arr = new ConsiderationItem[](1); arr[0] = a; return arr; } function ConsiderationItems( ConsiderationItem memory a, ConsiderationItem memory b ) internal pure returns (ConsiderationItem[] memory) { ConsiderationItem[] memory arr = new ConsiderationItem[](2); arr[0] = a; arr[1] = b; return arr; } function ConsiderationItems( ConsiderationItem memory a, ConsiderationItem memory b, ConsiderationItem memory c ) internal pure returns (ConsiderationItem[] memory) { ConsiderationItem[] memory arr = new ConsiderationItem[](3); arr[0] = a; arr[1] = b; arr[2] = c; return arr; } function ConsiderationItems( ConsiderationItem memory a, ConsiderationItem memory b, ConsiderationItem memory c, ConsiderationItem memory d ) internal pure returns (ConsiderationItem[] memory) { ConsiderationItem[] memory arr = new ConsiderationItem[](4); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; return arr; } function ConsiderationItems( ConsiderationItem memory a, ConsiderationItem memory b, ConsiderationItem memory c, ConsiderationItem memory d, ConsiderationItem memory e ) internal pure returns (ConsiderationItem[] memory) { ConsiderationItem[] memory arr = new ConsiderationItem[](5); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; return arr; } function ConsiderationItems( ConsiderationItem memory a, ConsiderationItem memory b, ConsiderationItem memory c, ConsiderationItem memory d, ConsiderationItem memory e, ConsiderationItem memory f ) internal pure returns (ConsiderationItem[] memory) { ConsiderationItem[] memory arr = new ConsiderationItem[](6); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; return arr; } function ConsiderationItems( ConsiderationItem memory a, ConsiderationItem memory b, ConsiderationItem memory c, ConsiderationItem memory d, ConsiderationItem memory e, ConsiderationItem memory f, ConsiderationItem memory g ) internal pure returns (ConsiderationItem[] memory) { ConsiderationItem[] memory arr = new ConsiderationItem[](7); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; arr[6] = g; return arr; } function SpentItems( SpentItem memory a ) internal pure returns (SpentItem[] memory) { SpentItem[] memory arr = new SpentItem[](1); arr[0] = a; return arr; } function SpentItems( SpentItem memory a, SpentItem memory b ) internal pure returns (SpentItem[] memory) { SpentItem[] memory arr = new SpentItem[](2); arr[0] = a; arr[1] = b; return arr; } function SpentItems( SpentItem memory a, SpentItem memory b, SpentItem memory c ) internal pure returns (SpentItem[] memory) { SpentItem[] memory arr = new SpentItem[](3); arr[0] = a; arr[1] = b; arr[2] = c; return arr; } function SpentItems( SpentItem memory a, SpentItem memory b, SpentItem memory c, SpentItem memory d ) internal pure returns (SpentItem[] memory) { SpentItem[] memory arr = new SpentItem[](4); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; return arr; } function SpentItems( SpentItem memory a, SpentItem memory b, SpentItem memory c, SpentItem memory d, SpentItem memory e ) internal pure returns (SpentItem[] memory) { SpentItem[] memory arr = new SpentItem[](5); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; return arr; } function SpentItems( SpentItem memory a, SpentItem memory b, SpentItem memory c, SpentItem memory d, SpentItem memory e, SpentItem memory f ) internal pure returns (SpentItem[] memory) { SpentItem[] memory arr = new SpentItem[](6); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; return arr; } function SpentItems( SpentItem memory a, SpentItem memory b, SpentItem memory c, SpentItem memory d, SpentItem memory e, SpentItem memory f, SpentItem memory g ) internal pure returns (SpentItem[] memory) { SpentItem[] memory arr = new SpentItem[](7); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; arr[6] = g; return arr; } function ReceivedItems( ReceivedItem memory a ) internal pure returns (ReceivedItem[] memory) { ReceivedItem[] memory arr = new ReceivedItem[](1); arr[0] = a; return arr; } function ReceivedItems( ReceivedItem memory a, ReceivedItem memory b ) internal pure returns (ReceivedItem[] memory) { ReceivedItem[] memory arr = new ReceivedItem[](2); arr[0] = a; arr[1] = b; return arr; } function ReceivedItems( ReceivedItem memory a, ReceivedItem memory b, ReceivedItem memory c ) internal pure returns (ReceivedItem[] memory) { ReceivedItem[] memory arr = new ReceivedItem[](3); arr[0] = a; arr[1] = b; arr[2] = c; return arr; } function ReceivedItems( ReceivedItem memory a, ReceivedItem memory b, ReceivedItem memory c, ReceivedItem memory d ) internal pure returns (ReceivedItem[] memory) { ReceivedItem[] memory arr = new ReceivedItem[](4); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; return arr; } function ReceivedItems( ReceivedItem memory a, ReceivedItem memory b, ReceivedItem memory c, ReceivedItem memory d, ReceivedItem memory e ) internal pure returns (ReceivedItem[] memory) { ReceivedItem[] memory arr = new ReceivedItem[](5); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; return arr; } function ReceivedItems( ReceivedItem memory a, ReceivedItem memory b, ReceivedItem memory c, ReceivedItem memory d, ReceivedItem memory e, ReceivedItem memory f ) internal pure returns (ReceivedItem[] memory) { ReceivedItem[] memory arr = new ReceivedItem[](6); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; return arr; } function ReceivedItems( ReceivedItem memory a, ReceivedItem memory b, ReceivedItem memory c, ReceivedItem memory d, ReceivedItem memory e, ReceivedItem memory f, ReceivedItem memory g ) internal pure returns (ReceivedItem[] memory) { ReceivedItem[] memory arr = new ReceivedItem[](7); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; arr[6] = g; return arr; } function FulfillmentComponents( FulfillmentComponent memory a ) internal pure returns (FulfillmentComponent[] memory) { FulfillmentComponent[] memory arr = new FulfillmentComponent[](1); arr[0] = a; return arr; } function FulfillmentComponents( FulfillmentComponent memory a, FulfillmentComponent memory b ) internal pure returns (FulfillmentComponent[] memory) { FulfillmentComponent[] memory arr = new FulfillmentComponent[](2); arr[0] = a; arr[1] = b; return arr; } function FulfillmentComponents( FulfillmentComponent memory a, FulfillmentComponent memory b, FulfillmentComponent memory c ) internal pure returns (FulfillmentComponent[] memory) { FulfillmentComponent[] memory arr = new FulfillmentComponent[](3); arr[0] = a; arr[1] = b; arr[2] = c; return arr; } function FulfillmentComponents( FulfillmentComponent memory a, FulfillmentComponent memory b, FulfillmentComponent memory c, FulfillmentComponent memory d ) internal pure returns (FulfillmentComponent[] memory) { FulfillmentComponent[] memory arr = new FulfillmentComponent[](4); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; return arr; } function FulfillmentComponents( FulfillmentComponent memory a, FulfillmentComponent memory b, FulfillmentComponent memory c, FulfillmentComponent memory d, FulfillmentComponent memory e ) internal pure returns (FulfillmentComponent[] memory) { FulfillmentComponent[] memory arr = new FulfillmentComponent[](5); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; return arr; } function FulfillmentComponents( FulfillmentComponent memory a, FulfillmentComponent memory b, FulfillmentComponent memory c, FulfillmentComponent memory d, FulfillmentComponent memory e, FulfillmentComponent memory f ) internal pure returns (FulfillmentComponent[] memory) { FulfillmentComponent[] memory arr = new FulfillmentComponent[](6); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; return arr; } function FulfillmentComponents( FulfillmentComponent memory a, FulfillmentComponent memory b, FulfillmentComponent memory c, FulfillmentComponent memory d, FulfillmentComponent memory e, FulfillmentComponent memory f, FulfillmentComponent memory g ) internal pure returns (FulfillmentComponent[] memory) { FulfillmentComponent[] memory arr = new FulfillmentComponent[](7); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; arr[6] = g; return arr; } function FulfillmentComponentArrays( FulfillmentComponent[] memory a ) internal pure returns (FulfillmentComponent[][] memory) { FulfillmentComponent[][] memory arr = new FulfillmentComponent[][](1); arr[0] = a; return arr; } function FulfillmentComponentArrays( FulfillmentComponent[] memory a, FulfillmentComponent[] memory b ) internal pure returns (FulfillmentComponent[][] memory) { FulfillmentComponent[][] memory arr = new FulfillmentComponent[][](2); arr[0] = a; arr[1] = b; return arr; } function FulfillmentComponentArrays( FulfillmentComponent[] memory a, FulfillmentComponent[] memory b, FulfillmentComponent[] memory c ) internal pure returns (FulfillmentComponent[][] memory) { FulfillmentComponent[][] memory arr = new FulfillmentComponent[][](3); arr[0] = a; arr[1] = b; arr[2] = c; return arr; } function FulfillmentComponentArrays( FulfillmentComponent[] memory a, FulfillmentComponent[] memory b, FulfillmentComponent[] memory c, FulfillmentComponent[] memory d ) internal pure returns (FulfillmentComponent[][] memory) { FulfillmentComponent[][] memory arr = new FulfillmentComponent[][](4); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; return arr; } function FulfillmentComponentArrays( FulfillmentComponent[] memory a, FulfillmentComponent[] memory b, FulfillmentComponent[] memory c, FulfillmentComponent[] memory d, FulfillmentComponent[] memory e ) internal pure returns (FulfillmentComponent[][] memory) { FulfillmentComponent[][] memory arr = new FulfillmentComponent[][](5); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; return arr; } function FulfillmentComponentArrays( FulfillmentComponent[] memory a, FulfillmentComponent[] memory b, FulfillmentComponent[] memory c, FulfillmentComponent[] memory d, FulfillmentComponent[] memory e, FulfillmentComponent[] memory f ) internal pure returns (FulfillmentComponent[][] memory) { FulfillmentComponent[][] memory arr = new FulfillmentComponent[][](6); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; return arr; } function FulfillmentComponentArrays( FulfillmentComponent[] memory a, FulfillmentComponent[] memory b, FulfillmentComponent[] memory c, FulfillmentComponent[] memory d, FulfillmentComponent[] memory e, FulfillmentComponent[] memory f, FulfillmentComponent[] memory g ) internal pure returns (FulfillmentComponent[][] memory) { FulfillmentComponent[][] memory arr = new FulfillmentComponent[][](7); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; arr[6] = g; return arr; } function CriteriaResolvers( CriteriaResolver memory a ) internal pure returns (CriteriaResolver[] memory) { CriteriaResolver[] memory arr = new CriteriaResolver[](1); arr[0] = a; return arr; } function CriteriaResolvers( CriteriaResolver memory a, CriteriaResolver memory b ) internal pure returns (CriteriaResolver[] memory) { CriteriaResolver[] memory arr = new CriteriaResolver[](2); arr[0] = a; arr[1] = b; return arr; } function CriteriaResolvers( CriteriaResolver memory a, CriteriaResolver memory b, CriteriaResolver memory c ) internal pure returns (CriteriaResolver[] memory) { CriteriaResolver[] memory arr = new CriteriaResolver[](3); arr[0] = a; arr[1] = b; arr[2] = c; return arr; } function CriteriaResolvers( CriteriaResolver memory a, CriteriaResolver memory b, CriteriaResolver memory c, CriteriaResolver memory d ) internal pure returns (CriteriaResolver[] memory) { CriteriaResolver[] memory arr = new CriteriaResolver[](4); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; return arr; } function CriteriaResolvers( CriteriaResolver memory a, CriteriaResolver memory b, CriteriaResolver memory c, CriteriaResolver memory d, CriteriaResolver memory e ) internal pure returns (CriteriaResolver[] memory) { CriteriaResolver[] memory arr = new CriteriaResolver[](5); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; return arr; } function CriteriaResolvers( CriteriaResolver memory a, CriteriaResolver memory b, CriteriaResolver memory c, CriteriaResolver memory d, CriteriaResolver memory e, CriteriaResolver memory f ) internal pure returns (CriteriaResolver[] memory) { CriteriaResolver[] memory arr = new CriteriaResolver[](6); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; return arr; } function CriteriaResolvers( CriteriaResolver memory a, CriteriaResolver memory b, CriteriaResolver memory c, CriteriaResolver memory d, CriteriaResolver memory e, CriteriaResolver memory f, CriteriaResolver memory g ) internal pure returns (CriteriaResolver[] memory) { CriteriaResolver[] memory arr = new CriteriaResolver[](7); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; arr[6] = g; return arr; } function AdditionalRecipients( AdditionalRecipient memory a ) internal pure returns (AdditionalRecipient[] memory) { AdditionalRecipient[] memory arr = new AdditionalRecipient[](1); arr[0] = a; return arr; } function AdditionalRecipients( AdditionalRecipient memory a, AdditionalRecipient memory b ) internal pure returns (AdditionalRecipient[] memory) { AdditionalRecipient[] memory arr = new AdditionalRecipient[](2); arr[0] = a; arr[1] = b; return arr; } function AdditionalRecipients( AdditionalRecipient memory a, AdditionalRecipient memory b, AdditionalRecipient memory c ) internal pure returns (AdditionalRecipient[] memory) { AdditionalRecipient[] memory arr = new AdditionalRecipient[](3); arr[0] = a; arr[1] = b; arr[2] = c; return arr; } function AdditionalRecipients( AdditionalRecipient memory a, AdditionalRecipient memory b, AdditionalRecipient memory c, AdditionalRecipient memory d ) internal pure returns (AdditionalRecipient[] memory) { AdditionalRecipient[] memory arr = new AdditionalRecipient[](4); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; return arr; } function AdditionalRecipients( AdditionalRecipient memory a, AdditionalRecipient memory b, AdditionalRecipient memory c, AdditionalRecipient memory d, AdditionalRecipient memory e ) internal pure returns (AdditionalRecipient[] memory) { AdditionalRecipient[] memory arr = new AdditionalRecipient[](5); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; return arr; } function AdditionalRecipients( AdditionalRecipient memory a, AdditionalRecipient memory b, AdditionalRecipient memory c, AdditionalRecipient memory d, AdditionalRecipient memory e, AdditionalRecipient memory f ) internal pure returns (AdditionalRecipient[] memory) { AdditionalRecipient[] memory arr = new AdditionalRecipient[](6); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; return arr; } function AdditionalRecipients( AdditionalRecipient memory a, AdditionalRecipient memory b, AdditionalRecipient memory c, AdditionalRecipient memory d, AdditionalRecipient memory e, AdditionalRecipient memory f, AdditionalRecipient memory g ) internal pure returns (AdditionalRecipient[] memory) { AdditionalRecipient[] memory arr = new AdditionalRecipient[](7); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; arr[6] = g; return arr; } function BasicOrderParametersArray( BasicOrderParameters memory a ) internal pure returns (BasicOrderParameters[] memory) { BasicOrderParameters[] memory arr = new BasicOrderParameters[](1); arr[0] = a; return arr; } function BasicOrderParametersArray( BasicOrderParameters memory a, BasicOrderParameters memory b ) internal pure returns (BasicOrderParameters[] memory) { BasicOrderParameters[] memory arr = new BasicOrderParameters[](2); arr[0] = a; arr[1] = b; return arr; } function BasicOrderParametersArray( BasicOrderParameters memory a, BasicOrderParameters memory b, BasicOrderParameters memory c ) internal pure returns (BasicOrderParameters[] memory) { BasicOrderParameters[] memory arr = new BasicOrderParameters[](3); arr[0] = a; arr[1] = b; arr[2] = c; return arr; } function BasicOrderParametersArray( BasicOrderParameters memory a, BasicOrderParameters memory b, BasicOrderParameters memory c, BasicOrderParameters memory d ) internal pure returns (BasicOrderParameters[] memory) { BasicOrderParameters[] memory arr = new BasicOrderParameters[](4); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; return arr; } function BasicOrderParametersArray( BasicOrderParameters memory a, BasicOrderParameters memory b, BasicOrderParameters memory c, BasicOrderParameters memory d, BasicOrderParameters memory e ) internal pure returns (BasicOrderParameters[] memory) { BasicOrderParameters[] memory arr = new BasicOrderParameters[](5); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; return arr; } function BasicOrderParametersArray( BasicOrderParameters memory a, BasicOrderParameters memory b, BasicOrderParameters memory c, BasicOrderParameters memory d, BasicOrderParameters memory e, BasicOrderParameters memory f ) internal pure returns (BasicOrderParameters[] memory) { BasicOrderParameters[] memory arr = new BasicOrderParameters[](6); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; return arr; } function BasicOrderParametersArray( BasicOrderParameters memory a, BasicOrderParameters memory b, BasicOrderParameters memory c, BasicOrderParameters memory d, BasicOrderParameters memory e, BasicOrderParameters memory f, BasicOrderParameters memory g ) internal pure returns (BasicOrderParameters[] memory) { BasicOrderParameters[] memory arr = new BasicOrderParameters[](7); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; arr[6] = g; return arr; } function Fulfillments( Fulfillment memory a ) internal pure returns (Fulfillment[] memory) { Fulfillment[] memory arr = new Fulfillment[](1); arr[0] = a; return arr; } function Fulfillments( Fulfillment memory a, Fulfillment memory b ) internal pure returns (Fulfillment[] memory) { Fulfillment[] memory arr = new Fulfillment[](2); arr[0] = a; arr[1] = b; return arr; } function Fulfillments( Fulfillment memory a, Fulfillment memory b, Fulfillment memory c ) internal pure returns (Fulfillment[] memory) { Fulfillment[] memory arr = new Fulfillment[](3); arr[0] = a; arr[1] = b; arr[2] = c; return arr; } function Fulfillments( Fulfillment memory a, Fulfillment memory b, Fulfillment memory c, Fulfillment memory d ) internal pure returns (Fulfillment[] memory) { Fulfillment[] memory arr = new Fulfillment[](4); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; return arr; } function Fulfillments( Fulfillment memory a, Fulfillment memory b, Fulfillment memory c, Fulfillment memory d, Fulfillment memory e ) internal pure returns (Fulfillment[] memory) { Fulfillment[] memory arr = new Fulfillment[](5); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; return arr; } function Fulfillments( Fulfillment memory a, Fulfillment memory b, Fulfillment memory c, Fulfillment memory d, Fulfillment memory e, Fulfillment memory f ) internal pure returns (Fulfillment[] memory) { Fulfillment[] memory arr = new Fulfillment[](6); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; return arr; } function Fulfillments( Fulfillment memory a, Fulfillment memory b, Fulfillment memory c, Fulfillment memory d, Fulfillment memory e, Fulfillment memory f, Fulfillment memory g ) internal pure returns (Fulfillment[] memory) { Fulfillment[] memory arr = new Fulfillment[](7); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; arr[4] = e; arr[5] = f; arr[6] = g; return arr; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { BasicOrderParameters, OrderParameters } from "../../../lib/ConsiderationStructs.sol"; import { OrderType, BasicOrderType, ItemType, BasicOrderRouteType } from "../../../lib/ConsiderationEnums.sol"; library SeaportEnumsLib { function parseBasicOrderType( BasicOrderType basicOrderType ) internal pure returns ( OrderType orderType, ItemType offerType, ItemType considerationType, ItemType additionalRecipientsType, bool offerTypeIsAdditionalRecipientsType ) { assembly { // Mask all but 2 least-significant bits to derive the order type. orderType := and(basicOrderType, 3) // Divide basicOrderType by four to derive the route. let route := shr(2, basicOrderType) offerTypeIsAdditionalRecipientsType := gt(route, 3) // If route > 1 additionalRecipient items are ERC20 (1) else Eth (0) additionalRecipientsType := gt(route, 1) // If route > 2, receivedItemType is route - 2. If route is 2, // the receivedItemType is ERC20 (1). Otherwise, it is Eth (0). considerationType := add( mul(sub(route, 2), gt(route, 2)), eq(route, 2) ) // If route > 3, offeredItemType is ERC20 (1). Route is 2 or 3, // offeredItemType = route. Route is 0 or 1, it is route + 2. offerType := add(route, mul(iszero(additionalRecipientsType), 2)) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { SeaportRouterInterface } from "../interfaces/SeaportRouterInterface.sol"; import { SeaportInterface } from "../interfaces/SeaportInterface.sol"; import { ReentrancyGuard } from "../lib/ReentrancyGuard.sol"; import { Execution, AdvancedOrder, CriteriaResolver, FulfillmentComponent } from "../lib/ConsiderationStructs.sol"; /** * @title SeaportRouter * @author Ryan Ghods (ralxz.eth), 0age (0age.eth), James Wenzel (emo.eth) * @notice A utility contract for fulfilling orders with multiple * Seaport versions. DISCLAIMER: This contract only works when * all consideration items across all listings are native tokens. */ contract SeaportRouter is SeaportRouterInterface, ReentrancyGuard { /// @dev The allowed v1.1 contract usable through this router. address private immutable _SEAPORT_V1_1; /// @dev The allowed v1.2 contract usable through this router. address private immutable _SEAPORT_V1_2; /** * @dev Deploy contract with the supported Seaport contracts. * * @param seaportV1point1 The address of the Seaport v1.1 contract. * @param seaportV1point2 The address of the Seaport v1.2 contract. */ constructor(address seaportV1point1, address seaportV1point2) { _SEAPORT_V1_1 = seaportV1point1; _SEAPORT_V1_2 = seaportV1point2; } /** * @dev Fallback function to receive excess ether, in case total amount of * ether sent is more than the amount required to fulfill the order. */ receive() external payable override { // Ensure we only receive ether from Seaport. _assertSeaportAllowed(msg.sender); } /** * @notice Fulfill available advanced orders through multiple Seaport * versions. * See {SeaportInterface-fulfillAvailableAdvancedOrders} * * @param params The parameters for fulfilling available advanced orders. */ function fulfillAvailableAdvancedOrders( FulfillAvailableAdvancedOrdersParams calldata params ) external payable override returns ( bool[][] memory availableOrders, Execution[][] memory executions ) { // Ensure this function cannot be triggered during a reentrant call. _setReentrancyGuard(true); // Put the number of Seaport contracts on the stack. uint256 seaportContractsLength = params.seaportContracts.length; // Set the availableOrders and executions arrays to the correct length. availableOrders = new bool[][](seaportContractsLength); executions = new Execution[][](seaportContractsLength); // Track the number of order fulfillments left. uint256 fulfillmentsLeft = params.maximumFulfilled; // To help avoid stack too deep errors, we format the calldata // params in a struct and put it on the stack. AdvancedOrder[] memory emptyAdvancedOrders; CriteriaResolver[] memory emptyCriteriaResolvers; FulfillmentComponent[][] memory emptyFulfillmentComponents; CalldataParams memory calldataParams = CalldataParams({ advancedOrders: emptyAdvancedOrders, criteriaResolvers: emptyCriteriaResolvers, offerFulfillments: emptyFulfillmentComponents, considerationFulfillments: emptyFulfillmentComponents, fulfillerConduitKey: params.fulfillerConduitKey, recipient: params.recipient, maximumFulfilled: fulfillmentsLeft }); // Iterate through the provided Seaport contracts. for (uint256 i = 0; i < params.seaportContracts.length; ) { // Ensure the provided Seaport contract is allowed. _assertSeaportAllowed(params.seaportContracts[i]); // Put the order params on the stack. AdvancedOrderParams calldata orderParams = params .advancedOrderParams[i]; // Assign the variables to the calldata params. calldataParams.advancedOrders = orderParams.advancedOrders; calldataParams.criteriaResolvers = orderParams.criteriaResolvers; calldataParams.offerFulfillments = orderParams.offerFulfillments; calldataParams.considerationFulfillments = orderParams .considerationFulfillments; // Execute the orders, collecting availableOrders and executions. // This is wrapped in a try/catch in case a single order is // executed that is no longer available, leading to a revert // with `NoSpecifiedOrdersAvailable()`. try SeaportInterface(params.seaportContracts[i]) .fulfillAvailableAdvancedOrders{ value: orderParams.etherValue }( calldataParams.advancedOrders, calldataParams.criteriaResolvers, calldataParams.offerFulfillments, calldataParams.considerationFulfillments, calldataParams.fulfillerConduitKey, calldataParams.recipient, calldataParams.maximumFulfilled ) returns ( bool[] memory newAvailableOrders, Execution[] memory newExecutions ) { availableOrders[i] = newAvailableOrders; executions[i] = newExecutions; // Subtract the number of orders fulfilled. uint256 newAvailableOrdersLength = newAvailableOrders.length; for (uint256 j = 0; j < newAvailableOrdersLength; ) { if (newAvailableOrders[j]) { unchecked { --fulfillmentsLeft; ++j; } } } // Break if the maximum number of executions has been reached. if (fulfillmentsLeft == 0) { break; } } catch {} // Update fulfillments left. calldataParams.maximumFulfilled = fulfillmentsLeft; unchecked { ++i; } } // Return excess ether that may not have been used or was sent back. if (address(this).balance > 0) { _returnExcessEther(); } // Clear the reentrancy guard. _clearReentrancyGuard(); } /** * @notice Returns the Seaport contracts allowed to be used through this * router. */ function getAllowedSeaportContracts() external view override returns (address[] memory seaportContracts) { seaportContracts = new address[](2); seaportContracts[0] = _SEAPORT_V1_1; seaportContracts[1] = _SEAPORT_V1_2; } /** * @dev Reverts if the provided Seaport contract is not allowed. */ function _assertSeaportAllowed(address seaport) internal view { if ( _cast(seaport == _SEAPORT_V1_1) | _cast(seaport == _SEAPORT_V1_2) == 0 ) { revert SeaportNotAllowed(seaport); } } /** * @dev Function to return excess ether, in case total amount of * ether sent is more than the amount required to fulfill the order. */ function _returnExcessEther() private { // Send received funds back to msg.sender. (bool success, bytes memory data) = payable(msg.sender).call{ value: address(this).balance }(""); // Revert with an error if the ether transfer failed. if (!success) { revert EtherReturnTransferFailed( msg.sender, address(this).balance, data ); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { AdvancedOrder, CriteriaResolver, FulfillmentComponent } from "../lib/ConsiderationStructs.sol"; import { Execution } from "../lib/ConsiderationStructs.sol"; /** * @title SeaportRouterInterface * @author Ryan Ghods (ralxz.eth), 0age (0age.eth), James Wenzel (emo.eth) * @notice A utility contract for fulfilling orders with multiple * Seaport versions. DISCLAIMER: This contract only works when * all consideration items across all listings are native tokens. */ interface SeaportRouterInterface { /** * @dev Advanced order parameters for use through the * FulfillAvailableAdvancedOrdersParams struct. */ struct AdvancedOrderParams { AdvancedOrder[] advancedOrders; CriteriaResolver[] criteriaResolvers; FulfillmentComponent[][] offerFulfillments; FulfillmentComponent[][] considerationFulfillments; uint256 etherValue; /// The ether value to send with the set of orders. } /** * @dev Parameters for using fulfillAvailableAdvancedOrders * through SeaportRouter. */ struct FulfillAvailableAdvancedOrdersParams { address[] seaportContracts; AdvancedOrderParams[] advancedOrderParams; bytes32 fulfillerConduitKey; address recipient; uint256 maximumFulfilled; } /** * @dev Calldata params for calling FulfillAvailableAdvancedOrders. */ struct CalldataParams { AdvancedOrder[] advancedOrders; CriteriaResolver[] criteriaResolvers; FulfillmentComponent[][] offerFulfillments; FulfillmentComponent[][] considerationFulfillments; bytes32 fulfillerConduitKey; address recipient; uint256 maximumFulfilled; } /** * @dev Revert with an error if a provided Seaport contract is not allowed * to be used in the router. */ error SeaportNotAllowed(address seaport); /** * @dev Revert with an error if an ether transfer back to the fulfiller * fails. */ error EtherReturnTransferFailed( address recipient, uint256 amount, bytes returnData ); /** * @dev Fallback function to receive excess ether, in case total amount of * ether sent is more than the amount required to fulfill the order. */ receive() external payable; /** * @notice Fulfill available advanced orders through multiple Seaport * versions. * See {SeaportInterface-fulfillAvailableAdvancedOrders} * * @param params The parameters for fulfilling available advanced orders. */ function fulfillAvailableAdvancedOrders( FulfillAvailableAdvancedOrdersParams calldata params ) external payable returns ( bool[][] memory availableOrders, Execution[][] memory executions ); /** * @notice Returns the Seaport contracts allowed to be used through this * router. */ function getAllowedSeaportContracts() external view returns (address[] memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import { AdvancedOrder, CriteriaResolver } from "../../lib/ConsiderationStructs.sol"; /** * @title ZoneInterface1.1 * @author 0age * @custom:version 1.1 * * @dev This is the legacy ZoneInterface from Seaport 1.1 */ interface ZoneInterface1_1 { // Called by Consideration whenever extraData is not provided by the caller. function isValidOrder( bytes32 orderHash, address caller, address offerer, bytes32 zoneHash ) external view returns (bytes4 validOrderMagicValue); // Called by Consideration whenever any extraData is provided by the caller. function isValidOrderIncludingExtraData( bytes32 orderHash, address caller, AdvancedOrder calldata order, bytes32[] calldata priorOrderHashes, CriteriaResolver[] calldata criteriaResolvers ) external view returns (bytes4 validOrderMagicValue); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import { BasicOrderParameters, OrderComponents, Fulfillment, FulfillmentComponent, Execution, Order, AdvancedOrder, OrderStatus, CriteriaResolver } from "../../lib/ConsiderationStructs.sol"; /** * @title ConsiderationInterface1.1 * @author 0age * @custom:version 1.1 * * * @dev This is the legacy ConsiderationInterface from Seaport 1.1 */ interface ConsiderationInterface1_1 { /** * @notice Fulfill an order offering an ERC721 token by supplying Ether (or * the native token for the given chain) as consideration for the * order. An arbitrary number of "additional recipients" may also be * supplied which will each receive native tokens from the fulfiller * as consideration. * * @param parameters Additional information on the fulfilled order. Note * that the offerer must first approve this contract (or * their preferred conduit if indicated by the order) for * their offered ERC721 token to be transferred. * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillBasicOrder( BasicOrderParameters calldata parameters ) external payable returns (bool fulfilled); /** * @notice Fulfill an order with an arbitrary number of items for offer and * consideration. Note that this function does not support * criteria-based orders or partial filling of orders (though * filling the remainder of a partially-filled order is supported). * * @param order The order to fulfill. Note that both the * offerer and the fulfiller must first approve * this contract (or the corresponding conduit if * indicated) to transfer any relevant tokens on * their behalf and that contracts must implement * `onERC1155Received` to receive ERC1155 tokens * as consideration. * @param fulfillerConduitKey A bytes32 value indicating what conduit, if * any, to source the fulfiller's token approvals * from. The zero hash signifies that no conduit * should be used, with direct approvals set on * Consideration. * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillOrder( Order calldata order, bytes32 fulfillerConduitKey ) external payable returns (bool fulfilled); /** * @notice Fill an order, fully or partially, with an arbitrary number of * items for offer and consideration alongside criteria resolvers * containing specific token identifiers and associated proofs. * * @param advancedOrder The order to fulfill along with the fraction * of the order to attempt to fill. Note that * both the offerer and the fulfiller must first * approve this contract (or their preferred * conduit if indicated by the order) to transfer * any relevant tokens on their behalf and that * contracts must implement `onERC1155Received` * to receive ERC1155 tokens as consideration. * Also note that all offer and consideration * components must have no remainder after * multiplication of the respective amount with * the supplied fraction for the partial fill to * be considered valid. * @param criteriaResolvers An array where each element contains a * reference to a specific offer or * consideration, a token identifier, and a proof * that the supplied token identifier is * contained in the merkle root held by the item * in question's criteria element. Note that an * empty criteria indicates that any * (transferable) token identifier on the token * in question is valid and that no associated * proof needs to be supplied. * @param fulfillerConduitKey A bytes32 value indicating what conduit, if * any, to source the fulfiller's token approvals * from. The zero hash signifies that no conduit * should be used, with direct approvals set on * Consideration. * @param recipient The intended recipient for all received items, * with `address(0)` indicating that the caller * should receive the items. * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillAdvancedOrder( AdvancedOrder calldata advancedOrder, CriteriaResolver[] calldata criteriaResolvers, bytes32 fulfillerConduitKey, address recipient ) external payable returns (bool fulfilled); /** * @notice Attempt to fill a group of orders, each with an arbitrary number * of items for offer and consideration. Any order that is not * currently active, has already been fully filled, or has been * cancelled will be omitted. Remaining offer and consideration * items will then be aggregated where possible as indicated by the * supplied offer and consideration component arrays and aggregated * items will be transferred to the fulfiller or to each intended * recipient, respectively. Note that a failing item transfer or an * issue with order formatting will cause the entire batch to fail. * Note that this function does not support criteria-based orders or * partial filling of orders (though filling the remainder of a * partially-filled order is supported). * * @param orders The orders to fulfill. Note that both * the offerer and the fulfiller must first * approve this contract (or the * corresponding conduit if indicated) to * transfer any relevant tokens on their * behalf and that contracts must implement * `onERC1155Received` to receive ERC1155 * tokens as consideration. * @param offerFulfillments An array of FulfillmentComponent arrays * indicating which offer items to attempt * to aggregate when preparing executions. * @param considerationFulfillments An array of FulfillmentComponent arrays * indicating which consideration items to * attempt to aggregate when preparing * executions. * @param fulfillerConduitKey A bytes32 value indicating what conduit, * if any, to source the fulfiller's token * approvals from. The zero hash signifies * that no conduit should be used, with * direct approvals set on this contract. * @param maximumFulfilled The maximum number of orders to fulfill. * * @return availableOrders An array of booleans indicating if each order * with an index corresponding to the index of the * returned boolean was fulfillable or not. * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function fulfillAvailableOrders( Order[] calldata orders, FulfillmentComponent[][] calldata offerFulfillments, FulfillmentComponent[][] calldata considerationFulfillments, bytes32 fulfillerConduitKey, uint256 maximumFulfilled ) external payable returns (bool[] memory availableOrders, Execution[] memory executions); /** * @notice Attempt to fill a group of orders, fully or partially, with an * arbitrary number of items for offer and consideration per order * alongside criteria resolvers containing specific token * identifiers and associated proofs. Any order that is not * currently active, has already been fully filled, or has been * cancelled will be omitted. Remaining offer and consideration * items will then be aggregated where possible as indicated by the * supplied offer and consideration component arrays and aggregated * items will be transferred to the fulfiller or to each intended * recipient, respectively. Note that a failing item transfer or an * issue with order formatting will cause the entire batch to fail. * * @param advancedOrders The orders to fulfill along with the * fraction of those orders to attempt to * fill. Note that both the offerer and the * fulfiller must first approve this * contract (or their preferred conduit if * indicated by the order) to transfer any * relevant tokens on their behalf and that * contracts must implement * `onERC1155Received` to enable receipt of * ERC1155 tokens as consideration. Also * note that all offer and consideration * components must have no remainder after * multiplication of the respective amount * with the supplied fraction for an * order's partial fill amount to be * considered valid. * @param criteriaResolvers An array where each element contains a * reference to a specific offer or * consideration, a token identifier, and a * proof that the supplied token identifier * is contained in the merkle root held by * the item in question's criteria element. * Note that an empty criteria indicates * that any (transferable) token * identifier on the token in question is * valid and that no associated proof needs * to be supplied. * @param offerFulfillments An array of FulfillmentComponent arrays * indicating which offer items to attempt * to aggregate when preparing executions. * @param considerationFulfillments An array of FulfillmentComponent arrays * indicating which consideration items to * attempt to aggregate when preparing * executions. * @param fulfillerConduitKey A bytes32 value indicating what conduit, * if any, to source the fulfiller's token * approvals from. The zero hash signifies * that no conduit should be used, with * direct approvals set on this contract. * @param recipient The intended recipient for all received * items, with `address(0)` indicating that * the caller should receive the items. * @param maximumFulfilled The maximum number of orders to fulfill. * * @return availableOrders An array of booleans indicating if each order * with an index corresponding to the index of the * returned boolean was fulfillable or not. * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function fulfillAvailableAdvancedOrders( AdvancedOrder[] calldata advancedOrders, CriteriaResolver[] calldata criteriaResolvers, FulfillmentComponent[][] calldata offerFulfillments, FulfillmentComponent[][] calldata considerationFulfillments, bytes32 fulfillerConduitKey, address recipient, uint256 maximumFulfilled ) external payable returns (bool[] memory availableOrders, Execution[] memory executions); /** * @notice Match an arbitrary number of orders, each with an arbitrary * number of items for offer and consideration along with as set of * fulfillments allocating offer components to consideration * components. Note that this function does not support * criteria-based or partial filling of orders (though filling the * remainder of a partially-filled order is supported). * * @param orders The orders to match. Note that both the offerer and * fulfiller on each order must first approve this * contract (or their conduit if indicated by the order) * to transfer any relevant tokens on their behalf and * each consideration recipient must implement * `onERC1155Received` to enable ERC1155 token receipt. * @param fulfillments An array of elements allocating offer components to * consideration components. Note that each * consideration component must be fully met for the * match operation to be valid. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function matchOrders( Order[] calldata orders, Fulfillment[] calldata fulfillments ) external payable returns (Execution[] memory executions); /** * @notice Match an arbitrary number of full or partial orders, each with an * arbitrary number of items for offer and consideration, supplying * criteria resolvers containing specific token identifiers and * associated proofs as well as fulfillments allocating offer * components to consideration components. * * @param orders The advanced orders to match. Note that both the * offerer and fulfiller on each order must first * approve this contract (or a preferred conduit if * indicated by the order) to transfer any relevant * tokens on their behalf and each consideration * recipient must implement `onERC1155Received` in * order to receive ERC1155 tokens. Also note that * the offer and consideration components for each * order must have no remainder after multiplying * the respective amount with the supplied fraction * in order for the group of partial fills to be * considered valid. * @param criteriaResolvers An array where each element contains a reference * to a specific order as well as that order's * offer or consideration, a token identifier, and * a proof that the supplied token identifier is * contained in the order's merkle root. Note that * an empty root indicates that any (transferable) * token identifier is valid and that no associated * proof needs to be supplied. * @param fulfillments An array of elements allocating offer components * to consideration components. Note that each * consideration component must be fully met in * order for the match operation to be valid. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function matchAdvancedOrders( AdvancedOrder[] calldata orders, CriteriaResolver[] calldata criteriaResolvers, Fulfillment[] calldata fulfillments ) external payable returns (Execution[] memory executions); /** * @notice Cancel an arbitrary number of orders. Note that only the offerer * or the zone of a given order may cancel it. Callers should ensure * that the intended order was cancelled by calling `getOrderStatus` * and confirming that `isCancelled` returns `true`. * * @param orders The orders to cancel. * * @return cancelled A boolean indicating whether the supplied orders have * been successfully cancelled. */ function cancel( OrderComponents[] calldata orders ) external returns (bool cancelled); /** * @notice Validate an arbitrary number of orders, thereby registering their * signatures as valid and allowing the fulfiller to skip signature * verification on fulfillment. Note that validated orders may still * be unfulfillable due to invalid item amounts or other factors; * callers should determine whether validated orders are fulfillable * by simulating the fulfillment call prior to execution. Also note * that anyone can validate a signed order, but only the offerer can * validate an order without supplying a signature. * * @param orders The orders to validate. * * @return validated A boolean indicating whether the supplied orders have * been successfully validated. */ function validate( Order[] calldata orders ) external returns (bool validated); /** * @notice Cancel all orders from a given offerer with a given zone in bulk * by incrementing a counter. Note that only the offerer may * increment the counter. * * @return newCounter The new counter. */ function incrementCounter() external returns (uint256 newCounter); /** * @notice Retrieve the order hash for a given order. * * @param order The components of the order. * * @return orderHash The order hash. */ function getOrderHash( OrderComponents calldata order ) external view returns (bytes32 orderHash); /** * @notice Retrieve the status of a given order by hash, including whether * the order has been cancelled or validated and the fraction of the * order that has been filled. * * @param orderHash The order hash in question. * * @return isValidated A boolean indicating whether the order in question * has been validated (i.e. previously approved or * partially filled). * @return isCancelled A boolean indicating whether the order in question * has been cancelled. * @return totalFilled The total portion of the order that has been filled * (i.e. the "numerator"). * @return totalSize The total size of the order that is either filled or * unfilled (i.e. the "denominator"). */ function getOrderStatus( bytes32 orderHash ) external view returns ( bool isValidated, bool isCancelled, uint256 totalFilled, uint256 totalSize ); /** * @notice Retrieve the current counter for a given offerer. * * @param offerer The offerer in question. * * @return counter The current counter. */ function getCounter( address offerer ) external view returns (uint256 counter); /** * @notice Retrieve configuration information for this contract. * * @return version The contract version. * @return domainSeparator The domain separator for this contract. * @return conduitController The conduit Controller set for this contract. */ function information() external view returns ( string memory version, bytes32 domainSeparator, address conduitController ); /** * @notice Retrieve the name of this contract. * * @return contractName The name of this contract. */ function name() external view returns (string memory contractName); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @title EIP1271Interface * @notice Interface for the EIP-1271 standard signature validation method for * contracts. */ interface EIP1271Interface { /** * @dev Validates a smart contract signature * * @param digest bytes32 The digest of the data to be signed. * @param signature bytes The signature of the data to be validated. * * @return bytes4 The magic value, if the signature is valid. */ function isValidSignature( bytes32 digest, bytes calldata signature ) external view returns (bytes4); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; /** * @title ImmutableCreate2FactoryInterface * @author 0age * @notice This contract provides a safeCreate2 function that takes a salt value * and a block of initialization code as arguments and passes them into * inline assembly. The contract prevents redeploys by maintaining a * mapping of all contracts that have already been deployed, and * prevents frontrunning or other collisions by requiring that the first * 20 bytes of the salt are equal to the address of the caller (this can * be bypassed by setting the first 20 bytes to the null address). There * is also a view function that computes the address of the contract * that will be created when submitting a given salt or nonce along with * a given block of initialization code. */ interface ImmutableCreate2FactoryInterface { /** * @dev Create a contract using CREATE2 by submitting a given salt or nonce * along with the initialization code for the contract. Note that the * first 20 bytes of the salt must match those of the calling address, * which prevents contract creation events from being submitted by * unintended parties. * * @param salt The nonce that will be passed into the CREATE2 * call. * @param initializationCode The initialization code that will be passed * into the CREATE2 call. * * @return deploymentAddress Address of the contract that will be created. */ function safeCreate2( bytes32 salt, bytes calldata initializationCode ) external payable returns (address deploymentAddress); /** * @dev Compute the address of the contract that will be created when * submitting a given salt or nonce to the contract along with the * contract's initialization code. The CREATE2 address is computed in * accordance with EIP-1014, and adheres to the formula therein of * `keccak256( 0xff ++ address ++ salt ++ keccak256(init_code)))[12:]` * when performing the computation. The computed address is then * checked for any existing contract code - if so, the null address * will be returned instead. * * @param salt The nonce passed into the CREATE2 address calculation. * @param initCode The contract initialization code to be used that will be * passed into the CREATE2 address calculation. * * @return deploymentAddress Address of the contract that will be created, * or the null address if a contract already * exists at that address. */ function findCreate2Address( bytes32 salt, bytes calldata initCode ) external view returns (address deploymentAddress); /** * @dev Compute the address of the contract that will be created when * submitting a given salt or nonce to the contract along with the * keccak256 hash of the contract's initialization code. The CREATE2 * address is computed in accordance with EIP-1014, and adheres to the * `keccak256( 0xff ++ address ++ salt ++ keccak256(init_code)))[12:]` * formula when performing the computation. The computed address is * then checked for any existing contract code - if so, the null * address will be returned instead. * * @param salt The nonce passed into the CREATE2 address * calculation. * @param initCodeHash The keccak256 hash of the initialization code that * will be passed into the CREATE2 address calculation. * * @return deploymentAddress Address of the contract that will be created, * or the null address if a contract already * exists at that address. */ function findCreate2AddressViaHash( bytes32 salt, bytes32 initCodeHash ) external view returns (address deploymentAddress); /** * @dev Determine if a contract has already been deployed by the factory to * a given address. * * @param deploymentAddress The contract address to check. * * @return True if the contract has been deployed, false otherwise. */ function hasBeenDeployed( address deploymentAddress ) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; interface ERC20ApprovalInterface { function approve(address, uint256) external returns (bool); } interface NFTApprovalInterface { function setApprovalForAll(address, bool) external; } contract EIP1271Wallet { bytes4 private constant _EIP_1271_MAGIC_VALUE = 0x1626ba7e; address public immutable owner; bool public showRevertMessage; mapping(bytes32 => bool) public digestApproved; bool public isValid; constructor(address _owner) { owner = _owner; showRevertMessage = true; isValid = true; } function setValid(bool valid) external { isValid = valid; } function revertWithMessage(bool showMessage) external { showRevertMessage = showMessage; } function registerDigest(bytes32 digest, bool approved) external { digestApproved[digest] = approved; } function approveERC20( ERC20ApprovalInterface token, address operator, uint256 amount ) external { if (msg.sender != owner) { revert("Only owner"); } token.approve(operator, amount); } function approveNFT(NFTApprovalInterface token, address operator) external { if (msg.sender != owner) { revert("Only owner"); } token.setApprovalForAll(operator, true); } function isValidSignature( bytes32 digest, bytes memory signature ) external view returns (bytes4) { if (digestApproved[digest]) { return _EIP_1271_MAGIC_VALUE; } // NOTE: this is obviously not secure, do not use outside of testing. if (signature.length == 64) { // All signatures of length 64 are OK as long as valid is true return isValid ? _EIP_1271_MAGIC_VALUE : bytes4(0xffffffff); } if (signature.length != 65) { revert(); } bytes32 r; bytes32 s; uint8 v; assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } if ( uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 ) { revert(); } if (v != 27 && v != 28) { revert(); } address signer = ecrecover(digest, v, r, s); if (signer == address(0)) { revert(); } if (signer != owner) { if (showRevertMessage) { revert("BAD SIGNER"); } revert(); } return isValid ? _EIP_1271_MAGIC_VALUE : bytes4(0xffffffff); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; contract ERC1155BatchRecipient { error UnexpectedBatchData(); function onERC1155BatchReceived( address, address, uint256[] calldata, uint256[] calldata, bytes memory data ) external pure returns (bytes4) { if (data.length != 0) { revert UnexpectedBatchData(); } return ERC1155BatchRecipient.onERC1155BatchReceived.selector; } }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.13; contract ExcessReturnDataRecipient { uint256 private revertDataSize; function setRevertDataSize(uint256 size) external { revertDataSize = size; } // Code created with the help of Stack Exchange question // https://ethereum.stackexchange.com/questions/8086 // Question by Doug King: // https://ethereum.stackexchange.com/users/2041/doug-king // Answer by Tjaden Hess: // https://ethereum.stackexchange.com/users/131/tjaden-hess // Modified to use Yul instead of Solidity and added change of // base to convert to natural logarithm function ln(uint256 x) internal pure returns (uint256 y) { assembly { let arg := x x := sub(x, 1) x := or(x, div(x, 0x02)) x := or(x, div(x, 0x04)) x := or(x, div(x, 0x10)) x := or(x, div(x, 0x100)) x := or(x, div(x, 0x10000)) x := or(x, div(x, 0x100000000)) x := or(x, div(x, 0x10000000000000000)) x := or(x, div(x, 0x100000000000000000000000000000000)) x := add(x, 1) let m := mload(0x40) mstore( m, 0xf8f9cbfae6cc78fbefe7cdc3a1793dfcf4f0e8bbd8cec470b6a28a7a5a3e1efd ) mstore( add(m, 0x20), 0xf5ecf1b3e9debc68e1d9cfabc5997135bfb7a7a3938b7b606b5b4b3f2f1f0ffe ) mstore( add(m, 0x40), 0xf6e4ed9ff2d6b458eadcdf97bd91692de2d4da8fd2d0ac50c6ae9a8272523616 ) mstore( add(m, 0x60), 0xc8c0b887b0a8a4489c948c7f847c6125746c645c544c444038302820181008ff ) mstore( add(m, 0x80), 0xf7cae577eec2a03cf3bad76fb589591debb2dd67e0aa9834bea6925f6a4a2e0e ) mstore( add(m, 0xa0), 0xe39ed557db96902cd38ed14fad815115c786af479b7e83247363534337271707 ) mstore( add(m, 0xc0), 0xc976c13bb96e881cb166a933a55e490d9d56952b8d4e801485467d2362422606 ) mstore( add(m, 0xe0), 0x753a6d1b65325d0c552a4d1345224105391a310b29122104190a110309020100 ) mstore(0x40, add(m, 0x100)) let magic := 0x818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff let shift := 0x100000000000000000000000000000000000000000000000000000000000000 let a := div(mul(x, magic), shift) y := div(mload(add(m, sub(255, a))), shift) y := add( y, mul( 256, gt( arg, 0x8000000000000000000000000000000000000000000000000000000000000000 ) ) ) y := mul(y, 10000000000000000) y := div(y, 14426950408889632) } } function sqrt(uint256 y) internal pure returns (uint256 z) { assembly { switch gt(y, 3) case 1 { z := y let x := div(add(y, 1), 2) for { } lt(x, z) { } { z := x x := div(add(div(y, x), x), 2) } } case 0 { z := 1 } } } function onERC1155Received( address, address, uint256, uint256, bytes calldata ) external view returns (bytes4 magic) { magic = this.onERC1155Received.selector; if (revertDataSize > 0) { uint256 gasToCalculateSqrt = (54 * ln(gasleft())) + 1200; uint256 w = (sqrt( 2048 * (gasleft() - gasToCalculateSqrt) + 9431040 ) - 3072) / 4; assembly { let size := mul(w, 32) calldatacopy(0, 0, mul(w, 32)) revert(0, size) } } } receive() external payable { if (revertDataSize > 0) { uint256 gasToCalculateSqrt = (54 * ln(gasleft())) + 1200; uint256 w = (sqrt( 2048 * (gasleft() - gasToCalculateSqrt) + 9431040 ) - 3072) / 2; assembly { let size := mul(w, 32) calldatacopy(0, 0, mul(w, 32)) revert(0, size) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; interface IERC721Receiver { function onERC721Received( address, address, uint256, bytes calldata ) external returns (bytes4); } contract InvalidERC721Recipient is IERC721Receiver { function onERC721Received( address /* operator */, address /* from */, uint256 /* tokenId */, bytes calldata /* data */ ) external pure override returns (bytes4) { return 0xabcd0000; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; contract InvalidEthRecipient { receive() external payable { revert( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; contract Reenterer { bool public isPrepared; address public target; uint256 public msgValue; bytes public callData; event Reentered(bytes returnData); function prepare( address targetToUse, uint256 msgValueToUse, bytes calldata callDataToUse ) external { target = targetToUse; msgValue = msgValueToUse; callData = callDataToUse; isPrepared = true; } receive() external payable { if (isPrepared) { (bool success, bytes memory returnData) = target.call{ value: msgValue }(callData); if (!success) { assembly { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } emit Reentered(returnData); isPrepared = false; } } function execute(address to, uint256 value, bytes memory data) external { (bool success, ) = payable(to).call{ value: value }(data); if (!success) { assembly { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } } }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.13; import { ERC1155 } from "@rari-capital/solmate/src/tokens/ERC1155.sol"; // Used for minting test ERC1155s in our tests contract TestERC1155 is ERC1155 { function mint( address to, uint256 tokenId, uint256 amount ) public returns (bool) { _mint(to, tokenId, amount, ""); return true; } function uri(uint256) public pure override returns (string memory) { return "uri"; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Minimalist and gas efficient standard ERC1155 implementation. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC1155.sol) abstract contract ERC1155 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event TransferSingle( address indexed operator, address indexed from, address indexed to, uint256 id, uint256 amount ); event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] amounts ); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); event URI(string value, uint256 indexed id); /*////////////////////////////////////////////////////////////// ERC1155 STORAGE //////////////////////////////////////////////////////////////*/ mapping(address => mapping(uint256 => uint256)) public balanceOf; mapping(address => mapping(address => bool)) public isApprovedForAll; /*////////////////////////////////////////////////////////////// METADATA LOGIC //////////////////////////////////////////////////////////////*/ function uri(uint256 id) public view virtual returns (string memory); /*////////////////////////////////////////////////////////////// ERC1155 LOGIC //////////////////////////////////////////////////////////////*/ function setApprovalForAll(address operator, bool approved) public virtual { isApprovedForAll[msg.sender][operator] = approved; emit ApprovalForAll(msg.sender, operator, approved); } function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) public virtual { require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED"); balanceOf[from][id] -= amount; balanceOf[to][id] += amount; emit TransferSingle(msg.sender, from, to, id, amount); require( to.code.length == 0 ? to != address(0) : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, from, id, amount, data) == ERC1155TokenReceiver.onERC1155Received.selector, "UNSAFE_RECIPIENT" ); } function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) public virtual { require(ids.length == amounts.length, "LENGTH_MISMATCH"); require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED"); // Storing these outside the loop saves ~15 gas per iteration. uint256 id; uint256 amount; for (uint256 i = 0; i < ids.length; ) { id = ids[i]; amount = amounts[i]; balanceOf[from][id] -= amount; balanceOf[to][id] += amount; // An array can't have a total length // larger than the max uint256 value. unchecked { ++i; } } emit TransferBatch(msg.sender, from, to, ids, amounts); require( to.code.length == 0 ? to != address(0) : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, from, ids, amounts, data) == ERC1155TokenReceiver.onERC1155BatchReceived.selector, "UNSAFE_RECIPIENT" ); } function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) public view virtual returns (uint256[] memory balances) { require(owners.length == ids.length, "LENGTH_MISMATCH"); balances = new uint256[](owners.length); // Unchecked because the only math done is incrementing // the array index counter which cannot possibly overflow. unchecked { for (uint256 i = 0; i < owners.length; ++i) { balances[i] = balanceOf[owners[i]][ids[i]]; } } } /*////////////////////////////////////////////////////////////// ERC165 LOGIC //////////////////////////////////////////////////////////////*/ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165 interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155 interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint( address to, uint256 id, uint256 amount, bytes memory data ) internal virtual { balanceOf[to][id] += amount; emit TransferSingle(msg.sender, address(0), to, id, amount); require( to.code.length == 0 ? to != address(0) : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, address(0), id, amount, data) == ERC1155TokenReceiver.onERC1155Received.selector, "UNSAFE_RECIPIENT" ); } function _batchMint( address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { uint256 idsLength = ids.length; // Saves MLOADs. require(idsLength == amounts.length, "LENGTH_MISMATCH"); for (uint256 i = 0; i < idsLength; ) { balanceOf[to][ids[i]] += amounts[i]; // An array can't have a total length // larger than the max uint256 value. unchecked { ++i; } } emit TransferBatch(msg.sender, address(0), to, ids, amounts); require( to.code.length == 0 ? to != address(0) : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, address(0), ids, amounts, data) == ERC1155TokenReceiver.onERC1155BatchReceived.selector, "UNSAFE_RECIPIENT" ); } function _batchBurn( address from, uint256[] memory ids, uint256[] memory amounts ) internal virtual { uint256 idsLength = ids.length; // Saves MLOADs. require(idsLength == amounts.length, "LENGTH_MISMATCH"); for (uint256 i = 0; i < idsLength; ) { balanceOf[from][ids[i]] -= amounts[i]; // An array can't have a total length // larger than the max uint256 value. unchecked { ++i; } } emit TransferBatch(msg.sender, from, address(0), ids, amounts); } function _burn( address from, uint256 id, uint256 amount ) internal virtual { balanceOf[from][id] -= amount; emit TransferSingle(msg.sender, from, address(0), id, amount); } } /// @notice A generic interface for a contract which properly accepts ERC1155 tokens. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC1155.sol) abstract contract ERC1155TokenReceiver { function onERC1155Received( address, address, uint256, uint256, bytes calldata ) external virtual returns (bytes4) { return ERC1155TokenReceiver.onERC1155Received.selector; } function onERC1155BatchReceived( address, address, uint256[] calldata, uint256[] calldata, bytes calldata ) external virtual returns (bytes4) { return ERC1155TokenReceiver.onERC1155BatchReceived.selector; } }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.0; contract TestERC1155Revert { function safeTransferFrom( address /* from */, address /* to */, uint256 /* id */, uint256 /* amount */, bytes calldata /* data */ ) public pure { revert( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ); } function safeBatchTransferFrom( address /* from */, address /* to */, uint256[] memory /* ids */, uint256[] memory /* values */, bytes memory /* data */ ) public pure { revert("Some ERC1155 revert message for batch transfers"); } function getRevertData() public pure returns (bytes memory) { assembly { mstore(0x40, 0) mstore(0, shl(20, 1)) mstore(add(0x20, shl(20, 1)), 1) return(0, add(0x20, shl(20, 1))) } } }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.13; import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol"; // Used for minting test ERC20s in our tests contract TestERC20 is ERC20("Test20", "TST20", 18) { bool public blocked; bool public noReturnData; constructor() { blocked = false; noReturnData = false; } function blockTransfer(bool blocking) external { blocked = blocking; } function setNoReturnData(bool noReturn) external { noReturnData = noReturn; } function mint(address to, uint256 amount) external returns (bool) { _mint(to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public override returns (bool ok) { if (blocked) { return false; } super.transferFrom(from, to, amount); if (noReturnData) { assembly { return(0, 0) } } ok = true; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol"; contract TestERC20Revert is ERC20("TestRevert", "REVERT", 18) { function mint(address to, uint256 amount) external { _mint(to, amount); } function transferFrom( address /* from */, address /* to */, uint256 /* amount */ ) public pure override returns (bool) { revert( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol"; contract TestERC20Panic is ERC20("TestPanic", "PANIC", 18) { function mint(address to, uint256 amount) external returns (bool) { _mint(to, amount); return true; } function transferFrom( address /* from */, address /* to */, uint256 /* amount */ ) public pure override returns (bool) { uint256 a = uint256(0) / uint256(0); a; return true; } }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.13; import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol"; // Used for minting test ERC20s in our tests. contract TestERC20NotOk is ERC20("Test20NotOk", "TST20NO", 18) { bool public notOk; function mint(address to, uint256 amount) external returns (bool) { _mint(to, amount); return true; } function transferFrom( address /* from */, address /* to */, uint256 /* amount */ ) public pure override returns (bool) { return false; } }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.13; import { ERC721 } from "@rari-capital/solmate/src/tokens/ERC721.sol"; // Used for minting test ERC721s in our tests contract TestERC721 is ERC721("Test721", "TST721") { function mint(address to, uint256 tokenId) public returns (bool) { _mint(to, tokenId); return true; } function tokenURI(uint256) public pure override returns (string memory) { return "tokenURI"; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern, minimalist, and gas efficient ERC-721 implementation. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol) abstract contract ERC721 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 indexed id); event Approval(address indexed owner, address indexed spender, uint256 indexed id); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /*////////////////////////////////////////////////////////////// METADATA STORAGE/LOGIC //////////////////////////////////////////////////////////////*/ string public name; string public symbol; function tokenURI(uint256 id) public view virtual returns (string memory); /*////////////////////////////////////////////////////////////// ERC721 BALANCE/OWNER STORAGE //////////////////////////////////////////////////////////////*/ mapping(uint256 => address) internal _ownerOf; mapping(address => uint256) internal _balanceOf; function ownerOf(uint256 id) public view virtual returns (address owner) { require((owner = _ownerOf[id]) != address(0), "NOT_MINTED"); } function balanceOf(address owner) public view virtual returns (uint256) { require(owner != address(0), "ZERO_ADDRESS"); return _balanceOf[owner]; } /*////////////////////////////////////////////////////////////// ERC721 APPROVAL STORAGE //////////////////////////////////////////////////////////////*/ mapping(uint256 => address) public getApproved; mapping(address => mapping(address => bool)) public isApprovedForAll; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor(string memory _name, string memory _symbol) { name = _name; symbol = _symbol; } /*////////////////////////////////////////////////////////////// ERC721 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 id) public virtual { address owner = _ownerOf[id]; require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED"); getApproved[id] = spender; emit Approval(owner, spender, id); } function setApprovalForAll(address operator, bool approved) public virtual { isApprovedForAll[msg.sender][operator] = approved; emit ApprovalForAll(msg.sender, operator, approved); } function transferFrom( address from, address to, uint256 id ) public virtual { require(from == _ownerOf[id], "WRONG_FROM"); require(to != address(0), "INVALID_RECIPIENT"); require( msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id], "NOT_AUTHORIZED" ); // Underflow of the sender's balance is impossible because we check for // ownership above and the recipient's balance can't realistically overflow. unchecked { _balanceOf[from]--; _balanceOf[to]++; } _ownerOf[id] = to; delete getApproved[id]; emit Transfer(from, to, id); } function safeTransferFrom( address from, address to, uint256 id ) public virtual { transferFrom(from, to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } function safeTransferFrom( address from, address to, uint256 id, bytes calldata data ) public virtual { transferFrom(from, to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } /*////////////////////////////////////////////////////////////// ERC165 LOGIC //////////////////////////////////////////////////////////////*/ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165 interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721 interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 id) internal virtual { require(to != address(0), "INVALID_RECIPIENT"); require(_ownerOf[id] == address(0), "ALREADY_MINTED"); // Counter overflow is incredibly unrealistic. unchecked { _balanceOf[to]++; } _ownerOf[id] = to; emit Transfer(address(0), to, id); } function _burn(uint256 id) internal virtual { address owner = _ownerOf[id]; require(owner != address(0), "NOT_MINTED"); // Ownership check above ensures no underflow. unchecked { _balanceOf[owner]--; } delete _ownerOf[id]; delete getApproved[id]; emit Transfer(owner, address(0), id); } /*////////////////////////////////////////////////////////////// INTERNAL SAFE MINT LOGIC //////////////////////////////////////////////////////////////*/ function _safeMint(address to, uint256 id) internal virtual { _mint(to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } function _safeMint( address to, uint256 id, bytes memory data ) internal virtual { _mint(to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } } /// @notice A generic interface for a contract which properly accepts ERC721 tokens. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol) abstract contract ERC721TokenReceiver { function onERC721Received( address, address, uint256, bytes calldata ) external virtual returns (bytes4) { return ERC721TokenReceiver.onERC721Received.selector; } }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.0; contract TestERC721Revert { function transferFrom( address /* from */, address /* to */, uint256 /* amount */ ) public pure { revert( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ); } }
{ "viaIR": true, "optimizer": { "enabled": true, "runs": 4294967295 }, "metadata": { "bytecodeHash": "none" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"conduitController","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"structOfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"addresspayable","name":"recipient","type":"address"}],"internalType":"structConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enumOrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"counter","type":"uint256"}],"internalType":"structOrderComponents[]","name":"orders","type":"tuple[]"}],"name":"cancel","outputs":[{"internalType":"bool","name":"cancelled","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"structOfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"addresspayable","name":"recipient","type":"address"}],"internalType":"structConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enumOrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"structOrderParameters","name":"parameters","type":"tuple"},{"internalType":"uint120","name":"numerator","type":"uint120"},{"internalType":"uint120","name":"denominator","type":"uint120"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"structAdvancedOrder","name":"advancedOrder","type":"tuple"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"enumSide","name":"side","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"bytes32[]","name":"criteriaProof","type":"bytes32[]"}],"internalType":"structCriteriaResolver[]","name":"criteriaResolvers","type":"tuple[]"},{"internalType":"bytes32","name":"fulfillerConduitKey","type":"bytes32"},{"internalType":"address","name":"recipient","type":"address"}],"name":"fulfillAdvancedOrder","outputs":[{"internalType":"bool","name":"fulfilled","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"structOfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"addresspayable","name":"recipient","type":"address"}],"internalType":"structConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enumOrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"structOrderParameters","name":"parameters","type":"tuple"},{"internalType":"uint120","name":"numerator","type":"uint120"},{"internalType":"uint120","name":"denominator","type":"uint120"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"structAdvancedOrder[]","name":"advancedOrders","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"enumSide","name":"side","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"bytes32[]","name":"criteriaProof","type":"bytes32[]"}],"internalType":"structCriteriaResolver[]","name":"criteriaResolvers","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"structFulfillmentComponent[][]","name":"offerFulfillments","type":"tuple[][]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"structFulfillmentComponent[][]","name":"considerationFulfillments","type":"tuple[][]"},{"internalType":"bytes32","name":"fulfillerConduitKey","type":"bytes32"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"maximumFulfilled","type":"uint256"}],"name":"fulfillAvailableAdvancedOrders","outputs":[{"internalType":"bool[]","name":"availableOrders","type":"bool[]"},{"components":[{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"addresspayable","name":"recipient","type":"address"}],"internalType":"structReceivedItem","name":"item","type":"tuple"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"}],"internalType":"structExecution[]","name":"executions","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"structOfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"addresspayable","name":"recipient","type":"address"}],"internalType":"structConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enumOrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"structOrderParameters","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"structOrder[]","name":"orders","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"structFulfillmentComponent[][]","name":"offerFulfillments","type":"tuple[][]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"structFulfillmentComponent[][]","name":"considerationFulfillments","type":"tuple[][]"},{"internalType":"bytes32","name":"fulfillerConduitKey","type":"bytes32"},{"internalType":"uint256","name":"maximumFulfilled","type":"uint256"}],"name":"fulfillAvailableOrders","outputs":[{"internalType":"bool[]","name":"availableOrders","type":"bool[]"},{"components":[{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"addresspayable","name":"recipient","type":"address"}],"internalType":"structReceivedItem","name":"item","type":"tuple"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"}],"internalType":"structExecution[]","name":"executions","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"considerationToken","type":"address"},{"internalType":"uint256","name":"considerationIdentifier","type":"uint256"},{"internalType":"uint256","name":"considerationAmount","type":"uint256"},{"internalType":"addresspayable","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"internalType":"address","name":"offerToken","type":"address"},{"internalType":"uint256","name":"offerIdentifier","type":"uint256"},{"internalType":"uint256","name":"offerAmount","type":"uint256"},{"internalType":"enumBasicOrderType","name":"basicOrderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"offererConduitKey","type":"bytes32"},{"internalType":"bytes32","name":"fulfillerConduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalAdditionalRecipients","type":"uint256"},{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"addresspayable","name":"recipient","type":"address"}],"internalType":"structAdditionalRecipient[]","name":"additionalRecipients","type":"tuple[]"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"structBasicOrderParameters","name":"parameters","type":"tuple"}],"name":"fulfillBasicOrder","outputs":[{"internalType":"bool","name":"fulfilled","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"considerationToken","type":"address"},{"internalType":"uint256","name":"considerationIdentifier","type":"uint256"},{"internalType":"uint256","name":"considerationAmount","type":"uint256"},{"internalType":"addresspayable","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"internalType":"address","name":"offerToken","type":"address"},{"internalType":"uint256","name":"offerIdentifier","type":"uint256"},{"internalType":"uint256","name":"offerAmount","type":"uint256"},{"internalType":"enumBasicOrderType","name":"basicOrderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"offererConduitKey","type":"bytes32"},{"internalType":"bytes32","name":"fulfillerConduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalAdditionalRecipients","type":"uint256"},{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"addresspayable","name":"recipient","type":"address"}],"internalType":"structAdditionalRecipient[]","name":"additionalRecipients","type":"tuple[]"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"structBasicOrderParameters","name":"parameters","type":"tuple"}],"name":"fulfillBasicOrder_efficient_6GL6yc","outputs":[{"internalType":"bool","name":"fulfilled","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"structOfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"addresspayable","name":"recipient","type":"address"}],"internalType":"structConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enumOrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"structOrderParameters","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"structOrder","name":"order","type":"tuple"},{"internalType":"bytes32","name":"fulfillerConduitKey","type":"bytes32"}],"name":"fulfillOrder","outputs":[{"internalType":"bool","name":"fulfilled","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"contractOfferer","type":"address"}],"name":"getContractOffererNonce","outputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"offerer","type":"address"}],"name":"getCounter","outputs":[{"internalType":"uint256","name":"counter","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"structOfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"addresspayable","name":"recipient","type":"address"}],"internalType":"structConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enumOrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"counter","type":"uint256"}],"internalType":"structOrderComponents","name":"order","type":"tuple"}],"name":"getOrderHash","outputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"getOrderStatus","outputs":[{"internalType":"bool","name":"isValidated","type":"bool"},{"internalType":"bool","name":"isCancelled","type":"bool"},{"internalType":"uint256","name":"totalFilled","type":"uint256"},{"internalType":"uint256","name":"totalSize","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"incrementCounter","outputs":[{"internalType":"uint256","name":"newCounter","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"information","outputs":[{"internalType":"string","name":"version","type":"string"},{"internalType":"bytes32","name":"domainSeparator","type":"bytes32"},{"internalType":"address","name":"conduitController","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"structOfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"addresspayable","name":"recipient","type":"address"}],"internalType":"structConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enumOrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"structOrderParameters","name":"parameters","type":"tuple"},{"internalType":"uint120","name":"numerator","type":"uint120"},{"internalType":"uint120","name":"denominator","type":"uint120"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"structAdvancedOrder[]","name":"orders","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"enumSide","name":"side","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"bytes32[]","name":"criteriaProof","type":"bytes32[]"}],"internalType":"structCriteriaResolver[]","name":"criteriaResolvers","type":"tuple[]"},{"components":[{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"structFulfillmentComponent[]","name":"offerComponents","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"structFulfillmentComponent[]","name":"considerationComponents","type":"tuple[]"}],"internalType":"structFulfillment[]","name":"fulfillments","type":"tuple[]"},{"internalType":"address","name":"recipient","type":"address"}],"name":"matchAdvancedOrders","outputs":[{"components":[{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"addresspayable","name":"recipient","type":"address"}],"internalType":"structReceivedItem","name":"item","type":"tuple"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"}],"internalType":"structExecution[]","name":"executions","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"structOfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"addresspayable","name":"recipient","type":"address"}],"internalType":"structConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enumOrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"structOrderParameters","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"structOrder[]","name":"orders","type":"tuple[]"},{"components":[{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"structFulfillmentComponent[]","name":"offerComponents","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"structFulfillmentComponent[]","name":"considerationComponents","type":"tuple[]"}],"internalType":"structFulfillment[]","name":"fulfillments","type":"tuple[]"}],"name":"matchOrders","outputs":[{"components":[{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"addresspayable","name":"recipient","type":"address"}],"internalType":"structReceivedItem","name":"item","type":"tuple"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"}],"internalType":"structExecution[]","name":"executions","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"contractName","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"structOfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"addresspayable","name":"recipient","type":"address"}],"internalType":"structConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enumOrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"structOrderParameters","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"structOrder[]","name":"orders","type":"tuple[]"}],"name":"validate","outputs":[{"internalType":"bool","name":"validated","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"BadContractSignature","type":"error"},{"inputs":[],"name":"BadFraction","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BadReturnValueFromERC20OnTransfer","type":"error"},{"inputs":[{"internalType":"uint8","name":"v","type":"uint8"}],"name":"BadSignatureV","type":"error"},{"inputs":[],"name":"CannotCancelOrder","type":"error"},{"inputs":[],"name":"ConsiderationCriteriaResolverOutOfRange","type":"error"},{"inputs":[],"name":"ConsiderationLengthNotEqualToTotalOriginal","type":"error"},{"inputs":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"considerationIndex","type":"uint256"},{"internalType":"uint256","name":"shortfallAmount","type":"uint256"}],"name":"ConsiderationNotMet","type":"error"},{"inputs":[],"name":"CriteriaNotEnabledForItem","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"identifiers","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"ERC1155BatchTransferGenericFailure","type":"error"},{"inputs":[],"name":"InexactFraction","type":"error"},{"inputs":[],"name":"InsufficientNativeTokensSupplied","type":"error"},{"inputs":[],"name":"Invalid1155BatchTransferEncoding","type":"error"},{"inputs":[],"name":"InvalidBasicOrderParameterEncoding","type":"error"},{"inputs":[{"internalType":"address","name":"conduit","type":"address"}],"name":"InvalidCallToConduit","type":"error"},{"inputs":[{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"address","name":"conduit","type":"address"}],"name":"InvalidConduit","type":"error"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"InvalidContractOrder","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"InvalidERC721TransferAmount","type":"error"},{"inputs":[],"name":"InvalidFulfillmentComponentData","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"InvalidMsgValue","type":"error"},{"inputs":[],"name":"InvalidNativeOfferItem","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"InvalidRestrictedOrder","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"InvalidTime","type":"error"},{"inputs":[{"internalType":"uint256","name":"fulfillmentIndex","type":"uint256"}],"name":"MismatchedFulfillmentOfferAndConsiderationComponents","type":"error"},{"inputs":[{"internalType":"enumSide","name":"side","type":"uint8"}],"name":"MissingFulfillmentComponentOnAggregation","type":"error"},{"inputs":[],"name":"MissingItemAmount","type":"error"},{"inputs":[],"name":"MissingOriginalConsiderationItems","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"NativeTokenTransferGenericFailure","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NoContract","type":"error"},{"inputs":[],"name":"NoReentrantCalls","type":"error"},{"inputs":[],"name":"NoSpecifiedOrdersAvailable","type":"error"},{"inputs":[],"name":"OfferAndConsiderationRequiredOnFulfillment","type":"error"},{"inputs":[],"name":"OfferCriteriaResolverOutOfRange","type":"error"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"OrderAlreadyFilled","type":"error"},{"inputs":[{"internalType":"enumSide","name":"side","type":"uint8"}],"name":"OrderCriteriaResolverOutOfRange","type":"error"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"OrderIsCancelled","type":"error"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"OrderPartiallyFilled","type":"error"},{"inputs":[],"name":"PartialFillsNotEnabledForOrder","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenTransferGenericFailure","type":"error"},{"inputs":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"considerationIndex","type":"uint256"}],"name":"UnresolvedConsiderationCriteria","type":"error"},{"inputs":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"offerIndex","type":"uint256"}],"name":"UnresolvedOfferCriteria","type":"error"},{"inputs":[],"name":"UnusedItemParameters","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newCounter","type":"uint256"},{"indexed":true,"internalType":"address","name":"offerer","type":"address"}],"name":"CounterIncremented","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"offerer","type":"address"},{"indexed":true,"internalType":"address","name":"zone","type":"address"}],"name":"OrderCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"offerer","type":"address"},{"indexed":true,"internalType":"address","name":"zone","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"indexed":false,"internalType":"structSpentItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"addresspayable","name":"recipient","type":"address"}],"indexed":false,"internalType":"structReceivedItem[]","name":"consideration","type":"tuple[]"}],"name":"OrderFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"structOfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enumItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"addresspayable","name":"recipient","type":"address"}],"internalType":"structConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enumOrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"indexed":false,"internalType":"structOrderParameters","name":"orderParameters","type":"tuple"}],"name":"OrderValidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32[]","name":"orderHashes","type":"bytes32[]"}],"name":"OrdersMatched","type":"event"}]
Contract Creation Code
6101c060405234620000b9576200001f6200001962000114565b62000151565b604051615f459081620006bd823960805181612622015260a05181612646015260c051816125ff015260e0518181816113b80152612430015261010051818181611257015261247f01526101205181818161145e01526124eb015261014051816125ac015261016051816125d3015261018051818181610f1f01528181612144015261226501526101a05181818161218201526122a30152f35b600080fd5b604081019081106001600160401b03821117620000da57604052565b634e487b7160e01b600052604160045260246000fd5b601f909101601f19168101906001600160401b03821190821017620000da57604052565b6200660260208138039182604051938492620001318285620000f0565b833981010312620000b957516001600160a01b0381168103620000b95790565b60406004916200016062000587565b610120526101005260e05260c05260a0526080524661014052620001b060c0519060805160a0516040519360005281602052604052466060523060805260a0600020926040526000606052608052565b610160526001600160a01b03166101808190528151630a96ad3960e01b815292839182905afa90811562000230575b600091620001fa575b506101a052620001f86001600055565b565b62000220915060403d811162000228575b620002178183620000f0565b81019062000240565b5038620001e8565b503d6200020b565b6200023a62000257565b620001df565b9190826040910312620000b9576020825192015190565b506040513d6000823e3d90fd5b604051906200027382620000be565b60038252565b6040519060a082016001600160401b03811183821017620000da57604052606a8252565b6040519060c082016001600160401b03811183821017620000da576040526084825263656e742960e01b60a0837f436f6e73696465726174696f6e4974656d2875696e7438206974656d5479706560208201527f2c6164647265737320746f6b656e2c75696e74323536206964656e746966696560408201527f724f7243726974657269612c75696e74323536207374617274416d6f756e742c60608201527f75696e7432353620656e64416d6f756e742c616464726573732072656369706960808201520152565b6040519061010082016001600160401b03811183821017620000da5760405260d482527f4b65792c75696e7432353620636f756e7465722900000000000000000000000060e0837f4f72646572436f6d706f6e656e74732861646472657373206f6666657265722c60208201527f61646472657373207a6f6e652c4f666665724974656d5b5d206f666665722c4360408201527f6f6e73696465726174696f6e4974656d5b5d20636f6e73696465726174696f6e60608201527f2c75696e7438206f72646572547970652c75696e74323536207374617274546960808201527f6d652c75696e7432353620656e6454696d652c62797465733332207a6f6e654860a08201527f6173682c75696e743235362073616c742c6279746573333220636f6e6475697460c08201520152565b60405190608082016001600160401b03811183821017620000da576040526052825271766572696679696e67436f6e74726163742960701b6060837f454950373132446f6d61696e28737472696e67206e616d652c737472696e672060208201527f76657273696f6e2c75696e7432353620636861696e49642c616464726573732060408201520152565b9081519160005b83811062000539575050016000815290565b806020809284010151818501520162000527565b6200057862000571949362000571620001f894604051978895602087019062000520565b9062000520565b03601f198101845283620000f0565b6040516200059581620000be565b600781526614d9585c1bdc9d60ca1b6020918201527f32b5c112df393a49218d7552f96b2eeb829dfb4272f4f24eef510a586b85feef91620005d662000264565b82810190620c4b8d60ea1b825251902091620005f162000279565b818101927f4f666665724974656d2875696e7438206974656d547970652c6164647265737384527f20746f6b656e2c75696e74323536206964656e7469666965724f72437269746560408301527f7269612c75696e74323536207374617274416d6f756e742c75696e7432353620606083015269656e64416d6f756e742960b01b6080830152620006816200029d565b92620006b46200069062000366565b936200069b62000495565b838151910120968151902095805184820120956200054d565b80519101209056fe60806040526004361015610023575b361561001957600080fd5b610021614fac565b005b60003560e01c80156100eb57806306fdde031461016957806346423aa7146101605780635b34b9661461015757806379df72bd1461014e57806387201b4114610145578063881477321461013c578063a817440414610133578063a900866b1461012a578063b3a34c4c14610121578063e7acab2414610118578063ed98a5741461010f578063f07ec37314610106578063f2d12b12146100fd578063f47b7740146100f4578063fb0f3ee1146100eb5763fd9f1e100361000e576100e6610f50565b61000e565b506100e66101c8565b506100e6610ec8565b506100e6610df2565b506100e6610d8a565b506100e6610cc2565b506100e6610c05565b506100e6610b81565b506100e6610b17565b506100e6610a60565b506100e66108d6565b506100e66107c6565b506100e661059d565b506100e66104f5565b506100e6610474565b506100e661042e565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc906020828201126101c3576004359167ffffffffffffffff83116101c35782610240920301126101c35760040190565b600080fd5b506101d236610172565b6101243590600382169160021c91600183119234158403610420575b60038111907f0203020301010000000000000000000000000000000000000000000000000000811a9061024c8260a0850260240135887d010102030000000000000000000000000000000000000000000000000000851a888a61121a565b928060051b6101c4013596610260816106a8565b6102b3575050604435602435176102a55761028b9461027e916115b5565b61028661166d565b6159e2565b6102956001600055565b60405160018152602090f35b0390f35b636ab37ce76000526004601cfd5b610286925061028b969161032a916102c96111a8565b9384836102d682956106a8565b6002810361032f5750610325918a6102f060a082016111bf565b6102fc606083016111bf565b60c060e08401359301359173ffffffffffffffffffffffffffffffffffffffff33921690611efe565b611738565b612105565b610338816106a8565b600381036103875750610325918a61035260a082016111bf565b61035e606083016111bf565b60c060e08401359301359173ffffffffffffffffffffffffffffffffffffffff33921690611fff565b806103936004926106a8565b036103dc57610325918a6103a6816111bf565b6103b2606083016111bf565b9073ffffffffffffffffffffffffffffffffffffffff602060408501359401359216903390611efe565b610325918a6103ea816111bf565b6103f6606083016111bf565b9073ffffffffffffffffffffffffffffffffffffffff602060408501359401359216903390611fff565b61042934611d42565b6101ee565b50346101c35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c357602080526707536561706f727460475260606020f35b50346101c35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c357600435600052600260205260806040600020546040519060ff81161515825260ff8160081c16151560208301526effffffffffffffffffffffffffffff8160101c16604083015260881c6060820152f35b50346101c35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c35761052d614f92565b3360005260016020526020604060002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff43014060801c018091556040518181527f721c20121297512b72821b97f5326877ea8ecf4bb9948fea5bfcb6453074d37f833392a2604051908152f35b50346101c3577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6020813601126101c3576004359067ffffffffffffffff82116101c3576101609082360301126101c35761061263ffffffff6020921661014461060982600401611cd6565b91013590612423565b604051908152f35b9181601f840112156101c35782359167ffffffffffffffff83116101c3576020808501948460051b0101116101c357565b73ffffffffffffffffffffffffffffffffffffffff8116036101c357565b60a435906106768261064b565b565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600611156106b257565b610676610678565b60809080516106c8816106a8565b83528173ffffffffffffffffffffffffffffffffffffffff918260208201511660208601526040810151604086015260608101516060860152015116910152565b90815180825260208080930193019160005b828110610729575050505090565b909192938260e0600192604088516107428382516106ba565b8085015173ffffffffffffffffffffffffffffffffffffffff1660a0840152015160c08201520195019392910161071b565b9092916040820191604081528451809352606081019260208096019060005b8181106107b0575050506107ad9394818403910152610709565b90565b8251151586529487019491870191600101610793565b5060e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c35767ffffffffffffffff6004358181116101c35761081290369060040161061a565b50506024358181116101c35761082c90369060040161061a565b50506044358181116101c35761084690369060040161061a565b50506064359081116101c35761086090369060040161061a565b505061087961086d610669565b60c43590608435611813565b906102a160405192839283610774565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126101c3576004359067ffffffffffffffff82116101c3576108d29160040161061a565b9091565b50346101c3576108e536610889565b505060046108fb63ffffffff8235168201611aba565b90610904614f92565b81519060005b82811061091d5760405160018152602090f35b8061092a60019286612988565b51805184608082015161093c81612934565b61094581612934565b14610a4857805173ffffffffffffffffffffffffffffffffffffffff1661096b82614778565b90610980826000526002602052604060002090565b61098a8184615906565b5061099d610999825460ff1690565b1590565b6109ae575b50505050505b0161090a565b6109f4610a1f928460207ff280791efe782edcf06ce15c8f4dff17601db3b88eb3805a0db7d77faf757f04986060890151516101408a015103610a3b575b0151916151af565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b610a2e60405192839283614e6c565b0390a138808080806109a2565b610a43614c7e565b6109ec565b50506109a8565b9060206107ad928181520190610709565b5060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c35760043567ffffffffffffffff8082116101c357610aab368360040161061a565b50506024359081116101c3576102a191610b0391610acc368260040161061a565b5050610afb610ae463ffffffff809416600401615edb565b92610aed6110db565b926000845216600401611c52565b903392613bac565b604051918291602083526020830190610709565b50346101c35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c35773ffffffffffffffffffffffffffffffffffffffff600435610b688161064b565b1660005260036020526020604060002054604051908152f35b507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6040813601126101c3576004359067ffffffffffffffff82116101c35760409082360301126101c357610bfb610be363ffffffff602093166004016119cd565b610beb6110db565b9060008252339160243591613f26565b6040519015158152f35b507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6080813601126101c3576004359067ffffffffffffffff908183116101c35760a09083360301126101c3576024359081116101c3576102a191610cb091610c71368260040161061a565b5050610ca060643592610c838461064b565b610c9663ffffffff80921660040161186c565b9216600401611a2d565b9133811502019160443591613f26565b60405190151581529081906020820190565b5060a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c357600467ffffffffffffffff81358181116101c357610d0d3682850161061a565b5050602435908282116101c357610d263683860161061a565b50506044359283116101c357610d7b61087994610d453686830161061a565b5050610d5963ffffffff8094168201615edb565b92610d7381610d666110db565b9660008852168301611b44565b951601611b44565b608435933393606435936126d4565b50346101c35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c3576020610612600435610dcb8161064b565b73ffffffffffffffffffffffffffffffffffffffff16600052600160205260406000205490565b5060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c35767ffffffffffffffff600480358281116101c357610e3d3682840161061a565b5050602435908382116101c357610e563683850161061a565b50506044359384116101c3576102a193610eb0610ebc94610e793684830161061a565b5050610e9f610ea860643595610e8e8761064b565b63ffffffff92838092168501611bf5565b97168301611a2d565b931601611c52565b91338115020192613bac565b60405191829182610a4f565b50346101c35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c357610f006125a7565b606060005260205273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166040526303312e3460635260a06000f35b50346101c357610f5f36610889565b90610f68614f92565b600091825b818110610f925783610f855760405160018152602090f35b610f8d614d39565b610295565b80610fa06001928486614cde565b94610faa866111bf565b907f6bacc01dbe442496068f7d234edd811f1a5f833243e0aec824f86ab861f3c90d611075611006610fde60208b016111bf565b93610feb60808c01614d2c565b60048633148833141715911417179961014061060982611cd6565b9261104a61101e856000526002602052604060002090565b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016610100179055565b60405193845273ffffffffffffffffffffffffffffffffffffffff9081169416929081906020820190565b0390a301610f6d565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519060a0820182811067ffffffffffffffff8211176110ce57604052565b6110d661107e565b604052565b604051906020820182811067ffffffffffffffff8211176110ce57604052565b604051906040820182811067ffffffffffffffff8211176110ce57604052565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f604051930116820182811067ffffffffffffffff8211176110ce57604052565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f60209267ffffffffffffffff811161119b575b01160190565b6111a361107e565b611195565b6111b06110fb565b90602082526020828136910137565b356107ad8161064b565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156101c3570180359067ffffffffffffffff82116101c3576020019181360383136101c357565b959392919094611228614f64565b61123061155f565b6101643561014435428211154282111761154b57505061020435610264351061153d5793907f00000000000000000000000000000000000000000000000000000000000000006080528060a0526060602460c037604060646101203760e06080908120610160526001610264359081016102a060059290921b918201526102c081019283526024906102e00137610160948360a0528460c052600060e05260009260005b83610204358210156113315790604060019261010060a060208560061b9a818c610284018537858c61028401610120376102a48c0135179d019860e06080208a5201988a8a528b60c08401526102840191013701969392966112d4565b5096509192979690976001610204350160051b610160206060525b836102643588101561138957906102a460a060019301958787528860c082015260408a60061b91610100836102840191013701351796019561134c565b50925095945095925073ffffffffffffffffffffffffffffffffffffffff91501161152f576107ad91611528917f00000000000000000000000000000000000000000000000000000000000000006080528060a052606060c460c03760206101046101203760c0608020600052602060002060e05260016102643560051b610200015261022090816102643560051b0152606060c46102406102643560051b013761036060843561145a8173ffffffffffffffffffffffffffffffffffffffff166000526001602052604060002090565b54967f00000000000000000000000000000000000000000000000000000000000000006080526040608460a037606051610100526101205260a0610144610140376101e09687526101809687608020976102643560051b0191888352336101a06102643560051b015260806101c06102643560051b0152610120826102643560051b01527f9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f3160a06102643502938460a435940190a360006060526102643560051b01016040528101906111c9565b9083614323565b6339f3e3fd6000526004601cfd5b63466aa6166000526004601cfd5b6321ccfeb76000526020526040526044601cfd5b7401000000000000000000000000000000000000000060243560c4351760a43560843517171060186101243510166102643560061b61026001610244351461024061022435146020600435141616161561152f57565b608435916101043560e43560c4358315611627579461067695604051957f4ce34aa200000000000000000000000000000000000000000000000000000000875260206004880152600160248801526044870152606486015260848501523360a485015260c484015260e483015261223e565b925092806116366002926106a8565b0361166057928360016106769503611651575b503391614fc1565b61165a90611d31565b38611649565b91906106769333916150a0565b3460643560006102643560061b815b8181106116bd575050508181116116b0575b61169a81608435611d62565b8082116116a5575050565b610676910333611d62565b6116b8611d22565b61168e565b806102840135948086116116e657906116e08660409303966102a4830135611d62565b0161167c565b638ffff98084526004601cfd5b507f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9190820391821161173057565b6106766116f3565b919082156117d95760843592610104353360c43560e4355b6117cc575b8360051b6101e40335936102643560061b9060005b82811061177f57505050956106769596611dae565b87876102848301358c856117ab575b918493916117a5936102a46040970135908a611dae565b0161176a565b9891816117bf60409695936117a595611723565b9a9193509193945061178e565b6117d4611d53565b611755565b3392606435608435602435604435611750565b60209067ffffffffffffffff8111611806575b60051b0190565b61180e61107e565b6117ff565b906108d2929163ffffffff9161182f8360043516600401611bf5565b926118408160243516600401611a2d565b6118606118538360443516600401611b44565b9260643516600401611b44565b923381150201946126d4565b90604051610200810160405260806118c68294604060208201602086013760a084018085526118a563ffffffff918284351684016118f5565b6118b68160608401351683016118cb565b60608601528382013516016118cb565b910152565b9060206040519263ffffffff813563ffffffe0601f82011692848401908737168452830101604052565b6118c660609161016081853763ffffffff611917816040840135168301611927565b604086015283820135160161197a565b90641fffffffe082359263ffffffff841660405194818652602093849160051b168601019283928160a0809402910185378086015b83811061196c5750505050604052565b84815293820193810161195c565b90641fffffffe082359263ffffffff841660405194818652602093849160051b168601019283928160c0809402910185378086015b8381106119bf5750505050604052565b8481529382019381016119af565b906040516102008101604052611a13819360a083018084526119f963ffffffff918284351684016118f5565b6001602085015260016040850152602082013516016118cb565b606082015260806040519160208301604052600083520152565b803591600592641fffffffe081851b16604080519060209384848401018252829663ffffffff809216845260005b858110611a6e5750505050505050909150565b8083888093850101351683018551908360a091828401895287608093848484018737820135160101908d60018884351601901b8851928184018a52833782015282828801015201611a5b565b908135641fffffffe08160051b166040805160209384848301018352819663ffffffff809216835260005b858110611af55750505050505050565b808388809385010135168301611b34838851928984016101a085018b52611b2581848b81860135168501016118f5565b8452878a8201351601016118cb565b8382015282828701015201611ae5565b90813591641fffffffe08360051b166040516020928383830101604052819563ffffffff809116835260005b848110611b7f57505050505050565b80611b9587848180958801013516860101611ba1565b82828701015201611b70565b90813591604080519363ffffffff81168552602080641fffffffe08360051b168701019381643fffffffc0869460061b16910185378086015b828110611be75750505052565b848152938301938101611bda565b90813591641fffffffe08360051b166040516020928383830101604052819563ffffffff809116835260005b848110611c3057505050505050565b80611c468784818095880101351686010161186c565b82828701015201611c21565b908135641fffffffe08160051b166040805160209384848301018352819663ffffffff809216835260005b858110611c8d5750505050505050565b808388809385010135168301611cc6838851928984018a52611cb782898184013516830101611ba1565b8452878a820135160101611ba1565b8382015282828701015201611c7d565b9060405161016081016040528092611d16610140918281853763ffffffff611d05816040840135168301611927565b60408601526060820135160161197a565b80606084015251910152565b50638ffff9806000526004601cfd5b6369f958276000526020526024601cfd5b63a61be9f06000526020526024601cfd5b50636ab37ce76000526004601cfd5b611d6b82611d99565b600080808085855af115611d7d575050565b611d85612681565b63bc806b966000526020526040526044601cfd5b15611da057565b6391b3e5146000526004601cfd5b929193949094611dbd83611d99565b611dc781836120f2565b80611ef0575050604051926000947f23b872dd00000000000000000000000000000000000000000000000000000000865280600452816024528260445260208660648180885af1803d15601f3d1160018a51141617163d1515811615611e36575b505050505050604052606052565b80863b151516611e2857908795969115611e5b5786635f15d67287526020526024601cfd5b959192939515611e80575063988919238594526020526040526060526080526084601cfd5b3d611ea3575b5063f486bc87845260205260405260605260805260a05260a4601cfd5b601f3d0160051c9060051c908060030291808211611ed7575b505060205a910110611ece5785611e86565b833d81803e3d90fd5b8080600392028380020360091c92030201018680611ebc565b906106769592949391612359565b919395909294611f0e81836120f2565b80611f375750508460016106769603611f28575b50614fc1565b611f3190611d31565b38611f22565b815160649693959394929190602003611fec5760c0906001906040845260208401527f4ce34aa20000000000000000000000000000000000000000000000000000000060408401526020604484015280888401525b02019360027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc48601527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe48501526004840152602483015260448201520152565b5060c08682016001815101809152611f8c565b95909192939461200e86611d99565b61201881836120f2565b80612028575050610676946150a0565b90606495969493929160208251146000146120df5760c0906001906040845260208401527f4ce34aa20000000000000000000000000000000000000000000000000000000060408401526020604484015280888401525b02019360037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc48601527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe48501526004840152602483015260448201520152565b5060c0868201600181510180915261207f565b906020820151036121005750565b610676905b90604082510361223a5760208201519160c06064820151026044019260405193602073ffffffffffffffffffffffffffffffffffffffff6000928184927f00000000000000000000000000000000000000000000000000000000000000001674ff00000000000000000000000000000000000000001783528584527f00000000000000000000000000000000000000000000000000000000000000006040526055600b2016976040528180526040860182895af190805191156122215750937f4ce34aa2000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000060209596160361221557505052565b61221e91612345565b52565b63d13d53d48691612230612681565b526020526024601cfd5b9050565b9060405190602073ffffffffffffffffffffffffffffffffffffffff6101046000938285937f00000000000000000000000000000000000000000000000000000000000000001674ff00000000000000000000000000000000000000001784528785527f00000000000000000000000000000000000000000000000000000000000000006040526055600b20169560405282805282865af1908051911561233657507fffffffff000000000000000000000000000000000000000000000000000000007f4ce34aa20000000000000000000000000000000000000000000000000000000091160361232d575050565b61067691612345565b63d13d53d49150612230612681565b631cf99b266000526020526040526044601cfd5b9060649492939160208251146000146124105760c0906001906040845260208401527f4ce34aa20000000000000000000000000000000000000000000000000000000060408401526020604484015280878401525b02019260017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc48501527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe484015260048301526024820152600060448201520152565b5060c085820160018151018091526123ae565b91909161014081018051917f0000000000000000000000000000000000000000000000000000000000000000604051604083018051928351926020809501906000915b868684106125665750505050506040519160051b8220917f00000000000000000000000000000000000000000000000000000000000000009093606086019481865101906000915b8a83106125245750505050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08660051b604051209401978851907f00000000000000000000000000000000000000000000000000000000000000008a5282519383528451958552865261018089209852525252565b8380827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0600194510180519089815260e08120875252019201920191906124ae565b80827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0600194510180519088815260c0812087525201920192019190612466565b6000467f0000000000000000000000000000000000000000000000000000000000000000036125f557507f000000000000000000000000000000000000000000000000000000000000000090565b60405190608051907f000000000000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006020527f0000000000000000000000000000000000000000000000000000000000000000604052466060523060805260a081209260405260605260805290565b3d61268857565b601f3d0160051c60405160051c9080600302918082116126bb575b505060205a9101106126b157565b3d6000803e3d6000fd5b8080600392028380020360091c920302010138806126a3565b93959480939297956126e692866129aa565b93909187519681516127006126fb828b612e96565b613337565b9860009a8b905b8282106127cb5750506000925b8284106127575750505050509461273b949587829861274c575b5081511561273f576136eb565b9190565b61274761339a565b6136eb565b82510382523861272e565b909192939a8a6127738361276c8f8990612988565b5189613417565b61278c8180516080602082511515930151910151141690565b156127a65750506001809101945b019291909a939a612714565b86916127c5916127be85886001979b01038093612988565b528d612988565b5061279a565b90949b6127e7896127e0888598969798612988565b51896133a9565b8c6128018280516080602082511515930151910151141690565b1561281d5750506001809101955b01909b949b93929193612707565b879161283a91846001959a03916128348383612988565b52612988565b5061280f565b6128486110ae565b90604051610160810181811067ffffffffffffffff8211176128c7575b604052600080825280602083015260609182604082015282808201528160808201528160a08201528160c08201528160e08201528161010082015281610120820152816101408201528452806020850152604084015280808401526080830152565b6128cf61107e565b612865565b6128dc6110fb565b600181529060203681840137565b906128fc6128f7836117ec565b61111b565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061292a82946117ec565b0190602036910137565b600511156106b257565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60209080511561297c570190565b61298461293e565b0190565b602091815181101561299d575b60051b010190565b6129a561293e565b612995565b9391936000936129b8614f73565b6000357c400000000000000000000000000000000000000000000000000000000016926129e3612840565b508251936129f0856128ea565b9760205b6001870160051b8110612ac6575050907c4000000000000000000000000000000000000000000000000000000001612a329214612ab9575b83612fb7565b60205b6001840160051b8110612a485750505050565b6020816001928901518015612ab357612aab90828701515186612a7f825173ffffffffffffffffffffffffffffffffffffffff1690565b8287015173ffffffffffffffffffffffffffffffffffffffff165b906060604085015194015194614248565b019050612a35565b50612aab565b612ac1612f94565b612a2c565b808601518215612c5557612ad98161467e565b918d82969215612c42578501527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019382519260a08401519360c08101519060408101519e8f519160800151612b2e81612934565b60048110600052600110179e60005b828110612bd757505050606080925101519485519560005b878110612b6e5750505050505050506020905b016129f4565b80878760a0612b7f60019587612988565b51612bb789898c6080850196612b9788518a83612f61565b9186019889519089518214600014612bc7575050508088525b8751612eef565b8094520190815190525201612b55565b612bd092612f61565b8852612bb0565b8087612be560019385612988565b519c8d600051905110179c612c28878c60808401938c6060612c0987518984612f61565b92019687519087518214600014612c32575050508086525b8551612ea3565b8092525201612b3d565b612c3b92612f61565b8652612c21565b5050935050906000602080930152612b68565b906000602080930152612b68565b939193600093612c71614f73565b6000357c40000000000000000000000000000000000000000000000000000000001692612c9c612840565b50825193612ca9856128ea565b9760205b6001870160051b8110612d45575050907c4000000000000000000000000000000000000000000000000000000001612cea9214612ab95783612fb7565b60205b6001840160051b8110612d005750505050565b6020816001928901518015612d3f57612d3790828701515186612a7f825173ffffffffffffffffffffffffffffffffffffffff1690565b019050612ced565b50612d37565b808601518215612e7557612d588161442a565b918d82969215612e62578501527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019382519260a08401519360c08101519060408101519e8f519160800151612dad81612934565b60048110600052600110179e60005b828110612e2657505050606080925101519485519560005b878110612ded5750505050505050506020905b01612cad565b80878760a0612dfe60019587612988565b51612e1689898c6080850196612b9788518a83612f61565b8094520190815190525201612dd4565b8087612e3460019385612988565b519c8d600051905110179c612e58878c60808401938c6060612c0987518984612f61565b8092525201612dbc565b5050935050906000602080930152612de7565b906000602080930152612de7565b8181029291811591840414171561173057565b9190820180921161173057565b929092838103612eb35750505090565b612ec983612ecf93039342039182850390612e83565b93612e83565b8201809211612ee2575b81049015150290565b612eea6116f3565b612ed9565b919092838303612eff5750505090565b600192612f1883612f1e93039342039182850390612e83565b94612e83565b8301809311612f54575b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff830104019015150290565b612f5c6116f3565b612f28565b919091828114612f8e5782818309612f8057612f7c91612e83565b0490565b63c63cf0896000526004601cfd5b50905090565b506312d3f5a36000526004601cfd5b600211156106b257565b516107ad816106a8565b815181519260005b8281106130c05750505060005b828110612fd857505050565b612fe28183612988565b5161301661300260208301516effffffffffffffffffffffffffffff1690565b6effffffffffffffffffffffffffffff1690565b156130b75751606081018051519060005b828110613089575050506040018051519060005b82811061304f575050506001905b01612fcc565b8061306f6130696130636001948651612988565b51612fad565b60031090565b61307a575b0161303b565b61308481866131ba565b613074565b8061309d6130696130636001948651612988565b6130a8575b01613027565b6130b281876131a6565b6130a2565b50600190613049565b6130ca8183612988565b516130df81518781101561317a575b86612988565b51602090613101613002838301516effffffffffffffffffffffffffffff1690565b1561316f57519060409081830151918401519263bfb3f8ce9185015161312681612fa3565b61312f81612fa3565b61315c575b50815183101561315357509161314d91600194936131d7565b01612fbf565b6000526004601cfd5b9050606091500151636088d7de38613134565b50505060019061314d565b613190602084015161318b81612fa3565b613195565b6130d9565b63133c37c66000526020526024601cfd5b63a8930e9a6000526020526040526044601cfd5b63d69293326000526020526040526044601cfd5b61221e826106a8565b906131e191612988565b518051916131ee836106a8565b600383111561324d5761322e8260046040606095019586518015156000146132345761322490878701519060808801519161326a565b14600303906131ce565b01519052565b50608085015151156132245761324861325b565b613224565b6394eb6af66000526004601cfd5b506309bde3396000526004601cfd5b916000928352602090818420918082019181815191600592831b0101905b8184106132a857505050500361329b5750565b6309bde33990526004601cfd5b8351808611821b95865294831894909452604086209392820192613288565b6132cf6110ae565b906000825260006020830152600060408301526000606083015260006080830152565b604051906060820182811067ffffffffffffffff82111761332a575b604052600060408361331e6132c7565b81528260208201520152565b61333261107e565b61330e565b906133446128f7836117ec565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061337282946117ec565b019060005b82811061338357505050565b60209061338e6132f2565b82828501015201613377565b5063d5da9a1b6000526004601cfd5b929190926133b56132f2565b9380511561340457846133e79181519373ffffffffffffffffffffffffffffffffffffffff6080860196168652613499565b6060810151156133f5575050565b60006001928160208701525252565b63375c24c160005260006020526024601cfd5b929190926134236132f2565b938051156134635784613438918151936135e0565b60208401913383526040850152606081015115613453575050565b6000600192526000608082015252565b63375c24c160005260016020526024601cfd5b50637fda72796000526004601cfd5b50634e487b7160005260116020526024601cfd5b9092919260009081928290828351905b8160051b850181106134d857505050505060608293945101526134c95750565b600114611da057610676613485565b6020909695960190602082515184518110156135d3575b60051b8401015180519060208451015160206040840151920151158251821015176135c8579060209160051b0101519660609081890151998a81019a15908b1060011b171798976000828201528b51871560011461357b57502085189060408b0151610120820151189060208c0151905118171761356e575b906134a9565b613576613476565b613568565b929061012092949750806040915185526020810151602086015201516040840152805160208d0152015160408b01522092602085018281186135be575b50613568565b82519052386135b8565b505050959495613568565b6135db613476565b6134ef565b9092919260009081928291808051600590811b82015b8084106136125750505050505060608293945101526134c95750565b6020979697809401938085515187518110156136de575b841b8701015190808651015191606092828483510151920151158251821015176136d2576000918391871b010151928301998a519b8c81019c15908d1060011b17179a99528b51881560011461369257505060a0902086146135f65761368d613476565b6135f6565b8251815281830151818301526040808401519082015260808084015191015260a0909120965083018481186136c8575b506135f6565b84519052386136c2565b505050509695966135f6565b6136e6613476565b613629565b9092938151936136fa856128ea565b956137036111a8565b9180519060005b8281106138ce5750505060005b8681106137a957505061372990612105565b4780613799575b50613743575b5050506107ad6001600055565b60005b8381106137535750613736565b8061376961376360019388612988565b51151590565b613774575b01613746565b6137946137818285612988565b518561378d8482612988565b5191615ac1565b61376e565b6137a39033611d62565b38613730565b6137b38186612988565b516137d361300260208301516effffffffffffffffffffffffffffff1690565b156138b8576137eb6137e5838b612988565b60019052565b51604081015180519060005b82811061385b575050506060809101519081519160005b83811061382357505050506001905b01613717565b8061383060019284612988565b5160a08582019182518061384a575b50015190520161380e565b61385590858b61395a565b3861383f565b8061386860019284612988565b51608060608201918251613881575b01519052016137f7565b6138b38b61388f8c84613948565b8a5173ffffffffffffffffffffffffffffffffffffffff166101208c015191613971565b613877565b508060006138c86001938b612988565b5261381d565b80613929866138df60019486612988565b5180519081516138ee816106a8565b6138f7816106a8565b1561392f575b6040613920602083015173ffffffffffffffffffffffffffffffffffffffff1690565b91015191613971565b0161370a565b47606083015111156138fd57613943611d22565b6138fd565b91906139526132c7565b506080830152565b63a5f542086000526020526040526060526064601cfd5b929190835161397f816106a8565b613988816106a8565b613a2b57505050806139d06139b7602061067694015173ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff6040830151911617613a1e575b6060613a15608083015173ffffffffffffffffffffffffffffffffffffffff1690565b91015190611d62565b613a26611d53565b6139f2565b60018451613a38816106a8565b613a41816106a8565b03613ac15792610676936040820151613ab4575b602082015173ffffffffffffffffffffffffffffffffffffffff169073ffffffffffffffffffffffffffffffffffffffff6060613aa9608086015173ffffffffffffffffffffffffffffffffffffffff1690565b940151931691611dae565b613abc611d53565b613a55565b60028451613ace816106a8565b613ad7816106a8565b03613b445783613b01602061067696015173ffffffffffffffffffffffffffffffffffffffff1690565b608082015173ffffffffffffffffffffffffffffffffffffffff169273ffffffffffffffffffffffffffffffffffffffff60606040850151940151941691611efe565b83613b69602061067696015173ffffffffffffffffffffffffffffffffffffffff1690565b608082015173ffffffffffffffffffffffffffffffffffffffff169273ffffffffffffffffffffffffffffffffffffffff60606040850151940151941691611fff565b9193929081613bbe9184519085612c63565b9190805160051b604001937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082018051907f4b9f2d36e1b4c93de62cc077b00b1a91d84b6c31b4a14e012718dcca230689e760209788835282a152865196613c2588613337565b9560009889915b818310613c5a575050505093613c4b9487829798613c4f575b506136eb565b5090565b825103825238613c45565b9091929988613c7b85613c6d818f612988565b518581519101519089613cd0565b613c948180516080602082511515930151910151141690565b15613cad5750506001809101935b019190999299613c2c565b8591613cca91613cc38560019699038093612988565b528b612988565b50613ca2565b909192613cdb6132f2565b938351158015613ec5575b613eb8575b613cf36132f2565b90613cff8282866135e0565b81519460609384870193845115613e98575092859288836107ad9996613d2c8360809a97613e2f9c613499565b613d368351612fad565b613d3f816106a8565b885190613d4b826106a8565b613d54826106a8565b60ff85519273ffffffffffffffffffffffffffffffffffffffff8c604080613d966139b760208a015173ffffffffffffffffffffffffffffffffffffffff1690565b613dba6139b7602086015173ffffffffffffffffffffffffffffffffffffffff1690565b189701519101511894169218161717613e89575b50835182518601511015613e4f57505090602083613e03613df1613e109561296e565b5193518c518301518551910397612988565b5151015191015190612988565b5101525b015173ffffffffffffffffffffffffffffffffffffffff1690565b60808351019073ffffffffffffffffffffffffffffffffffffffff169052565b8495939492509060206040613e0385613e6a613e7b9661296e565b519451015188518551910397612988565b510152519086510152613e14565b613e9290613ece565b38613dce565b9750505050505050608060009182602085015201526107ad815160019052565b613ec0613edf565b613ceb565b50805115613ce6565b63bced929d6000526020526024601cfd5b506398e9db6e6000526004601cfd5b613ef66110fb565b90600182528160005b60209081811015613f2157602091613f15612840565b90828501015201613eff565b505050565b92613fc0613f8c92613ff895613f5660046080835101516005811015614007575b613f5081612934565b14614f82565b613f9e84613f638361442a565b9098829a9296613f71613eee565b96613f7b8861296e565b52613f858761296e565b5086612fb7565b613f958561296e565b51519889614014565b613fba613fa96128d4565b9183613fb48461296e565b5261296e565b51615ac1565b815173ffffffffffffffffffffffffffffffffffffffff16602083015173ffffffffffffffffffffffffffffffffffffffff16612a9a565b6140026001600055565b600190565b61400f610678565b613f47565b60a08082015160c083015197969095939161402d6111a8565b9689604086019384515190600095865b8c898d86841061412d57505050505050505060809260048487015161406181612934565b1016614120575b6060809501968751519760005b8981106140a45750505050505050505050614091919250612105565b478061409a5750565b6106769033611d62565b806141008c8f8b8b8b8f936140d5908c8c6140c260019c8e51612988565b51968701958651958801958651906141d6565b8092528b830151905281516140e9816106a8565b6140f2816106a8565b15614106575b503390613971565b01614075565b4710614113575b386140f8565b61411b611d22565b61410d565b614128612f94565b614068565b99856141949392869798999c61416f6141498860019a51612988565b51948551614156816106a8565b15179e8d6060870193845195608089019687519061419f565b9052528c610120613920825173ffffffffffffffffffffffffffffffffffffffff1690565b01908d93929161403d565b9093908481036141b55750506107ad9350612f61565b93836141ca6107ad97966141d0949686612f61565b93612f61565b90612ea3565b9093908481036141ec5750506107ad9350612f61565b93836141ca6107ad9796614201949686612f61565b90612eef565b90815180825260208080930193019160005b828110614227575050505090565b909192938260a08261423c60019489516106ba565b01950193929101614219565b929094939160409182519460809182870191875273ffffffffffffffffffffffffffffffffffffffff94856020921682890152838189015286518093528160a089019701936000915b8483106142df5750505050505082828594936142da93867f9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f31989603606087015216971695614207565b0390a3565b90919293949784836001928b5180516142f7816106a8565b8252808401518c1684830152858101518683015260609081015190820152019901959493019190614291565b9092916000938285526002602052604085209283549260ff8460081c16614405576effffffffffffffffffffffffffffff8460101c166143f45760ff84161561438a575b505071010000000000000000000000000000010001909255509091506106769050565b6143966128f78261115f565b9281845236828201116143f0579262010001949261067697986020846143e8957fffffffffffffffffffffffffffffff00000000000000000000000000000000009883870137840101526084356151af565b918594614367565b8780fd5b5063ee9e0e6386526020526024601cfd5b50631a51557486526020526024601cfd5b90805b614421575090565b80910680614419565b80519061444361099960a084015160c08501519061519a565b614671576effffffffffffffffffffffffffffff92602092848484015116938560408501511693608083016004815161447b81612934565b61448481612934565b1461463e57861586881117614631575b519161449f83612934565b60018093161586881016614624575b6144b784614778565b976144cc896000526002602052604060002090565b946144da610999878c615906565b614615578554938a60ff8616156145e1575b5050508260881c8481159061450e575b505050508460881b9060101b17179055565b98979893909192936145d15760101c82168885146145bd5781891461459f578882910297029702958701968688118789030280910397039181871182841117614559575b80806144fc565b9095919661457061456a848a614416565b82614416565b8015018080920498049204958087119083111761458d5780614552565b601190634e487b71600052526024601cfd5b925050508495940194848611858703028091039503388080806144fc565b9397509550505083039383388080806144fc565b50505050839493388080806144fc565b606061460461460d945173ffffffffffffffffffffffffffffffffffffffff1690565b920151916151af565b38808a6144ec565b50600097508796505050505050565b61462c6147e4565b6144ae565b6146396147d5565b614494565b50919360809396506001915061465d950218614664575b0151906147f3565b9192909190565b61466c6147d5565b614655565b5050600090600090600090565b80519061469b61099960a084015160c08501514210904210151690565b614671576effffffffffffffffffffffffffffff9260209284848401511693856040850151169360808301600481516146d381612934565b6146dc81612934565b1461474c5786158688111761473f575b51916146f783612934565b60018093161586881016614732575b61470f84614778565b97614724896000526002602052604060002090565b946144da610999878c615969565b61473a6147e4565b614706565b6147476147d5565b6146ec565b50919360809396506001915061465d95021861476b575b0151906149b2565b6147736147d5565b614763565b6060810151516101408201511161153d57806147cf73ffffffffffffffffffffffffffffffffffffffff6107ad93511673ffffffffffffffffffffffffffffffffffffffff16600052600160205260406000205490565b90612423565b50635a052b326000526004601cfd5b5063a11b63ff6000526004601cfd5b6060906040828201805151610140840151036149a5575b60008061483561482e865173ffffffffffffffffffffffffffffffffffffffff1690565b9786614b81565b9082895af1936148658673ffffffffffffffffffffffffffffffffffffffff166000526003602052604060002090565b958654906001978883019055821b189415614997575b614883615de3565b9490919586614989575b018051518251811161497b575b6000905b89818310614945575050505281519083519180518311614937575b91906000925b888385106148e4575050505050526148d657918190565b6148df81614c6d565b918190565b90919293966148f38884612988565b5161492b6149018a8a612988565b518681015187840151106149158285614c8d565b179260a080910151910151908091149015171590565b171796019291906148bf565b61494087614c6d565b6148b9565b909197614953898551612988565b516149716149618b88612988565b5188830151898201511092614c8d565b171797019061489e565b61498488614c6d565b61489a565b61499288614c6d565b61488d565b6149a085614c6d565b61487b565b6149ad614c7e565b61480a565b60609081810180515161014083015103614b19575b6149ef6149e8835173ffffffffffffffffffffffffffffffffffffffff1690565b9483614b81565b9060008092819282895af193614a258673ffffffffffffffffffffffffffffffffffffffff166000526003602052604060002090565b958654906001978883019055821b189415614b0f579060409291614a47615de3565b9590919687614b01575b0180515182518111614af3575b84905b8a818310614acd5750505052825184519281518411614abf575b9291905b88838510614a96575050505050526148d657918190565b9091929396614aa58884612988565b51614ab36149018a8a612988565b17179601929190614a7f565b614ac888614c6d565b614a7b565b909198614adb8a8551612988565b51614ae96149618c88612988565b1717980190614a61565b614afc89614c6d565b614a5e565b614b0a89614c6d565b614a51565b5093505050918190565b614b21614c7e565b6149c7565b91909160408051936020928360e083028701018352818652839160010160051b92838701915b848410614b5b57505050505050565b60c060a0879285878c01528460808083893e606083019088013e01930193019291614b4c565b9190608490614be8604051916398919765835260a0601c84019633602086015260806040860152614bd46060614bbe604084015185890190614c12565b9283608001828901520151838388010190614c12565b018094608082016080820152010190614bed565b010190565b8051603f0163ffffffe0169291610676918491905b829060045afa153d15176101c357565b9081519081815260209283808083019301918460051b0101915b84838210614c3f575050505060071b0190565b8160809251805185528281015183860152604080820151908601526060809101519085015201910190614c2c565b63939792856000526020526024601cfd5b50632165628a6000526004601cfd5b90815191604081015180156003851116614cca575b6020809160608401516080850151149060408601511416948451149301519101511416161590565b506040820151600490931460030392614ca2565b9190811015614d1f575b60051b810135907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffea1813603018212156101c3570190565b614d2761293e565b614ce8565b3560058110156101c35790565b5063fed398fc6000526004601cfd5b90815180825260208080930193019160005b828110614d68575050505090565b909192938260a060019287518051614d7f816106a8565b82528084015173ffffffffffffffffffffffffffffffffffffffff168483015260408082015190830152606080820151908301526080908101519082015201950193929101614d5a565b90815180825260208080930193019160005b828110614de9575050505090565b909192938260c060019287518051614e00816106a8565b82528084015173ffffffffffffffffffffffffffffffffffffffff9081168584015260408083015190840152606080830151908401526080808301519084015260a091820151169082015201950193929101614ddb565b906005821015614e645752565b61221e610678565b90815260406020820152614e9960408201835173ffffffffffffffffffffffffffffffffffffffff169052565b602082015173ffffffffffffffffffffffffffffffffffffffff1660608201526101806040830151614f10614edc610160928360808701526101a0860190614d48565b60608601517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08683030160a0870152614dc9565b93614f23608082015160c0860190614e57565b60a081015160e085015260c081015191610100928386015260e082015192610120938487015282015192610140938487015282015190850152015191015290565b614f6c614f92565b6002600055565b614f7b614f92565b6003600055565b614f8a614f92565b600201600055565b600160005403614f9e57565b637fa8a9876000526004601cfd5b600360005403614fb857565b61067634611d42565b929091833b1561508e57604051926000947f23b872dd000000000000000000000000000000000000000000000000000000008652816004528260245283604452858060648180855af11561501b5750505050604052606052565b85853d615042575b5063f486bc879052602052604052606052608052600160a05260a4601cfd5b601f3d0160051c9060051c908060030291808211615075575b505060205a91011061506d5785615023565b3d81803e3d90fd5b8080600392028380020360091c9203020101868061505b565b83635f15d6726000526020526024601cfd5b9392919091843b1561518857604051936080519160a0519360c051956000987ff242432a000000000000000000000000000000000000000000000000000000008a528160045282602452836044528460645260a06084528960a452898060c48180855af11561511f57505050505060805260a05260c052604052606052565b89893d615144575b5063f486bc87905260205260405260605260805260a05260a4601cfd5b601f3d0160051c9060051c90806003029180821161516f575b505060205a91011061506d5786615127565b8080600392028380020360091c9203020101878061515d565b84635f15d6726000526020526024601cfd5b9190428111428411151692831561154b575050565b929190338414615330576151c16125a7565b936151fe82867f19010000000000000000000000000000000000000000000000000000000000006000526002526022526042600020906000602252565b908351926002601f601d860116106102e27fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9d860110166000146153225760018085169081604103927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf600593880101831c93808952880160209384820151928560238560e81c94019460e31c1690815285845191185283925b868410615302575050505050966152fc9161067697986152bb60406000209261552a565b600052526040600020907f19010000000000000000000000000000000000000000000000000000000000006000526002526022526042600020906000602252565b90615336565b85859101938684821c841b16604060002081528786519118520192615297565b506106769495508190615336565b50509050565b909291926000948580528051957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0820180519188604103908091600181119687156154c0575b5050508514851515169788156153b2575b50505050505050501561539c57565b6153a4612681565b634f7fb80d6000526004601cfd5b909192939495809798508452604082527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc8401938451957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08201976020600060648b519c7f1626ba7e000000000000000000000000000000000000000000000000000000009e8f8c528d520189845afa9a8b61545e575b5050505050525252388080808080808061538d565b6000510361546c5780615449565b3b6153a4576154b257606001906041640101000000835160001a1a1591141661549d5763815e1d646000526004601cfd5b631f003d0a6000525160001a6020526024601cfd5b638baa579f6000526004601cfd5b9091925060408601908151926060880151851a906154f8575b8752845260208360808660015afa508484528a8652525138808061537c565b50601b8360ff1c017f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841683526154d9565b600981106157c2576011811061567e57601581106155e057601781106155955760177f403be09941a31d05cfc2f896505811353d45d38743288b016630cce39435476a9114027f1d51df90cba8de7637ca3e8fe1e3511d1dc2f23487d05dbdecb781860c21ac1c1890565b60157fbb40bf8cea3a5a716e2b6eb08bbdac8ec159f82f380783db3c56904f15a43d049114027f3bd8cff538aba49a9c374c806d277181e9651624b3e31111bc0624574f8bca1d1890565b601381106156335760137f54b3212a178782f104e0d514b41a9a5c4ca9c980bf6597c3cecbf280917e202a9114027f5a4f867d3d458dabecad65f6201ceeaba0096df2d0c491cc32e6ea4e643500171890565b60117f2d7a3ed6dab270fdb8e054b2ad525f0ce2a8b89cc76c17f0965434740f673a559114027fc3939feff011e53ab8c35ca3370aad54c5df1fc2938cd62543174fa6e7d858771890565b600d811061572457600f81106156d957600f7fcc4886e37eedd9aacd6c1c2c9247197a621a71282e87a7cbc673f3736d9aa1419114027f1da3eed3ecef6ebaa6e5023c057ec2c75150693fd0dac5c90f4a142f9879fde81890565b600d7f8df51df98847160517f5b1186b4bc3f418d98b8a7f17f1292f392d79d600d79e9114027f6b5b04cbae4fcb1a9d78e7b2dfc51a36933d023cf6e347e03d517b472a8525901890565b600b811061577757600b7f32f4e7485d6485f9f6c255929b9905c62ba919758bbe231f231eaeecf33d810c9114027fbb98d87cc12922b83759626c5f07d72266da9702d19ffad6a514c73a89002f5f1890565b60097f6f0ec38c21f6f583ab7f3c5413c773ffd5344c34fde1d390958e438bf667448f9114027fd1d97d1ef5eaa37a4ee5fbf234e6f6d64eb511eb562221cd7edfbdde0848da051890565b60058110615868576007811061581d5760077fb58d772fb09b426b9dece637f61ca9065f2b994f1464b51e9207f55f7c8f59489114027f7ff98d9d4e55d876c5cfac10b43c04039522f3ddfb0ea9bfe70c68cfb5c7cc141890565b60057f25d02425402d882d211a7ab774c0ed6eca048c4d03d9af40132475744753b2a39114027f1c19f71958cdd8f081b4c31f7caf5c010b29d12950be2fa1c95070dc47e30b551890565b600381106158bb5760037ff3e8417a785f980bdaf134fa0274a6bf891eeb8195cd94b09d2aa651046e28bc9114027fa02eb7ff164c884e5e2c336dc85f81c6a93329d8e9adf214b32729b894de2af11890565b60017f832c58a5b611aadcfa6a082ac9d04bace53d8278387f10040347b7e98eb5b3029114027fbf8e29b89f29ed9b529c154a63038ffca562f8d7cd1e2545dda53a1b582dde301890565b905460ff8160081c16615957576effffffffffffffffffffffffffffff8160101c169081615937575b505050600190565b60881c1115615948575b808061592f565b615951906159d1565b38615941565b50631a5155746000526020526024601cfd5b906000905460ff8160081c166159c8576effffffffffffffffffffffffffffff8160101c16908161599e575b50505050600190565b60881c11156159ae578080615995565b6159b9575b50600090565b6159c2906159d1565b386159b3565b50905050600090565b6310fda3e16000526020526024601cfd5b9190608082019081356159f48161064b565b3314159060046001821191101616615a0b57505050565b61067692615a396139b76060604051956317b1f94287526020808801528460408801523382880152016111bf565b6080840152606061014461012085013761014060a08401526101e060c0840152615abc601c61032461026435615a8560a08202918261016001906101808a019060051b61020001614c02565b6102a0810160e08801528461032082890160006102e08201526102c084016101008b015260016103008201520152019401926111bf565b615d27565b919082519060808201918251926005841015615b7c575b615b09602083019473ffffffffffffffffffffffffffffffffffffffff865116331415906004600182119110161690565b15615b31575090615b239160806106769601519085615c0d565b91519263fb5014fc93615d8f565b60049194935051615b4181612934565b615b4a81612934565b03615b765761067693615b6a9184519460808660601b9301519085615b89565b91639397928593615d8f565b50505050565b615b84610678565b615ad8565b9493919260c060a494615bf9614be8946040519663f4dd92ce8852601c88019a1860a088015260a06020880152615be36060615bcc6040840151878b0190614c12565b928360a00160408b0152015185838a010190615cdf565b019160a083016060880152838388010190614bed565b01809460a082016080820152010190615cc3565b9392614be8906101649392604051936317b1f9428552601c85019760208087015260408601523360608601528151608086015260a082015161012086015260c082015190610140918287015260e08301516101608701528160a0870152615cb3604084015193615c9e6060615c8861018097888c0190614c12565b9283870160c08c0152015186838b010190615cdf565b019183830160e0890152848389010190614bed565b0194859182016101008201520101905b612984602092839283815180845260051b948593019101614c02565b8051908183526020928380808401938560051b01019101915b818110615d095750505060a0020190565b60a090818481835160045afa153d15176101c3578501920191615cf8565b6020909391937fffffffff00000000000000000000000000000000000000000000000000000000845116926000948580938180525af1908251149015615d805715615d70575050565b63fb5014fc90526020526024601cfd5b5063fb5014fc90612230612681565b602090949391947fffffffff00000000000000000000000000000000000000000000000000000000845116926000948580938180525af1908251149015615dda571561223057505050565b50612230612681565b60009081906080803d109060009081908280918515615e86575b8515615e0e575b5050505050929190565b91939750919550602094939480920196604051918360c08302840101604052818352839160010160051b98898401905b8a8410615e635750505050615e5893949596509501614b26565b913880808080615e04565b60a083879284878901528181863e60608501518286015201920193019290615e3e565b9450909150604081803e5190602051913d81113d8411179485615dfd5794508093506020915060003e60005191602082813e602051903d8260a0028560071b0186011161ffff83861711179460008052615dfd565b908135641fffffffe08160051b169060405191602091828285010160405263ffffffff809116845260005b828110615f165750929450505050565b80615f2c85848180958c010135168a01016119cd565b82828801015201615f0656fea164736f6c6343000811000a00000000000000000000000000000000f9490004c11cef243f5400493c00ad63
Deployed Bytecode
0x60806040526004361015610023575b361561001957600080fd5b610021614fac565b005b60003560e01c80156100eb57806306fdde031461016957806346423aa7146101605780635b34b9661461015757806379df72bd1461014e57806387201b4114610145578063881477321461013c578063a817440414610133578063a900866b1461012a578063b3a34c4c14610121578063e7acab2414610118578063ed98a5741461010f578063f07ec37314610106578063f2d12b12146100fd578063f47b7740146100f4578063fb0f3ee1146100eb5763fd9f1e100361000e576100e6610f50565b61000e565b506100e66101c8565b506100e6610ec8565b506100e6610df2565b506100e6610d8a565b506100e6610cc2565b506100e6610c05565b506100e6610b81565b506100e6610b17565b506100e6610a60565b506100e66108d6565b506100e66107c6565b506100e661059d565b506100e66104f5565b506100e6610474565b506100e661042e565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc906020828201126101c3576004359167ffffffffffffffff83116101c35782610240920301126101c35760040190565b600080fd5b506101d236610172565b6101243590600382169160021c91600183119234158403610420575b60038111907f0203020301010000000000000000000000000000000000000000000000000000811a9061024c8260a0850260240135887d010102030000000000000000000000000000000000000000000000000000851a888a61121a565b928060051b6101c4013596610260816106a8565b6102b3575050604435602435176102a55761028b9461027e916115b5565b61028661166d565b6159e2565b6102956001600055565b60405160018152602090f35b0390f35b636ab37ce76000526004601cfd5b610286925061028b969161032a916102c96111a8565b9384836102d682956106a8565b6002810361032f5750610325918a6102f060a082016111bf565b6102fc606083016111bf565b60c060e08401359301359173ffffffffffffffffffffffffffffffffffffffff33921690611efe565b611738565b612105565b610338816106a8565b600381036103875750610325918a61035260a082016111bf565b61035e606083016111bf565b60c060e08401359301359173ffffffffffffffffffffffffffffffffffffffff33921690611fff565b806103936004926106a8565b036103dc57610325918a6103a6816111bf565b6103b2606083016111bf565b9073ffffffffffffffffffffffffffffffffffffffff602060408501359401359216903390611efe565b610325918a6103ea816111bf565b6103f6606083016111bf565b9073ffffffffffffffffffffffffffffffffffffffff602060408501359401359216903390611fff565b61042934611d42565b6101ee565b50346101c35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c357602080526707536561706f727460475260606020f35b50346101c35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c357600435600052600260205260806040600020546040519060ff81161515825260ff8160081c16151560208301526effffffffffffffffffffffffffffff8160101c16604083015260881c6060820152f35b50346101c35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c35761052d614f92565b3360005260016020526020604060002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff43014060801c018091556040518181527f721c20121297512b72821b97f5326877ea8ecf4bb9948fea5bfcb6453074d37f833392a2604051908152f35b50346101c3577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6020813601126101c3576004359067ffffffffffffffff82116101c3576101609082360301126101c35761061263ffffffff6020921661014461060982600401611cd6565b91013590612423565b604051908152f35b9181601f840112156101c35782359167ffffffffffffffff83116101c3576020808501948460051b0101116101c357565b73ffffffffffffffffffffffffffffffffffffffff8116036101c357565b60a435906106768261064b565b565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600611156106b257565b610676610678565b60809080516106c8816106a8565b83528173ffffffffffffffffffffffffffffffffffffffff918260208201511660208601526040810151604086015260608101516060860152015116910152565b90815180825260208080930193019160005b828110610729575050505090565b909192938260e0600192604088516107428382516106ba565b8085015173ffffffffffffffffffffffffffffffffffffffff1660a0840152015160c08201520195019392910161071b565b9092916040820191604081528451809352606081019260208096019060005b8181106107b0575050506107ad9394818403910152610709565b90565b8251151586529487019491870191600101610793565b5060e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c35767ffffffffffffffff6004358181116101c35761081290369060040161061a565b50506024358181116101c35761082c90369060040161061a565b50506044358181116101c35761084690369060040161061a565b50506064359081116101c35761086090369060040161061a565b505061087961086d610669565b60c43590608435611813565b906102a160405192839283610774565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126101c3576004359067ffffffffffffffff82116101c3576108d29160040161061a565b9091565b50346101c3576108e536610889565b505060046108fb63ffffffff8235168201611aba565b90610904614f92565b81519060005b82811061091d5760405160018152602090f35b8061092a60019286612988565b51805184608082015161093c81612934565b61094581612934565b14610a4857805173ffffffffffffffffffffffffffffffffffffffff1661096b82614778565b90610980826000526002602052604060002090565b61098a8184615906565b5061099d610999825460ff1690565b1590565b6109ae575b50505050505b0161090a565b6109f4610a1f928460207ff280791efe782edcf06ce15c8f4dff17601db3b88eb3805a0db7d77faf757f04986060890151516101408a015103610a3b575b0151916151af565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b610a2e60405192839283614e6c565b0390a138808080806109a2565b610a43614c7e565b6109ec565b50506109a8565b9060206107ad928181520190610709565b5060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c35760043567ffffffffffffffff8082116101c357610aab368360040161061a565b50506024359081116101c3576102a191610b0391610acc368260040161061a565b5050610afb610ae463ffffffff809416600401615edb565b92610aed6110db565b926000845216600401611c52565b903392613bac565b604051918291602083526020830190610709565b50346101c35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c35773ffffffffffffffffffffffffffffffffffffffff600435610b688161064b565b1660005260036020526020604060002054604051908152f35b507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6040813601126101c3576004359067ffffffffffffffff82116101c35760409082360301126101c357610bfb610be363ffffffff602093166004016119cd565b610beb6110db565b9060008252339160243591613f26565b6040519015158152f35b507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6080813601126101c3576004359067ffffffffffffffff908183116101c35760a09083360301126101c3576024359081116101c3576102a191610cb091610c71368260040161061a565b5050610ca060643592610c838461064b565b610c9663ffffffff80921660040161186c565b9216600401611a2d565b9133811502019160443591613f26565b60405190151581529081906020820190565b5060a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c357600467ffffffffffffffff81358181116101c357610d0d3682850161061a565b5050602435908282116101c357610d263683860161061a565b50506044359283116101c357610d7b61087994610d453686830161061a565b5050610d5963ffffffff8094168201615edb565b92610d7381610d666110db565b9660008852168301611b44565b951601611b44565b608435933393606435936126d4565b50346101c35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c3576020610612600435610dcb8161064b565b73ffffffffffffffffffffffffffffffffffffffff16600052600160205260406000205490565b5060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c35767ffffffffffffffff600480358281116101c357610e3d3682840161061a565b5050602435908382116101c357610e563683850161061a565b50506044359384116101c3576102a193610eb0610ebc94610e793684830161061a565b5050610e9f610ea860643595610e8e8761064b565b63ffffffff92838092168501611bf5565b97168301611a2d565b931601611c52565b91338115020192613bac565b60405191829182610a4f565b50346101c35760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101c357610f006125a7565b606060005260205273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000f9490004c11cef243f5400493c00ad63166040526303312e3460635260a06000f35b50346101c357610f5f36610889565b90610f68614f92565b600091825b818110610f925783610f855760405160018152602090f35b610f8d614d39565b610295565b80610fa06001928486614cde565b94610faa866111bf565b907f6bacc01dbe442496068f7d234edd811f1a5f833243e0aec824f86ab861f3c90d611075611006610fde60208b016111bf565b93610feb60808c01614d2c565b60048633148833141715911417179961014061060982611cd6565b9261104a61101e856000526002602052604060002090565b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016610100179055565b60405193845273ffffffffffffffffffffffffffffffffffffffff9081169416929081906020820190565b0390a301610f6d565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519060a0820182811067ffffffffffffffff8211176110ce57604052565b6110d661107e565b604052565b604051906020820182811067ffffffffffffffff8211176110ce57604052565b604051906040820182811067ffffffffffffffff8211176110ce57604052565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f604051930116820182811067ffffffffffffffff8211176110ce57604052565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f60209267ffffffffffffffff811161119b575b01160190565b6111a361107e565b611195565b6111b06110fb565b90602082526020828136910137565b356107ad8161064b565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156101c3570180359067ffffffffffffffff82116101c3576020019181360383136101c357565b959392919094611228614f64565b61123061155f565b6101643561014435428211154282111761154b57505061020435610264351061153d5793907f42d81c6929ffdc4eb27a0808e40e82516ad42296c166065de7f812492304ff6e6080528060a0526060602460c037604060646101203760e06080908120610160526001610264359081016102a060059290921b918201526102c081019283526024906102e00137610160948360a0528460c052600060e05260009260005b83610204358210156113315790604060019261010060a060208560061b9a818c610284018537858c61028401610120376102a48c0135179d019860e06080208a5201988a8a528b60c08401526102840191013701969392966112d4565b5096509192979690976001610204350160051b610160206060525b836102643588101561138957906102a460a060019301958787528860c082015260408a60061b91610100836102840191013701351796019561134c565b50925095945095925073ffffffffffffffffffffffffffffffffffffffff91501161152f576107ad91611528917fa66999307ad1bb4fde44d13a5d710bd7718e0c87c1eef68a571629fbf5b93d026080528060a052606060c460c03760206101046101203760c0608020600052602060002060e05260016102643560051b610200015261022090816102643560051b0152606060c46102406102643560051b013761036060843561145a8173ffffffffffffffffffffffffffffffffffffffff166000526001602052604060002090565b54967ffa445660b7e21515a59617fcd68910b487aa5808b8abda3d78bc85df364b2c2f6080526040608460a037606051610100526101205260a0610144610140376101e09687526101809687608020976102643560051b0191888352336101a06102643560051b015260806101c06102643560051b0152610120826102643560051b01527f9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f3160a06102643502938460a435940190a360006060526102643560051b01016040528101906111c9565b9083614323565b6339f3e3fd6000526004601cfd5b63466aa6166000526004601cfd5b6321ccfeb76000526020526040526044601cfd5b7401000000000000000000000000000000000000000060243560c4351760a43560843517171060186101243510166102643560061b61026001610244351461024061022435146020600435141616161561152f57565b608435916101043560e43560c4358315611627579461067695604051957f4ce34aa200000000000000000000000000000000000000000000000000000000875260206004880152600160248801526044870152606486015260848501523360a485015260c484015260e483015261223e565b925092806116366002926106a8565b0361166057928360016106769503611651575b503391614fc1565b61165a90611d31565b38611649565b91906106769333916150a0565b3460643560006102643560061b815b8181106116bd575050508181116116b0575b61169a81608435611d62565b8082116116a5575050565b610676910333611d62565b6116b8611d22565b61168e565b806102840135948086116116e657906116e08660409303966102a4830135611d62565b0161167c565b638ffff98084526004601cfd5b507f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9190820391821161173057565b6106766116f3565b919082156117d95760843592610104353360c43560e4355b6117cc575b8360051b6101e40335936102643560061b9060005b82811061177f57505050956106769596611dae565b87876102848301358c856117ab575b918493916117a5936102a46040970135908a611dae565b0161176a565b9891816117bf60409695936117a595611723565b9a9193509193945061178e565b6117d4611d53565b611755565b3392606435608435602435604435611750565b60209067ffffffffffffffff8111611806575b60051b0190565b61180e61107e565b6117ff565b906108d2929163ffffffff9161182f8360043516600401611bf5565b926118408160243516600401611a2d565b6118606118538360443516600401611b44565b9260643516600401611b44565b923381150201946126d4565b90604051610200810160405260806118c68294604060208201602086013760a084018085526118a563ffffffff918284351684016118f5565b6118b68160608401351683016118cb565b60608601528382013516016118cb565b910152565b9060206040519263ffffffff813563ffffffe0601f82011692848401908737168452830101604052565b6118c660609161016081853763ffffffff611917816040840135168301611927565b604086015283820135160161197a565b90641fffffffe082359263ffffffff841660405194818652602093849160051b168601019283928160a0809402910185378086015b83811061196c5750505050604052565b84815293820193810161195c565b90641fffffffe082359263ffffffff841660405194818652602093849160051b168601019283928160c0809402910185378086015b8381106119bf5750505050604052565b8481529382019381016119af565b906040516102008101604052611a13819360a083018084526119f963ffffffff918284351684016118f5565b6001602085015260016040850152602082013516016118cb565b606082015260806040519160208301604052600083520152565b803591600592641fffffffe081851b16604080519060209384848401018252829663ffffffff809216845260005b858110611a6e5750505050505050909150565b8083888093850101351683018551908360a091828401895287608093848484018737820135160101908d60018884351601901b8851928184018a52833782015282828801015201611a5b565b908135641fffffffe08160051b166040805160209384848301018352819663ffffffff809216835260005b858110611af55750505050505050565b808388809385010135168301611b34838851928984016101a085018b52611b2581848b81860135168501016118f5565b8452878a8201351601016118cb565b8382015282828701015201611ae5565b90813591641fffffffe08360051b166040516020928383830101604052819563ffffffff809116835260005b848110611b7f57505050505050565b80611b9587848180958801013516860101611ba1565b82828701015201611b70565b90813591604080519363ffffffff81168552602080641fffffffe08360051b168701019381643fffffffc0869460061b16910185378086015b828110611be75750505052565b848152938301938101611bda565b90813591641fffffffe08360051b166040516020928383830101604052819563ffffffff809116835260005b848110611c3057505050505050565b80611c468784818095880101351686010161186c565b82828701015201611c21565b908135641fffffffe08160051b166040805160209384848301018352819663ffffffff809216835260005b858110611c8d5750505050505050565b808388809385010135168301611cc6838851928984018a52611cb782898184013516830101611ba1565b8452878a820135160101611ba1565b8382015282828701015201611c7d565b9060405161016081016040528092611d16610140918281853763ffffffff611d05816040840135168301611927565b60408601526060820135160161197a565b80606084015251910152565b50638ffff9806000526004601cfd5b6369f958276000526020526024601cfd5b63a61be9f06000526020526024601cfd5b50636ab37ce76000526004601cfd5b611d6b82611d99565b600080808085855af115611d7d575050565b611d85612681565b63bc806b966000526020526040526044601cfd5b15611da057565b6391b3e5146000526004601cfd5b929193949094611dbd83611d99565b611dc781836120f2565b80611ef0575050604051926000947f23b872dd00000000000000000000000000000000000000000000000000000000865280600452816024528260445260208660648180885af1803d15601f3d1160018a51141617163d1515811615611e36575b505050505050604052606052565b80863b151516611e2857908795969115611e5b5786635f15d67287526020526024601cfd5b959192939515611e80575063988919238594526020526040526060526080526084601cfd5b3d611ea3575b5063f486bc87845260205260405260605260805260a05260a4601cfd5b601f3d0160051c9060051c908060030291808211611ed7575b505060205a910110611ece5785611e86565b833d81803e3d90fd5b8080600392028380020360091c92030201018680611ebc565b906106769592949391612359565b919395909294611f0e81836120f2565b80611f375750508460016106769603611f28575b50614fc1565b611f3190611d31565b38611f22565b815160649693959394929190602003611fec5760c0906001906040845260208401527f4ce34aa20000000000000000000000000000000000000000000000000000000060408401526020604484015280888401525b02019360027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc48601527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe48501526004840152602483015260448201520152565b5060c08682016001815101809152611f8c565b95909192939461200e86611d99565b61201881836120f2565b80612028575050610676946150a0565b90606495969493929160208251146000146120df5760c0906001906040845260208401527f4ce34aa20000000000000000000000000000000000000000000000000000000060408401526020604484015280888401525b02019360037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc48601527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe48501526004840152602483015260448201520152565b5060c0868201600181510180915261207f565b906020820151036121005750565b610676905b90604082510361223a5760208201519160c06064820151026044019260405193602073ffffffffffffffffffffffffffffffffffffffff6000928184927f00000000000000000000000000000000f9490004c11cef243f5400493c00ad631674ff00000000000000000000000000000000000000001783528584527f023d904f2503c37127200ca07b976c3a53cc562623f67023115bf311f58050596040526055600b2016976040528180526040860182895af190805191156122215750937f4ce34aa2000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000060209596160361221557505052565b61221e91612345565b52565b63d13d53d48691612230612681565b526020526024601cfd5b9050565b9060405190602073ffffffffffffffffffffffffffffffffffffffff6101046000938285937f00000000000000000000000000000000f9490004c11cef243f5400493c00ad631674ff00000000000000000000000000000000000000001784528785527f023d904f2503c37127200ca07b976c3a53cc562623f67023115bf311f58050596040526055600b20169560405282805282865af1908051911561233657507fffffffff000000000000000000000000000000000000000000000000000000007f4ce34aa20000000000000000000000000000000000000000000000000000000091160361232d575050565b61067691612345565b63d13d53d49150612230612681565b631cf99b266000526020526040526044601cfd5b9060649492939160208251146000146124105760c0906001906040845260208401527f4ce34aa20000000000000000000000000000000000000000000000000000000060408401526020604484015280878401525b02019260017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc48501527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe484015260048301526024820152600060448201520152565b5060c085820160018151018091526123ae565b91909161014081018051917fa66999307ad1bb4fde44d13a5d710bd7718e0c87c1eef68a571629fbf5b93d02604051604083018051928351926020809501906000915b868684106125665750505050506040519160051b8220917f42d81c6929ffdc4eb27a0808e40e82516ad42296c166065de7f812492304ff6e9093606086019481865101906000915b8a83106125245750505050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08660051b604051209401978851907ffa445660b7e21515a59617fcd68910b487aa5808b8abda3d78bc85df364b2c2f8a5282519383528451958552865261018089209852525252565b8380827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0600194510180519089815260e08120875252019201920191906124ae565b80827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0600194510180519088815260c0812087525201920192019190612466565b6000467f0000000000000000000000000000000000000000000000000000000000000001036125f557507f276bc64a43ff20d362b6c982bc21d1f83716496363478990aa0bbaa99044923a90565b60405190608051907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f32b5c112df393a49218d7552f96b2eeb829dfb4272f4f24eef510a586b85feef6020527f996eb83fe7b4a46fd8cc5be6a9370a3780cc7673130cba9dcaafe9f664b0c71c604052466060523060805260a081209260405260605260805290565b3d61268857565b601f3d0160051c60405160051c9080600302918082116126bb575b505060205a9101106126b157565b3d6000803e3d6000fd5b8080600392028380020360091c920302010138806126a3565b93959480939297956126e692866129aa565b93909187519681516127006126fb828b612e96565b613337565b9860009a8b905b8282106127cb5750506000925b8284106127575750505050509461273b949587829861274c575b5081511561273f576136eb565b9190565b61274761339a565b6136eb565b82510382523861272e565b909192939a8a6127738361276c8f8990612988565b5189613417565b61278c8180516080602082511515930151910151141690565b156127a65750506001809101945b019291909a939a612714565b86916127c5916127be85886001979b01038093612988565b528d612988565b5061279a565b90949b6127e7896127e0888598969798612988565b51896133a9565b8c6128018280516080602082511515930151910151141690565b1561281d5750506001809101955b01909b949b93929193612707565b879161283a91846001959a03916128348383612988565b52612988565b5061280f565b6128486110ae565b90604051610160810181811067ffffffffffffffff8211176128c7575b604052600080825280602083015260609182604082015282808201528160808201528160a08201528160c08201528160e08201528161010082015281610120820152816101408201528452806020850152604084015280808401526080830152565b6128cf61107e565b612865565b6128dc6110fb565b600181529060203681840137565b906128fc6128f7836117ec565b61111b565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061292a82946117ec565b0190602036910137565b600511156106b257565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60209080511561297c570190565b61298461293e565b0190565b602091815181101561299d575b60051b010190565b6129a561293e565b612995565b9391936000936129b8614f73565b6000357c400000000000000000000000000000000000000000000000000000000016926129e3612840565b508251936129f0856128ea565b9760205b6001870160051b8110612ac6575050907c4000000000000000000000000000000000000000000000000000000001612a329214612ab9575b83612fb7565b60205b6001840160051b8110612a485750505050565b6020816001928901518015612ab357612aab90828701515186612a7f825173ffffffffffffffffffffffffffffffffffffffff1690565b8287015173ffffffffffffffffffffffffffffffffffffffff165b906060604085015194015194614248565b019050612a35565b50612aab565b612ac1612f94565b612a2c565b808601518215612c5557612ad98161467e565b918d82969215612c42578501527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019382519260a08401519360c08101519060408101519e8f519160800151612b2e81612934565b60048110600052600110179e60005b828110612bd757505050606080925101519485519560005b878110612b6e5750505050505050506020905b016129f4565b80878760a0612b7f60019587612988565b51612bb789898c6080850196612b9788518a83612f61565b9186019889519089518214600014612bc7575050508088525b8751612eef565b8094520190815190525201612b55565b612bd092612f61565b8852612bb0565b8087612be560019385612988565b519c8d600051905110179c612c28878c60808401938c6060612c0987518984612f61565b92019687519087518214600014612c32575050508086525b8551612ea3565b8092525201612b3d565b612c3b92612f61565b8652612c21565b5050935050906000602080930152612b68565b906000602080930152612b68565b939193600093612c71614f73565b6000357c40000000000000000000000000000000000000000000000000000000001692612c9c612840565b50825193612ca9856128ea565b9760205b6001870160051b8110612d45575050907c4000000000000000000000000000000000000000000000000000000001612cea9214612ab95783612fb7565b60205b6001840160051b8110612d005750505050565b6020816001928901518015612d3f57612d3790828701515186612a7f825173ffffffffffffffffffffffffffffffffffffffff1690565b019050612ced565b50612d37565b808601518215612e7557612d588161442a565b918d82969215612e62578501527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019382519260a08401519360c08101519060408101519e8f519160800151612dad81612934565b60048110600052600110179e60005b828110612e2657505050606080925101519485519560005b878110612ded5750505050505050506020905b01612cad565b80878760a0612dfe60019587612988565b51612e1689898c6080850196612b9788518a83612f61565b8094520190815190525201612dd4565b8087612e3460019385612988565b519c8d600051905110179c612e58878c60808401938c6060612c0987518984612f61565b8092525201612dbc565b5050935050906000602080930152612de7565b906000602080930152612de7565b8181029291811591840414171561173057565b9190820180921161173057565b929092838103612eb35750505090565b612ec983612ecf93039342039182850390612e83565b93612e83565b8201809211612ee2575b81049015150290565b612eea6116f3565b612ed9565b919092838303612eff5750505090565b600192612f1883612f1e93039342039182850390612e83565b94612e83565b8301809311612f54575b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff830104019015150290565b612f5c6116f3565b612f28565b919091828114612f8e5782818309612f8057612f7c91612e83565b0490565b63c63cf0896000526004601cfd5b50905090565b506312d3f5a36000526004601cfd5b600211156106b257565b516107ad816106a8565b815181519260005b8281106130c05750505060005b828110612fd857505050565b612fe28183612988565b5161301661300260208301516effffffffffffffffffffffffffffff1690565b6effffffffffffffffffffffffffffff1690565b156130b75751606081018051519060005b828110613089575050506040018051519060005b82811061304f575050506001905b01612fcc565b8061306f6130696130636001948651612988565b51612fad565b60031090565b61307a575b0161303b565b61308481866131ba565b613074565b8061309d6130696130636001948651612988565b6130a8575b01613027565b6130b281876131a6565b6130a2565b50600190613049565b6130ca8183612988565b516130df81518781101561317a575b86612988565b51602090613101613002838301516effffffffffffffffffffffffffffff1690565b1561316f57519060409081830151918401519263bfb3f8ce9185015161312681612fa3565b61312f81612fa3565b61315c575b50815183101561315357509161314d91600194936131d7565b01612fbf565b6000526004601cfd5b9050606091500151636088d7de38613134565b50505060019061314d565b613190602084015161318b81612fa3565b613195565b6130d9565b63133c37c66000526020526024601cfd5b63a8930e9a6000526020526040526044601cfd5b63d69293326000526020526040526044601cfd5b61221e826106a8565b906131e191612988565b518051916131ee836106a8565b600383111561324d5761322e8260046040606095019586518015156000146132345761322490878701519060808801519161326a565b14600303906131ce565b01519052565b50608085015151156132245761324861325b565b613224565b6394eb6af66000526004601cfd5b506309bde3396000526004601cfd5b916000928352602090818420918082019181815191600592831b0101905b8184106132a857505050500361329b5750565b6309bde33990526004601cfd5b8351808611821b95865294831894909452604086209392820192613288565b6132cf6110ae565b906000825260006020830152600060408301526000606083015260006080830152565b604051906060820182811067ffffffffffffffff82111761332a575b604052600060408361331e6132c7565b81528260208201520152565b61333261107e565b61330e565b906133446128f7836117ec565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061337282946117ec565b019060005b82811061338357505050565b60209061338e6132f2565b82828501015201613377565b5063d5da9a1b6000526004601cfd5b929190926133b56132f2565b9380511561340457846133e79181519373ffffffffffffffffffffffffffffffffffffffff6080860196168652613499565b6060810151156133f5575050565b60006001928160208701525252565b63375c24c160005260006020526024601cfd5b929190926134236132f2565b938051156134635784613438918151936135e0565b60208401913383526040850152606081015115613453575050565b6000600192526000608082015252565b63375c24c160005260016020526024601cfd5b50637fda72796000526004601cfd5b50634e487b7160005260116020526024601cfd5b9092919260009081928290828351905b8160051b850181106134d857505050505060608293945101526134c95750565b600114611da057610676613485565b6020909695960190602082515184518110156135d3575b60051b8401015180519060208451015160206040840151920151158251821015176135c8579060209160051b0101519660609081890151998a81019a15908b1060011b171798976000828201528b51871560011461357b57502085189060408b0151610120820151189060208c0151905118171761356e575b906134a9565b613576613476565b613568565b929061012092949750806040915185526020810151602086015201516040840152805160208d0152015160408b01522092602085018281186135be575b50613568565b82519052386135b8565b505050959495613568565b6135db613476565b6134ef565b9092919260009081928291808051600590811b82015b8084106136125750505050505060608293945101526134c95750565b6020979697809401938085515187518110156136de575b841b8701015190808651015191606092828483510151920151158251821015176136d2576000918391871b010151928301998a519b8c81019c15908d1060011b17179a99528b51881560011461369257505060a0902086146135f65761368d613476565b6135f6565b8251815281830151818301526040808401519082015260808084015191015260a0909120965083018481186136c8575b506135f6565b84519052386136c2565b505050509695966135f6565b6136e6613476565b613629565b9092938151936136fa856128ea565b956137036111a8565b9180519060005b8281106138ce5750505060005b8681106137a957505061372990612105565b4780613799575b50613743575b5050506107ad6001600055565b60005b8381106137535750613736565b8061376961376360019388612988565b51151590565b613774575b01613746565b6137946137818285612988565b518561378d8482612988565b5191615ac1565b61376e565b6137a39033611d62565b38613730565b6137b38186612988565b516137d361300260208301516effffffffffffffffffffffffffffff1690565b156138b8576137eb6137e5838b612988565b60019052565b51604081015180519060005b82811061385b575050506060809101519081519160005b83811061382357505050506001905b01613717565b8061383060019284612988565b5160a08582019182518061384a575b50015190520161380e565b61385590858b61395a565b3861383f565b8061386860019284612988565b51608060608201918251613881575b01519052016137f7565b6138b38b61388f8c84613948565b8a5173ffffffffffffffffffffffffffffffffffffffff166101208c015191613971565b613877565b508060006138c86001938b612988565b5261381d565b80613929866138df60019486612988565b5180519081516138ee816106a8565b6138f7816106a8565b1561392f575b6040613920602083015173ffffffffffffffffffffffffffffffffffffffff1690565b91015191613971565b0161370a565b47606083015111156138fd57613943611d22565b6138fd565b91906139526132c7565b506080830152565b63a5f542086000526020526040526060526064601cfd5b929190835161397f816106a8565b613988816106a8565b613a2b57505050806139d06139b7602061067694015173ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff6040830151911617613a1e575b6060613a15608083015173ffffffffffffffffffffffffffffffffffffffff1690565b91015190611d62565b613a26611d53565b6139f2565b60018451613a38816106a8565b613a41816106a8565b03613ac15792610676936040820151613ab4575b602082015173ffffffffffffffffffffffffffffffffffffffff169073ffffffffffffffffffffffffffffffffffffffff6060613aa9608086015173ffffffffffffffffffffffffffffffffffffffff1690565b940151931691611dae565b613abc611d53565b613a55565b60028451613ace816106a8565b613ad7816106a8565b03613b445783613b01602061067696015173ffffffffffffffffffffffffffffffffffffffff1690565b608082015173ffffffffffffffffffffffffffffffffffffffff169273ffffffffffffffffffffffffffffffffffffffff60606040850151940151941691611efe565b83613b69602061067696015173ffffffffffffffffffffffffffffffffffffffff1690565b608082015173ffffffffffffffffffffffffffffffffffffffff169273ffffffffffffffffffffffffffffffffffffffff60606040850151940151941691611fff565b9193929081613bbe9184519085612c63565b9190805160051b604001937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082018051907f4b9f2d36e1b4c93de62cc077b00b1a91d84b6c31b4a14e012718dcca230689e760209788835282a152865196613c2588613337565b9560009889915b818310613c5a575050505093613c4b9487829798613c4f575b506136eb565b5090565b825103825238613c45565b9091929988613c7b85613c6d818f612988565b518581519101519089613cd0565b613c948180516080602082511515930151910151141690565b15613cad5750506001809101935b019190999299613c2c565b8591613cca91613cc38560019699038093612988565b528b612988565b50613ca2565b909192613cdb6132f2565b938351158015613ec5575b613eb8575b613cf36132f2565b90613cff8282866135e0565b81519460609384870193845115613e98575092859288836107ad9996613d2c8360809a97613e2f9c613499565b613d368351612fad565b613d3f816106a8565b885190613d4b826106a8565b613d54826106a8565b60ff85519273ffffffffffffffffffffffffffffffffffffffff8c604080613d966139b760208a015173ffffffffffffffffffffffffffffffffffffffff1690565b613dba6139b7602086015173ffffffffffffffffffffffffffffffffffffffff1690565b189701519101511894169218161717613e89575b50835182518601511015613e4f57505090602083613e03613df1613e109561296e565b5193518c518301518551910397612988565b5151015191015190612988565b5101525b015173ffffffffffffffffffffffffffffffffffffffff1690565b60808351019073ffffffffffffffffffffffffffffffffffffffff169052565b8495939492509060206040613e0385613e6a613e7b9661296e565b519451015188518551910397612988565b510152519086510152613e14565b613e9290613ece565b38613dce565b9750505050505050608060009182602085015201526107ad815160019052565b613ec0613edf565b613ceb565b50805115613ce6565b63bced929d6000526020526024601cfd5b506398e9db6e6000526004601cfd5b613ef66110fb565b90600182528160005b60209081811015613f2157602091613f15612840565b90828501015201613eff565b505050565b92613fc0613f8c92613ff895613f5660046080835101516005811015614007575b613f5081612934565b14614f82565b613f9e84613f638361442a565b9098829a9296613f71613eee565b96613f7b8861296e565b52613f858761296e565b5086612fb7565b613f958561296e565b51519889614014565b613fba613fa96128d4565b9183613fb48461296e565b5261296e565b51615ac1565b815173ffffffffffffffffffffffffffffffffffffffff16602083015173ffffffffffffffffffffffffffffffffffffffff16612a9a565b6140026001600055565b600190565b61400f610678565b613f47565b60a08082015160c083015197969095939161402d6111a8565b9689604086019384515190600095865b8c898d86841061412d57505050505050505060809260048487015161406181612934565b1016614120575b6060809501968751519760005b8981106140a45750505050505050505050614091919250612105565b478061409a5750565b6106769033611d62565b806141008c8f8b8b8b8f936140d5908c8c6140c260019c8e51612988565b51968701958651958801958651906141d6565b8092528b830151905281516140e9816106a8565b6140f2816106a8565b15614106575b503390613971565b01614075565b4710614113575b386140f8565b61411b611d22565b61410d565b614128612f94565b614068565b99856141949392869798999c61416f6141498860019a51612988565b51948551614156816106a8565b15179e8d6060870193845195608089019687519061419f565b9052528c610120613920825173ffffffffffffffffffffffffffffffffffffffff1690565b01908d93929161403d565b9093908481036141b55750506107ad9350612f61565b93836141ca6107ad97966141d0949686612f61565b93612f61565b90612ea3565b9093908481036141ec5750506107ad9350612f61565b93836141ca6107ad9796614201949686612f61565b90612eef565b90815180825260208080930193019160005b828110614227575050505090565b909192938260a08261423c60019489516106ba565b01950193929101614219565b929094939160409182519460809182870191875273ffffffffffffffffffffffffffffffffffffffff94856020921682890152838189015286518093528160a089019701936000915b8483106142df5750505050505082828594936142da93867f9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f31989603606087015216971695614207565b0390a3565b90919293949784836001928b5180516142f7816106a8565b8252808401518c1684830152858101518683015260609081015190820152019901959493019190614291565b9092916000938285526002602052604085209283549260ff8460081c16614405576effffffffffffffffffffffffffffff8460101c166143f45760ff84161561438a575b505071010000000000000000000000000000010001909255509091506106769050565b6143966128f78261115f565b9281845236828201116143f0579262010001949261067697986020846143e8957fffffffffffffffffffffffffffffff00000000000000000000000000000000009883870137840101526084356151af565b918594614367565b8780fd5b5063ee9e0e6386526020526024601cfd5b50631a51557486526020526024601cfd5b90805b614421575090565b80910680614419565b80519061444361099960a084015160c08501519061519a565b614671576effffffffffffffffffffffffffffff92602092848484015116938560408501511693608083016004815161447b81612934565b61448481612934565b1461463e57861586881117614631575b519161449f83612934565b60018093161586881016614624575b6144b784614778565b976144cc896000526002602052604060002090565b946144da610999878c615906565b614615578554938a60ff8616156145e1575b5050508260881c8481159061450e575b505050508460881b9060101b17179055565b98979893909192936145d15760101c82168885146145bd5781891461459f578882910297029702958701968688118789030280910397039181871182841117614559575b80806144fc565b9095919661457061456a848a614416565b82614416565b8015018080920498049204958087119083111761458d5780614552565b601190634e487b71600052526024601cfd5b925050508495940194848611858703028091039503388080806144fc565b9397509550505083039383388080806144fc565b50505050839493388080806144fc565b606061460461460d945173ffffffffffffffffffffffffffffffffffffffff1690565b920151916151af565b38808a6144ec565b50600097508796505050505050565b61462c6147e4565b6144ae565b6146396147d5565b614494565b50919360809396506001915061465d950218614664575b0151906147f3565b9192909190565b61466c6147d5565b614655565b5050600090600090600090565b80519061469b61099960a084015160c08501514210904210151690565b614671576effffffffffffffffffffffffffffff9260209284848401511693856040850151169360808301600481516146d381612934565b6146dc81612934565b1461474c5786158688111761473f575b51916146f783612934565b60018093161586881016614732575b61470f84614778565b97614724896000526002602052604060002090565b946144da610999878c615969565b61473a6147e4565b614706565b6147476147d5565b6146ec565b50919360809396506001915061465d95021861476b575b0151906149b2565b6147736147d5565b614763565b6060810151516101408201511161153d57806147cf73ffffffffffffffffffffffffffffffffffffffff6107ad93511673ffffffffffffffffffffffffffffffffffffffff16600052600160205260406000205490565b90612423565b50635a052b326000526004601cfd5b5063a11b63ff6000526004601cfd5b6060906040828201805151610140840151036149a5575b60008061483561482e865173ffffffffffffffffffffffffffffffffffffffff1690565b9786614b81565b9082895af1936148658673ffffffffffffffffffffffffffffffffffffffff166000526003602052604060002090565b958654906001978883019055821b189415614997575b614883615de3565b9490919586614989575b018051518251811161497b575b6000905b89818310614945575050505281519083519180518311614937575b91906000925b888385106148e4575050505050526148d657918190565b6148df81614c6d565b918190565b90919293966148f38884612988565b5161492b6149018a8a612988565b518681015187840151106149158285614c8d565b179260a080910151910151908091149015171590565b171796019291906148bf565b61494087614c6d565b6148b9565b909197614953898551612988565b516149716149618b88612988565b5188830151898201511092614c8d565b171797019061489e565b61498488614c6d565b61489a565b61499288614c6d565b61488d565b6149a085614c6d565b61487b565b6149ad614c7e565b61480a565b60609081810180515161014083015103614b19575b6149ef6149e8835173ffffffffffffffffffffffffffffffffffffffff1690565b9483614b81565b9060008092819282895af193614a258673ffffffffffffffffffffffffffffffffffffffff166000526003602052604060002090565b958654906001978883019055821b189415614b0f579060409291614a47615de3565b9590919687614b01575b0180515182518111614af3575b84905b8a818310614acd5750505052825184519281518411614abf575b9291905b88838510614a96575050505050526148d657918190565b9091929396614aa58884612988565b51614ab36149018a8a612988565b17179601929190614a7f565b614ac888614c6d565b614a7b565b909198614adb8a8551612988565b51614ae96149618c88612988565b1717980190614a61565b614afc89614c6d565b614a5e565b614b0a89614c6d565b614a51565b5093505050918190565b614b21614c7e565b6149c7565b91909160408051936020928360e083028701018352818652839160010160051b92838701915b848410614b5b57505050505050565b60c060a0879285878c01528460808083893e606083019088013e01930193019291614b4c565b9190608490614be8604051916398919765835260a0601c84019633602086015260806040860152614bd46060614bbe604084015185890190614c12565b9283608001828901520151838388010190614c12565b018094608082016080820152010190614bed565b010190565b8051603f0163ffffffe0169291610676918491905b829060045afa153d15176101c357565b9081519081815260209283808083019301918460051b0101915b84838210614c3f575050505060071b0190565b8160809251805185528281015183860152604080820151908601526060809101519085015201910190614c2c565b63939792856000526020526024601cfd5b50632165628a6000526004601cfd5b90815191604081015180156003851116614cca575b6020809160608401516080850151149060408601511416948451149301519101511416161590565b506040820151600490931460030392614ca2565b9190811015614d1f575b60051b810135907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffea1813603018212156101c3570190565b614d2761293e565b614ce8565b3560058110156101c35790565b5063fed398fc6000526004601cfd5b90815180825260208080930193019160005b828110614d68575050505090565b909192938260a060019287518051614d7f816106a8565b82528084015173ffffffffffffffffffffffffffffffffffffffff168483015260408082015190830152606080820151908301526080908101519082015201950193929101614d5a565b90815180825260208080930193019160005b828110614de9575050505090565b909192938260c060019287518051614e00816106a8565b82528084015173ffffffffffffffffffffffffffffffffffffffff9081168584015260408083015190840152606080830151908401526080808301519084015260a091820151169082015201950193929101614ddb565b906005821015614e645752565b61221e610678565b90815260406020820152614e9960408201835173ffffffffffffffffffffffffffffffffffffffff169052565b602082015173ffffffffffffffffffffffffffffffffffffffff1660608201526101806040830151614f10614edc610160928360808701526101a0860190614d48565b60608601517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08683030160a0870152614dc9565b93614f23608082015160c0860190614e57565b60a081015160e085015260c081015191610100928386015260e082015192610120938487015282015192610140938487015282015190850152015191015290565b614f6c614f92565b6002600055565b614f7b614f92565b6003600055565b614f8a614f92565b600201600055565b600160005403614f9e57565b637fa8a9876000526004601cfd5b600360005403614fb857565b61067634611d42565b929091833b1561508e57604051926000947f23b872dd000000000000000000000000000000000000000000000000000000008652816004528260245283604452858060648180855af11561501b5750505050604052606052565b85853d615042575b5063f486bc879052602052604052606052608052600160a05260a4601cfd5b601f3d0160051c9060051c908060030291808211615075575b505060205a91011061506d5785615023565b3d81803e3d90fd5b8080600392028380020360091c9203020101868061505b565b83635f15d6726000526020526024601cfd5b9392919091843b1561518857604051936080519160a0519360c051956000987ff242432a000000000000000000000000000000000000000000000000000000008a528160045282602452836044528460645260a06084528960a452898060c48180855af11561511f57505050505060805260a05260c052604052606052565b89893d615144575b5063f486bc87905260205260405260605260805260a05260a4601cfd5b601f3d0160051c9060051c90806003029180821161516f575b505060205a91011061506d5786615127565b8080600392028380020360091c9203020101878061515d565b84635f15d6726000526020526024601cfd5b9190428111428411151692831561154b575050565b929190338414615330576151c16125a7565b936151fe82867f19010000000000000000000000000000000000000000000000000000000000006000526002526022526042600020906000602252565b908351926002601f601d860116106102e27fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9d860110166000146153225760018085169081604103927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf600593880101831c93808952880160209384820151928560238560e81c94019460e31c1690815285845191185283925b868410615302575050505050966152fc9161067697986152bb60406000209261552a565b600052526040600020907f19010000000000000000000000000000000000000000000000000000000000006000526002526022526042600020906000602252565b90615336565b85859101938684821c841b16604060002081528786519118520192615297565b506106769495508190615336565b50509050565b909291926000948580528051957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0820180519188604103908091600181119687156154c0575b5050508514851515169788156153b2575b50505050505050501561539c57565b6153a4612681565b634f7fb80d6000526004601cfd5b909192939495809798508452604082527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc8401938451957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08201976020600060648b519c7f1626ba7e000000000000000000000000000000000000000000000000000000009e8f8c528d520189845afa9a8b61545e575b5050505050525252388080808080808061538d565b6000510361546c5780615449565b3b6153a4576154b257606001906041640101000000835160001a1a1591141661549d5763815e1d646000526004601cfd5b631f003d0a6000525160001a6020526024601cfd5b638baa579f6000526004601cfd5b9091925060408601908151926060880151851a906154f8575b8752845260208360808660015afa508484528a8652525138808061537c565b50601b8360ff1c017f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841683526154d9565b600981106157c2576011811061567e57601581106155e057601781106155955760177f403be09941a31d05cfc2f896505811353d45d38743288b016630cce39435476a9114027f1d51df90cba8de7637ca3e8fe1e3511d1dc2f23487d05dbdecb781860c21ac1c1890565b60157fbb40bf8cea3a5a716e2b6eb08bbdac8ec159f82f380783db3c56904f15a43d049114027f3bd8cff538aba49a9c374c806d277181e9651624b3e31111bc0624574f8bca1d1890565b601381106156335760137f54b3212a178782f104e0d514b41a9a5c4ca9c980bf6597c3cecbf280917e202a9114027f5a4f867d3d458dabecad65f6201ceeaba0096df2d0c491cc32e6ea4e643500171890565b60117f2d7a3ed6dab270fdb8e054b2ad525f0ce2a8b89cc76c17f0965434740f673a559114027fc3939feff011e53ab8c35ca3370aad54c5df1fc2938cd62543174fa6e7d858771890565b600d811061572457600f81106156d957600f7fcc4886e37eedd9aacd6c1c2c9247197a621a71282e87a7cbc673f3736d9aa1419114027f1da3eed3ecef6ebaa6e5023c057ec2c75150693fd0dac5c90f4a142f9879fde81890565b600d7f8df51df98847160517f5b1186b4bc3f418d98b8a7f17f1292f392d79d600d79e9114027f6b5b04cbae4fcb1a9d78e7b2dfc51a36933d023cf6e347e03d517b472a8525901890565b600b811061577757600b7f32f4e7485d6485f9f6c255929b9905c62ba919758bbe231f231eaeecf33d810c9114027fbb98d87cc12922b83759626c5f07d72266da9702d19ffad6a514c73a89002f5f1890565b60097f6f0ec38c21f6f583ab7f3c5413c773ffd5344c34fde1d390958e438bf667448f9114027fd1d97d1ef5eaa37a4ee5fbf234e6f6d64eb511eb562221cd7edfbdde0848da051890565b60058110615868576007811061581d5760077fb58d772fb09b426b9dece637f61ca9065f2b994f1464b51e9207f55f7c8f59489114027f7ff98d9d4e55d876c5cfac10b43c04039522f3ddfb0ea9bfe70c68cfb5c7cc141890565b60057f25d02425402d882d211a7ab774c0ed6eca048c4d03d9af40132475744753b2a39114027f1c19f71958cdd8f081b4c31f7caf5c010b29d12950be2fa1c95070dc47e30b551890565b600381106158bb5760037ff3e8417a785f980bdaf134fa0274a6bf891eeb8195cd94b09d2aa651046e28bc9114027fa02eb7ff164c884e5e2c336dc85f81c6a93329d8e9adf214b32729b894de2af11890565b60017f832c58a5b611aadcfa6a082ac9d04bace53d8278387f10040347b7e98eb5b3029114027fbf8e29b89f29ed9b529c154a63038ffca562f8d7cd1e2545dda53a1b582dde301890565b905460ff8160081c16615957576effffffffffffffffffffffffffffff8160101c169081615937575b505050600190565b60881c1115615948575b808061592f565b615951906159d1565b38615941565b50631a5155746000526020526024601cfd5b906000905460ff8160081c166159c8576effffffffffffffffffffffffffffff8160101c16908161599e575b50505050600190565b60881c11156159ae578080615995565b6159b9575b50600090565b6159c2906159d1565b386159b3565b50905050600090565b6310fda3e16000526020526024601cfd5b9190608082019081356159f48161064b565b3314159060046001821191101616615a0b57505050565b61067692615a396139b76060604051956317b1f94287526020808801528460408801523382880152016111bf565b6080840152606061014461012085013761014060a08401526101e060c0840152615abc601c61032461026435615a8560a08202918261016001906101808a019060051b61020001614c02565b6102a0810160e08801528461032082890160006102e08201526102c084016101008b015260016103008201520152019401926111bf565b615d27565b919082519060808201918251926005841015615b7c575b615b09602083019473ffffffffffffffffffffffffffffffffffffffff865116331415906004600182119110161690565b15615b31575090615b239160806106769601519085615c0d565b91519263fb5014fc93615d8f565b60049194935051615b4181612934565b615b4a81612934565b03615b765761067693615b6a9184519460808660601b9301519085615b89565b91639397928593615d8f565b50505050565b615b84610678565b615ad8565b9493919260c060a494615bf9614be8946040519663f4dd92ce8852601c88019a1860a088015260a06020880152615be36060615bcc6040840151878b0190614c12565b928360a00160408b0152015185838a010190615cdf565b019160a083016060880152838388010190614bed565b01809460a082016080820152010190615cc3565b9392614be8906101649392604051936317b1f9428552601c85019760208087015260408601523360608601528151608086015260a082015161012086015260c082015190610140918287015260e08301516101608701528160a0870152615cb3604084015193615c9e6060615c8861018097888c0190614c12565b9283870160c08c0152015186838b010190615cdf565b019183830160e0890152848389010190614bed565b0194859182016101008201520101905b612984602092839283815180845260051b948593019101614c02565b8051908183526020928380808401938560051b01019101915b818110615d095750505060a0020190565b60a090818481835160045afa153d15176101c3578501920191615cf8565b6020909391937fffffffff00000000000000000000000000000000000000000000000000000000845116926000948580938180525af1908251149015615d805715615d70575050565b63fb5014fc90526020526024601cfd5b5063fb5014fc90612230612681565b602090949391947fffffffff00000000000000000000000000000000000000000000000000000000845116926000948580938180525af1908251149015615dda571561223057505050565b50612230612681565b60009081906080803d109060009081908280918515615e86575b8515615e0e575b5050505050929190565b91939750919550602094939480920196604051918360c08302840101604052818352839160010160051b98898401905b8a8410615e635750505050615e5893949596509501614b26565b913880808080615e04565b60a083879284878901528181863e60608501518286015201920193019290615e3e565b9450909150604081803e5190602051913d81113d8411179485615dfd5794508093506020915060003e60005191602082813e602051903d8260a0028560071b0186011161ffff83861711179460008052615dfd565b908135641fffffffe08160051b169060405191602091828285010160405263ffffffff809116845260005b828110615f165750929450505050565b80615f2c85848180958c010135168a01016119cd565b82828801015201615f0656fea164736f6c6343000811000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000f9490004c11cef243f5400493c00ad63
-----Decoded View---------------
Arg [0] : conduitController (address): 0x00000000F9490004C11Cef243f5400493c00Ad63
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000f9490004c11cef243f5400493c00ad63
Deployed Bytecode Sourcemap
3733:1283:3:-:0;;;;;;;;;-1:-1:-1;3733:1283:3;;;;;;;;2601:155:56;;:::i;:::-;3733:1283:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;3733:1283:3;;;;;;;:::i;:::-;6673:553:55;;;;;;;;;;;;;7433:254;;;;;7851:93;;3733:1283:3;6673:553:55;8379:1122;;;;;;;9608:261;8379:1122;;;;;;;;;;;9608:261;;;:::i;:::-;10062:321;;;;;;;3733:1283:3;;;;:::i;:::-;10444:47:55;;10707:661;;;;8379:1122;10707:661;;;;14651:10;11511;;;;:::i;:::-;;;:::i;:::-;14651;:::i;:::-;;2627:1:58;2139:31:74;3733:1283:3;2048:129:74;14651:10:55;3733:1283:3;;6673:553:55;3733:1283:3;;;;;;;;;10707:661:55;;-1:-1:-1;10707:661:55;3733:1283:3;10707:661:55;;10440:4064;14481:11;12080:30;;14651:10;12080:30;;14345:11;12080:30;;;:::i;:::-;3733:1283:3;;;;;;;:::i;:::-;6673:553:55;12210:44;;6673:553;;12392:21;12355:305;12392:21;;;8379:1122;12392:21;;;:::i;:::-;12435:18;;;;;:::i;:::-;12507:26;12555:22;;;20572:4:58;12507:26:55;;20572:4:58;12475:10:55;3733:1283:3;12475:10:55;3733:1283:3;;12355:305:55;;:::i;:::-;14345:11;:::i;:::-;14481;:::i;12206:1961::-;3733:1283:3;;;:::i;:::-;6673:553:55;12685:45;;6673:553;;12869:21;12831:306;12869:21;;;8379:1122;12869:21;;;:::i;:::-;12912:18;;;;;:::i;:::-;12984:26;13032:22;;;20572:4:58;12984:26:55;;20572:4:58;12952:10:55;3733:1283:3;12952:10:55;3733:1283:3;;12831:306:55;;:::i;12681:1486::-;3733:1283:3;;;;;:::i;:::-;13162:44:55;3733:1283:3;;13307:329:55;13344:29;;;;;:::i;:::-;13427:18;;;;;:::i;:::-;13523:30;3733:1283:3;20572:4:58;13523:30:55;;;20572:4:58;13467:34:55;;20572:4:58;3733:1283:3;;13395:10:55;;13307:329;;:::i;13158:1009::-;13822:330;13860:29;;;;;:::i;:::-;13943:18;;;;;:::i;:::-;14039:30;3733:1283:3;20572:4:58;14039:30:55;;;20572:4:58;13983:34:55;;20572:4:58;3733:1283:3;;13911:10:55;;13822:330;;:::i;7851:93::-;7919:9;7433:254;7919:9;:::i;:::-;7851:93;;3733:1283:3;;;;;;;;;;;;4492:127;;;;;;558:26:7;4492:127:3;;3733:1283;;;;;;;;;;;;;;-1:-1:-1;3733:1283:3;33821:12:73;3733:1283:3;;;;-1:-1:-1;3733:1283:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1355:18:65;;:::i;:::-;1630:811;3733:1283:3;1630:811:65;;;;;;3733:1283:3;1630:811:65;;;;;;;;;;;;;;3733:1283:3;;;;2509:42:65;1630:811;;2509:42;;1630:811;3733:1283:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;35978:266:56;740:10:7;3733:1283:3;3033:40:7;;3553:65;3733:1283:3;3553:65:7;3733:1283:3;3553:65:7;3733:1283:3;:::i;:::-;3553:65:7;;24102:61;35978:266:56;;:::i;:::-;3733:1283:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;:::o;:::-;;;;;;;:::i;:::-;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;3733:1283:3;;;:::o;:::-;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;-1:-1:-1;3733:1283:3;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;23664:1955:56;3733:1283:3;;:::i;:::-;;;;;;23664:1955:56;:::i;:::-;3733:1283:3;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;:::i;:::-;;;;;740:10:7;24102:61;;3033:40;3553:65;;3733:1283:3;:::i;:::-;29725:14:73;;;:::i;:::-;3733:1283:3;;30263:13:73;-1:-1:-1;30278:15:73;;;;;;3733:1283:3;;31401:4:73;3733:1283:3;;;;;30295:3:73;30378:9;;3733:1283:3;30378:9:73;;;:::i;:::-;;30497:16;;30577:25;;;;3733:1283:3;;;;:::i;:::-;;;;:::i;:::-;30577:47:73;30573:102;;21798:68:58;;3733:1283:3;;30895:96:73;;;:::i;:::-;31099:23;;;3733:1283:3;;31099:12:73;3733:1283:3;;;;;;;31099:23:73;31217:254;;;;:::i;:::-;;31560:24;3733:1283:3;;;;;;;;31560:24:73;;3733:1283:3;31560:24:73;31556:878;;30295:3;;;;;;30263:13;3733:1283:3;30263:13:73;;31556:878;32127:15;32237:30;31780:29;;32127:15;32373:42;31780:29;;;;;3733:1283:3;31844:47:73;;;3733:1283:3;31780:111:73;31751:263;;31556:878;32127:15;;;;:::i;:::-;31401:4;3733:1283:3;;;;;;;;32237:30:73;32373:42;3733:1283:3;;32373:42:73;;;;;:::i;:::-;;;;31556:878;;;;;;;31751:263;;;:::i;:::-;;;30573:102;30648:8;;;;3733:1283:3;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;27885:431:56;3733:1283:3;;;;;;;:::i;:::-;740:10:7;;3733:1283:3;27923:118:56;740:10:7;3033:40;;;3733:1283:3;3553:65:7;27923:118:56;:::i;:::-;558:26:7;;;:::i;:::-;;-1:-1:-1;558:26:7;;2602:59;3733:1283:3;3553:65:7;3733:1283:3;:::i;:::-;28292:10:56;;27885:431;;:::i;:::-;3733:1283:3;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;3733:1283:3;39369:15:56;3733:1283:3;;;;-1:-1:-1;3733:1283:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8457:294:56;3733:1283:3;740:10:7;3733:1283:3;3033:40:7;;3733:1283:3;3553:65:7;3733:1283:3;:::i;:::-;558:26:7;;:::i;:::-;;-1:-1:-1;558:26:7;;8731:10:56;3733:1283:3;;;8457:294:56;;:::i;:::-;3733:1283:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12143:453:56;3733:1283:3;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;740:10:7;3033:40;;;3733:1283:3;3553:65:7;3733:1283:3;:::i;:::-;2602:59:7;;3733:1283:3;3553:65:7;3733:1283:3;:::i;:::-;3551:180:70;;;;;;3733:1283:3;;;12143:453:56;;:::i;:::-;3733:1283:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;17025:967:56;3733:1283:3;;;;;;;:::i;:::-;740:10:7;;17074:118:56;740:10:7;3033:40;;;3553:65;;17074:118:56;:::i;:::-;558:26:7;3733:1283:3;558:26:7;;;:::i;:::-;;-1:-1:-1;558:26:7;;2602:59;3553:65;;3733:1283:3;:::i;:::-;2602:59:7;;3553:65;3733:1283:3;:::i;:::-;;;17934:10:56;;3733:1283:3;;;17025:967:56;;:::i;3733:1283:3:-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;3733:1283:3;2974:9:65;3733:1283:3;;;-1:-1:-1;3733:1283:3;;38028:203:56;;3733:1283:3;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;32499:612:56;3733:1283:3;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;740:10:7;3033:40;;;;;3553:65;;3733:1283:3;:::i;:::-;2602:59:7;;3553:65;;3733:1283:3;:::i;:::-;2602:59:7;;3553:65;3733:1283:3;:::i;:::-;3551:180:70;;;;;;32499:612:56;;:::i;:::-;3733:1283:3;;;;;;;:::i;:::-;;;;;;;;;;;;12961:18:69;;:::i;:::-;558:26:7;3733:1283:3;13208:393:69;;;3733:1283:3;13104:19:69;3733:1283:3;13208:393:69;;;;;;3733:1283:3;13208:393:69;3733:1283:3;;;;;;;;:::i;:::-;26183:14:73;;;:::i;:::-;-1:-1:-1;26783:13:73;;26798:15;;;;;;28618:88;;;3733:1283:3;;31401:4:73;3733:1283:3;;;;;28618:88:73;;;:::i;:::-;;;26783:13;26907:9;;28337:4;26907:9;;;;:::i;:::-;26953:13;;;;:::i;:::-;26999:10;28444:40;;27808:233;26999:10;;;;;:::i;:::-;27049:15;;;;;;:::i;:::-;3733:1283:3;27083:687:73;;;;;;;;;;;;3733:1283:3;28010:13:73;3733:1283:3;;;:::i;27808:233:73:-;28149:23;28311:30;28149:23;;3733:1283:3;;31099:12:73;3733:1283:3;;;;;;;28149:23:73;3733:1283:3;;;;;;;;;28311:30:73;3733:1283:3;;;;;;;;;;;;;;;;;;;;28444:40:73;;;;3733:1283:3;26783:13:73;;20572:4:58;;;;;;;;;;;;3733:1283:3;;20572:4:58;558:26:7;20572:4:58;;;;;;;;;;;3733:1283:3;20572:4:58;:::o;:::-;;;:::i;:::-;3733:1283:3;20572:4:58;:::o;:::-;3733:1283:3;;20572:4:58;558:26:7;20572:4:58;;;;;;;;;;;3733:1283:3;20572:4:58;:::o;:::-;;3733:1283:3;20572:4:58;;;;;;;;;;;;;;;:::o;:::-;;3733:1283:3;;;;;;;20572:4:58;;;;;;;;;;;3733:1283:3;20572:4:58;:::o;:::-;3733:1283:3;;20572:4:58;;;;;;;;3733:1283:3;;20572:4:58;;:::o;:::-;;;:::i;:::-;;;;;;:::i;:::-;;;;;;;;;;;;:::o;:::-;;;;;:::i;3733:1283:3:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;16467:27733:55:-;;;;;;;16901:5;;:::i;:::-;;;:::i;:::-;17500:1856;;;;;;;;;;;;;;;;;;;;;;;20489:28;;;20654:13195;;;;;;;;;;;;;;;;;;;;;17500:1856;;20654:13195;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;16901:5;20654:13195;;16901:5;20654:13195;16901:5;20654:13195;;17500:1856;;20654:13195;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;17500:1856;;20654:13195;;;;;;;;;17500:1856;;20654:13195;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;44103:20;34362;44103;34362;;20654:13195;34478:3011;;20654:13195;34478:3011;20654:13195;34478:3011;20654:13195;34478:3011;20654:13195;34478:3011;20654:13195;34478:3011;20654:13195;;34478:3011;16901:5;34478:3011;20654:13195;16901:5;34478:3011;20654:13195;34478:3011;20654:13195;17500:1856;;20654:13195;;34478:3011;;;;17500:1856;;;;20654:13195;;34478:3011;;20654:13195;34478:3011;;17500:1856;;20654:13195;;34478:3011;;40375:3610;38554:90;;2974:18:65;;3733:1283:3;;;;20654:13195:55;3733:1283:3;;;;;;;2974:18:65;3733:1283:3;38882:15:55;;20654:13195;38912:1443;20654:13195;38554:90;20654:13195;38912:1443;20654:13195;38912:1443;20654:13195;38912:1443;20654:13195;38912:1443;20654:13195;17500:1856;38912:1443;;;;;;;;;20654:13195;38912:1443;17500:1856;;;20654:13195;;40375:3610;;;;;;;17500:1856;;20654:13195;;40375:3610;;20654:13195;40375:3610;17500:1856;;20654:13195;;40375:3610;;20654:13195;17500:1856;;;20654:13195;;40375:3610;;;20654:13195;17500:1856;;40375:3610;;;;;;;;;16901:5;20654:13195;40375:3610;17500:1856;;20654:13195;;40375:3610;;20654:13195;40375:3610;44103:20;;;;:::i;:::-;;;;:::i;20654:13195::-;;16901:5;20654:13195;;;;17500:1856;;16901:5;17500:1856;;;;;;16901:5;17500:1856;;;;;;;;5171:4085:54;5428:3647;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9167:13;9163:87;;5171:4085::o;45226:4176:55:-;45597:280;;;;;;;;;45962:24;;;;46190:2188;48542:22;46190:2188;;;;;;;;;;;;;;;;;;;;;;;;;45597:280;46190:2188;;;;;;;;45597:280;46190:2188;;;45597:280;46190:2188;;;48542:22;:::i;45958:3438::-;3733:1283:3;;;;;48702:15:55;3733:1283:3;;:::i;:::-;48690:27:55;48702:15;;48815:11;;48825:1;49056:10;48815:11;;48811:100;;48686:700;49044:10;;49056;;:::i;48811:100::-;48885:6;;;:::i;:::-;48811:100;;;48686:700;49283:10;;49347:6;49283:10;;49347:6;;:::i;49888:3133::-;50054:9;50338:341;;-1:-1:-1;50338:341:55;;;;-1:-1:-1;50992:37:55;;;;;;52362:30;;;;;;52358:102;;50939:1330;52546:6;50338:341;;;52546:6;:::i;:::-;52646:30;;;52642:373;;49888:3133;;:::o;52642:373::-;52942:30;7079:4:58;;52909:10:55;52942:30;:::i;52358:102::-;;;:::i;:::-;;;51047:29;51109:543;;;;51745:49;;;;51741:137;;7079:4:58;52228:25:55;7079:4:58;;;;51109:543:55;;;;;52228:25;:::i;:::-;7079:4:58;50961:13:55;;51741:137;6314:386:63;;;;;;3733:1283:3;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;53802:4312:55:-;;;54444:1183;;;;54639:355;;;;;;;;;;54444:1183;55695:83;;54444:1183;55960:299;;;;;;56401:211;;;;;56749:13;-1:-1:-1;56764:37:55;;;;;;58095:11;;;;;;;;:::i;56749:13::-;56819:495;;;;;;;;57403:85;;56749:13;56819:495;;;;57754:11;56819:495;;7079:4:58;56819:495:55;;;57754:11;;;:::i;:::-;7079:4:58;56749:13:55;;57403:85;57438:35;;;;7079:4:58;57438:35:55;;;57754:11;57438:35;;:::i;:::-;57403:85;;;;;;;;;;55695:83;;;:::i;:::-;;;54444:1183;55188:425;;;;;;;;;;54444:1183;;558:26:7;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;23664:1955:56;;24483:1129;23664:1955;;740:10:7;24102:61;3733:1283:3;24102:61:7;579:4;24102:61;3033:40;579:4;3553:65;3733:1283:3;:::i;:::-;24102:61:7;3733:1283:3;24102:61:7;3553:65;24102:61;2602:59;579:4;3553:65;3733:1283:3;:::i;:::-;;;24102:61:7;3553:65;24102:61;2602:59;579:4;3553:65;3733:1283:3;:::i;:::-;24102:61:7;3553:65;24102:61;2602:59;579:4;3553:65;3733:1283:3;:::i;:::-;3551:180:70;;;;;;24483:1129:56;;:::i;11831:1559:59:-;;1155:118:7;;24320:6:58;1155:118:7;;;;5574:4:58;13317:56:59;12027:57;3553:65:7;1155:118;20572:4:58;3553:65:7;;20572:4:58;7652:63:7;;3850:61;5348:4:58;7652:63:7;;80285:55;;;12782:14:59;740:10:7;24102:61;;;;3033:40;3553:65;;12782:14:59;:::i;:::-;13024:56;3553:65:7;5518:4:58;3553:65:7;;24102:61;2602:59;3553:65;;13024:56:59;:::i;:::-;5518:4:58;7652:63:7;;80285:55;3553:65;;;24102:61;2602:59;3553:65;13317:56:59;:::i;:::-;7652:63:7;;80285:55;11831:1559:59:o;2200:1301::-;;2324:1171;;;;;;;;;;;;;;;;;;;;;;;;;;;2200:1301::o;8865:909::-;9652:105;5518:4:58;8865:909:59;24160:6:58;3850:61:7;;;740:10;9338:59:59;3553:65:7;7079:4:58;3553:65:7;;24102:61;2602:59;3553:65;;9338:59:59;:::i;:::-;7079:4:58;7652:63:7;;80285:55;3553:65;;;24102:61;2602:59;3553:65;9652:105:59;:::i;3917:2038::-;;4041:1908;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3917:2038::o;4041:1908::-;;;;;;;;;;;;6446:2065;;6578:1927;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6446:2065::o;6578:1927::-;;;;;;;;;;;;14074:1396;;1155:118:7;;24320:6:58;1155:118:7;;;;15145:48:59;14277:57;7652:63:7;5348:4:58;7652:63:7;;80285:55;;;14700:14:59;740:10:7;24102:61;;;;3033:40;3553:65;;14700:14:59;:::i;:::-;14852:1;20572:4:58;7652:63:7;;80285:55;14852:1:59;1155:118:7;7652:63;;80285:55;20572:4:58;3553:65:7;;24102:61;2602:59;3553:65;15145:48:59;:::i;:::-;5518:4:58;7652:63:7;;80285:55;5574:4:58;1155:118:7;;;20572:4:58;1155:118:7;;;;-1:-1:-1;80285:55:7;;7652:63;80285:55;14074:1396:59:o;20137:1328::-;24102:61:7;;6009:3:58;;;;;;;;1155:118:7;;;20572:4:58;;1155:118:7;;;;;;;;20649:41:59;740:10:7;;8753:40;;;80285:55;;-1:-1:-1;21104:19:59;;;;;;20137:1328;;;;;;;;;;:::o;21125:17::-;3553:65:7;;;;;;;;24102:61;2602:59;3553:65;;1155:118;;5348:4:58;;;1155:118:7;;;;;;5574:4:58;;3553:65:7;;;;;3850:61;;3553:65;;24102:61;2602:59;3553:65;;24102:61;;18207:1:59;24102:61:7;;;8753:40;7079:4:58;6009:3;;1155:118:7;;;;;;;;3850:61;;7652:63;;80285:55;7652:63;;;;;80285:55;7079:4:58;21084:18:59;;21887:1295;;24102:61:7;;6009:3:58;;;;;1155:118:7;;;20572:4:58;1155:118:7;;;;;;;;22388:41:59;740:10:7;;8753:40;;;80285:55;;-1:-1:-1;22843:19:59;;;;;;21887:1295;;;;;;;:::o;22864:17::-;3553:65:7;;;;;;;;24102:61;2602:59;3553:65;;11473:48:59;1155:118:7;;;;;;;;;;;;10488:4:59;3553:65:7;;;;;;24102:61;3033:40;3553:65;;;10488:4:59;:::i;:::-;80285:55:7;;3553:65;;;;24102:61;2602:59;3553:65;;11473:48:59;:::i;:::-;7652:63:7;;;80285:55;7652:63;;;;;80285:55;7079:4:58;22823:18:59;;25507:1344;;24102:61:7;;6009:3:58;;;;;;1155:118:7;;20572:4:58;1155:118:7;;;;;;;;26029:41:59;740:10:7;;8753:40;;;80285:55;;-1:-1:-1;26484:19:59;;;;;;25507:1344;;;;;;:::o;26505:17::-;3553:65:7;26750:52:59;3553:65:7;;;;;;;;24102:61;2602:59;3553:65;;;26750:52:59;:::i;:::-;7652:63:7;;;;;80285:55;7079:4:58;26464:18:59;;23716:1237;;23856:1091;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23716:1237::o;23856:1091::-;;;;;;;;;;;;27364:1319;;24102:61:7;;6009:3:58;;;;;;1155:118:7;;20572:4:58;1155:118:7;;;;;;;;27873:41:59;740:10:7;;8753:40;;;80285:55;;-1:-1:-1;28328:19:59;;;;;;27364:1319;;;;;;:::o;28349:17::-;3553:65:7;28590:44:59;3553:65:7;;;;;;;;24102:61;2602:59;3553:65;;;28590:44:59;:::i;:::-;7652:63:7;;;;;80285:55;7079:4:58;28308:18:59;;30365:1313;;24102:61:7;;6009:3:58;;;;;1155:118:7;;;20572:4:58;1155:118:7;;;;;;;;30872:41:59;740:10:7;;8753:40;;;80285:55;;-1:-1:-1;31327:19:59;;;;;;30365:1313;;;;;;;:::o;31348:17::-;3553:65:7;;;;;;;;24102:61;2602:59;3553:65;;29730:114:59;1155:118:7;;;;;;;;;29439:42:59;3553:65:7;;;;;24102:61;3033:40;3553:65;;;29439:42:59;:::i;:::-;80285:55:7;;3553:65;;;;24102:61;2602:59;3553:65;;29730:114:59;:::i;:::-;7652:63:7;;;80285:55;7652:63;;;;;80285:55;7079:4:58;31307:18:59;;32139:1321;;1155:118:7;;24160:6:58;1155:118:7;;;;32335:40:59;5242:5:58;33029:97:59;5242:5:58;3850:61:7;;;;;740:10;32759:59:59;3553:65:7;1155:118;3553:65;;24102:61;2602:59;3553:65;;32759:59:59;:::i;:::-;1155:118:7;7652:63;;80285:55;5518:4:58;3553:65:7;;24102:61;2602:59;3553:65;33029:97:59;:::i;:::-;7652:63:7;5518:4:58;7652:63:7;;80285:55;73322:53;7652:63;;80285:55;32139:1321:59:o;6252:450:63:-;;6314:386;;;;;;9614:565;9685:492;;;;;;;;10475:458;10533:398;;;;;;;;22724:368;;22774:316;;;;;;4921:1551:67;5106:6;;;:::i;:::-;-1:-1:-1;5228:154:67;;;;;;;5428:8;5424:1042;;4921:1551;;:::o;5424:1042::-;;;:::i;:::-;5640:816;-1:-1:-1;5640:816:67;;;;;;;;4228:435:54;4298:359;;;4228:435::o;4298:359::-;;;;;;;7408:969:67;;;;;;;7685:6;;;:::i;:::-;7816:10;;;;:::i;:::-;7889:24;;;4445:10336:76;;;;7911:1:67;;4445:10336:76;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7885:486:67;4445:10336:76;;;;;;;;;;7408:969:67:o;4445:10336:76:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7885:486:67;8340:6;;;;;;;;:::i;9378:1098::-;;;;;;;9720:10;;;;:::i;:::-;9793:24;;;9907:11;;;9917:1;10114:10;9907:11;;9903:92;;9789:681;10114:10;;:::i;9903:92::-;9973:6;;;:::i;:::-;9903:92;;;9789:681;3733:1283:3;;21565:671:67;;20348:16;;;;;;;20572:4:58;20522:41:67;20572:4:58;;21565:671:67;20579:12;20590:1;20670:498;;;;20572:4:58;20670:498:67;;;20623:33;20670:498;;;;20572:4:58;20670:498:67;;;;;;;;;20518:1009;21565:671;;;10306:22;21565:671;;;;;;;;;;;;;;;;;;;;;;9378:1098::o;20518:1009::-;21264:253;21565:671;21264:253;;;;;;;;;;20518:1009;;11443:1028;;;;;;;11750:6;;;:::i;:::-;11881:10;;;;:::i;:::-;11954:24;;;12112:6;;;;;:::i;11950:515::-;20348:16;21565:671;20348:16;;;;;;20572:4:58;3733:1283:3;;20522:41:67;20518:1009;20572:4:58;;;21565:671:67;20579:12;20590:1;20670:498;;;;20572:4:58;20670:498:67;;;20623:33;20670:498;;;;20572:4:58;20670:498:67;;;;;;;;;20518:1009;21565:671;;;12300:23;21565:671;;;;;;;;;;;;;;;;;;;;;;11443:1028::o;20518:1009::-;21264:253;21565:671;21264:253;;;;;;;;;;20518:1009;;13222:458;;18947:139;;;;13584:35;13580:94;;13222:458;:::o;13580:94::-;13651:11;;14044:437;;7079:4:58;3733:1283:3;;14169:38:67;14165:75;;18947:139;;;;15477:502;;;;;;;;;10562:1318:69;7079:4:58;10562:1318:69;3733:1283:3;18947:139:67;3733:1283:3;-1:-1:-1;10315:19:69;;;;;3733:1283:3;10562:1318:69;;;;;;;10460:27;7079:4:58;10562:1318:69;;;;;;7079:4:58;10562:1318:69;17316:506:67;;;7079:4:58;15477:502:67;;17316:506;;;;;;;17869:8;;17865:254;;3733:1283:3;;18216:33:67;3733:1283:3;18947:139:67;3733:1283:3;;;18206:43:67;18202:116;;16220:73;;;14044:437::o;18202:116::-;18299:7;;;:::i;:::-;16220:73;14044:437::o;17865:254::-;7633:467:63;17865:254:67;;;;:::i;:::-;7633:467:63;18947:139:67;7633:467:63;;;;14165:75:67;14223:7;;:::o;16969:1355::-;;10562:1318:69;;3733:1283:3;10562:1318:69;3733:1283:3;45597:280:55;-1:-1:-1;10315:19:69;;;;;3733:1283:3;10562:1318:69;;;;;;;10460:27;10562:1318;;;;;;;;;17316:506:67;;;;;;;;;;17869:8;;17865:254;;3733:1283:3;;18216:33:67;3733:1283:3;;18206:43:67;18202:116;;16969:1355;;:::o;18202:116::-;18299:7;;;:::i;17865:254::-;7633:467:63;17865:254:67;;;;:::i;8839:624:63:-;8918:543;;;;;;;;;;20088:2154:67;;21565:671;20088:2154;;;;20572:4:58;3733:1283:3;;20522:41:67;20518:1009;20572:4:58;;;21565:671:67;20579:12;8208:21;20670:498;;;;20572:4:58;20670:498:67;;;20623:33;20670:498;;;;20572:4:58;20670:498:67;;;;;;;;;20518:1009;21565:671;;;8208:21;21565:671;;;;;;;;;;;;;;;;7911:1;21565:671;;;;;;20088:2154::o;20518:1009::-;21264:253;21565:671;21264:253;;;8208:21;21264:253;;;;;;20518:1009;;2138:7363:69;;;;2428:47;;;3733:1283:3;;3004:20:69;;3115:1683;;;;;;;;;;;;;;;;-1:-1:-1;3115:1683:69;;;;;;;;;;;;;;;;;;;;5014:28;;5133:1832;;;;;;;;;;;-1:-1:-1;5133:1832:69;;;;;;;;;;;;3115:1683;5133:1832;3115:1683;5133:1832;3115:1683;5133:1832;;7173:2322;;;;;7066:15;;7173:2322;;;;;;;;;;;;;;;;;;;;;;2138:7363::o;5133:1832::-;;;;3115:1683;;5133:1832;;;;;;;;;;;;;;;;;;;;;;;;3115:1683;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12204:181;-1:-1:-1;12281:13:69;12298:9;12281:26;12298:9;;12322:17;;12204:181;:::o;12281:97::-;4399:1229:57;;;;;4199:24;;4399:1229;;4252:10;4399:1229;;4294:13;4399:1229;;12281:13:69;4399:1229:57;;;;;;;;;;;;;;;12204:181:69;:::o;676:2311:70:-;744:2237;;;676:2311::o;744:2237::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;676:2311::o;744:2237::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6267:1343:71;;;;;;;;;6964:251;6267:1343;6964:251;;:::i;:::-;3733:1283:3;;;;;;;;28835:94:71;28864:55;;;;:::i;:::-;28835:94;:::i;:::-;29095:35;7083:5;29202:13;;29197:885;29217:26;;;;;;30161:13;;7083:5;30156:991;30176:34;;;;;;31231:28;;;;;;31773:174;31231:28;;;;;31227:320;;30156:991;3733:1283:3;;;31617:22:71;31613:88;;31773:174;:::i;:::-;7305:298;6267:1343;:::o;31613:88::-;;;:::i;:::-;31773:174;:::i;31227:320::-;31347:186;;;;;31227:320;;;30161:13;30457:28;;;;;;30340:246;30457:28;;;;;;:::i;:::-;;30340:246;;:::i;:::-;30662:33;;51140:850;;;;;;;;;;;;;;;;50935:1061;;30662:33;;;;3733:1283:3;;;;;;30658:414:71;;3733:1283:3;30161:13:71;;;;;;;;30658:414;7079:4:58;;30931:122:71;7079:4:58;30931:122:71;7079:4:58;;3733:1283:3;7079:4:58;;;;30931:122:71;;;:::i;:::-;;;;:::i;:::-;;30658:414;;29202:13;29482:20;;;8568:2386:68;29482:20:71;;;;;;;;;:::i;:::-;;8568:2386:68;;:::i;:::-;29668:33:71;;;51140:850;;;;;;;;;;;;;;;;50935:1061;;29668:33;;;;3733:1283:3;;;;;;29664:343:71;;3733:1283:3;29202:13:71;;;;;;;;;;29664:343;7079:4:58;;29937:51:71;7079:4:58;;3733:1283:3;7079:4:58;;;29937:51:71;;;;;:::i;:::-;;;:::i;:::-;;29664:343;;3733:1283:3;558:26:7;;:::i;:::-;3733:1283:3;;;;20572:4:58;;;;;;;;;;;3733:1283:3;;20572:4:58;-1:-1:-1;3733:1283:3;;;;;;;;558:26:7;3733:1283:3;;;;;;;;;;;;;;;;;558:26:7;3733:1283:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;20572:4:58:-;;;:::i;:::-;;;3733:1283:3;558:26:7;;:::i;:::-;4009:4:72;558:26:7;;;;20572:4:58;3733:1283:3;;;20572:4:58;3733:1283:3:o;:::-;;558:26:7;;;;:::i;:::-;;:::i;:::-;;;;3733:1283:3;;;;;:::i;:::-;;20572:4:58;3733:1283:3;20572:4:58;3733:1283:3;;20572:4:58;3733:1283:3:o;:::-;;-1:-1:-1;3733:1283:3;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;9668:14254:71;;;;7083:5;10086:4;;;:::i;:::-;7083:5;10583:836;;;3733:1283:3;;;:::i;:::-;;;;11787:26:71;;;;:::i;:::-;12259:19;20572:4:58;12280:24:71;10086:4;7079::58;;6009:3;;12280:24:71;;;;22272:83;;;21804:60:58;22537:17:71;22272:83;;22255:167;;12254:9603;22537:17;;:::i;:::-;20572:4:58;22846:24:71;10086:4;7079::58;;6009:3;;22846:24:71;;;;9668:14254;;;;:::o;22872:12::-;20572:4:58;22904:88:71;10086:4;22904:88;;;;23083:23;;23079:78;;23844:29;23254:95;;;;;23496:24;21798:68:58;;;;3733:1283:3;;;;21798:68:58;23728:20:71;;;21798:68:58;3733:1283:3;;21798:68:58;23801:21:71;16890;14391:30;23801:21;;;23844:29;;;;;:::i;:::-;7079:4:58;22825:19:71;;;;23079:78;23130:8;;;22255:167;;;:::i;:::-;;;12306:12;12417:95;;;;12613:21;;12609:279;;13125:131;;;:::i;:::-;13360:14;;;;;;13356:272;;13710:87;;;3733:1283:3;;14119:24:71;;;:34;;;;3733:1283:3;14256:32:71;;;;3733:1283:3;14391:30:71;;;;;3733:1283:3;;;14849:34:71;;;3733:1283:3;;;;:::i;:::-;15202:588:71;;;7083:5;15202:588;10086:4;-1:-1:-1;15202:588:71;15893:13;7083:5;15908:19;;;;;;16890:21;;;;18191:24;;;:38;;3733:1283:3;;;18475:13:71;7083:5;18490:27;;;;;;12306:12;;;;;;;;20572:4:58;12306:12:71;12259:19;7079:4:58;12259:19:71;;18519:3;18673:16;;;14119:34;18673:16;10086:4;18673:16;;;:::i;:::-;;19886:266;18936:27;;;14849:34;18936:27;;3733:1283:3;18826:159:71;3733:1283:3;;18826:159:71;;;:::i;:::-;19116:29;;;3733:1283:3;;;;;;19116:84:71;;19087:646;19173:27;;;80285:55:7;;;;;;19087:646:71;3733:1283:3;;19886:266:71;:::i;:::-;80285:55:7;;;20609:1216:71;;;;;;;3733:1283:3;18475:13:71;;19087:646;19533:177;;;:::i;:::-;80285:55:7;;19087:646:71;;15929:3;16033:8;;;10086:4;16033:8;;;:::i;:::-;;16271:245;;7083:5;16271:245;;;;;16743:19;17546:237;16743:19;;14849:34;16743:19;;3733:1283:3;;16890:21:71;16633:151;3733:1283:3;;16633:151:71;;;:::i;:::-;16890:21;;3733:1283:3;;;;;;16890:44:71;;16886:539;16915:19;;;80285:55:7;;;;;;16886:539:71;3733:1283:3;;17546:237:71;:::i;:::-;80285:55:7;;;;3733:1283:3;15893:13:71;;16886:539;17233:169;;;:::i;:::-;80285:55:7;;16886:539:71;;13356:272;13479:23;;;;;;7083:5;20572:4:58;13479:23:71;;;3733:1283:3;13601:8:71;;12609:279;12739:23;7083:5;20572:4:58;12739:23:71;;;3733:1283:3;12861:8:71;;9668:14254;;;;3733:1283:3;10086:4:71;;;:::i;:::-;3733:1283:3;10583:836:71;;;3733:1283:3;;;:::i;:::-;;;;11787:26:71;;;;:::i;:::-;12259:19;20572:4:58;12280:24:71;46026:4;7079::58;;6009:3;;12280:24:71;;;;22272:83;;;21804:60:58;22537:17:71;22272:83;;22255:167;;22537:17;;:::i;:::-;20572:4:58;22846:24:71;46026:4;7079::58;;6009:3;;22846:24:71;;;;9668:14254;;;;:::o;22872:12::-;20572:4:58;22904:88:71;46026:4;22904:88;;;;23083:23;;23079:78;;23844:29;23254:95;;;;;23496:24;21798:68:58;;;;3733:1283:3;;;;23844:29:71;7079:4:58;22825:19:71;;;;23079:78;23130:8;;;12306:12;12417:95;;;;12613:21;;12609:279;;13125:131;;;:::i;:::-;13360:14;;;;;;13356:272;;13710:87;;;3733:1283:3;;14119:24:71;;;:34;;;;3733:1283:3;14256:32:71;;;;3733:1283:3;14391:30:71;;;;;3733:1283:3;;;14849:34:71;;;3733:1283:3;;;;:::i;:::-;15202:588:71;;;3733:1283:3;15202:588:71;46026:4;-1:-1:-1;15202:588:71;15893:13;3733:1283:3;15908:19:71;;;;;;16890:21;;;;18191:24;;;:38;;3733:1283:3;;;18475:13:71;3733:1283:3;18490:27:71;;;;;;12306:12;;;;;;;;20572:4:58;12306:12:71;12259:19;7079:4:58;12259:19:71;;18519:3;18673:16;;;14119:34;18673:16;46026:4;18673:16;;;:::i;:::-;;19886:266;18936:27;;;14849:34;18936:27;;3733:1283:3;18826:159:71;3733:1283:3;;18826:159:71;;;:::i;19886:266::-;80285:55:7;;;20609:1216:71;;;;;;;3733:1283:3;18475:13:71;;15929:3;16033:8;;;46026:4;16033:8;;;:::i;:::-;;16271:245;;3733:1283:3;16271:245:71;;;;;16743:19;17546:237;16743:19;;14849:34;16743:19;;3733:1283:3;;16890:21:71;16633:151;3733:1283:3;;16633:151:71;;;:::i;17546:237::-;80285:55:7;;;;3733:1283:3;15893:13:71;;13356:272;13479:23;;;;;;3733:1283:3;20572:4:58;13479:23:71;;;3733:1283:3;13601:8:71;;12609:279;12739:23;3733:1283:3;20572:4:58;12739:23:71;;;3733:1283:3;12861:8:71;;3733:1283:3;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;1701:2272:53:-;;;;1996:24;;;1992:1881;;3950:16;;;1701:2272;:::o;1992:1881::-;2827:23;7079:4:58;2871:19:53;7079:4:58;;2533:15:53;;7079:4:58;;;;;2827:23:53;;:::i;:::-;2871:19;;:::i;:::-;3733:1283:3;;;;;;;1992:1881:53;2988:805;;;;;;3849:13;:::o;3733:1283:3:-;;;:::i;:::-;;;1701:2272:53;;;;1996:24;;;1992:1881;;3950:16;;;1701:2272;:::o;1992:1881::-;10086:4:71;7079::58;2827:23:53;7079:4:58;2871:19:53;7079:4:58;;2533:15:53;;7079:4:58;;;;;2827:23:53;;:::i;:::-;2871:19;;:::i;:::-;3733:1283:3;;;;;;;1992:1881:53;2988:805;;;;;;;;;3849:13;:::o;3733:1283:3:-;;;:::i;:::-;;;4781:1333:53;;;;5016:24;;;5012:67;;5216:531;;;;;;5865:17;;;:::i;:::-;5974:134;4781:1333;:::o;5216:531::-;;;;;;;5012:67;5056:12;;;;:::o;11039:376:63:-;;11091:322;;;;;;3733:1283:3;;-1:-1:-1;3733:1283:3;;;:::o;4706:18:62:-;;3733:1283:3;;;:::i;2035:6735:66:-;3733:1283:3;;;;2642:13:66;2654:1;2657:26;;;;;;7003:13;;;2654:1;7018:23;;;;;;2035:6735;;;:::o;7043:3::-;7151:17;;;;:::i;:::-;;7263:28;3733:1283:3;3509:23:66;7263;;3733:1283:3;;;;;;;;;;7263:28:66;;7259:83;;7481:24;7640:29;;;;;3733:1283:3;7770:13:66;2654:1;7785:14;;;;;;8283:21;;;4110;8283;;;3733:1283:3;8397:13:66;2654:1;8412:14;;;;;;7043:3;;;3733:1283:3;7043:3:66;7003:13;3733:1283:3;7003:13:66;;8428:3;8580:21;8560:54;8580:33;:24;3733:1283:3;8580:21:66;;;:24;:::i;:::-;;:33;:::i;:::-;11455:64;-1:-1:-1;11261:264:66;;8560:54;8531:191;;8428:3;3733:1283:3;8397:13:66;;8531:191;8697:1;;;;:::i;:::-;8531:191;;7801:3;7982:29;7933:116;7982:41;:32;3733:1283:3;7982:29:66;;;:32;:::i;7933:116::-;7904:261;;7801:3;3733:1283:3;7770:13:66;;7904:261;8140:1;;;;:::i;:::-;7904:261;;7259:83;7315:8;3733:1283:3;7315:8:66;;;2685:3;2824:20;;;;:::i;:::-;;3388:26;3733:1283:3;;3091:33:66;;;;3087:187;;2685:3;3388:26;;:::i;:::-;;3509:23;;:28;3733:1283:3;3509:23:66;;;3733:1283:3;;;;;3509:28:66;;3505:83;;3727:24;4110:21;;;;;;;4258:22;;;3733:1283:3;4384:118:66;4233:10:62;4602:21:66;;;3733:1283:3;;;;:::i;:::-;;;;:::i;:::-;4598:1014:66;;2685:3;3733:1283:3;;;5706:30:66;;;5702:948;;6864:16;;;;3733:1283:3;6864:16:66;;;:::i;:::-;3733:1283:3;2642:13:66;;5702:948;2654:1;5764:864;;;;4598:1014;7079:4:58;;5518;7079;;;3733:1283:3;4712:10:62;4598:1014:66;;;3505:83;3561:8;;;3733:1283:3;3561:8:66;;;3087:187;3212:21;3509:23;3212:21;;3733:1283:3;;;;:::i;:::-;3212:21:66;:::i;:::-;3087:187;;18328:606:63;18398:534;;;;;;;;20975:881;21092:762;;;;;;;;;;21941:701;22042:598;;;;;;;;;;3733:1283:3;;;;:::i;9080:1682:66:-;;9345:21;9080:1682;9345:21;:::i;:::-;;4706:18:62;;3733:1283:3;;;;:::i;:::-;11455:64:66;;;9567:30;9563:95;;10599:32;9699:30;10455:135;9699:30;10728:27;9699:30;;3733:1283:3;;;9824:34:66;;;9820:476;9824:34;;;10060:30;9977:27;;;;3733:1283:3;10060:30:66;;;;;;;:::i;:::-;10455:135;11455:64;10455:135;10599:32;;:::i;:::-;10728:27;3733:1283:3;80285:55:7;;9080:1682:66:o;9820:476::-;10125:30;;;;;3733:1283:3;10121:175:66;9820:476;10121:175;;;:::i;:::-;9820:476;;9563:95;5803:331:63;;;;;;11503:336;;11545:292;;;;;;11859:2050:66;;-1:-1:-1;12165:1603:66;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13843:60;;11859:2050;:::o;13843:60::-;11545:292:63;;;;;;12165:1603:66;;;;;;;;;;;;;;;;;;;;;;;;;;;;3733:1283:3;558:26:7;;:::i;:::-;3733:1283:3;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;20572:4:58;3733:1283:3;20572:4:58;;;;;;;;;;;3733:1283:3;;20572:4:58;-1:-1:-1;3733:1283:3;;;;:::i;:::-;;;;;;;;;;:::o;20572:4:58:-;;;:::i;:::-;;;3733:1283:3;;558:26:7;;;;:::i;:::-;;;;3733:1283:3;;;;;:::i;:::-;;;-1:-1:-1;3733:1283:3;;;;;;;;;:::o;:::-;;;;;:::i;:::-;;;;;;;;;;16406:392:63;;16462:334;;;;;;8568:2386:68;;;;;3733:1283:3;;:::i;:::-;;;;9119:33:68;9115:125;;9356:14;9834:9;9356:14;;;9565;3733:1283:3;9565:14:68;;;3733:1283:3;;;;9834:9:68;:::i;:::-;10764:11;;;3733:1283:3;10764:16:68;10760:178;;8568:2386;;:::o;10760:178::-;7083:5:71;10909:14:68;10800:17;;;;;3733:1283:3;;;8568:2386:68:o;9115:125::-;14734:570:63;7083:5:71;14734:570:63;7083:5:71;14734:570:63;;;;;8568:2386:68;;;;;3733:1283:3;;:::i;:::-;;;;9119:33:68;9115:125;;9356:14;10231:9;9356:14;;;10231:9;;:::i;:::-;10344:17;;;10364:10;;3733:1283:3;;10471:20:68;;;80285:55:7;10764:11:68;;;3733:1283:3;10764:16:68;10760:178;;8568:2386;;:::o;10760:178::-;3733:1283:3;10909:14:68;3733:1283:3;;;10848:14:68;;;3733:1283:3;;8568:2386:68:o;9115:125::-;14734:570:63;;;30417:18:71;14734:570:63;;;;;11788:10147:68;;;;;;;;;;;;;;;;;;;11574:10367;;;;;-1:-1:-1;11788:10147:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11574:10367;:::o;11788:10147::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;11788:10147:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;23140:10401;;;;;-1:-1:-1;23443:10092:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23140:10401;:::o;23443:10092::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;23443:10092:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;23443:10092:68;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;23443:10092:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;33283:8373:71;;;;3733:1283:3;;33805:23:71;;;;:::i;:::-;34216:30;;;:::i;:::-;3733:1283:3;;;34572:13:71;-1:-1:-1;34587:19:71;;;;;;35966:13;;;-1:-1:-1;35981:15:71;;;;;;40081:11;;;;;:::i;:::-;40212:77;40371:32;40367:180;;35961:4014;40783:704;;;35961:4014;40783:704;;;;2627:1:58;2139:31:74;3733:1283:3;2048:129:74;40783:704:71;-1:-1:-1;40892:15:71;;;;;;40783:704;;;40877:13;41001:18;;;3733:1283:3;41001:18:71;;;:::i;:::-;3733:1283:3;;;;;41001:18:71;40997:313;;40877:13;3733:1283:3;40877:13:71;;40997:313;41255:14;41175:17;;;;:::i;:::-;;41255:14;;;;;:::i;:::-;3733:1283:3;41255:14:71;;:::i;:::-;40997:313;;40367:180;40495:27;40466:10;;40495:27;:::i;:::-;40367:180;;;35998:3;36109:17;;;;:::i;:::-;;36223:28;3733:1283:3;20572:4:58;36223:23:71;;3733:1283:3;;;;;36223:28:71;;36219:279;;36564:25;;;;;:::i;:::-;36585:4;3733:1283:3;;;36564:25:71;36694:24;35560:20;36831:16;;;3733:1283:3;;37075:13:71;-1:-1:-1;37090:19:71;;;;;;37478:21;;;;38323:24;;;;3733:1283:3;;;38611:13:71;-1:-1:-1;38626:27:71;;;;;;35998:3;;;;3733:1283:3;35998:3:71;35966:13;3733:1283:3;35966:13:71;;38655:3;38761:16;;3733:1283:3;38761:16:71;;;:::i;:::-;;39280:641;38928:29;;;3733:1283:3;;;39059:16:71;39055:124;;38655:3;39280:641;;;;;3733:1283:3;38611:13:71;;39055:124;39140:11;;;;;:::i;:::-;39055:124;;;37111:3;37235:8;;3733:1283:3;37235:8:71;;;:::i;:::-;;38077:19;37478:21;;;3733:1283:3;;;37474:483:71;;37111:3;38077:19;3733:1283:3;80285:55:7;;3733:1283:3;37075:13:71;;37474:483;37889:11;37579:169;;;;;:::i;:::-;21798:68:58;;3733:1283:3;;37834:21:71;;;3733:1283:3;37889:11:71;;:::i;:::-;37474:483;;36219:279;36423:26;;-1:-1:-1;36423:26:71;3733:1283:3;36423:26:71;;;:::i;:::-;3733:1283:3;36471:8:71;;34572:13;34733;35602:11;34733:13;;3733:1283:3;34733:13:71;;;:::i;:::-;;34791:14;;4706:18:62;;;3733:1283:3;;;:::i;:::-;;;;:::i;:::-;34909:32:71;34905:476;;34572:13;35560:20;21798:68:58;20572:4;35521:17:71;;21798:68:58;3733:1283:3;;;;21798:68:58;35560:20:71;;3733:1283:3;35602:11:71;;:::i;:::-;3733:1283:3;34572:13:71;;34905:476;35040:92;35239:11;;;3733:1283:3;35239:32:71;35235:128;34905:476;35235:128;;;:::i;:::-;34905:476;;51495:331:59;;;3733:1283:3;;:::i;:::-;;51682:138:59;;;;51495:331::o;4750:890:63:-;4884:754;;;;;;;;;;;;2884:1806:67;;;;4706:18:62;;3733:1283:3;;;:::i;:::-;;;;:::i;:::-;3115:32:67;;3255:10;;;;3247:19;21798:68:58;3255:10:67;3466:11;3255:10;;21798:68:58;3733:1283:3;;;;21798:68:58;3733:1283:3;;;;3247:19:67;3733:1283:3;3269:15:67;;;3733:1283:3;;;3247:37:67;3242:112;;3111:1573;3466:11;3733:1283:3;3450:14:67;;;3733:1283:3;;;;;;3466:11:67;;3733:1283:3;3466:11:67;;:::i;3242:112::-;;;:::i;:::-;;;3111:1573;3516:14;4706:18:62;;3733:1283:3;;;:::i;:::-;;;;:::i;:::-;3499:31:67;3516:14;;3604:15;3773:196;3604:15;;;;3733:1283:3;3600:88:67;;3495:1189;3805:10;;;21798:68:58;3733:1283:3;;3855:14:67;3733:1283:3;3887:11:67;3733:1283:3;3855:14:67;;;3733:1283:3;;;;;;3887:11:67;;3733:1283:3;;;3773:196:67;;:::i;3600:88::-;;;:::i;:::-;;;3495:1189;4007:15;4706:18:62;;3733:1283:3;;;:::i;:::-;;;;:::i;:::-;3990:32:67;4007:15;;4142:10;21798:68:58;4142:10:67;4109:230;4142:10;;21798:68:58;3733:1283:3;;;;21798:68:58;4192:14:67;;;3733:1283:3;;;4224:15:67;3733:1283:3;4257:11:67;4224:15;;;3733:1283:3;4257:11:67;;3733:1283:3;;;4109:230:67;;:::i;3986:698::-;4476:10;21798:68:58;4476:10:67;4442:231;4476:10;;21798:68:58;3733:1283:3;;;;21798:68:58;4526:14:67;;;3733:1283:3;;;4558:15:67;3733:1283:3;4591:11:67;4558:15;;;3733:1283:3;4591:11:67;;3733:1283:3;;;4442:231:67;;:::i;45470:1112:71:-;;;;;;45907:251;45470:1112;3733:1283:3;;45907:251:71;;;:::i;:::-;42030:872;;;;;;;;;;;;;;;;;;;;;;;;3733:1283:3;;48457:34:71;;;;:::i;:::-;48657:35;-1:-1:-1;48758:13:71;;48753:925;48773:21;;;;;;49762:28;;;;;50150:174;49762:28;;;;;49758:320;;48753:925;50150:174;;:::i;:::-;;45470:1112;:::o;49758:320::-;49878:186;;;;;49758:320;;;48796:3;48910:15;;;;;49049:200;48910:15;;;;;:::i;:::-;;49124:27;;;49173:35;;;49049:200;;;:::i;:::-;49325:33;;51140:850;;;;;;;;;;;;;;;;50935:1061;;49325:33;;;;3733:1283:3;;46026:4:71;3733:1283:3;;;49321:343:71;;3733:1283:3;48758:13:71;;;;;;;49321:343;7079:4:58;;49594:51:71;7079:4:58;49594:51:71;7079:4:58;46026::71;7079::58;;;49594:51:71;;;:::i;:::-;;;;:::i;:::-;;49321:343;;2791:4573:68;;;;3733:1283:3;;:::i;:::-;;;;3179:27:68;:66;;;;2791:4573;3162:170;;2791:4573;3733:1283:3;;:::i;:::-;3635:22:68;;;;;;:::i;:::-;3788:27;;3911:24;;;;;;3733:1283:3;;;3911:29:68;3907:495;;4706:9;;;;;;7141:54;4706:9;;;;7168:27;4706:9;;3733:1283:3;4706:9:68;;:::i;:::-;4991:23;:14;;:23;:::i;:::-;3733:1283:3;;;:::i;:::-;4706:18:62;;3733:1283:3;;;;:::i;:::-;;;;:::i;:::-;;5096:14:68;;:20;3733:1283:3;5096:20:68;5193:25;5096:20;5088:29;21798:68:58;5096:20:68;;;21798:68:58;3733:1283:3;;;;5088:29:68;5140:32;21798:68:58;5096:20:68;5148:23;;21798:68:58;3733:1283:3;;;;5140:32:68;5088:84;5193:25;;3733:1283:3;5221:28:68;;3733:1283:3;5193:56:68;3733:1283:3;;4985:82:68;;3733:1283:3;;4984:266:68;4966:433;;2791:4573;-1:-1:-1;3733:1283:3;;5509:14:68;;:21;;3733:1283:3;-1:-1:-1;3911:24:68;;;5690:26;;;5096:20;5690:26;5998:42;5690:26;5998:136;5690:26;;:::i;:::-;;3733:1283:3;;6218:14:68;;:21;;3733:1283:3;;;7079:4:58;;;5998:42:68;:::i;:::-;;:74;:109;;6108:25;;3733:1283:3;5998:136:68;;:::i;:::-;;:169;80285:55:7;5478:1611:68;7168:27;3733:1283:3;;;;;;7168:27:68;7141:14;;:24;3733:1283:3;;;;;;5478:1611:68;6403:18;;;;;;;5096:20;5193:25;6691:42;6403:18;;6691:128;6403:18;;:::i;:::-;;6856:14;;:21;3733:1283:3;;;;;7079:4:58;;;6691:42:68;:::i;:128::-;;:161;80285:55:7;3733:1283:3;7030:14:68;;;:21;80285:55:7;5478:1611:68;;4966:433;5358:16;;;:::i;:::-;4966:433;;;3907:495;4174:30;;;;;;;;4231:37;3733:1283:3;4174:30:68;;;;;3733:1283:3;4231:37:68;3733:1283:3;4295:53:68;:27;;10909:14;3733:1283:3;;;3162:170:68;;;:::i;:::-;;;3179:66;3733:1283:3;;;3210:35:68;3179:66;;13643:776:63;13755:662;;;;;;;;16909:518;;16981:444;;;;;;3733:1283:3;558:26:7;;:::i;:::-;;4009:4:72;558:26:7;;3733:1283:3;-1:-1:-1;3733:1283:3;558:26:7;3733:1283:3;;;;;;;558:26:7;3733:1283:3;;;:::i;:::-;;;;;;;;;;;;;;:::o;3263:2382:72:-;;5213:9;4402:17;3263:2382;5504:29;3263:2382;3697:56;3735:18;3697:34;:24;;:34;3733:1283:3;;;;;;;3263:2382:72;3733:1283:3;;;:::i;:::-;3697:56:72;;:::i;:::-;4827:9;3964:50;;;;:::i;:::-;4128:22;;;;;;;;:::i;:::-;4239:33;;;;:::i;:::-;;;;;:::i;:::-;;4402:17;;:::i;:::-;4548;;;:::i;:::-;;:28;4827:9;;;:::i;:::-;5157:17;4961:16;;:::i;:::-;4987:26;;;;;:::i;:::-;80285:55:7;5157:17:72;:::i;:::-;;5213:9;:::i;:::-;21798:68:58;;3733:1283:3;;5412:20:72;;;21798:68:58;3733:1283:3;;21798:68:58;3733:1283:3;5504:29:72;;2627:1:58;2139:31:74;3733:1283:3;2048:129:74;5504:29:72;4009:4;3263:2382;:::o;3733:1283:3:-;;;:::i;:::-;;;6598:9368:72;6931:25;;;;3733:1283:3;6984:23:72;;;3733:1283:3;;6598:9368:72;3733:1283:3;;6598:9368:72;;7395:30;;:::i;:::-;8728:21;;;;;;;;3733:1283:3;8876:22:72;-1:-1:-1;9047:13:72;;9062:19;;;;;;;;;9898;;;;;;;;;11230:25;11321:413;11230:25;;;3733:1283:3;;;;:::i;:::-;11321:413:72;;11751:105;;9042:2003;9851:21;12927:46;;;;;;3733:1283:3;13159:13:72;-1:-1:-1;13174:27:72;;;;;;15612:11;;;;;;;;;;;;;;;:::i;:::-;15698:68;15848:23;15844:116;;6598:9368;:::o;15844:116::-;15930:18;15379:10;;15930:18;:::i;13203:3::-;13345:29;3733:1283:3;13345:29:72;;;;;;;13512:282;13345:29;;;:32;3733:1283:3;13345:29:72;;;:32;:::i;:::-;;13548:29;;;3733:1283:3;;;13599:27:72;;;3733:1283:3;;;13512:282:72;;:::i;:::-;13892:709;;;;;;;;;4706:18:62;;3733:1283:3;;;:::i;:::-;;;;:::i;:::-;14703:45:72;14699:484;;13203:3;15379:10;;3733:1283:3;;:::i;:::-;;13159:13:72;;14699:484;14847:92;-1:-1:-1;15042:123:72;;14699:484;;;;15042:123;;;:::i;:::-;;;11751:105;;;:::i;:::-;;;9083:3;9179:21;;3733:1283:3;9179:21:72;;;;;;;9811:299;9179:24;:21;3733:1283:3;9179:21:72;;:24;:::i;:::-;;4706:18:62;;;3733:1283:3;;;:::i;:::-;9465:111:72;;9851:21;;;;;3733:1283:3;;;9898:19:72;;;;3733:1283:3;;;9811:299:72;;:::i;:::-;10212:507;;;21798:68:58;10953:26:72;21798:68:58;;;3733:1283:3;;;;;;9047:13:72;;;;;;;6909:866:53;;;;7254:24;;;;;7348:47;;;;;;:::i;7250:519::-;7553:49;;;7515:243;7553:49;;7620:47;7553:49;;;;:::i;:::-;7620:47;;:::i;:::-;7515:243;;:::i;6909:866::-;;;;7254:24;;;;;7348:47;;;;;;:::i;7250:519::-;7553:49;;;7515:243;7553:49;;7620:47;7553:49;;;;:::i;7620:47::-;7515:243;;:::i;3733:1283:3:-;;;;;;;;;;;;;;;-1:-1:-1;3733:1283:3;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;16610:855:72;;;;;;3733:1283:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3733:1283:3;;;;;;;;;;;;;;;;;;;;;17298:160:72;3733:1283:3;;;;;;;;;;;;:::i;:::-;17298:160:72;;;16610:855::o;3733:1283:3:-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2699:1197:73;;;;-1:-1:-1;3733:1283:3;;;;3161:12:73;3733:1283:3;;;;;;;;;;;;;;9873:301:78;;3733:1283:3;;;;;10369:754:78;;3733:1283:3;;;3567:24:73;3563:102;;2699:1197;-1:-1:-1;;3733:1283:3;;;;-1:-1:-1;3733:1283:3;;-1:-1:-1;3862:27:73;;-1:-1:-1;3733:1283:3;3563:102:73;3733:1283:3;;;;:::i;:::-;;;;;;;;;;;;;;;;3862:27:73;3733:1283:3;;;;3607:47:73;3733:1283:3;;;;;;;;;;;2972:82:73;;3607:47;:::i;:::-;3563:102;;;;;3733:1283:3;;;;10369:754:78;19866:473:63;;;;3733:1283:3;19866:473:63;;;;9873:301:78;19153:457:63;;;;3733:1283:3;19153:457:63;;;;9075:5325:73;;;;;;;;:::o;:::-;;;;;;;4851:9555;5168:24;;5331:25;5301:143;5302:142;5331:25;;;3733:1283:3;5374:23:73;;;3733:1283:3;5302:142:73;;:::i;5301:143::-;5284:302;;5725:317;;;;;;;;;;;;;;;;;6240:25;;;;6269:18;3733:1283:3;;;;;:::i;:::-;;;;:::i;:::-;6240:47:73;6236:1096;;7415:101;;;;;;7601:66;;4851:9555;3733:1283:3;;;;;:::i;:::-;4009:4:72;35804:212:73;;;;;;;;7758:309;;4851:9555;8170:58;;;:::i;:::-;8340:23;;;3733:1283:3;;31099:12:73;3733:1283:3;;;;;;;8340:23:73;8450:189;8449:190;8450:189;;;;:::i;8449:190::-;8432:348;;3733:1283:3;;;;;;;8875:24:73;8871:194;;4851:9555;9075:5325;;;;;;;;;;4009:4:72;;9075:5325:73;;;;;;;;;;;;;;;4851:9555::o;9075:5325::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;9075:5325:73;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8871:194;9017:23;21798:68:58;9017:23:73;21798:68:58;;3733:1283:3;;;;21798:68:58;9017:23:73;;;;;:::i;:::-;8871:194;;;;;8432:348;-1:-1:-1;;;;;;;;;;;;8745:24:73:o;7758:309::-;;;:::i;:::-;;;7601:66;;;:::i;:::-;;;6236:1096;6381:376;;;6240:25;6381:376;;;4009:4:72;6381:376:73;;7166:155;6381:376;;;6850:74;;6236:1096;7243:23;;7166:155;;:::i;:::-;7143:178;;;;;:::o;6850:74::-;;;:::i;:::-;;;5284:302;5550:25;;-1:-1:-1;5550:25:73;-1:-1:-1;5550:25:73;-1:-1:-1;5550:25:73;:::o;4851:9555::-;5168:24;;5331:25;5301:143;5302:142;5331:25;;;3733:1283:3;5374:23:73;;;3733:1283:3;2063:153:78;-1:-1:-1;2063:153:78;;-1:-1:-1;2063:153:78;;1836:570;;5301:143:73;5284:302;;5725:317;;;;;;;;;;;;;;;;;6240:25;;;;6269:18;3733:1283:3;;;;;:::i;:::-;;;;:::i;:::-;6240:47:73;6236:1096;;7415:101;;;;;;7601:66;;4851:9555;3733:1283:3;;;;;:::i;:::-;35804:212:73;;;;;;;;;7758:309;;4851:9555;8170:58;;;:::i;:::-;8340:23;;;3733:1283:3;;31099:12:73;3733:1283:3;;;;;;;8340:23:73;8450:189;8449:190;8450:189;;;;:::i;7758:309::-;;;:::i;:::-;;;7601:66;;;:::i;:::-;;;6236:1096;6381:376;;;6240:25;6381:376;;;;;;7166:155;6381:376;;;6850:74;;6236:1096;7243:23;;7166:155;;:::i;6850:74::-;;;:::i;:::-;;;2424:648:54;2732:29;;;;3733:1283:3;2782:47:54;;;3733:1283:3;-1:-1:-1;3920:136:54;;21798:68:58;3015:36:54;3733:1283:3;2948:117:54;21798:68:58;;3733:1283:3;;;-1:-1:-1;3733:1283:3;2974:9:65;3733:1283:3;;;-1:-1:-1;3733:1283:3;;38028:203:56;;3015:36:54;2948:117;;:::i;3854:332:63:-;;3895:289;;;;;;20432:442;;20492:380;;;;;;18871:6641:73;19256:29;;21621:21;19256:29;;;;;3733:1283:3;19308:47:73;;;3733:1283:3;19256:99:73;19239:203;;18871:6641;-1:-1:-1;21798:68:58;19585:92:73;21798:68:58;;;3733:1283:3;;;;21798:68:58;19585:92:73;;;:::i;:::-;19691:94;;;;;20280:24;;;3733:1283:3;;;;20280:15:73;3733:1283:3;;;;;;;20280:24:73;3733:1283:3;;;4009:4:72;;3733:1283:3;;;;;;20343:284:73;;;20740:8;;20736:102;;18871:6641;21304:65;;:::i;:::-;21166:203;;;;;21448:85;;18871:6641;21621:21;;;3733:1283:3;;;21786:36:73;;21782:113;;18871:6641;-1:-1:-1;21987:992:73;22007:23;;;;;;;23070:29;;;;23261;;3733:1283:3;;;;;;23448:58:73;;23444:135;;21987:992;23679:13;;-1:-1:-1;23674:1421:73;23694:26;;;;;;;25190:45;;;;;;25305:85;;25481:24;;18871:6641;:::o;25305:85::-;25369:9;;;:::i;:::-;25481:24;;18871:6641;:::o;23679:13::-;23844:29;;;;;;;;;:::i;:::-;;24600:329;24023:16;;;;:::i;:::-;;7652:63:7;;;73322:53;7652:63;;;73322:53;-1:-1:-1;24541:36:73;;;;:::i;:::-;24263:314;5348:4:58;;7652:63:7;;;59322:53;7652:63;;59322:53;24600:329:73;17471:363;;17620:208;;;;;17471:363;;24600:329;24263:666;24228:701;3733:1283:3;;23679:13:73;;;;;23444:135;23554:9;;;:::i;:::-;23444:135;;21992:13;22154:42;;;:45;:42;;;:45;:::i;:::-;;22777:36;22349:8;;;;:::i;:::-;;7652:63:7;;;73322:53;7652:63;;;73322:53;-1:-1:-1;22777:36:73;;:::i;:::-;22507:306;22472:341;3733:1283:3;;21992:13:73;;;21782:113;21870:9;;;:::i;:::-;21782:113;;21448:85;21512:9;;;:::i;:::-;21448:85;;20736:102;34783:17;;;:::i;:::-;20736:102;;19239:203;;;:::i;:::-;;;18871:6641;19256:29;;;;;;;3733:1283:3;19308:47:73;;;3733:1283:3;19256:99:73;19239:203;;18871:6641;19585:92;21798:68:58;;;3733:1283:3;;;;21798:68:58;19585:92:73;;;:::i;:::-;7083:5:71;;19691:94:73;;;;;;;;20280:24;;;3733:1283:3;;;;20280:15:73;3733:1283:3;;;;;;;20280:24:73;3733:1283:3;;;;;;;;;;;20343:284:73;;;20740:8;;20736:102;;21304:65;21621:21;21304:65;;;;:::i;:::-;21166:203;;;;;21448:85;;18871:6641;21621:21;;;3733:1283:3;;;21786:36:73;;21782:113;;18871:6641;21992:13;21987:992;22007:23;;;;;;;23070:29;;;;23261;;3733:1283:3;;;;;23448:58:73;;23444:135;;21987:992;23679:13;;;23694:26;;;;;;;25190:45;;;;;;25305:85;;25481:24;;18871:6641;:::o;23679:13::-;23844:29;;;;;;;;;:::i;:::-;;24600:329;24023:16;;;;:::i;24600:329::-;24263:666;24228:701;3733:1283:3;;23679:13:73;;;;;23444:135;23554:9;;;:::i;:::-;23444:135;;21992:13;22154:42;;;:45;:42;;;:45;:::i;:::-;;22777:36;22349:8;;;;:::i;22777:36::-;22507:306;22472:341;3733:1283:3;;21992:13:73;;;21782:113;21870:9;;;:::i;:::-;21782:113;;21448:85;21512:9;;;:::i;:::-;21448:85;;20736:102;20768:55;;;;;;;;:::o;19239:203::-;;;:::i;:::-;;;34190:7774:59;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4669:2995:60;;;7079:4:58;4669:2995:60;7311:86;645:4:7;3733:1283:3;80285:55:7;22136:10:58;80285:55:7;;7652:63;22197:4:58;7652:63:7;;5443:10:60;;7652:63:7;;;80285:55;5574:4:58;645::7;7652:63;;80285:55;6763:104:60;7652:63:7;6041:96:60;645:4:7;7652:63;;58656:53;7652:63;;;6041:96:60;;:::i;:::-;7079:4:58;;5574;7079;7652:63:7;;;80285:55;7652:63;58656:53;7652:63;;;;;6763:104:60;;:::i;:::-;7079:4:58;;;5574;7079;;5574;7652:63:7;;80285:55;7652:63;;7311:86:60;;:::i;:::-;7079:4:58;;4669:2995:60;:::o;3523:535::-;73322:53:7;;6088:4:58;7079;6130:10;3887:56:60;;3523:535;4036:4;;3887:56;;3523:535;6243:456:7;;;6363:330;;;;;;;;;6243:456::o;25095:2106:60:-;;25241:1954;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;25095:2106;:::o;25241:1954::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12020:543:63;12087:474;;;;;;;;23203:518;;23275:444;;;;;;15172:1827:73;;15320:1673;;;;;;;;;;;;;;;15172:1827;15320:1673;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15172:1827;:::o;15320:1673::-;-1:-1:-1;15320:1673:73;;;;;;;;;;;;;3733:1283:3;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;;;;;;;;;;:::o;8203:356:63:-;;8250:307;;;;;;3733:1283:3;;;;;;;;;;;;;;;-1:-1:-1;3733:1283:3;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3733:1283:3;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;1418:532:74:-;;;:::i;:::-;2658:1:58;16901:5:55;3733:1283:3;1418:532:74:o;:::-;;;:::i;:::-;7079:4:58;1878:55:74;3733:1283:3;1418:532:74:o;:::-;;;:::i;:::-;2658:1:58;7079:4;1878:55:74;3733:1283:3;1418:532:74:o;2325:215::-;2627:1:58;2450:16:74;3733:1283:3;2450:32:74;2446:88;;2325:215::o;2446:88::-;16013:304:63;2450:16:74;16013:304:63;;;;2719:256:74;2717:1:58;2853:16:74;3733:1283:3;2853:56:74;2849:120;;2719:256::o;2849:120::-;2948:9;;;:::i;15391:5413:76:-;;;;15616:5182;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15391:5413::o;15616:5182::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21452:6120;;;;;;21703:5863;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21452:6120::o;21703:5863::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1836:570:78;;;2063:153;;;;;;;;2329:6;;;2306:94;;1836:570;;:::o;3081:1637::-;;;;3307:73;;;3459:52;;3595:18;;:::i;:::-;3730:81;;;;14107:843:69;;;;;;;;;;;;;;13900:1056;3730:81:78;3733:1283:3;;;4043:14:78;5249:568;;;;;;;;;;;;;4067:396;5249:568;;;6648:1807;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4284:47;6648:1807;4692:9;6648:1807;;11415:6984:57;6648:1807:78;-1:-1:-1;6648:1807:78;11415:6984:57;;:::i;:::-;-1:-1:-1;8677:142:78;;6648:1807;-1:-1:-1;8677:142:78;4284:47;14107:843:69;;;;;;;;;;;;;;13900:1056;4284:47:78;4067:396;4692:9;:::i;6648:1807::-;;;;;;;;;;;;;;-1:-1:-1;6648:1807:78;;;;;;;;;;;;;4067:396;4429:23;4692:9;4429:23;;;;4067:396;4692:9;:::i;3459:52::-;3494:7;;;;:::o;2153:12808:75:-;;;;;-1:-1:-1;2546:11810:75;;;;;;;;;;;;;;;;;;;;;;;;;;;2153:12808;-1:-1:-1;;;2546:11810:75;;;;;;;;;;;2153:12808;14403:8;;;;;;;;;14399:556;;2153:12808::o;14399:556::-;;;:::i;:::-;14620:325;-1:-1:-1;14620:325:75;;;;2546:11810;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2546:11810:75;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2546:11810:75;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2546:11810:75;;;;;;;;;-1:-1:-1;2546:11810:75;;;;;;-1:-1:-1;2546:11810:75;;-1:-1:-1;2546:11810:75;;;;;;;;-1:-1:-1;2546:11810:75;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11415:6984:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;:::o;9609:1596:78:-;;3733:1283:3;;;;;;9873:301:78;;3733:1283:3;;;;;10373:25:78;;10369:754;;9609:1596;11186:12;;;31401:4:73;9609:1596:78;:::o;10369:754::-;3733:1283:3;;-1:-1:-1;10762:47:78;10758:355;;10369:754;;;;;10758:355;10975:9;;;:::i;:::-;10758:355;;;9873:301;19153:457:63;;-1:-1:-1;19153:457:63;;;;;;9609:1596:78;;7083:5:71;3733:1283:3;;;;;;;9873:301:78;;3733:1283:3;;;;;10373:25:78;;10369:754;;9609:1596;11186:12;;;;11194:4;9609:1596;:::o;10369:754::-;3733:1283:3;;-1:-1:-1;10762:47:78;10758:355;;10369:754;;;;10758:355;10906:98;;10758:355;11086:12;7083:5:71;11086:12:78;:::o;10906:98::-;10975:9;;;:::i;:::-;10906:98;;;9873:301;9989:88;;;10151:12;7083:5:71;10151:12:78;:::o;17582:532:63:-;17647:465;;;;;;;;1703:939:79;;;2108:15;;;20572:4:58;;;;;;:::i;:::-;6277:374:79;;;;;;;;;;;;2063:573;;1703:939;;;:::o;2063:573::-;2574:37;58656:53:7;19893:71:60;19945:18;7652:63:7;645:4;58656:53;80285:55;23113:10:58;80285:55:7;;7652:63;;;;80285:55;7652:63;645:4;7652:63;;80285:55;6277:374:79;7652:63:7;;;80285:55;19945:18:60;;:::i;19893:71::-;2108:15:79;7652:63:7;;80285:55;7652:63;14158:5:58;7652:63:7;;;3850:61;5242:5:58;7652:63:7;;;80285:55;7079:4:58;7652:63:7;;;80285:55;2466:15:79;22197:4:58;7079;14703:5;24102:61:7;21711:25:60;7652:63:7;12909:5:58;;7079:4;;24160:6;7079:4;7652:63:7;;;;12909:5:58;;;24320:6;7079:4;21711:25:60;:::i;:::-;7079:4:58;;;23766;7652:63:7;;80285:55;7652:63;;;;;-1:-1:-1;7652:63:7;;;80285:55;7079:4:58;;;7652:63:7;;;80285:55;6277:374:79;7652:63:7;;;80285:55;7652:63;80285:55;7079:4:58;7652:63:7;;2466:15:79;;:::i;:::-;2574:37;:::i;3289:2398::-;;;3754:24;;3917:20;;;;3733:1283:3;;;;;;;;;;3289:2398:79;3887:68;3939:15;;;21798:68:58;3733:1283:3;21798:68:58;;3733:1283:3;6277:374:79;;;;;;;;;;;;6129:528;;3887:68;3733:1283:3;;;4150:23:79;;4057:159;4150:23;3917:20;5666:13;4150:23;;;4057:159;;;:::i;:::-;4038:178;59322:53:7;4536::79;5756:10:62;3870:1654:79;5666:13;:::i;3870:1654::-;4634:18;3733:1283:3;;;;;;;;:::i;:::-;;;;:::i;:::-;4610:42:79;4634:18;;5666:13;59322:53:7;5158:189:79;59322:53:7;;;4902:167:79;3917:20;4902:167;;;5249:23;;;5158:189;;;:::i;:::-;5139:208;6193:10:62;4606:918:79;5666:13;:::i;4606:918::-;5507:7;;;;:::o;3733:1283:3:-;;;:::i;:::-;;;8898:3520:60;;;;;7652:63:7;7079:4:58;8898:3520:60;11601:100;12037:110;8898:3520;645:4:7;58656:53;80285:55;22605:10:58;80285:55:7;;22197:4:58;7652:63:7;;9876:35:60;;7652:63:7;;;80285:55;7652:63;;;;80285:55;11157:122:60;5518:4:58;10469:96:60;645:4:7;7652:63;;58656:53;7652:63;;;10469:96:60;;:::i;:::-;7079:4:58;;7652:63:7;7079:4:58;645::7;7652:63;;80285:55;7652:63;58656:53;7652:63;;;;;11157:122:60;;:::i;:::-;7079:4:58;;7652:63:7;7079:4:58;;5518;7652:63:7;;80285:55;7652:63;;;;;11601:100:60;;:::i;:::-;7079:4:58;;;7652:63:7;7079:4:58;;5574;7652:63:7;;80285:55;7652:63;;12037:110:60;;:::i;13819:4457::-;;;17854:110;13819:4457;7079:4:58;13819:4457:60;;645:4:7;58656:53;80285:55;23113:10:58;80285:55:7;;22197:4:58;7652:63:7;;;;;;;80285:55;645:4;7652:63;;80285:55;14962:10:60;7652:63:7;;;80285:55;73322:53;;7652:63;;;80285:55;5348:4:58;7652:63:7;;73322:53;7652:63;;;80285:55;23709:4:58;7652:63:7;;73322:53;7652:63;;;;;;80285:55;23766:4:58;7652:63:7;;73322:53;7652:63;;;80285:55;7652:63;5348:4:58;7652:63:7;;80285:55;17378:102:60;645:4:7;7652:63;;58656:53;7652:63;16924:122:60;7652:63:7;16211:96:60;7652:63:7;;;;;16211:96:60;;:::i;:::-;7079:4:58;;;;23709;7652:63:7;;80285:55;7652:63;58656:53;7652:63;;;;;16924:122:60;;:::i;:::-;7079:4:58;;;;;23766;7652:63:7;;80285:55;7652:63;;;;;17378:102:60;;:::i;:::-;7079:4:58;;;;;;23821:5;7652:63:7;;80285:55;7652:63;;17854:110:60;23543:797;24184:15;7374:64:7;23543:797:60;;;73322:53:7;;;80285:55;;;6009:3:58;;7374:64:7;;;;;;24184:15:60;:::i;27976:1402::-;73322:53:7;;80285:55;;;;7374:64;;;;;;;6009:3:58;;;;7079:4;;7374:64:7;;29039:263:60;6814:46:7;;;;;;12909:5:58;;;5348:4;12909:5;7079:4;27976:1402:60;:::o;29039:263::-;5348:4:58;3733:1283:3;;;;;;6363:330:7;;;;;;;;;7374:64;;7652:63;;29039:263:60;;;7365:2122:79;7602:527;7365:2122;;;;7602:527;;;;-1:-1:-1;;7602:527:79;;;;;;;;;;;;;8193:8;;8189:678;;8944:11;8940:541;;7365:2122;;:::o;8940:541::-;5756:10:62;9023:448:79;;7602:527;9023:448;;;;8189:678;;5756:10:62;8189:678:79;;;:::i;7365:2122::-;7602:527;7365:2122;;;;;7602:527;;;;-1:-1:-1;;7602:527:79;;;;;;;;;;;;;8193:8;;8189:678;;8944:11;8940:541;;7365:2122;;;:::o;8189:678::-;;;;:::i;3733:1283:3:-;-1:-1:-1;3733:1283:3;34105:19:59;34190:7774;;;;;;-1:-1:-1;34190:7774:59;;;;;;;;;;3733:1283:3;34190:7774:59;;;;3733:1283:3;;;;;;;;;:::o;34190:7774:59:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;34190:7774:59;-1:-1:-1;34190:7774:59;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;34190:7774:59;;;;3733:1283:3;;24102:61:7;;6009:3:58;;;;;1155:118:7;;;20572:4:58;;1155:118:7;;;;;;;;740:10;8753:40;;;80285:55;;-1:-1:-1;16949:19:59;;;;;;-1:-1:-1;3733:1283:3;;-1:-1:-1;;;;3733:1283:3:o;16970:17:59:-;3553:65:7;17220:51:59;3553:65:7;;;;;;;;24102:61;2602:59;3553:65;;;17220:51:59;:::i;:::-;7652:63:7;;;;;80285:55;7079:4:58;16929:18:59;
Swarm Source
none
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.