This is an old version of OpenSea's Seaport contract. It has been updated to a new version on this address.
More Info
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
Contract Name:
Seaport
Compiler Version
v0.8.13+commit.abaa5c0e
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import { ConduitTransfer, ConduitBatch1155Transfer } 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(); /** * @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 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(); /** * @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 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; import { ConduitItemType } from "./ConduitEnums.sol"; struct ConduitTransfer { ConduitItemType itemType; address token; address from; address to; uint256 identifier; uint256 amount; } struct ConduitBatch1155Transfer { address token; address from; address to; uint256[] ids; uint256[] amounts; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; enum ConduitItemType { NATIVE, // unused ERC20, ERC721, ERC1155 }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import { ERC20Interface, ERC721Interface, ERC1155Interface } from "../interfaces/AbridgedTokenInterfaces.sol"; import { ConduitInterface } from "../interfaces/ConduitInterface.sol"; import { ItemType } from "./ConsiderationEnums.sol"; import { ReceivedItem } from "./ConsiderationStructs.sol"; import { Verifiers } from "./Verifiers.sol"; import { TokenTransferrer } from "./TokenTransferrer.sol"; import "./ConsiderationConstants.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) { // transfer the native tokens to the recipient. _transferEth(item.recipient, item.amount); } else if (item.itemType == ItemType.ERC20) { // 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 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 itself. * * @param itemType The type of item to transfer, either ERC721 or ERC1155. * @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. * @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, address token, address from, address to, uint256 identifier, uint256 amount, bytes32 conduitKey ) internal { // 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 to memory. mstore(add(callDataOffset, Conduit_execute_transferTo_ptr), to) // 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) { revert InvalidERC721TransferAmount(); } // Perform transfer via the token contract directly. _performERC721Transfer(token, from, to, identifier); } else { // Perform transfer via the token contract directly. _performERC1155Transfer(token, from, to, identifier, amount); } } } /** * @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 _transferEth(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 ETH 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. revert EtherTransferGenericFailure(to, amount); } } /** * @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, uint256(1), 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) { revert InvalidERC721TransferAmount(); } // 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, uint256(2), 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, uint256(3), 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 != 64) { 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; // 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 ) } // If the call failed... if (!success) { // Pass along whatever revert reason was given by the conduit. _revertWithReasonIfOneIsReturned(); // Otherwise, revert with a generic error. revert InvalidCallToConduit(conduit); } // Ensure that the conduit returned the correct magic value. bytes4 result; assembly { // Take value from scratch space and place it on the stack. result := mload(0) } // Ensure result was extracted and matches EIP-1271 magic value. if (result != ConduitInterface.execute.selector) { revert InvalidConduit(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, uint256 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.13; interface ERC20Interface { function transferFrom( address, address, uint256 ) external returns (bool); } interface ERC721Interface { function transferFrom( address, address, uint256 ) external; } interface ERC1155Interface { function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) external; function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; }
// 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 } 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.13; import { OrderType, BasicOrderType, ItemType, Side } from "./ConsiderationEnums.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 nonce, 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 nonce; } /** * @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 an 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 nonce, 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 included in a staticcall to * `isValidOrderIncludingExtraData` on the zone for the order if the order * type is restricted and the offerer or zone are not the caller. */ 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 nonce), 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; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import { OrderStatus } from "./ConsiderationStructs.sol"; import { Assertions } from "./Assertions.sol"; import { SignatureVerification } from "./SignatureVerification.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) { // Revert if order's timespan hasn't started yet or has already ended. if (startTime > block.timestamp || endTime <= block.timestamp) { // Only revert if revertOnInvalid has been supplied as true. if (revertOnInvalid) { revert InvalidTime(); } // Return false as the order is invalid. return false; } // Return true as the order time is valid. valid = true; } /** * @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 32 or 33 bytes or if the recovered signer does not match the * supplied offerer. Note that in cases where a 32 or 33 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 { // Skip signature verification if the offerer is the caller. if (offerer == msg.sender) { return; } // Derive EIP-712 digest using the domain separator and the order hash. bytes32 digest = _deriveEIP712Digest(_domainSeparator(), orderHash); // Ensure that the signature for the digest is valid for the offerer. _assertValidSignature(offerer, digest, signature); } /** * @dev Internal pure 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 memory orderStatus, bool onlyAllowUnused, bool revertOnInvalid ) internal pure 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) { revert OrderIsCancelled(orderHash); } // Return false as the order status is invalid. return false; } // If the order is not entirely unused... if (orderStatus.numerator != 0) { // ensure the order has not been partially filled when not allowed. if (onlyAllowUnused) { // Always revert on partial fills when onlyAllowUnused is true. revert OrderPartiallyFilled(orderHash); // Otherwise, ensure that order has not been entirely filled. } else if (orderStatus.numerator >= orderStatus.denominator) { // Only revert if revertOnInvalid has been supplied as true. if (revertOnInvalid) { revert OrderAlreadyFilled(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 "./TokenTransferrerConstants.sol"; import { TokenTransferrerErrors } from "../interfaces/TokenTransferrerErrors.sol"; import { ConduitBatch1155Transfer } from "../conduit/lib/ConduitStructs.sol"; 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 { // Write calldata to the free memory pointer, but restore it later. let memPointer := mload(FreeMemoryPointerSlot) // Write calldata 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. 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 ) // If the transfer failed or it returned nothing: // Group these because they should be uncommon. // 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. let returnDataWords := div( returndatasize(), OneWord ) // 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 := div(memPointer, OneWord) // 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 ), div( sub( mul( returnDataWords, returnDataWords ), mul(msizeWords, msizeWords) ), MemoryExpansionCoefficient ) ) ) } // 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()) } } // Otherwise revert with a generic error message. mstore( TokenTransferGenericFailure_error_sig_ptr, TokenTransferGenericFailure_error_signature ) mstore( TokenTransferGenericFailure_error_token_ptr, token ) mstore( TokenTransferGenericFailure_error_from_ptr, from ) mstore(TokenTransferGenericFailure_error_to_ptr, to) mstore(TokenTransferGenericFailure_error_id_ptr, 0) mstore( TokenTransferGenericFailure_error_amount_ptr, amount ) revert( TokenTransferGenericFailure_error_sig_ptr, TokenTransferGenericFailure_error_length ) } // Otherwise revert with a message about the token // returning false. mstore( BadReturnValueFromERC20OnTransfer_error_sig_ptr, BadReturnValueFromERC20OnTransfer_error_signature ) 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( BadReturnValueFromERC20OnTransfer_error_sig_ptr, BadReturnValueFromERC20OnTransfer_error_length ) } // Otherwise revert with error about token not having code: mstore(NoContract_error_sig_ptr, NoContract_error_signature) mstore(NoContract_error_token_ptr, token) revert(NoContract_error_sig_ptr, NoContract_error_length) } // Otherwise the token just returned nothing but otherwise // 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. * * @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)) { mstore(NoContract_error_sig_ptr, NoContract_error_signature) mstore(NoContract_error_token_ptr, token) revert(NoContract_error_sig_ptr, NoContract_error_length) } // Write calldata to free memory pointer (restore it later). let memPointer := mload(FreeMemoryPointerSlot) // Write calldata 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. let returnDataWords := div(returndatasize(), OneWord) // 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 := div(memPointer, OneWord) // 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 ), div( sub( mul(returnDataWords, returnDataWords), mul(msizeWords, msizeWords) ), MemoryExpansionCoefficient ) ) ) } // 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. mstore( TokenTransferGenericFailure_error_sig_ptr, TokenTransferGenericFailure_error_signature ) mstore(TokenTransferGenericFailure_error_token_ptr, token) mstore(TokenTransferGenericFailure_error_from_ptr, from) mstore(TokenTransferGenericFailure_error_to_ptr, to) mstore(TokenTransferGenericFailure_error_id_ptr, identifier) mstore(TokenTransferGenericFailure_error_amount_ptr, 1) revert( TokenTransferGenericFailure_error_sig_ptr, 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 onReceived 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)) { mstore(NoContract_error_sig_ptr, NoContract_error_signature) mstore(NoContract_error_token_ptr, token) revert(NoContract_error_sig_ptr, NoContract_error_length) } // Write calldata to these slots below, but restore them later. let memPointer := mload(FreeMemoryPointerSlot) let slot0x80 := mload(Slot0x80) let slot0xA0 := mload(Slot0xA0) let slot0xC0 := mload(Slot0xC0) // Write calldata 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) 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. let returnDataWords := div(returndatasize(), OneWord) // 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 := div(memPointer, OneWord) // 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 ), div( sub( mul(returnDataWords, returnDataWords), mul(msizeWords, msizeWords) ), MemoryExpansionCoefficient ) ) ) } // 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. mstore( TokenTransferGenericFailure_error_sig_ptr, TokenTransferGenericFailure_error_signature ) mstore(TokenTransferGenericFailure_error_token_ptr, token) mstore(TokenTransferGenericFailure_error_from_ptr, from) mstore(TokenTransferGenericFailure_error_to_ptr, to) mstore(TokenTransferGenericFailure_error_id_ptr, identifier) mstore(TokenTransferGenericFailure_error_amount_ptr, amount) revert( TokenTransferGenericFailure_error_sig_ptr, 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 onReceived to indicate that they are willing to accept the * transfer. * * @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) ) // 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 ) // Get the total number of supplied ids. let idsLength := calldataload( add(elementPtr, ConduitBatch1155Transfer_ids_length_offset) ) // 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, mul(idsLength, TwoWords)) // 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_data_length_basePtr, mul(idsLength, TwoWords) ) // Copy second section of calldata (including dynamic values). calldatacopy( BatchTransfer1155Params_ids_length_ptr, add(elementPtr, ConduitBatch1155Transfer_ids_length_offset), idsAndAmountsSize ) // Determine the expected offset for the amounts array. let expectedAmountsOffset := add( ConduitBatch1155Transfer_amounts_length_baseOffset, mul(idsLength, OneWord) ) // 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, ConduitBatch1155Transfer_amounts_head_offset ) ), expectedAmountsOffset ) ) ) ) // Revert with an error if the encoding is not valid. if invalidEncoding { mstore( Invalid1155BatchTransferEncoding_ptr, Invalid1155BatchTransferEncoding_selector ) revert( Invalid1155BatchTransferEncoding_ptr, Invalid1155BatchTransferEncoding_length ) } // Retrieve the token from calldata. let token := calldataload(elementPtr) // If the token has no code, revert. if iszero(extcodesize(token)) { mstore(NoContract_error_sig_ptr, NoContract_error_signature) mstore(NoContract_error_token_ptr, token) revert(NoContract_error_sig_ptr, NoContract_error_length) } // 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. let returnDataWords := div(returndatasize(), OneWord) // 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 := div(transferDataSize, OneWord) // 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 ), div( sub( mul( returnDataWords, returnDataWords ), mul(msizeWords, msizeWords) ), MemoryExpansionCoefficient ) ) ) } // 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) // Move the ids and amounts offsets forward a word. mstore( BatchTransfer1155Params_ids_head_ptr, ConduitBatch1155Transfer_amounts_head_offset ) mstore( BatchTransfer1155Params_amounts_head_ptr, add( OneWord, mload(BatchTransfer1155Params_amounts_head_ptr) ) ) // Return modified region with one fewer word at the end. revert( 0, add(transferDataSize, BatchTransfer1155Params_ptr) ) } } // Reset the free memory pointer to the default value; memory must // be assumed to be dirtied and not reused from this point forward. mstore(FreeMemoryPointerSlot, DefaultFreeMemoryPointer) } } }
// 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.13/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 lets us write both values at once. // Length goes at byte 63, and name fills bytes 64-77, so we write // both values left-padded to 45. uint256 constant NameLengthPtr = 45; uint256 constant NameWithLength = 0x0d436F6E73696465726174696F6E; uint256 constant Version = 0x31; uint256 constant Version_length = 1; uint256 constant _NOT_ENTERED = 1; uint256 constant _ENTERED = 2; // Common Offsets // Offsets for identically positioned fields shared by: // OfferItem, ConsiderationItem, SpentItem, ReceivedItem uint256 constant Common_token_offset = 0x20; uint256 constant Common_identifier_offset = 0x40; uint256 constant Common_amount_offset = 0x60; 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_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 InvalidFulfillmentComponentData_error_signature = ( 0x7fda727900000000000000000000000000000000000000000000000000000000 ); uint256 constant InvalidFulfillmentComponentData_error_len = 0x20; uint256 constant Panic_error_signature = ( 0x4e487b7100000000000000000000000000000000000000000000000000000000 ); uint256 constant Panic_error_offset = 0x04; uint256 constant Panic_error_length = 0x24; uint256 constant Panic_arithmetic = 0x11; uint256 constant MissingItemAmount_error_signature = ( 0x91b3e51400000000000000000000000000000000000000000000000000000000 ); uint256 constant MissingItemAmount_error_len = 0x20; uint256 constant OrderParameters_offer_head_offset = 0x40; uint256 constant OrderParameters_consideration_head_offset = 0x60; uint256 constant OrderParameters_conduit_offset = 0x120; uint256 constant OrderParameters_nonce_offset = 0x140; uint256 constant Fulfillment_itemIndex_offset = 0x20; uint256 constant AdvancedOrder_numerator_offset = 0x20; uint256 constant OneWord = 0x20; uint256 constant TwoWords = 0x40; uint256 constant ThreeWords = 0x60; uint256 constant FourWords = 0x80; uint256 constant FiveWords = 0xa0; 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_considerationHashesArray_ptr = 0x160; uint256 constant EIP712_Order_size = 0x180; uint256 constant EIP712_OfferItem_size = 0xc0; uint256 constant EIP712_ConsiderationItem_size = 0xe0; uint256 constant AdditionalRecipients_size = 0x40; uint256 constant EIP712_DomainSeparator_offset = 0x02; uint256 constant EIP712_OrderHash_offset = 0x22; uint256 constant EIP712_DigestPayload_size = 0x42; 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; // 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; /* * 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 = DefaultFreeMemoryPointer; 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: _nonces[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_nonce_ptr = 0x1e0; uint256 constant BasicOrder_additionalRecipients_head_ptr = 0x240; uint256 constant BasicOrder_signature_ptr = 0x260; // Signature-related bytes32 constant EIP2098_allButHighestBitMask = ( 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ); // abi.encodeWithSignature("NoContract(address)") uint256 constant NoContract_error_signature = ( 0x5f15d67200000000000000000000000000000000000000000000000000000000 ); uint256 constant NoContract_error_sig_ptr = 0x0; uint256 constant NoContract_error_token_ptr = 0x4; uint256 constant NoContract_error_length = 0x24; // 4 + 32 == 36 uint256 constant EIP_712_PREFIX = ( 0x1901000000000000000000000000000000000000000000000000000000000000 ); uint256 constant ExtraGasBuffer = 0x20; uint256 constant CostPerWord = 3; uint256 constant MemoryExpansionCoefficient = 0x200; uint256 constant Create2AddressDerivation_ptr = 0x0b; uint256 constant Create2AddressDerivation_length = 0x55; uint256 constant MaskOverByteTwelve = ( 0x0000000000000000000000ff0000000000000000000000000000000000000000 ); uint256 constant MaskOverLastTwentyBytes = ( 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff ); uint256 constant MaskOverFirstFourBytes = ( 0xffffffff00000000000000000000000000000000000000000000000000000000 ); uint256 constant Conduit_execute_signature = ( 0x4ce34aa200000000000000000000000000000000000000000000000000000000 ); 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;
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import { OrderParameters } from "./ConsiderationStructs.sol"; import { GettersAndDerivers } from "./GettersAndDerivers.sol"; import { TokenTransferrerErrors } from "../interfaces/TokenTransferrerErrors.sol"; import { NonceManager } from "./NonceManager.sol"; import "./ConsiderationConstants.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, NonceManager, 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 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 nonce 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 _assertConsiderationLengthAndGetNoncedOrderHash( 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 nonce for the offerer. return _deriveOrderHash( orderParameters, _getNonce(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) { revert MissingOriginalConsiderationItems(); } } /** * @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 { // Revert if the supplied amont is equal to zero. if (amount == 0) { revert MissingItemAmount(); } } /** * @dev Internal pure function to validate calldata offsets for dynamic * types in BasicOrderParameters. This ensures that functions using the * calldata object normally will be using the same data as the assembly * functions. Note that no parameters are supplied as all basic order * functions use the same calldata encoding. */ function _assertValidBasicOrderParameterOffsets() 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) */ validOffsets := and( // Order parameters at calldata 0x04 must have offset of 0x20. eq( calldataload(BasicOrder_parameters_cdPtr), BasicOrder_parameters_ptr ), // Additional recipients at cd 0x224 must have offset of 0x240. eq( calldataload(BasicOrder_additionalRecipients_head_cdPtr), BasicOrder_additionalRecipients_head_ptr ) ) validOffsets := and( validOffsets, eq( // Load signature offset from calldata 0x244. calldataload(BasicOrder_signature_cdPtr), // Derive expected offset as start of recipients + len * 64. add( BasicOrder_signature_ptr, mul( // Additional recipients length at calldata 0x264. calldataload( BasicOrder_additionalRecipients_length_cdPtr ), // Each additional recipient has a length of 0x40. AdditionalRecipients_size ) ) ) ) } // Revert with an error if basic order parameter offsets are invalid. if (!validOffsets) { revert InvalidBasicOrderParameterEncoding(); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import { EIP1271Interface } from "../interfaces/EIP1271Interface.sol"; import { SignatureVerificationErrors } from "../interfaces/SignatureVerificationErrors.sol"; import { LowLevelHelpers } from "./LowLevelHelpers.sol"; import "./ConsiderationConstants.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 32 or 33 bytes or if the recovered signer does not match the * supplied signer. Note that in cases where a 32 or 33 byte signature * is supplied, only standard ECDSA signatures that recover to a * non-zero address are supported. * * @param signer The signer for the order. * @param digest The digest to verify the signature against. * @param signature A signature from the signer indicating that the order * has been approved. */ function _assertValidSignature( address signer, bytes32 digest, bytes memory signature ) internal view { // Declare r, s, and v signature parameters. bytes32 r; bytes32 s; uint8 v; // If signature contains 64 bytes, parse as EIP-2098 signature (r+s&v). if (signature.length == 64) { // Declare temporary vs that will be decomposed into s and v. bytes32 vs; // Read each parameter directly from the signature's memory region. assembly { // Put the first word from the signature onto the stack as r. r := mload(add(signature, OneWord)) // Put the second word from the signature onto the stack as vs. vs := mload(add(signature, TwoWords)) // Extract canonical s from vs (all but the highest bit). s := and(vs, EIP2098_allButHighestBitMask) // Extract yParity from highest bit of vs and add 27 to get v. v := add(shr(255, vs), 27) } } else if (signature.length == 65) { // If signature is 65 bytes, parse as a standard signature (r+s+v). // Read each parameter directly from the signature's memory region. assembly { // Place first word on the stack at r. r := mload(add(signature, OneWord)) // Place second word on the stack at s. s := mload(add(signature, TwoWords)) // Place final byte on the stack at v. v := byte(0, mload(add(signature, ThreeWords))) } // Ensure v value is properly formatted. if (v != 27 && v != 28) { revert BadSignatureV(v); } } else { // For all other signature lengths, try verification via EIP-1271. // Attempt EIP-1271 static call to signer in case it's a contract. _assertValidEIP1271Signature(signer, digest, signature); // Return early if the ERC-1271 signature check succeeded. return; } // Attempt to recover signer using the digest and signature parameters. address recoveredSigner = ecrecover(digest, v, r, s); // Disallow invalid signers. if (recoveredSigner == address(0)) { revert InvalidSignature(); // Should a signer be recovered, but it doesn't match the signer... } else if (recoveredSigner != signer) { // Attempt EIP-1271 static call to signer in case it's a contract. _assertValidEIP1271Signature(signer, digest, signature); } } /** * @dev Internal view function to verify the signature of an order using * ERC-1271 (i.e. contract signatures via `isValidSignature`). Note * that, in contrast to standard ECDSA signatures, 1271 signatures may * be valid in certain contexts and invalid in others, or vice versa; * orders that validate signatures ahead of time must explicitly cancel * those orders to invalidate them. * * @param signer The signer for the order. * @param digest The signature digest, derived from the domain separator * and the order hash. * @param signature A signature (or other data) used to validate the digest. */ function _assertValidEIP1271Signature( address signer, bytes32 digest, bytes memory signature ) internal view { // Attempt an EIP-1271 staticcall to the signer. bool success = _staticcall( signer, abi.encodeWithSelector( EIP1271Interface.isValidSignature.selector, digest, signature ) ); // If the call fails... if (!success) { // Revert and pass reason along if one was returned. _revertWithReasonIfOneIsReturned(); // Otherwise, revert with a generic error message. revert BadContractSignature(); } // Ensure result was extracted and matches EIP-1271 magic value. if (_doesNotMatchMagic(EIP1271Interface.isValidSignature.selector)) { revert InvalidSigner(); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import { OrderParameters } from "./ConsiderationStructs.sol"; import { ConsiderationBase } from "./ConsiderationBase.sol"; import "./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 nonce The nonce of the order to hash. * * @return orderHash The hash. */ function _deriveOrderHash( OrderParameters memory orderParameters, uint256 nonce ) 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, TwoWords)) // 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), mul(offerLength, OneWord) ) } // 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 offer 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), mul(originalConsiderationLength, OneWord) ) } // 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 nonce. let noncePtr := add(orderParameters, OrderParameters_nonce_offset) // Store the nonce at the retrieved memory location. mstore(noncePtr, nonce) // 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 original consideration item length at the nonce pointer. mstore(noncePtr, 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. */ 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 version The contract version. * @return domainSeparator The domain separator for this contract. * @return conduitController The conduit Controller set for this contract. */ function _information() internal view returns ( string memory version, bytes32 domainSeparator, address conduitController ) { // Derive the domain separator. domainSeparator = _domainSeparator(); // Declare variable as immutables cannot be accessed within assembly. conduitController = address(_CONDUIT_CONTROLLER); // Allocate a string with the intended length. version = new string(Version_length); // Set the version as data on the newly allocated string. assembly { mstore(add(version, OneWord), shl(0xf8, Version)) } } /** * @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. */ error InvalidERC721TransferAmount(); /** * @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 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); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import { ConsiderationEventsAndErrors } from "../interfaces/ConsiderationEventsAndErrors.sol"; import { ReentrancyGuard } from "./ReentrancyGuard.sol"; /** * @title NonceManager * @author 0age * @notice NonceManager contains a storage mapping and related functionality * for retrieving and incrementing a per-offerer nonce. */ contract NonceManager is ConsiderationEventsAndErrors, ReentrancyGuard { // Only orders signed using an offerer's current nonce are fulfillable. mapping(address => uint256) private _nonces; /** * @dev Internal function to cancel all orders from a given offerer with a * given zone in bulk by incrementing a nonce. Note that only the * offerer may increment the nonce. * * @return newNonce The new nonce. */ function _incrementNonce() internal returns (uint256 newNonce) { // Ensure that the reentrancy guard is not currently set. _assertNonReentrant(); // No need to check for overflow; nonce cannot be incremented that far. unchecked { // Increment current nonce for the supplied offerer. newNonce = ++_nonces[msg.sender]; } // Emit an event containing the new nonce. emit NonceIncremented(newNonce, msg.sender); } /** * @dev Internal view function to retrieve the current nonce for a given * offerer. * * @param offerer The offerer in question. * * @return currentNonce The current nonce. */ function _getNonce(address offerer) internal view returns (uint256 currentNonce) { // Return the nonce for the supplied offerer. currentNonce = _nonces[offerer]; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import { ConduitControllerInterface } from "../interfaces/ConduitControllerInterface.sol"; import { ConsiderationEventsAndErrors } from "../interfaces/ConsiderationEventsAndErrors.sol"; import "./ConsiderationConstants.sol"; /** * @title ConsiderationBase * @author 0age * @notice ConsiderationBase contains immutable constants and constructor logic. */ contract ConsiderationBase is 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 The derived domain separator. */ function _deriveDomainSeparator() internal view returns (bytes32) { return keccak256( abi.encode( _EIP_712_DOMAIN_TYPEHASH, _NAME_HASH, _VERSION_HASH, block.chainid, address(this) ) ); } /** * @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 { mstore(0, OneWord) // First element is the offset. // Name is right padded, so it touches the length which is left // padded. This enables writing both values at once. mstore(NameLengthPtr, NameWithLength) return(0, ThreeWords) // Return all three words. } } /** * @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")); // Construct the OfferItem type string. bytes memory offerItemTypeString = abi.encodePacked( "OfferItem(", "uint8 itemType,", "address token,", "uint256 identifierOrCriteria,", "uint256 startAmount,", "uint256 endAmount", ")" ); // Construct the ConsiderationItem type string. bytes memory considerationItemTypeString = abi.encodePacked( "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 = abi.encodePacked( "OrderComponents(", "address offerer,", "address zone,", "OfferItem[] offer,", "ConsiderationItem[] consideration,", "uint8 orderType,", "uint256 startTime,", "uint256 endTime,", "bytes32 zoneHash,", "uint256 salt,", "bytes32 conduitKey,", "uint256 nonce", ")" ); // Construct the primary EIP-712 domain type string. eip712DomainTypehash = keccak256( abi.encodePacked( "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); // Derive OrderItem type hash via combination of relevant type strings. orderTypehash = keccak256( abi.encodePacked( orderComponentsPartialTypeString, considerationItemTypeString, offerItemTypeString ) ); } }
// 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 conduit The conduit for which ownership may now be * transferred. * @param newPotentialOwner The new potential owner of the conduit. */ event PotentialOwnerUpdated( address indexed conduit, address indexed newPotentialOwner ); /** * @dev Revert with an error when attempting to create a new conduit using a * conduit key where the last twenty bytes of the key do not match the * address of the caller. */ error InvalidCreator(); /** * @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 last * 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 last 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. */ 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 { SpentItem, ReceivedItem } 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 fulfiller The fulfiller of the order, or the null address if * there is no specific fulfiller (i.e. the order is * part of a group of orders). * @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 fulfiller, 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 offerer The offerer of the validated order. * @param zone The zone of the validated order. */ event OrderValidated( bytes32 orderHash, address indexed offerer, address indexed zone ); /** * @dev Emit an event whenever a nonce for a given offerer is incremented. * * @param newNonce The new nonce for the offerer. * @param offerer The offerer in question. */ event NonceIncremented(uint256 newNonce, 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. */ error InvalidTime(); /** * @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 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 ether is supplied as part of * msg.value when fulfilling orders. */ error InsufficientEtherSupplied(); /** * @dev Revert with an error when an ether transfer reverts. */ error EtherTransferGenericFailure(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. */ error InvalidCanceller(); /** * @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(); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import { ReentrancyErrors } from "../interfaces/ReentrancyErrors.sol"; import "./ConsiderationConstants.sol"; /** * @title ReentrancyGuard * @author 0age * @notice ReentrancyGuard contains a storage variable and related functionality * for protecting against reentrancy. */ contract ReentrancyGuard is ReentrancyErrors { // 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 the sentinel value for the * reentrancy guard is not currently set and, if not, to set the * sentinel value for the reentrancy guard. */ function _setReentrancyGuard() internal { // Ensure that the reentrancy guard is not already set. _assertNonReentrant(); // Set the reentrancy guard. _reentrancyGuard = _ENTERED; } /** * @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 the 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) { revert NoReentrantCalls(); } } }
// 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.13; interface EIP1271Interface { function isValidSignature(bytes32 digest, bytes calldata signature) external view returns (bytes4); }
// 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; import "./ConsiderationConstants.sol"; /** * @title LowLevelHelpers * @author 0age * @notice LowLevelHelpers contains logic for performing various low-level * operations. */ contract LowLevelHelpers { /** * @dev Internal view function to staticcall an arbitrary target with given * calldata. Note that no data is written to memory and no contract * size check is performed. * * @param target The account to staticcall. * @param callData The calldata to supply when staticcalling the target. * * @return success The status of the staticcall to the target. */ function _staticcall(address target, bytes memory callData) internal view returns (bool success) { assembly { // Perform the staticcall. success := staticcall( gas(), target, add(callData, OneWord), mload(callData), 0, 0 ) } } /** * @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 := div(returndatasize(), OneWord) // 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 := div(mload(FreeMemoryPointerSlot), OneWord) // 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), div( sub( mul(returnDataWords, returnDataWords), mul(msizeWords, msizeWords) ), MemoryExpansionCoefficient ) ) ) } // 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 pure function to determine if the first word of returndata * matches an expected magic value. * * @param expected The expected magic value. * * @return A boolean indicating whether the expected value matches the one * located in the first word of returndata. */ function _doesNotMatchMagic(bytes4 expected) internal pure returns (bool) { // Declare a variable for the value held by the return data buffer. bytes4 result; // Utilize assembly in order to read directly from returndata buffer. assembly { // Only put result on stack if return data is exactly one word. if eq(returndatasize(), OneWord) { // Copy the word directly from return data into scratch space. returndatacopy(0, 0, OneWord) // Take value from scratch space and place it on the stack. result := mload(0) } } // Return a boolean indicating whether expected and located value match. return result != expected; } }
// 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.13/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 OneWord = 0x20; uint256 constant TwoWords = 0x40; uint256 constant ThreeWords = 0x60; uint256 constant FreeMemoryPointerSlot = 0x40; uint256 constant ZeroSlot = 0x60; uint256 constant DefaultFreeMemoryPointer = 0x80; uint256 constant Slot0x80 = 0x80; uint256 constant Slot0xA0 = 0xa0; uint256 constant Slot0xC0 = 0xc0; // 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 = ERC20_transferFrom_signature; 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 // abi.encodeWithSignature("NoContract(address)") uint256 constant NoContract_error_signature = ( 0x5f15d67200000000000000000000000000000000000000000000000000000000 ); uint256 constant NoContract_error_sig_ptr = 0x0; uint256 constant NoContract_error_token_ptr = 0x4; uint256 constant NoContract_error_length = 0x24; // 4 + 32 == 36 // abi.encodeWithSignature( // "TokenTransferGenericFailure(address,address,address,uint256,uint256)" // ) uint256 constant TokenTransferGenericFailure_error_signature = ( 0xf486bc8700000000000000000000000000000000000000000000000000000000 ); uint256 constant TokenTransferGenericFailure_error_sig_ptr = 0x0; uint256 constant TokenTransferGenericFailure_error_token_ptr = 0x4; uint256 constant TokenTransferGenericFailure_error_from_ptr = 0x24; uint256 constant TokenTransferGenericFailure_error_to_ptr = 0x44; uint256 constant TokenTransferGenericFailure_error_id_ptr = 0x64; uint256 constant TokenTransferGenericFailure_error_amount_ptr = 0x84; // 4 + 32 * 5 == 164 uint256 constant TokenTransferGenericFailure_error_length = 0xa4; uint256 constant ERC1155BatchTransferGenericFailure_error_signature = ( 0xafc445e200000000000000000000000000000000000000000000000000000000 ); uint256 constant ERC1155BatchTransferGenericFailure_token_ptr = 0x04; // abi.encodeWithSignature( // "BadReturnValueFromERC20OnTransfer(address,address,address,uint256)" // ) uint256 constant BadReturnValueFromERC20OnTransfer_error_signature = ( 0x9889192300000000000000000000000000000000000000000000000000000000 ); uint256 constant BadReturnValueFromERC20OnTransfer_error_sig_ptr = 0x0; uint256 constant BadReturnValueFromERC20OnTransfer_error_token_ptr = 0x4; uint256 constant BadReturnValueFromERC20OnTransfer_error_from_ptr = 0x24; uint256 constant BadReturnValueFromERC20OnTransfer_error_to_ptr = 0x44; uint256 constant BadReturnValueFromERC20OnTransfer_error_amount_ptr = 0x64; // 4 + 32 * 4 == 132 uint256 constant BadReturnValueFromERC20OnTransfer_error_length = 0x84; uint256 constant ExtraGasBuffer = 0x20; uint256 constant CostPerWord = 3; uint256 constant MemoryExpansionCoefficient = 0x200; // 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 = 0x44; uint256 constant BatchTransfer1155Params_amounts_head_ptr = 0x84; uint256 constant BatchTransfer1155Params_data_head_ptr = 0xa4; uint256 constant BatchTransfer1155Params_data_length_basePtr = 0x104; 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; uint256 constant Invalid1155BatchTransferEncoding_ptr = 0x00; uint256 constant Invalid1155BatchTransferEncoding_length = 0x04; uint256 constant Invalid1155BatchTransferEncoding_selector = ( 0xeba2084c00000000000000000000000000000000000000000000000000000000 );
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import { ItemType, Side } from "./ConsiderationEnums.sol"; import { OfferItem, ConsiderationItem, ReceivedItem, OrderParameters, AdvancedOrder, Execution, FulfillmentComponent } from "./ConsiderationStructs.sol"; import "./ConsiderationConstants.sol"; import { FulfillmentApplicationErrors } from "../interfaces/FulfillmentApplicationErrors.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 view 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. * * @return execution The transfer performed as a result of the fulfillment. */ function _applyFulfillment( AdvancedOrder[] memory advancedOrders, FulfillmentComponent[] calldata offerComponents, FulfillmentComponent[] calldata considerationComponents ) internal view returns (Execution memory execution) { // Ensure 1+ of both offer and consideration components are supplied. if ( offerComponents.length == 0 || considerationComponents.length == 0 ) { revert OfferAndConsiderationRequiredOnFulfillment(); } // 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; // Validate & aggregate offer items to Execution object. _aggregateValidFulfillmentOfferItems( advancedOrders, offerComponents, execution ); // Ensure offer and consideration share types, tokens and identifiers. if ( execution.item.itemType != considerationItem.itemType || execution.item.token != considerationItem.token || execution.item.identifier != considerationItem.identifier ) { revert MismatchedFulfillmentOfferAndConsiderationComponents(); } // 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] ); // Add excess consideration item amount to original array of orders. advancedOrders[targetComponent.orderIndex] .parameters .consideration[targetComponent.itemIndex] .startAmount = considerationItem.amount - execution.item.amount; // Reduce total consideration amount to equal the offer amount. considerationItem.amount = execution.item.amount; } else { // Retrieve the first offer component from the fulfillment. FulfillmentComponent memory targetComponent = (offerComponents[0]); // Add excess offer item amount to the original array of orders. advancedOrders[targetComponent.orderIndex] .parameters .offer[targetComponent.itemIndex] .startAmount = execution.item.amount - considerationItem.amount; } // Reuse execution struct with consideration amount and recipient. execution.item.amount = considerationItem.amount; 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. * * @return execution The transfer performed as a result of the fulfillment. */ function _aggregateAvailable( AdvancedOrder[] memory advancedOrders, Side side, FulfillmentComponent[] memory fulfillmentComponents, bytes32 fulfillerConduitKey ) 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) { revert MissingFulfillmentComponentOnAggregation(side); } // If the fulfillment components are offer components... if (side == Side.OFFER) { // 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 as the receipient if execution amount is nonzero. if (execution.item.amount == 0) { execution.item.recipient = payable(execution.offerer); } } } /** * @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 view { assembly { // Declare function for reverts on invalid fulfillment data. function throwInvalidFulfillmentComponentData() { // Store the InvalidFulfillmentComponentData error signature. mstore(0, InvalidFulfillmentComponentData_error_signature) // Return, supplying InvalidFulfillmentComponentData signature. revert(0, InvalidFulfillmentComponentData_error_len) } // Declare function for reverts due to arithmetic overflows. function throwOverflow() { // Store the Panic error signature. mstore(0, Panic_error_signature) // Store the arithmetic (0x11) panic code as initial argument. mstore(Panic_error_offset, Panic_arithmetic) // Return, supplying Panic signature and arithmetic code. revert(0, Panic_error_length) } // Get position in offerComponents head. let fulfillmentHeadPtr := add(offerComponents, 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), mul(orderIndex, OneWord)) ) // Read the pointer to OrderParameters from the AdvancedOrder. let paramsPtr := mload(orderPtr) // Load the offer array pointer. let offerArrPtr := mload( add(paramsPtr, OrderParameters_offer_head_offset) ) // Retrieve item index using an offset of the fulfillment pointer. let itemIndex := mload( add(mload(fulfillmentHeadPtr), Fulfillment_itemIndex_offset) ) // Only continue if the fulfillment is not invalid. if iszero(lt(itemIndex, mload(offerArrPtr))) { throwInvalidFulfillmentComponentData() } // Retrieve consideration item pointer using the item index. let offerItemPtr := mload( add( // Get pointer to beginning of receivedItem. add(offerArrPtr, OneWord), // Calculate offset to pointer for desired order. mul(itemIndex, OneWord) ) ) // Declare a variable for the final aggregated item amount. let amount := 0 // Create variable to track errors encountered with amount. let errorBuffer := 0 // Only add offer amount to execution amount on a nonzero numerator. if mload(add(orderPtr, AdvancedOrder_numerator_offset)) { // Retrieve amount pointer using consideration item pointer. let amountPtr := add(offerItemPtr, Common_amount_offset) // Set the amount. amount := mload(amountPtr) // Zero out amount on item to indicate it is credited. mstore(amountPtr, 0) // Buffer indicating whether issues were found. errorBuffer := iszero(amount) } // Retrieve the received item pointer. let receivedItemPtr := mload(execution) // Set the caller as the recipient on the received item. mstore( add(receivedItemPtr, ReceivedItem_recipient_offset), caller() ) // Set the item type on the received item. mstore(receivedItemPtr, mload(offerItemPtr)) // Set the token on the received item. mstore( add(receivedItemPtr, Common_token_offset), mload(add(offerItemPtr, Common_token_offset)) ) // Set the identifier on the received item. mstore( add(receivedItemPtr, Common_identifier_offset), mload(add(offerItemPtr, Common_identifier_offset)) ) // Set the offerer on returned execution using order pointer. mstore(add(execution, Execution_offerer_offset), mload(paramsPtr)) // Set conduitKey on returned execution via offset of order pointer. mstore( add(execution, Execution_conduit_offset), mload(add(paramsPtr, OrderParameters_conduit_offset)) ) // Calculate the hash of (itemType, token, identifier). let dataHash := keccak256( receivedItemPtr, ReceivedItem_CommonParams_size ) // Get position one word past last element in head of array. let endPtr := add( offerComponents, mul(mload(offerComponents), OneWord) ) // Iterate over remaining offer components. for {} lt(fulfillmentHeadPtr, endPtr) {} { // Increment the pointer to the fulfillment head by one word. fulfillmentHeadPtr := add(fulfillmentHeadPtr, OneWord) // Get the order index using the fulfillment pointer. orderIndex := mload(mload(fulfillmentHeadPtr)) // Ensure the order index is in range. if iszero(lt(orderIndex, mload(advancedOrders))) { throwInvalidFulfillmentComponentData() } // Get pointer to AdvancedOrder element. orderPtr := mload( add( add(advancedOrders, OneWord), mul(orderIndex, OneWord) ) ) // Only continue if numerator is not zero. if iszero(mload( add(orderPtr, AdvancedOrder_numerator_offset) )) { continue } // Read the pointer to OrderParameters from the AdvancedOrder. paramsPtr := mload(orderPtr) // Load offer array pointer. offerArrPtr := mload( add( paramsPtr, OrderParameters_offer_head_offset ) ) // Get the item index using the fulfillment pointer. itemIndex := mload(add(mload(fulfillmentHeadPtr), OneWord)) // Throw if itemIndex is out of the range of array. if iszero( lt(itemIndex, mload(offerArrPtr)) ) { throwInvalidFulfillmentComponentData() } // Retrieve offer item pointer using index. offerItemPtr := mload( add( // Get pointer to beginning of receivedItem. add(offerArrPtr, OneWord), // Use offset to pointer for desired order. mul(itemIndex, OneWord) ) ) // Retrieve amount pointer using offer item pointer. let amountPtr := add( offerItemPtr, Common_amount_offset ) // Add offer amount to execution amount. let newAmount := add(amount, mload(amountPtr)) // Update error buffer (1 = zero amount, 2 = overflow). 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 credited. mstore(amountPtr, 0) // Ensure the indicated item matches original item. if iszero( and( and( // The offerer must match on both items. eq( mload(paramsPtr), mload( add(execution, Execution_offerer_offset) ) ), // The conduit key must match on both items. eq( mload( add( paramsPtr, OrderParameters_conduit_offset ) ), mload( add( execution, Execution_conduit_offset ) ) ) ), // The itemType, token, and identifier must match. eq( 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 if an error code is contained in the error buffer. switch errorBuffer case 1 { // Store the MissingItemAmount error signature. mstore(0, MissingItemAmount_error_signature) // Return, supplying MissingItemAmount signature. revert(0, MissingItemAmount_error_len) } case 2 { // If the sum overflowed, panic. throwOverflow() } } } /** * @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. * * @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 function for reverts on invalid fulfillment data. function throwInvalidFulfillmentComponentData() { // Store the InvalidFulfillmentComponentData error signature. mstore(0, InvalidFulfillmentComponentData_error_signature) // Return, supplying InvalidFulfillmentComponentData signature. revert(0, InvalidFulfillmentComponentData_error_len) } // Declare function for reverts due to arithmetic overflows. function throwOverflow() { // Store the Panic error signature. mstore(0, Panic_error_signature) // Store the arithmetic (0x11) panic code as initial argument. mstore(Panic_error_offset, Panic_arithmetic) // Return, supplying Panic signature and arithmetic code. revert(0, Panic_error_length) } // Get position in considerationComponents head. let fulfillmentHeadPtr := add(considerationComponents, 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), mul(orderIndex, OneWord)) ) // Load consideration array pointer. let considerationArrPtr := mload( add( // Read pointer to OrderParameters from the AdvancedOrder. mload(orderPtr), OrderParameters_consideration_head_offset ) ) // Retrieve item index using an offset of the fulfillment pointer. let itemIndex := mload( add(mload(fulfillmentHeadPtr), Fulfillment_itemIndex_offset) ) // Ensure that the order index is not out of range. if iszero(lt(itemIndex, mload(considerationArrPtr))) { throwInvalidFulfillmentComponentData() } // Retrieve consideration item pointer using the item index. let considerationItemPtr := mload( add( // Get pointer to beginning of receivedItem. add(considerationArrPtr, OneWord), // Calculate offset to pointer for desired order. mul(itemIndex, OneWord) ) ) // Declare a variable for the final aggregated item amount. let amount := 0 // Create variable to track errors encountered with amount. let errorBuffer := 0 // Only add consideration amount to execution amount if numerator is // greater than zero. if mload(add(orderPtr, AdvancedOrder_numerator_offset)) { // Retrieve amount pointer using consideration item pointer. let amountPtr := add(considerationItemPtr, Common_amount_offset) // Set the amount. amount := mload(amountPtr) // Set error bit if amount is zero. errorBuffer := iszero(amount) // Zero out amount on item to indicate it is credited. mstore(amountPtr, 0) } // Retrieve ReceivedItem pointer from Execution. let receivedItem := mload(execution) // 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. mstore( add(receivedItem, ReceivedItem_recipient_offset), mload( add( considerationItemPtr, ConsiderationItem_recipient_offset ) ) ) // Calculate the hash of (itemType, token, identifier). let dataHash := keccak256( receivedItem, ReceivedItem_CommonParams_size ) // Get position one word past last element in head of array. let endPtr := add( considerationComponents, mul(mload(considerationComponents), OneWord) ) // Iterate over remaining offer components. for {} lt(fulfillmentHeadPtr, endPtr) {} { // Increment position in considerationComponents head. fulfillmentHeadPtr := add(fulfillmentHeadPtr, OneWord) // Get the order index using the fulfillment pointer. orderIndex := mload(mload(fulfillmentHeadPtr)) // Ensure the order index is in range. if iszero(lt(orderIndex, mload(advancedOrders))) { throwInvalidFulfillmentComponentData() } // Get pointer to AdvancedOrder element. orderPtr := mload( add( add(advancedOrders, OneWord), mul(orderIndex, OneWord) ) ) // Only continue if numerator is not zero. if iszero( mload(add(orderPtr, AdvancedOrder_numerator_offset)) ) { continue } // Load consideration array pointer from OrderParameters. considerationArrPtr := mload( add( // Get pointer to OrderParameters from AdvancedOrder. mload(orderPtr), OrderParameters_consideration_head_offset ) ) // Get the item index using the fulfillment pointer. itemIndex := mload(add(mload(fulfillmentHeadPtr), OneWord)) // Check if itemIndex is within the range of array. if iszero(lt(itemIndex, mload(considerationArrPtr))) { throwInvalidFulfillmentComponentData() } // Retrieve consideration item pointer using index. considerationItemPtr := mload( add( // Get pointer to beginning of receivedItem. add(considerationArrPtr, OneWord), // Use offset to pointer for desired order. mul(itemIndex, OneWord) ) ) // Retrieve amount pointer using consideration item pointer. let amountPtr := add( considerationItemPtr, Common_amount_offset ) // Add offer amount to execution amount. let newAmount := add(amount, mload(amountPtr)) // Update error buffer (1 = zero amount, 2 = overflow). 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 credited. mstore(amountPtr, 0) // Ensure the indicated item matches original item. if iszero( and( // Item recipients must match. eq( mload( add( considerationItemPtr, ConsiderItem_recipient_offset ) ), mload( add( receivedItem, ReceivedItem_recipient_offset ) ) ), // The itemType, token, identifier must match. eq( dataHash, keccak256( considerationItemPtr, ReceivedItem_CommonParams_size ) ) ) ) { // Throw if any of the requirements are not met. throwInvalidFulfillmentComponentData() } } // Write final amount to execution. mstore(add(receivedItem, Common_amount_offset), amount) // Determine if an error code is contained in the error buffer. switch errorBuffer case 1 { // Store the MissingItemAmount error signature. mstore(0, MissingItemAmount_error_signature) // Return, supplying MissingItemAmount signature. revert(0, MissingItemAmount_error_len) } case 2 { // If the sum overflowed, panic. throwOverflow() } } } }
// 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 as part of an * call to fulfill available orders that does not declare at least one * component. */ 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. */ error MismatchedFulfillmentOfferAndConsiderationComponents(); /** * @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.13; import { ItemType, Side } from "./ConsiderationEnums.sol"; import { OfferItem, ConsiderationItem, OrderParameters, AdvancedOrder, CriteriaResolver } from "./ConsiderationStructs.sol"; import "./ConsiderationConstants.sol"; import { CriteriaResolutionErrors } from "../interfaces/CriteriaResolutionErrors.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 transferrable 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) { revert OrderCriteriaResolverOutOfRange(); } // Skip criteria resolution for order if not fulfilled. if (advancedOrders[orderIndex].numerator == 0) { continue; } // Retrieve the parameters for the order. OrderParameters memory orderParameters = ( advancedOrders[orderIndex].parameters ); // Read component index from memory and place it on the stack. uint256 componentIndex = criteriaResolver.index; // Declare values for item's type and criteria. ItemType itemType; uint256 identifierOrCriteria; // If the criteria resolver refers to an offer item... if (criteriaResolver.side == Side.OFFER) { // Retrieve the offer. OfferItem[] memory offer = orderParameters.offer; // Ensure that the component index is in range. if (componentIndex >= offer.length) { revert OfferCriteriaResolverOutOfRange(); } // Retrieve relevant item using the component index. OfferItem memory offerItem = offer[componentIndex]; // Read item type and criteria from memory & place on stack. itemType = offerItem.itemType; identifierOrCriteria = offerItem.identifierOrCriteria; // Optimistically update item type to remove criteria usage. ItemType newItemType; assembly { newItemType := sub(3, eq(itemType, 4)) } offerItem.itemType = newItemType; // Optimistically update identifier w/ supplied identifier. offerItem.identifierOrCriteria = criteriaResolver .identifier; } else { // Otherwise, the resolver refers to a consideration item. ConsiderationItem[] memory consideration = ( orderParameters.consideration ); // Ensure that the component index is in range. if (componentIndex >= consideration.length) { revert ConsiderationCriteriaResolverOutOfRange(); } // Retrieve relevant item using order and component index. ConsiderationItem memory considerationItem = ( consideration[componentIndex] ); // Read item type and criteria from memory & place on stack. itemType = considerationItem.itemType; identifierOrCriteria = ( considerationItem.identifierOrCriteria ); // Optimistically update item type to remove criteria usage. ItemType newItemType; assembly { newItemType := sub(3, eq(itemType, 4)) } considerationItem.itemType = newItemType; // Optimistically update identifier w/ supplied identifier. considerationItem.identifierOrCriteria = ( criteriaResolver.identifier ); } // Ensure the specified item type indicates criteria usage. if (!_isItemWithCriteria(itemType)) { revert CriteriaNotEnabledForItem(); } // If criteria is not 0 (i.e. a collection-wide offer)... if (identifierOrCriteria != uint256(0)) { // Verify identifier inclusion in criteria root using proof. _verifyProof( criteriaResolver.identifier, identifierOrCriteria, criteriaResolver.criteriaProof ); } } // 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 = ( advancedOrders[i].parameters ); // Read consideration length from memory and place on stack. uint256 totalItems = orderParameters.consideration.length; // Iterate over each consideration item on the order. for (uint256 j = 0; j < totalItems; ++j) { // Ensure item type no longer indicates criteria usage. if ( _isItemWithCriteria( orderParameters.consideration[j].itemType ) ) { revert UnresolvedConsiderationCriteria(); } } // Read offer length from memory and place on stack. totalItems = orderParameters.offer.length; // Iterate over each offer item on the order. for (uint256 j = 0; j < totalItems; ++j) { // Ensure item type no longer indicates criteria usage. if ( _isItemWithCriteria(orderParameters.offer[j].itemType) ) { revert UnresolvedOfferCriteria(); } } } } } /** * @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 { bool isValid; assembly { // Start the hash off as just the starting leaf. let computedHash := leaf // Get memory start location of the first element in proof array. let data := add(proof, OneWord) // Iterate over proof elements to compute root hash. for { let end := add(data, mul(mload(proof), OneWord)) } lt(data, end) { data := add(data, OneWord) } { // Get the proof element. let loadedData := mload(data) // Sort and store proof element and hash. switch gt(computedHash, loadedData) case 0 { mstore(0, computedHash) // Place existing hash first. mstore(0x20, loadedData) // Place new hash next. } default { mstore(0, loadedData) // Place new hash first. mstore(0x20, computedHash) // Place existing hash next. } // 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) { revert InvalidProof(); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; /** * @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. */ error OrderCriteriaResolverOutOfRange(); /** * @dev Revert with an error if an offer item still has unresolved criteria * after applying all criteria resolvers. */ error UnresolvedOfferCriteria(); /** * @dev Revert with an error if a consideration item still has unresolved * criteria after applying all criteria resolvers. */ error UnresolvedConsiderationCriteria(); /** * @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; import { AdvancedOrder, CriteriaResolver } from "../lib/ConsiderationStructs.sol"; interface ZoneInterface { // 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.13; import { ZoneInterface } from "../interfaces/ZoneInterface.sol"; import { OrderType } from "./ConsiderationEnums.sol"; import { AdvancedOrder, CriteriaResolver } from "./ConsiderationStructs.sol"; import "./ConsiderationConstants.sol"; import { ZoneInteractionErrors } from "../interfaces/ZoneInteractionErrors.sol"; import { LowLevelHelpers } from "./LowLevelHelpers.sol"; /** * @title ZoneInteraction * @author 0age * @notice ZoneInteraction contains logic related to interacting with zones. */ contract ZoneInteraction is ZoneInteractionErrors, LowLevelHelpers { /** * @dev Internal view function to determine if an order has a restricted * order type and, if so, to ensure that either the offerer or the zone * are the fulfiller or that a staticcall to `isValidOrder` on the zone * returns a magic value indicating that the order is currently valid. * * @param orderHash The hash of the order. * @param zoneHash The hash to provide upon calling the zone. * @param orderType The type of the order. * @param offerer The offerer in question. * @param zone The zone in question. */ function _assertRestrictedBasicOrderValidity( bytes32 orderHash, bytes32 zoneHash, OrderType orderType, address offerer, address zone ) internal view { // Order type 2-3 require zone or offerer be caller or zone to approve. if ( uint256(orderType) > 1 && msg.sender != zone && msg.sender != offerer ) { // Perform minimal staticcall to the zone. _callIsValidOrder(zone, orderHash, offerer, zoneHash); } } function _callIsValidOrder( address zone, bytes32 orderHash, address offerer, bytes32 zoneHash ) internal view { // Perform minimal staticcall to the zone. bool success = _staticcall( zone, abi.encodeWithSelector( ZoneInterface.isValidOrder.selector, orderHash, msg.sender, offerer, zoneHash ) ); // Ensure call was successful and returned the correct magic value. _assertIsValidOrderStaticcallSuccess(success, orderHash); } /** * @dev Internal view function to determine whether an order is a restricted * order and, if so, to ensure that it was either submitted by the * offerer or the zone for the order, or that the zone returns the * expected magic value upon performing a staticcall to `isValidOrder` * or `isValidOrderIncludingExtraData` depending on whether the order * fulfillment specifies extra data or criteria resolvers. * * @param advancedOrder The advanced order in question. * @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 (transferrable) token identifier is * valid and that no proof needs to be supplied. * @param priorOrderHashes The order hashes of each order supplied prior to * the current order as part of a "match" variety * of order fulfillment (e.g. this array will be * empty for single or "fulfill available"). * @param orderHash The hash of the order. * @param zoneHash The hash to provide upon calling the zone. * @param orderType The type of the order. * @param offerer The offerer in question. * @param zone The zone in question. */ function _assertRestrictedAdvancedOrderValidity( AdvancedOrder memory advancedOrder, CriteriaResolver[] memory criteriaResolvers, bytes32[] memory priorOrderHashes, bytes32 orderHash, bytes32 zoneHash, OrderType orderType, address offerer, address zone ) internal view { // Order type 2-3 require zone or offerer be caller or zone to approve. if ( uint256(orderType) > 1 && msg.sender != zone && msg.sender != offerer ) { // If no extraData or criteria resolvers are supplied... if ( advancedOrder.extraData.length == 0 && criteriaResolvers.length == 0 ) { // Perform minimal staticcall to the zone. _callIsValidOrder(zone, orderHash, offerer, zoneHash); } else { // Otherwise, extra data or criteria resolvers were supplied; in // that event, perform a more verbose staticcall to the zone. bool success = _staticcall( zone, abi.encodeWithSelector( ZoneInterface.isValidOrderIncludingExtraData.selector, orderHash, msg.sender, advancedOrder, priorOrderHashes, criteriaResolvers ) ); // Ensure call was successful and returned correct magic value. _assertIsValidOrderStaticcallSuccess(success, orderHash); } } } /** * @dev Internal view function to ensure that a staticcall to `isValidOrder` * or `isValidOrderIncludingExtraData` as part of validating a * restricted order that was not submitted by the named offerer or zone * was successful and returned the required magic value. * * @param success A boolean indicating the status of the staticcall. * @param orderHash The order hash of the order in question. */ function _assertIsValidOrderStaticcallSuccess( bool success, bytes32 orderHash ) internal view { // If the call failed... if (!success) { // Revert and pass reason along if one was returned. _revertWithReasonIfOneIsReturned(); // Otherwise, revert with a generic error message. revert InvalidRestrictedOrder(orderHash); } // Ensure result was extracted and matches isValidOrder magic value. if (_doesNotMatchMagic(ZoneInterface.isValidOrder.selector)) { revert InvalidRestrictedOrder(orderHash); } } }
// 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 offerrer or the order's zone or approved as valid by the * zone in question via a staticcall to `isValidOrder`. * * @param orderHash The order hash for the invalid restricted order. */ error InvalidRestrictedOrder(bytes32 orderHash); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import { OrderType } from "./ConsiderationEnums.sol"; import { OrderParameters, Order, AdvancedOrder, OrderComponents, OrderStatus, CriteriaResolver } from "./ConsiderationStructs.sol"; import { Executor } from "./Executor.sol"; import { ZoneInteraction } from "./ZoneInteraction.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; /** * @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. * * @param orderHash The hash of the order. * @param offerer The offerer of the order. * @param signature A signature from the offerer indicating that the order * has been approved. */ function _validateBasicOrderAndUpdateStatus( bytes32 orderHash, address offerer, bytes memory signature ) internal { // Retrieve the order status for the given order hash. OrderStatus memory 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[orderHash].isValidated = true; _orderStatus[orderHash].isCancelled = false; _orderStatus[orderHash].numerator = 1; _orderStatus[orderHash].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 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 (transferrable) token identifier is * valid and that no proof needs to be supplied. * @param revertOnInvalid A boolean indicating whether to revert if the * order is invalid due to the time or status. * @param priorOrderHashes The order hashes of each order supplied prior to * the current order as part of a "match" variety * of order fulfillment (e.g. this array will be * empty for single or "fulfill available"). * * @return orderHash The order hash. * @return newNumerator A value indicating the portion of the order that * will be filled. * @return newDenominator A value indicating the total size of the order. */ function _validateOrderAndUpdateStatus( AdvancedOrder memory advancedOrder, CriteriaResolver[] memory criteriaResolvers, bool revertOnInvalid, bytes32[] memory priorOrderHashes ) internal returns ( bytes32 orderHash, uint256 newNumerator, uint256 newDenominator ) { // 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. uint256 numerator = uint256(advancedOrder.numerator); uint256 denominator = uint256(advancedOrder.denominator); // Ensure that the supplied numerator and denominator are valid. if (numerator > denominator || numerator == 0) { revert BadFraction(); } // If attempting partial fill (n < d) check order type & ensure support. if ( numerator < denominator && _doesNotSupportPartialFills(orderParameters.orderType) ) { // Revert if partial fill was attempted on an unsupported order. revert PartialFillsNotEnabledForOrder(); } // Retrieve current nonce and use it w/ parameters to derive order hash. orderHash = _assertConsiderationLengthAndGetNoncedOrderHash( orderParameters ); // Ensure restricted orders have a valid submitter or pass a zone check. _assertRestrictedAdvancedOrderValidity( advancedOrder, criteriaResolvers, priorOrderHashes, orderHash, orderParameters.zoneHash, orderParameters.orderType, orderParameters.offerer, orderParameters.zone ); // Retrieve the order status using the derived order hash. OrderStatus memory 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 ); } // Read filled amount as numerator and denominator and put on the stack. uint256 filledNumerator = orderStatus.numerator; uint256 filledDenominator = orderStatus.denominator; // If order currently has a non-zero denominator it is partially filled. if (filledDenominator != 0) { // If denominator of 1 supplied, fill all remaining amount on order. if (denominator == 1) { // Scale numerator & denominator to match current denominator. numerator = filledDenominator; denominator = filledDenominator; } // Otherwise, if supplied denominator differs from current one... else if (filledDenominator != denominator) { // scale current numerator by the supplied denominator, then... filledNumerator *= denominator; // the supplied numerator & denominator by current denominator. numerator *= filledDenominator; denominator *= filledDenominator; } // Once adjusted, if current+supplied numerator exceeds denominator: if (filledNumerator + numerator > denominator) { // Skip underflow check: denominator >= orderStatus.numerator unchecked { // Reduce current numerator so it + supplied = denominator. numerator = denominator - filledNumerator; } } // Skip overflow check: checked above unless numerator is reduced. unchecked { // Update order status and fill amount, packing struct values. _orderStatus[orderHash].isValidated = true; _orderStatus[orderHash].isCancelled = false; _orderStatus[orderHash].numerator = uint120( filledNumerator + numerator ); _orderStatus[orderHash].denominator = uint120(denominator); } } else { // Update order status and fill amount, packing struct values. _orderStatus[orderHash].isValidated = true; _orderStatus[orderHash].isCancelled = false; _orderStatus[orderHash].numerator = uint120(numerator); _orderStatus[orderHash].denominator = uint120(denominator); } // Return order hash, a modified numerator, and a modified denominator. return (orderHash, numerator, denominator); } /** * @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`. * * @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(); address offerer; address zone; // 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]; offerer = order.offerer; zone = order.zone; // Ensure caller is either offerer or zone of the order. if (msg.sender != offerer && msg.sender != zone) { revert InvalidCanceller(); } // Derive order hash using the order parameters and the nonce. bytes32 orderHash = _deriveOrderHash( OrderParameters( offerer, zone, order.offer, order.consideration, order.orderType, order.startTime, order.endTime, order.zoneHash, order.salt, order.conduitKey, order.consideration.length ), order.nonce ); // Update the order status as not valid and cancelled. _orderStatus[orderHash].isValidated = false; _orderStatus[orderHash].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; } } // 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[] calldata orders) internal returns (bool validated) { // Ensure that the reentrancy guard is not currently set. _assertNonReentrant(); // Declare variables outside of the loop. 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; ) { // Retrieve the order. Order calldata order = orders[i]; // Retrieve the order parameters. OrderParameters calldata orderParameters = order.parameters; // Move offerer from memory to the stack. offerer = orderParameters.offerer; // Get current nonce and use it w/ params to derive order hash. orderHash = _assertConsiderationLengthAndGetNoncedOrderHash( orderParameters ); // Retrieve the order status using the derived order hash. OrderStatus memory 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) { // Verify the supplied signature. _verifySignature(offerer, orderHash, order.signature); // Update order status to mark the order as valid. _orderStatus[orderHash].isValidated = true; // Emit an event signifying the order has been validated. emit OrderValidated( orderHash, offerer, orderParameters.zone ); } // Increment counter inside body of the loop for gas efficiency. ++i; } } // 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 memory orderStatus = _orderStatus[orderHash]; // Return the fields on the order status. return ( orderStatus.isValidated, orderStatus.isCancelled, orderStatus.numerator, orderStatus.denominator ); } /** * @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. * * @return isFullOrder A boolean indicating whether the order type only * supports full fills. */ function _doesNotSupportPartialFills(OrderType orderType) 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. assembly { // Equivalent to `uint256(orderType) & 1 == 0`. isFullOrder := iszero(and(orderType, 1)) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import { ConduitInterface } from "../interfaces/ConduitInterface.sol"; import { OrderType, ItemType, BasicOrderRouteType } from "./ConsiderationEnums.sol"; import { AdditionalRecipient, BasicOrderParameters, OfferItem, ConsiderationItem, SpentItem, ReceivedItem } from "./ConsiderationStructs.sol"; import { OrderValidator } from "./OrderValidator.sol"; import "./ConsiderationConstants.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; // Utilize assembly to extract the order type and the basic order route. assembly { // Mask all but 2 least-significant bits to derive the order type. orderType := and(calldataload(BasicOrder_basicOrderType_cdPtr), 3) // Divide basicOrderType by four to derive the route. route := div(calldataload(BasicOrder_basicOrderType_cdPtr), 4) // If route > 1 additionalRecipient items are ERC20 (1) else Eth (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) { revert InvalidMsgValue(msg.value); } } // Declare more arguments that will be derived from route and calldata. address additionalRecipientsToken; ItemType receivedItemType; ItemType offeredItemType; // Utilize assembly to retrieve function arguments and cast types. assembly { // Determine if offered item type == additional recipient item type. let offerTypeIsAdditionalRecipientsType := gt(route, 3) // If route > 3 additionalRecipientsToken is at 0xc4 else 0x24. additionalRecipientsToken := calldataload( add( BasicOrder_considerationToken_cdPtr, mul(offerTypeIsAdditionalRecipientsType, FiveWords) ) ) // If route > 2, receivedItemType is route - 2. If route is 2, then // receivedItemType is ERC20 (1). Otherwise, it is Eth (0). receivedItemType := add( mul(sub(route, 2), gt(route, 2)), eq(route, 2) ) // If route > 3, offeredItemType is ERC20 (1). If route is 2 or 3, // offeredItemType = route. If route is 0 or 1, it is route + 2. offeredItemType := sub( add(route, mul(iszero(additionalRecipientsItemType), 2)), mul( offerTypeIsAdditionalRecipientsType, add(receivedItemType, 1) ) ) } // Derive & validate order using parameters and update order status. _prepareBasicFulfillmentFromCalldata( parameters, orderType, receivedItemType, additionalRecipientsItemType, additionalRecipientsToken, offeredItemType ); // Read offerer from calldata and place on the stack. address payable offerer = parameters.offerer; // 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, mul(gt(route, 3), OneWord)) ) } // Transfer tokens based on the route. if (additionalRecipientsItemType == ItemType.NATIVE) { _transferIndividual721Or1155Item( offeredItemType, parameters.offerToken, offerer, msg.sender, parameters.offerIdentifier, parameters.offerAmount, conduitKey ); // Transfer native to recipients, return excess to caller & wrap up. _transferEthAndFinalize( parameters.considerationAmount, offerer, parameters.additionalRecipients ); } 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); if (route == BasicOrderRouteType.ERC20_TO_ERC721) { // Transfer ERC721 to caller using offerer's conduit preference. _transferERC721( parameters.offerToken, offerer, msg.sender, parameters.offerIdentifier, parameters.offerAmount, conduitKey, accumulator ); // Transfer ERC20 tokens to all recipients and wrap up. _transferERC20AndFinalize( msg.sender, offerer, parameters.considerationToken, parameters.considerationAmount, parameters.additionalRecipients, false, // Send full amount indicated by consideration items. accumulator ); } else if (route == BasicOrderRouteType.ERC20_TO_ERC1155) { // Transfer ERC1155 to caller with offerer's conduit preference. _transferERC1155( parameters.offerToken, offerer, msg.sender, parameters.offerIdentifier, parameters.offerAmount, conduitKey, accumulator ); // Transfer ERC20 tokens to all recipients and wrap up. _transferERC20AndFinalize( msg.sender, offerer, parameters.considerationToken, parameters.considerationAmount, parameters.additionalRecipients, false, // Send full amount indicated by consideration items. accumulator ); } else if (route == BasicOrderRouteType.ERC721_TO_ERC20) { // Transfer ERC721 to offerer using caller's conduit preference. _transferERC721( parameters.considerationToken, msg.sender, offerer, parameters.considerationIdentifier, parameters.considerationAmount, conduitKey, accumulator ); // Transfer ERC20 tokens to all recipients and wrap up. _transferERC20AndFinalize( offerer, msg.sender, parameters.offerToken, parameters.offerAmount, parameters.additionalRecipients, true, // Reduce fulfiller amount sent by additional amounts. accumulator ); } else { // route == BasicOrderRouteType.ERC1155_TO_ERC20 // Transfer ERC1155 to offerer with caller's conduit preference. _transferERC1155( parameters.considerationToken, msg.sender, offerer, parameters.considerationIdentifier, parameters.considerationAmount, conduitKey, accumulator ); // Transfer ERC20 tokens to all recipients and wrap up. _transferERC20AndFinalize( offerer, msg.sender, parameters.offerToken, parameters.offerAmount, parameters.additionalRecipients, true, // Reduce fulfiller amount sent by additional amounts. accumulator ); } // Trigger any remaining accumulated transfers via call to conduit. _triggerIfArmed(accumulator); } 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. It does not clear the expanded * memory regions used, nor does it update the free memory pointer, so * other direct memory access must not assume that unused memory is * empty. * * @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. */ function _prepareBasicFulfillmentFromCalldata( BasicOrderParameters calldata parameters, OrderType orderType, ItemType receivedItemType, ItemType additionalRecipientsItemType, address additionalRecipientsToken, ItemType offeredItemType ) internal { // Ensure this function cannot be triggered during a reentrant call. _setReentrancyGuard(); // Ensure current timestamp falls between order start time and end time. _verifyTime(parameters.startTime, parameters.endTime, true); // Verify that calldata offsets for all dynamic types were produced by // default encoding. This ensures that the constants we use for calldata // pointers to dynamic types are the same as those calculated by // Solidity using their offsets. _assertValidBasicOrderParameterOffsets(); // Ensure supplied consideration array length is not less than original. _assertConsiderationLengthIsNotLessThanOriginalConsiderationLength( parameters.additionalRecipients.length + 1, parameters.totalOriginalAdditionalRecipients ); // Declare stack element for the order hash. bytes32 orderHash; { /** * 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, mul(totalAdditionalRecipients, OneWord) ) // Set the length of the consideration array to the number of // additional recipients, plus one for the primary consideration // item. mstore( eventConsiderationArrPtr, add( calldataload( BasicOrder_additionalRecipients_length_cdPtr ), 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 considerations signed by * the offerer aside from the primary consideration 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) // 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(AdditionalRecipients_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, AdditionalRecipients_size ) // 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, mul(add(totalAdditionalRecipients, 1), OneWord) ) ) /* * 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(AdditionalRecipients_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 ) } } } { /** * 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, mul( calldataload( BasicOrder_additionalRecipients_length_cdPtr ), OneWord ) ) // 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, AdditionalRecipients_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: _nonces[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 nonce from storage and place on the stack. uint256 nonce = _getNonce(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 ) // Take offerer's nonce retrieved from storage, write to struct. mstore(BasicOrder_order_nonce_ptr, nonce) // 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, mul( calldataload(BasicOrder_additionalRecipients_length_cdPtr), OneWord ) ) // Write the order hash to the head of the event's data region. mstore(eventDataPtr, orderHash) // Write the fulfiller (i.e. the caller) next. 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) } // Determine whether order is restricted and, if so, that it is valid. _assertRestrictedBasicOrderValidity( orderHash, parameters.zoneHash, orderType, parameters.offerer, parameters.zone ); // Verify and update the status of the derived order. _validateBasicOrderAndUpdateStatus( orderHash, parameters.offerer, parameters.signature ); } /** * @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. * * @param amount The amount to transfer. * @param to The recipient of the native token transfer. * @param additionalRecipients The additional recipients of the order. */ function _transferEthAndFinalize( uint256 amount, address payable to, AdditionalRecipient[] calldata additionalRecipients ) internal { // Put ether value supplied by the caller on the stack. uint256 etherRemaining = msg.value; // Retrieve total number of additional recipients and place on stack. uint256 totalAdditionalRecipients = additionalRecipients.length; // Iterate over each additional recipient. for (uint256 i = 0; i < totalAdditionalRecipients; ) { // Retrieve the additional recipient. AdditionalRecipient calldata additionalRecipient = ( additionalRecipients[i] ); // Read ether amount to transfer to recipient and place on stack. uint256 additionalRecipientAmount = additionalRecipient.amount; // Ensure that sufficient Ether is available. if (additionalRecipientAmount > etherRemaining) { revert InsufficientEtherSupplied(); } // Transfer Ether to the additional recipient. _transferEth( additionalRecipient.recipient, additionalRecipientAmount ); // Skip underflow check as subtracted value is less than remaining. unchecked { // Reduce ether value available. etherRemaining -= additionalRecipientAmount; } // Skip overflow check as for loop is indexed starting at zero. unchecked { ++i; } } // Ensure that sufficient Ether is still available. if (amount > etherRemaining) { revert InsufficientEtherSupplied(); } // Transfer Ether to the offerer. _transferEth(to, amount); // If any Ether remains after transfers, return it to the caller. if (etherRemaining > amount) { // Skip underflow check as etherRemaining > amount. unchecked { // Transfer remaining Ether to the caller. _transferEth(payable(msg.sender), etherRemaining - amount); } } // Clear the reentrancy guard. _clearReentrancyGuard(); } /** * @dev Internal function to transfer ERC20 tokens to a given recipient as * part of basic order fulfillment. * * @param from The originator of the ERC20 token transfer. * @param to The recipient of the ERC20 token transfer. * @param erc20Token The ERC20 token to transfer. * @param amount The amount of ERC20 tokens to transfer. * @param additionalRecipients The additional recipients of the order. * @param fromOfferer A boolean indicating whether to decrement * amount from the offered amount. */ function _transferERC20AndFinalize( address from, address to, address erc20Token, uint256 amount, AdditionalRecipient[] calldata additionalRecipients, bool fromOfferer, bytes memory accumulator ) internal { // 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, mul(fromOfferer, OneWord) ) ) } // Retrieve total number of additional recipients and place on stack. uint256 totalAdditionalRecipients = additionalRecipients.length; // Iterate over each additional recipient. for (uint256 i = 0; i < totalAdditionalRecipients; ) { // Retrieve the additional recipient. AdditionalRecipient calldata additionalRecipient = ( additionalRecipients[i] ); uint256 additionalRecipientAmount = additionalRecipient.amount; // Decrement the amount to transfer to fulfiller if indicated. if (fromOfferer) { amount -= additionalRecipientAmount; } // Transfer ERC20 tokens to additional recipient given approval. _transferERC20( erc20Token, from, additionalRecipient.recipient, additionalRecipientAmount, conduitKey, accumulator ); // Skip overflow check as for loop is indexed starting at zero. unchecked { ++i; } } // Transfer ERC20 token amount (from account must have proper approval). _transferERC20(erc20Token, from, to, amount, conduitKey, accumulator); // Clear the reentrancy guard. _clearReentrancyGuard(); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import { OrderType, ItemType } from "./ConsiderationEnums.sol"; import { OfferItem, ConsiderationItem, SpentItem, ReceivedItem, OrderParameters, Order, AdvancedOrder, CriteriaResolver } from "./ConsiderationStructs.sol"; import { BasicOrderFulfiller } from "./BasicOrderFulfiller.sol"; import { CriteriaResolution } from "./CriteriaResolution.sol"; import { AmountDeriver } from "./AmountDeriver.sol"; import "./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 * (transferrable) 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. * * @return A boolean indicating whether the order has been fulfilled. */ function _validateAndFulfillAdvancedOrder( AdvancedOrder memory advancedOrder, CriteriaResolver[] memory criteriaResolvers, bytes32 fulfillerConduitKey ) internal returns (bool) { // Ensure this function cannot be triggered during a reentrant call. _setReentrancyGuard(); // Declare empty bytes32 array (unused, will remain empty). bytes32[] memory priorOrderHashes; // Validate order, update status, and determine fraction to fill. ( bytes32 orderHash, uint256 fillNumerator, uint256 fillDenominator ) = _validateOrderAndUpdateStatus( advancedOrder, criteriaResolvers, true, priorOrderHashes ); // 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, orderParameters.conduitKey, fulfillerConduitKey ); // Emit an event signifying that the order has been fulfilled. _emitOrderFulfilledEvent( orderHash, orderParameters.offerer, orderParameters.zone, msg.sender, 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 offererConduitKey An address indicating what conduit, if any, to * source the offerer's token approvals from. The * zero hash signifies that no conduit should be * used, with direct approvals set on * 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. */ function _applyFractionsAndTransferEach( OrderParameters memory orderParameters, uint256 numerator, uint256 denominator, bytes32 offererConduitKey, bytes32 fulfillerConduitKey ) internal { // Derive order duration, time elapsed, and time remaining. uint256 duration = orderParameters.endTime - orderParameters.startTime; uint256 elapsed = block.timestamp - orderParameters.startTime; uint256 remaining = duration - elapsed; // Put ether value supplied by the caller on the stack. uint256 etherRemaining = msg.value; // 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 in order to recast the type of a function, we need to // create a local variable to reference the internal function definition // (using the same type) and a local variable with the desired type, // and then cast the original function pointer 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. { // Declare a virtual function pointer taking an OfferItem argument. function(OfferItem memory, address, bytes32, bytes memory) internal _transferOfferItem; { // Assign _transfer function to a new function pointer (it takes // a ReceivedItem as its initial argument) function(ReceivedItem memory, address, bytes32, bytes memory) internal _transferReceivedItem = _transfer; // Utilize assembly to override the virtual function pointer. assembly { // Cast initial ReceivedItem type to an OfferItem type. _transferOfferItem := _transferReceivedItem } } // Iterate over each offer on the order. for (uint256 i = 0; i < orderParameters.offer.length; ) { // Retrieve the offer item. OfferItem memory offerItem = orderParameters.offer[i]; // Apply fill fraction to derive offer item amount to transfer. uint256 amount = _applyFraction( offerItem.startAmount, offerItem.endAmount, numerator, denominator, elapsed, remaining, duration, false ); // Utilize assembly to set overloaded offerItem arguments. assembly { // Write derived fractional amount to startAmount as amount. mstore(add(offerItem, ReceivedItem_amount_offset), amount) // Write fulfiller (i.e. caller) to endAmount as recipient. mstore( add(offerItem, ReceivedItem_recipient_offset), caller() ) } // Reduce available value if offer spent ETH or a native token. if (offerItem.itemType == ItemType.NATIVE) { // Ensure that sufficient native tokens are still available. if (amount > etherRemaining) { revert InsufficientEtherSupplied(); } // Skip underflow check as a comparison has just been made. unchecked { etherRemaining -= amount; } } // Transfer the item from the offerer to the caller. _transferOfferItem( offerItem, orderParameters.offerer, offererConduitKey, accumulator ); // Skip overflow check as for loop is indexed starting at zero. unchecked { ++i; } } } /** * 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. { // Declare virtual function pointer with ConsiderationItem argument. function(ConsiderationItem memory, address, bytes32, bytes memory) internal _transferConsiderationItem; { // Reassign _transfer function to a new function pointer (it // takes a ReceivedItem as its initial argument). function(ReceivedItem memory, address, bytes32, bytes memory) internal _transferReceivedItem = _transfer; // Utilize assembly to override the virtual function pointer. assembly { // Cast ReceivedItem type to ConsiderationItem type. _transferConsiderationItem := _transferReceivedItem } } // Iterate over each consideration item on the order. for (uint256 i = 0; i < orderParameters.consideration.length; ) { // 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, elapsed, remaining, duration, 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) { // Ensure that sufficient native tokens are still available. if (amount > etherRemaining) { revert InsufficientEtherSupplied(); } // Skip underflow check as a comparison has just been made. unchecked { etherRemaining -= amount; } } // Transfer item from caller to recipient specified by the item. _transferConsiderationItem( considerationItem, msg.sender, fulfillerConduitKey, accumulator ); // Skip overflow check as for loop is indexed starting at zero. unchecked { ++i; } } } // Trigger any remaining accumulated transfers via call to the conduit. _triggerIfArmed(accumulator); // If any ether remains after fulfillments... if (etherRemaining != 0) { // return it to the caller. _transferEth(payable(msg.sender), etherRemaining); } } /** * @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 fulfiller The fulfiller 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 fulfiller, 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, fulfiller, spentItems, receivedItems ); } /** * @dev Internal pure function to convert an order to an advanced order with * numerator and denominator of 1 and empty extraData. * * @param order The order to convert. * * @return advancedOrder The new advanced order. */ function _convertOrderToAdvanced(Order calldata order) internal pure returns (AdvancedOrder memory advancedOrder) { // Convert to partial order (1/1 or full fill) and return new value. advancedOrder = AdvancedOrder( order.parameters, 1, 1, order.signature, "" ); } /** * @dev Internal pure function to convert an array of orders to an array of * advanced orders with numerator and denominator of 1. * * @param orders The orders to convert. * * @return advancedOrders The new array of partial orders. */ function _convertOrdersToAdvanced(Order[] calldata orders) internal pure returns (AdvancedOrder[] memory advancedOrders) { // Read the number of orders from calldata and place on the stack. uint256 totalOrders = orders.length; // Allocate new empty array for each partial order in memory. advancedOrders = new AdvancedOrder[](totalOrders); // Skip overflow check as the index for the loop starts at zero. unchecked { // Iterate over the given orders. for (uint256 i = 0; i < totalOrders; ++i) { // Convert to partial order (1/1 or full fill) and update array. advancedOrders[i] = _convertOrderToAdvanced(orders[i]); } } // Return the array of advanced orders. return advancedOrders; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import { AmountDerivationErrors } from "../interfaces/AmountDerivationErrors.sol"; /** * @title AmountDeriver * @author 0age * @notice AmountDeriver contains pure functions related to deriving item * amounts based on partial fill quantity and on linear extrapolation * based on current time when the start amount and end amount differ. */ contract AmountDeriver is AmountDerivationErrors { /** * @dev Internal pure 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 * extrapolated on a linear basis. * * @param startAmount The starting amount of the item. * @param endAmount The ending amount of the item. * @param elapsed The time elapsed since the order's start time. * @param remaining The time left until the order's end time. * @param duration The total duration of the order. * @param roundUp A boolean indicating whether the resultant amount * should be rounded up or down. * * @return The current amount. */ function _locateCurrentAmount( uint256 startAmount, uint256 endAmount, uint256 elapsed, uint256 remaining, uint256 duration, bool roundUp ) internal pure returns (uint256) { // Only modify end amount if it doesn't already equal start amount. if (startAmount != endAmount) { // Leave extra amount to add for rounding at zero (i.e. round down). uint256 extraCeiling = 0; // If rounding up, set rounding factor to one less than denominator. if (roundUp) { // Skip underflow check: duration cannot be zero. unchecked { extraCeiling = duration - 1; } } // Aggregate new amounts weighted by time with rounding factor uint256 totalBeforeDivision = ( (startAmount * remaining) + (endAmount * elapsed) + extraCeiling ); // Division performed with no zero check as duration cannot be zero. uint256 newAmount; assembly { newAmount := div(totalBeforeDivision, duration) } // Return the current amount (expressed as endAmount internally). return newAmount; } // Return the original amount (now expressed as endAmount internally). 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. bool exact; assembly { // Ensure new value contains no remainder via mulmod operator. // Credit to @hrkrshnn + @axic for proposing this optimal solution. exact := iszero(mulmod(value, numerator, denominator)) } // Ensure that division gave a final result with no remainder. if (!exact) { revert InexactFraction(); } // 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 pure 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 elapsed The time elapsed since the order's start time. * @param remaining The time left until the order's end time. * @param duration The total duration of the order. * * @return amount The received item to transfer with the final amount. */ function _applyFraction( uint256 startAmount, uint256 endAmount, uint256 numerator, uint256 denominator, uint256 elapsed, uint256 remaining, uint256 duration, bool roundUp ) internal pure 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 extrapolate final amount. amount = _locateCurrentAmount( _getFraction(numerator, denominator, startAmount), _getFraction(numerator, denominator, endAmount), elapsed, remaining, duration, roundUp ); } } }
// 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, ItemType } from "./ConsiderationEnums.sol"; import { AdditionalRecipient, OfferItem, ConsiderationItem, SpentItem, ReceivedItem, OrderParameters, Fulfillment, FulfillmentComponent, Execution, Order, AdvancedOrder, CriteriaResolver } from "./ConsiderationStructs.sol"; import { OrderFulfiller } from "./OrderFulfiller.sol"; import { FulfillmentApplier } from "./FulfillmentApplier.sol"; import "./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 (transferrable) 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 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[][] calldata offerFulfillments, FulfillmentComponent[][] calldata considerationFulfillments, bytes32 fulfillerConduitKey, uint256 maximumFulfilled ) internal returns (bool[] memory availableOrders, Execution[] memory executions) { // Validate orders, apply amounts, & determine if they utilize conduits. _validateOrdersAndPrepareToFulfill( advancedOrders, criteriaResolvers, false, // Signifies that invalid orders should NOT revert. maximumFulfilled ); // Aggregate used offer and consideration items and execute transfers. (availableOrders, executions) = _executeAvailableFulfillments( advancedOrders, offerFulfillments, considerationFulfillments, fulfillerConduitKey ); // Return order fulfillment details and executions. return (availableOrders, executions); } /** * @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. * * @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 transferrable * 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. */ function _validateOrdersAndPrepareToFulfill( AdvancedOrder[] memory advancedOrders, CriteriaResolver[] memory criteriaResolvers, bool revertOnInvalid, uint256 maximumFulfilled ) internal { // Ensure this function cannot be triggered during a reentrant call. _setReentrancyGuard(); // Read length of orders array and place on the stack. uint256 totalOrders = advancedOrders.length; // Track the order hash for each order being fulfilled. bytes32[] memory orderHashes = new bytes32[](totalOrders); // Override orderHashes length to zero after memory has been allocated. assembly { mstore(orderHashes, 0) } // 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 current order. AdvancedOrder memory advancedOrder = 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; // Update the length of the orderHashes array. assembly { mstore(orderHashes, add(i, 1)) } // Continue iterating through the remaining orders. continue; } // Validate it, update status, and determine fraction to fill. ( bytes32 orderHash, uint256 numerator, uint256 denominator ) = _validateOrderAndUpdateStatus( advancedOrder, criteriaResolvers, revertOnInvalid, orderHashes ); // Update the length of the orderHashes array. assembly { mstore(orderHashes, add(i, 1)) } // 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. orderHashes[i] = orderHash; // Decrement the number of fulfilled orders. maximumFulfilled--; // Place the start time for the order on the stack. uint256 startTime = advancedOrder.parameters.startTime; // Derive the duration for the order and place it on the stack. uint256 duration = advancedOrder.parameters.endTime - startTime; // Derive time elapsed since the order started & place on stack. uint256 elapsed = block.timestamp - startTime; // Derive time remaining until order expires and place on stack. uint256 remaining = duration - elapsed; // Retrieve array of offer items for the order in question. OfferItem[] memory offer = advancedOrder.parameters.offer; // Iterate over each offer item on the order. for (uint256 j = 0; j < offer.length; ++j) { // Retrieve the offer item. OfferItem memory offerItem = offer[j]; // 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 ); } // Update end amount in memory to match the derived amount. offerItem.endAmount = endAmount; // Adjust offer amount using current time; round down. offerItem.startAmount = _locateCurrentAmount( offerItem.startAmount, offerItem.endAmount, elapsed, remaining, duration, false // round down ); } // Retrieve array of consideration items for order in question. ConsiderationItem[] memory consideration = ( advancedOrder.parameters.consideration ); // Iterate over each consideration item on the order. for (uint256 j = 0; j < consideration.length; ++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 ); } // Update end amount in memory to match the derived amount. considerationItem.endAmount = endAmount; // Adjust consideration amount using current time; round up. considerationItem.startAmount = ( _locateCurrentAmount( considerationItem.startAmount, considerationItem.endAmount, elapsed, remaining, duration, true // round up ) ); // Utilize assembly to manually "shift" the recipient value. assembly { // 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( add( considerationItem, ConsiderationItem_recipient_offset ) ) ) } } } } // Apply criteria resolvers to each order as applicable. _applyCriteriaResolvers(advancedOrders, criteriaResolvers); // Determine the fulfiller (revertOnInvalid ? address(0) : msg.sender). address fulfiller; // Utilize assembly to operate on revertOnInvalid boolean as an integer. assembly { // Set the fulfiller to the caller if revertOnValid is false. fulfiller := mul(iszero(revertOnInvalid), caller()) } // 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 { // Iterate over each order. for (uint256 i = 0; i < totalOrders; ++i) { // Do not emit an event if no order hash is present. if (orderHashes[i] == bytes32(0)) { continue; } // Retrieve parameters for the order in question. OrderParameters memory orderParameters = ( advancedOrders[i].parameters ); // Emit an OrderFulfilled event. _emitOrderFulfilledEvent( orderHashes[i], orderParameters.offerer, orderParameters.zone, fulfiller, 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. * * @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 ) 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; ++i) { /// Retrieve the offer fulfillment components in question. FulfillmentComponent[] memory components = ( offerFulfillments[i] ); // Derive aggregated execution corresponding with fulfillment. Execution memory execution = _aggregateAvailable( advancedOrders, Side.OFFER, components, fulfillerConduitKey ); // If offerer and recipient on the execution are the same... if (execution.item.recipient == execution.offerer) { // increment total filtered executions. totalFilteredExecutions += 1; } else { // Otherwise, assign the execution to the executions array. executions[i - totalFilteredExecutions] = execution; } } // Iterate over each consideration fulfillment. for (uint256 i = 0; i < totalConsiderationFulfillments; ++i) { /// Retrieve consideration fulfillment components in question. FulfillmentComponent[] memory components = ( considerationFulfillments[i] ); // Derive aggregated execution corresponding with fulfillment. Execution memory execution = _aggregateAvailable( advancedOrders, Side.CONSIDERATION, components, fulfillerConduitKey ); // If offerer and recipient on the execution are the same... if (execution.item.recipient == execution.offerer) { // increment total filtered executions. totalFilteredExecutions += 1; } else { // Otherwise, assign the execution to the executions array. executions[ i + totalOfferFulfillments - 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) ) } } } // Revert if no orders are available. if (executions.length == 0) { revert NoSpecifiedOrdersAvailable(); } // Perform final checks and return. availableOrders = _performFinalChecksAndExecuteOrders( advancedOrders, executions ); 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. * * @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 ) 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. availableOrders = new bool[](totalOrders); // Skip overflow checks as all for loops are indexed starting at zero. unchecked { // Iterate over orders to ensure all considerations are met. for (uint256 i = 0; i < totalOrders; ++i) { // Retrieve the order in question. AdvancedOrder memory advancedOrder = advancedOrders[i]; // Skip consideration item checks for order if not fulfilled. if (advancedOrder.numerator == 0) { // Note: orders do not need to be marked as unavailable as a // new memory region has been allocated. Review carefully if // altering compiler version or managing memory manually. continue; } // Mark the order as available. availableOrders[i] = true; // Retrieve consideration items to ensure they are fulfilled. ConsiderationItem[] memory consideration = ( advancedOrder.parameters.consideration ); // Iterate over each consideration item to ensure it is met. for (uint256 j = 0; j < consideration.length; ++j) { // Retrieve remaining amount on the consideration item. uint256 unmetAmount = consideration[j].startAmount; // Revert if the remaining amount is not zero. if (unmetAmount != 0) { revert ConsiderationNotMet(i, j, unmetAmount); } } } } // Put ether value supplied by the caller on the stack. uint256 etherRemaining = msg.value; // 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); // Iterate over each execution. for (uint256 i = 0; i < executions.length; ) { // 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) { // Ensure that sufficient native tokens are still available. if (item.amount > etherRemaining) { revert InsufficientEtherSupplied(); } // Skip underflow check as amount is less than ether remaining. unchecked { etherRemaining -= item.amount; } } // 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; } } // Trigger any remaining accumulated transfers via call to the conduit. _triggerIfArmed(accumulator); // If any ether remains after fulfillments, return it to the caller. if (etherRemaining != 0) { _transferEth(payable(msg.sender), etherRemaining); } // Clear the reentrancy guard. _clearReentrancyGuard(); // Return the array containing available orders. return (availableOrders); } /** * @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 (transferrable) * 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[] memory advancedOrders, CriteriaResolver[] memory criteriaResolvers, Fulfillment[] calldata fulfillments ) internal returns (Execution[] memory executions) { // Validate orders, update order status, and determine item amounts. _validateOrdersAndPrepareToFulfill( advancedOrders, criteriaResolvers, true, // Signifies that invalid orders should revert. advancedOrders.length ); // Fulfill the orders using the supplied fulfillments. return _fulfillAdvancedOrders(advancedOrders, fulfillments); } /** * @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. * * @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[] calldata fulfillments ) 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 calldata fulfillment = fulfillments[i]; // Derive the execution corresponding with the fulfillment. Execution memory execution = _applyFulfillment( advancedOrders, fulfillment.offerComponents, fulfillment.considerationComponents ); // If offerer and recipient on the execution are the same... if (execution.item.recipient == execution.offerer) { // increment total filtered executions. totalFilteredExecutions += 1; } 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); // Return the executions array. return (executions); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import { ConsiderationInterface } from "./interfaces/ConsiderationInterface.sol"; import { OrderComponents, BasicOrderParameters, OrderParameters, Order, AdvancedOrder, OrderStatus, CriteriaResolver, Fulfillment, FulfillmentComponent, Execution } from "./lib/ConsiderationStructs.sol"; import { OrderCombiner } from "./lib/OrderCombiner.sol"; /** * @title Consideration * @author 0age * @custom:coauthor d1ll0n * @custom:coauthor transmissions11 * @custom:version 1 * @notice Consideration is a generalized ETH/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 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 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 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 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 (and 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 override returns (bool fulfilled) { // Convert order to "advanced" order, then validate and fulfill it. fulfilled = _validateAndFulfillAdvancedOrder( _convertOrderToAdvanced(order), new CriteriaResolver[](0), // No criteria resolvers supplied. fulfillerConduitKey ); } /** * @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 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 * (transferrable) 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 * Consideration). * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillAdvancedOrder( AdvancedOrder calldata advancedOrder, CriteriaResolver[] calldata criteriaResolvers, bytes32 fulfillerConduitKey ) external payable override returns (bool fulfilled) { // Validate and fulfill the order. fulfilled = _validateAndFulfillAdvancedOrder( advancedOrder, criteriaResolvers, fulfillerConduitKey ); } /** * @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 (and * direct approvals set on Consideration). * @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 override returns (bool[] memory availableOrders, Execution[] memory executions) { // Convert orders to "advanced" orders and fulfill all available orders. return _fulfillAvailableAdvancedOrders( _convertOrdersToAdvanced(orders), // Convert to advanced orders. new CriteriaResolver[](0), // No criteria resolvers supplied. offerFulfillments, considerationFulfillments, fulfillerConduitKey, 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. * * @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` 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 (transferrable) 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 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[] calldata criteriaResolvers, FulfillmentComponent[][] calldata offerFulfillments, FulfillmentComponent[][] calldata considerationFulfillments, bytes32 fulfillerConduitKey, uint256 maximumFulfilled ) external payable override returns (bool[] memory availableOrders, Execution[] memory executions) { // Fulfill all available orders. return _fulfillAvailableAdvancedOrders( advancedOrders, criteriaResolvers, offerFulfillments, considerationFulfillments, fulfillerConduitKey, 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). * * @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` in order to * receive ERC1155 tokens. * @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 matchOrders( Order[] calldata orders, Fulfillment[] calldata fulfillments ) external payable override returns (Execution[] memory executions) { // Convert to advanced, validate, and match orders using fulfillments. return _matchAdvancedOrders( _convertOrdersToAdvanced(orders), new CriteriaResolver[](0), // No criteria resolvers supplied. fulfillments ); } /** * @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 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 (transferrable) * 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[] memory advancedOrders, CriteriaResolver[] calldata criteriaResolvers, Fulfillment[] calldata fulfillments ) external payable override returns (Execution[] memory executions) { // Validate and match the advanced orders using supplied fulfillments. return _matchAdvancedOrders( advancedOrders, criteriaResolvers, fulfillments ); } /** * @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. * * @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 override returns (bool validated) { // Validate the orders. validated = _validate(orders); } /** * @notice Cancel all orders from a given offerer with a given zone in bulk * by incrementing a nonce. Note that only the offerer may increment * the nonce. * * @return newNonce The new nonce. */ function incrementNonce() external override returns (uint256 newNonce) { // Increment current nonce for the supplied offerer. newNonce = _incrementNonce(); } /** * @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 override returns (bytes32 orderHash) { // Derive order hash by supplying order parameters along with the nonce. orderHash = _deriveOrderHash( OrderParameters( order.offerer, order.zone, order.offer, order.consideration, order.orderType, order.startTime, order.endTime, order.zoneHash, order.salt, order.conduitKey, order.consideration.length ), order.nonce ); } /** * @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 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 nonce for a given offerer. * * @param offerer The offerer in question. * * @return nonce The current nonce. */ function getNonce(address offerer) external view override returns (uint256 nonce) { // Return the nonce for the supplied offerer. nonce = _getNonce(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(); } /** * @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. contractName = _name(); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import { BasicOrderParameters, OrderComponents, Fulfillment, FulfillmentComponent, Execution, Order, AdvancedOrder, OrderStatus, CriteriaResolver } from "../lib/ConsiderationStructs.sol"; /** * @title ConsiderationInterface * @author 0age * @custom:version 1 * @notice Consideration is a generalized ETH/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 * (transferrable) 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. * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillAdvancedOrder( AdvancedOrder calldata advancedOrder, CriteriaResolver[] calldata criteriaResolvers, bytes32 fulfillerConduitKey ) 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 (transferrable) 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 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, 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 toreceive 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 (transferrable) * 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 nonce. Note that only the offerer may increment * the nonce. * * @return newNonce The new nonce. */ function incrementNonce() external returns (uint256 newNonce); /** * @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 nonce for a given offerer. * * @param offerer The offerer in question. * * @return nonce The current nonce. */ function getNonce(address offerer) external view returns (uint256 nonce); /** * @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; import { Consideration } from "./Consideration.sol"; /** * @title Seaport * @author 0age * @custom:coauthor d1ll0n * @custom:coauthor transmissions11 * @custom:version 1 * @notice Seaport is a generalized ETH/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 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(0, 0x20) mstore(0x27, 0x07536561706f7274) return(0, 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"; } }
{ "viaIR": true, "optimizer": { "enabled": true, "runs": 15000 }, "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":[],"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":"ConsiderationCriteriaResolverOutOfRange","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":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EtherTransferGenericFailure","type":"error"},{"inputs":[],"name":"InexactFraction","type":"error"},{"inputs":[],"name":"InsufficientEtherSupplied","type":"error"},{"inputs":[],"name":"InvalidBasicOrderParameterEncoding","type":"error"},{"inputs":[{"internalType":"address","name":"conduit","type":"address"}],"name":"InvalidCallToConduit","type":"error"},{"inputs":[],"name":"InvalidCanceller","type":"error"},{"inputs":[{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"address","name":"conduit","type":"address"}],"name":"InvalidConduit","type":"error"},{"inputs":[],"name":"InvalidERC721TransferAmount","type":"error"},{"inputs":[],"name":"InvalidFulfillmentComponentData","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"InvalidMsgValue","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":[],"name":"InvalidTime","type":"error"},{"inputs":[],"name":"MismatchedFulfillmentOfferAndConsiderationComponents","type":"error"},{"inputs":[{"internalType":"enum Side","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"}],"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":[],"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":[],"name":"UnresolvedConsiderationCriteria","type":"error"},{"inputs":[],"name":"UnresolvedOfferCriteria","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newNonce","type":"uint256"},{"indexed":true,"internalType":"address","name":"offerer","type":"address"}],"name":"NonceIncremented","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":"fulfiller","type":"address"},{"components":[{"internalType":"enum ItemType","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":"struct SpentItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"indexed":false,"internalType":"struct ReceivedItem[]","name":"consideration","type":"tuple[]"}],"name":"OrderFulfilled","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":"OrderValidated","type":"event"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","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":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","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":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","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":"nonce","type":"uint256"}],"internalType":"struct OrderComponents[]","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":"enum ItemType","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":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","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":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","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":"struct OrderParameters","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":"struct AdvancedOrder","name":"advancedOrder","type":"tuple"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"enum Side","name":"side","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"bytes32[]","name":"criteriaProof","type":"bytes32[]"}],"internalType":"struct CriteriaResolver[]","name":"criteriaResolvers","type":"tuple[]"},{"internalType":"bytes32","name":"fulfillerConduitKey","type":"bytes32"}],"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":"enum ItemType","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":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","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":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","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":"struct OrderParameters","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":"struct AdvancedOrder[]","name":"advancedOrders","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"enum Side","name":"side","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"bytes32[]","name":"criteriaProof","type":"bytes32[]"}],"internalType":"struct CriteriaResolver[]","name":"criteriaResolvers","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct FulfillmentComponent[][]","name":"offerFulfillments","type":"tuple[][]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct FulfillmentComponent[][]","name":"considerationFulfillments","type":"tuple[][]"},{"internalType":"bytes32","name":"fulfillerConduitKey","type":"bytes32"},{"internalType":"uint256","name":"maximumFulfilled","type":"uint256"}],"name":"fulfillAvailableAdvancedOrders","outputs":[{"internalType":"bool[]","name":"availableOrders","type":"bool[]"},{"components":[{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ReceivedItem","name":"item","type":"tuple"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"}],"internalType":"struct Execution[]","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":"enum ItemType","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":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","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":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","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":"struct OrderParameters","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Order[]","name":"orders","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct FulfillmentComponent[][]","name":"offerFulfillments","type":"tuple[][]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct FulfillmentComponent[][]","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":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ReceivedItem","name":"item","type":"tuple"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"}],"internalType":"struct Execution[]","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":"address payable","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":"enum BasicOrderType","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":"address payable","name":"recipient","type":"address"}],"internalType":"struct AdditionalRecipient[]","name":"additionalRecipients","type":"tuple[]"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct BasicOrderParameters","name":"parameters","type":"tuple"}],"name":"fulfillBasicOrder","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":"enum ItemType","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":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","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":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","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":"struct OrderParameters","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Order","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":"offerer","type":"address"}],"name":"getNonce","outputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","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":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","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":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","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":"nonce","type":"uint256"}],"internalType":"struct OrderComponents","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":"incrementNonce","outputs":[{"internalType":"uint256","name":"newNonce","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":"enum ItemType","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":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","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":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","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":"struct OrderParameters","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":"struct AdvancedOrder[]","name":"advancedOrders","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"enum Side","name":"side","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"bytes32[]","name":"criteriaProof","type":"bytes32[]"}],"internalType":"struct CriteriaResolver[]","name":"criteriaResolvers","type":"tuple[]"},{"components":[{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct FulfillmentComponent[]","name":"offerComponents","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct FulfillmentComponent[]","name":"considerationComponents","type":"tuple[]"}],"internalType":"struct Fulfillment[]","name":"fulfillments","type":"tuple[]"}],"name":"matchAdvancedOrders","outputs":[{"components":[{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ReceivedItem","name":"item","type":"tuple"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"}],"internalType":"struct Execution[]","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":"enum ItemType","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":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","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":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","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":"struct OrderParameters","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Order[]","name":"orders","type":"tuple[]"},{"components":[{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct FulfillmentComponent[]","name":"offerComponents","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct FulfillmentComponent[]","name":"considerationComponents","type":"tuple[]"}],"internalType":"struct Fulfillment[]","name":"fulfillments","type":"tuple[]"}],"name":"matchOrders","outputs":[{"components":[{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ReceivedItem","name":"item","type":"tuple"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"}],"internalType":"struct Execution[]","name":"executions","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"contractName","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","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":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","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":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","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":"struct OrderParameters","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Order[]","name":"orders","type":"tuple[]"}],"name":"validate","outputs":[{"internalType":"bool","name":"validated","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101c060405234620000b9576200001f6200001962000114565b62000151565b604051615f3990816200076982396080518161287c015260a051816128a2015260c05181612859015260e0518181816119f501526126e70152610100518181816118c10152612736015261012051818181611a910152612784015261014051816128070152610160518161282d015261018051818181610f820152818161233f01526124b901526101a05181818161237d01526124f70152f35b600080fd5b604081019081106001600160401b03821117620000da57604052565b634e487b7160e01b600052604160045260246000fd5b601f909101601f19168101906001600160401b03821190821017620000da57604052565b620066a260208138039182604051938492620001318285620000f0565b833981010312620000b957516001600160a01b0381168103620000b95790565b604060049162000160620002e1565b610120526101005260e05260c05260a05260805246610140526200018362000237565b610160526001600160a01b03166101808190528151630a96ad3960e01b815292839182905afa90811562000203575b600091620001cd575b506101a052620001cb6001600055565b565b620001f3915060403d8111620001fb575b620001ea8183620000f0565b81019062000213565b5038620001bb565b503d620001de565b6200020d6200022a565b620001b2565b9190826040910312620000b9576020825192015190565b506040513d6000823e3d90fd5b60c05160805160a0516040519160208301938452604083015260608201524660808201523060a082015260a0815260c0810181811060018060401b03821117620000da5760405251902090565b604051906200029382620000be565b60018252603160f81b6020830152565b90815180926000905b828210620002c9575011620002bf570190565b6000828201520190565b915080602080928401015181850152018391620002ac565b620002eb62000743565b805160208092012091620002fe62000284565b8281519101209160405181810192816200032985600a906909ecccccae492e8cada560b31b81520190565b6e1d5a5b9d0e081a5d195b551e5c194b608a1b8152600f016d1859191c995cdcc81d1bdad95b8b60921b8152600e017f75696e74323536206964656e7469666965724f7243726974657269612c0000008152601d017f75696e74323536207374617274416d6f756e742c0000000000000000000000008152601401701d5a5b9d0c8d4d88195b99105b5bdd5b9d607a1b8152601101602960f81b81526001010392601f19938481018452620003df9084620000f0565b60405171086dedce6d2c8cae4c2e8d2dedc92e8cada560731b8282019081529481601287016e1d5a5b9d0e081a5d195b551e5c194b608a1b8152600f016d1859191c995cdcc81d1bdad95b8b60921b8152600e017f75696e74323536206964656e7469666965724f7243726974657269612c0000008152601d017f75696e74323536207374617274416d6f756e742c0000000000000000000000008152601401711d5a5b9d0c8d4d88195b99105b5bdd5b9d0b60721b8152601201701859191c995cdcc81c9958da5c1a595b9d607a1b8152601101602960f81b8152600101038181018352620004d09083620000f0565b6040519283818101620004fa906010906f09ee4c8cae486dedae0dedccadce8e6560831b81520190565b6f1859191c995cdcc81bd999995c995c8b60821b81526010016c1859191c995cdcc81e9bdb994b609a1b8152600d017113d999995c925d195b56d7481bd999995c8b60721b81526012017f436f6e73696465726174696f6e4974656d5b5d20636f6e73696465726174696f8152611b8b60f21b60208201526022016f1d5a5b9d0e081bdc99195c951e5c194b60821b8152601001711d5a5b9d0c8d4d881cdd185c9d151a5b594b60721b81526012016f1d5a5b9d0c8d4d88195b99151a5b594b60821b815260100170189e5d195ccccc881e9bdb9952185cda0b607a1b81526011016c1d5a5b9d0c8d4d881cd85b1d0b609a1b8152600d017f6279746573333220636f6e647569744b65792c0000000000000000000000000081526013016c75696e74323536206e6f6e636560981b8152600d01602960f81b81526001010382810185526200064a9085620000f0565b6040516c08a92a06e626488dedac2d2dc5609b1b8282019081529080600d83016b1cdd1c9a5b99c81b985b594b60a21b8152600c016e1cdd1c9a5b99c81d995c9cda5bdb8b608a1b8152600f016f1d5a5b9d0c8d4d8818da185a5b92590b60821b81526010017f6164647265737320766572696679696e67436f6e7472616374000000000000008152601901602960f81b8152600101038481018252620006f29082620000f0565b5190209786519020968351902095604051938492830195866200071591620002a3565b6200072091620002a3565b6200072b91620002a3565b0390810182526200073d9082620000f0565b51902090565b604051906200075282620000be565b600782526614d9585c1bdc9d60ca1b602083015256fe60806040526004361015610013575b600080fd5b60003560e01c806306fdde031461013f5780632d0335ab1461013657806346423aa71461012d57806355944a4214610124578063627cdcb91461011b57806379df72bd146101125780638814773214610109578063a817440414610100578063b3a34c4c146100f7578063df7b0dac146100ee578063ed98a574146100e5578063f47b7740146100dc578063fb0f3ee1146100d3578063fb4c2af9146100ca5763fd9f1e10146100c257600080fd5b61000e611301565b5061000e611272565b5061000e610fab565b5061000e610f0a565b5061000e610e74565b5061000e610db4565b5061000e610d53565b5061000e610ce2565b5061000e610b7b565b5061000e610a20565b5061000e6109bb565b5061000e61092e565b5061000e610225565b5061000e6101e0565b5061000e610199565b91908251928382526000905b8482106101815750601f8460209495601f199311610174575b0116010190565b600085828601015261016d565b90602090818082850101519082860101520190610154565b503461000e57600060031936011261000e5760206000526707536561706f727460275260606000f35b6001600160a01b0381160361000e57565b35906101de826101c2565b565b503461000e57602060031936011261000e57602061021d600435610203816101c2565b6001600160a01b0316600052600160205260406000205490565b604051908152f35b503461000e57602060031936011261000e576004356000526002602052604060002060405190610254826102f3565b546102bf606060ff831615159283855260ff8160081c161515948560208201526effffffffffffffffffffffffffffff8260101c169182604083015260881c928391015260405194859485909493926060926080830196151583521515602083015260408201520152565b0390f35b507f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6080810190811067ffffffffffffffff82111761030f57604052565b6103176102c3565b604052565b60a0810190811067ffffffffffffffff82111761030f57604052565b60c0810190811067ffffffffffffffff82111761030f57604052565b6020810190811067ffffffffffffffff82111761030f57604052565b6040810190811067ffffffffffffffff82111761030f57604052565b90601f601f19910116810190811067ffffffffffffffff82111761030f57604052565b60405190610160820182811067ffffffffffffffff82111761030f57604052565b604051906101de8261031c565b60209067ffffffffffffffff81116103f7575b60051b0190565b6103ff6102c3565b6103f0565b3590600682101561000e57565b92919261041d826103dd565b60409461042c8651928361038c565b819584835260208093019160a080960285019481861161000e57925b8584106104585750505050505050565b868483031261000e57848791845161046f8161031c565b61047887610404565b815282870135610487816101c2565b8382015285870135868201526060808801359082015260808088013590820152815201930192610448565b9080601f8301121561000e578160206104cd93359101610411565b90565b9291926104dc826103dd565b6040946104eb8651928361038c565b819584835260208093019160c080960285019481861161000e57925b8584106105175750505050505050565b868483031261000e57848791845161052e81610338565b61053787610404565b815282870135610546816101c2565b838201528587013586820152606080880135908201526080808801359082015260a08088013590610576826101c2565b820152815201930192610507565b9080601f8301121561000e578160206104cd933591016104d0565b6004111561000e57565b35906101de8261059f565b9190916101608184031261000e576105ca6103af565b926105d4826101d3565b84526105e2602083016101d3565b602085015267ffffffffffffffff90604083013582811161000e57816106099185016104b2565b6040860152606083013591821161000e57610625918301610584565b6060840152610636608082016105a9565b608084015260a081013560a084015260c081013560c084015260e081013560e0840152610100808201359084015261012080820135908401526101408091013590830152565b35906effffffffffffffffffffffffffffff8216820361000e57565b92919267ffffffffffffffff82116106e0575b604051916106c36020601f19601f840116018461038c565b82948184528183011161000e578281602093846000960137010152565b6106e86102c3565b6106ab565b9080601f8301121561000e578160206104cd93359101610698565b91909160a08184031261000e5761071d6103d0565b9267ffffffffffffffff823581811161000e578261073c9185016105b4565b855261074a6020840161067c565b602086015261075b6040840161067c565b6040860152606083013581811161000e57826107789185016106ed565b6060860152608083013590811161000e5761079392016106ed565b6080830152565b9080601f8301121561000e578135906107b2826103dd565b926107c0604051948561038c565b828452602092838086019160051b8301019280841161000e57848301915b8483106107ee5750505050505090565b823567ffffffffffffffff811161000e57869161081084848094890101610708565b8152019201916107de565b9181601f8401121561000e5782359167ffffffffffffffff831161000e576020808501948460051b01011161000e57565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6006111561088657565b6101de61084c565b608090805161089c8161087c565b8352816001600160a01b03918260208201511660208601526040810151604086015260608101516060860152015116910152565b90815180825260208080930193019160005b8281106108f0575050505090565b909192938260e06001926040885161090983825161088e565b808501516001600160a01b031660a0840152015160c0820152019501939291016108e2565b50606060031936011261000e5767ffffffffffffffff60043581811161000e5761095c90369060040161079a565b9060243581811161000e5761097590369060040161081b565b60443592831161000e576102bf936109a16109976109a795369060040161081b565b9490933691611580565b90613d9c565b6040519182916020835260208301906108d0565b503461000e57600060031936011261000e576109d5614f45565b3360005260016020526020604060002060018154018091556040518181527f7ab0fc7de8910a6100b24df423c3d0835534506dca9473d30c3e7df51241b2cf833392a2604051908152f35b503461000e5760031960208136011261000e5760043567ffffffffffffffff811161000e576101608160040192823603011261000e57610a5f8261165f565b91610a6c6024830161165f565b90610a7a6044840182611669565b606485019291610a8a84846116bd565b92909360848801610a9a9061171b565b95610aa4916116bd565b969050610aaf6103af565b6001600160a01b0390991689526001600160a01b031660208901523690610ad592610411565b60408701523690610ae5926104d0565b6060850152610af79060808501611725565b60a482013560a084015260c482013560c084015260e482013560e08401526101048201356101008401526101248201356101208401526101408301526101440135610b41916126da565b604051908152602090f35b602060031982011261000e576004359067ffffffffffffffff821161000e57610b779160040161081b565b9091565b503461000e57610b8a36610b4c565b610b92614f45565b60005b818110610ba85760405160018152602090f35b80610bb66001928486613e8e565b610bc08180614681565b90610bca8261165f565b91610bdd610bd836836105b4565b614ed7565b91610c15610c11610c00610bfb866000526002602052604060002090565b6147af565b610c0a8187615504565b5051151590565b1590565b610c24575b5050505001610b95565b610cb8610cd6917ffde361574a066b44b3b5fe98a87108b7565e327327954c4faeea56a4e6491a0a93610c70610c69610c626020948581019061181f565b3691610698565b878961522b565b610cb2610c87876000526002602052604060002090565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b0161165f565b6040519384526001600160a01b039081169416929081906020820190565b0390a338808080610c1a565b50604060031936011261000e5767ffffffffffffffff60043581811161000e57610d1090369060040161081b565b60249291923591821161000e576102bf92610d3d610d356109a794369060040161081b565b939092614723565b60405190610d4a82610354565b60008252613d9c565b5060031960408136011261000e576004359067ffffffffffffffff821161000e57604090823603011261000e57610daa610d916020926004016146b4565b604051610d9d81610354565b600081526024359161417d565b6040519015158152f35b5060031960608136011261000e5760043567ffffffffffffffff9182821161000e5760a090823603011261000e5760243591821161000e57610e13610daa91610e1f610e06602095369060040161081b565b9390923690600401610708565b91604435933691611580565b9061417d565b9092916040820191604081528451809352606081019260208096019060005b818110610e5e575050506104cd93948184039101526108d0565b8251151586529487019491870191600101610e44565b5060a060031936011261000e5767ffffffffffffffff60043581811161000e57610ea290369060040161081b565b60243583811161000e57610eba90369060040161081b565b91909260443594851161000e57610edb610d35610efa96369060040161081b565b9260405194610ee986610354565b600086526084359560643595612a58565b906102bf60405192839283610e25565b503461000e57600060031936011261000e57610f72610f27612804565b60405190610f3482610370565b600182527f31000000000000000000000000000000000000000000000000000000000000006020830152604051928392606084526060840190610148565b9060208301526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660408301520390f35b5060031960208136011261000e576004359067ffffffffffffffff821161000e576102408260040191833603011261000e5761012435908160021c60018111903415820361123d5780600383921194600282149061105182600285117ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe86010201851592600182018a028460011b870103968792600360a08d026024013593168b611870565b61106f61106060648a0161165f565b9760051b6101c401359561087c565b156110d257505084926110b1604495936110bc9361109260a46110c69a0161165f565b9060e48801359160c48901359133916001600160a01b038a1691611e1a565b610204840190611755565b9390920135611c79565b60405160018152602090f35b926111579694919592506110e461173c565b9586946110f08261087c565b1561115c575091849161112e856044956001600160a01b0361111760a46111529b0161165f565b95169460e48701359060c488013590873391612110565b61114661113a8261165f565b91610204850190611755565b94909301359133611dbc565b61230c565b6110c6565b6111658161087c565b600381036111a6575091849161112e856044956001600160a01b0361118f60a46111529b0161165f565b95169460e48701359060c488013590873391612206565b806111b260049261087c565b036112085791816111ec8560e4956001600160a01b036111d56111529a9761165f565b951694604487013590866024890135913390612110565b6111fb61113a60a4850161165f565b9490930135913390611d3d565b91816111ec8560e4956001600160a01b036112266111529a9761165f565b951694604487013590866024890135913390612206565b6040517fa61be9f0000000000000000000000000000000000000000000000000000000008152346004820152602490fd5b0390fd5b5060c060031936011261000e5767ffffffffffffffff60043581811161000e576112a090369060040161079a565b60243582811161000e576112b890369060040161081b565b60449291923584811161000e576112d390369060040161081b565b60649291923595861161000e576112f1610efa96369060040161081b565b93909260a4359660843596611643565b503461000e5761131036610b4c565b611318614f45565b60005b81811061132e5760405160018152602090f35b611339818385614f10565b6113428161165f565b60209061135082840161165f565b6001600160a01b0391828116938433141580611516575b6114ec5760409561137a81880182611669565b60608084019261138a84866116bd565b90916080948a86890161139c9061171b565b976113a7908a6116bd565b9a90506113b26103af565b6001600160a01b03909c168c526001600160a01b03909116908b015236906113d992610411565b8c89015236906113e8926104d0565b908601528401906113f891611725565b60a0808201359084015260c0808201359084015260e08082013590840152610100808201359084015261012080820135908401526101409182840152013561143f916126da565b93611454856000526002602052604060002090565b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905561148e856000526002602052604060002090565b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555193845216917f6bacc01dbe442496068f7d234edd811f1a5f833243e0aec824f86ab861f3c90d90602090a360010161131b565b60046040517f80ec7374000000000000000000000000000000000000000000000000000000008152fd5b50838316331415611367565b81601f8201121561000e57803591611539836103dd565b92611547604051948561038c565b808452602092838086019260051b82010192831161000e578301905b828210611571575050505090565b81358152908301908301611563565b90929161158c846103dd565b9160409461159c8651948561038c565b839581855260208095019160051b83019380851161000e5783925b8584106115c75750505050505050565b67ffffffffffffffff90843582811161000e5786019060a08285031261000e5784516115f28161031c565b8235815289830135600281101561000e578a82015285830135868201526060808401359082015260808084013594851161000e57611634868c96879601611522565b908201528152019301926115b7565b9061165990610b77999897969594933691611580565b90612a58565b356104cd816101c2565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561000e570180359067ffffffffffffffff821161000e576020019160a082023603831361000e57565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561000e570180359067ffffffffffffffff821161000e576020019160c082023603831361000e57565b6004111561088657565b356104cd8161059f565b60048210156117315752565b61173961084c565b52565b6040519061174982610370565b60208083523683820137565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561000e570180359067ffffffffffffffff821161000e57602001918160061b3603831361000e57565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6001907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe8111611807570190565b61180f6117a9565b0190565b81198111611807570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561000e570180359067ffffffffffffffff821161000e5760200191813603831361000e57565b95919061187b614f36565b61188f6101408801356101208901356151be565b50611898611bc9565b6118bf6118b36118ac6102008a018a611755565b90506117d9565b6101e089013590611b98565b7f00000000000000000000000000000000000000000000000000000000000000006080528160a0526060602460c037604060646101203760e06080908120610160526001610264359081016102a060059290921b918201526102c081019384526024906102e00137610160928460a0528560c052600060e05260005b8394610204358210156119985790604060a0600193602090818560061b6102840161010037838560061b6102840161012037019660e0608020885201968888528960c08201526101008360061b610284019101370193929361193b565b5090929350969590966001610204350160051b610160206060525b83610264358210156119e65790604060a060019301958787528860c08201526101008360061b61028401910137016119b3565b505093509490506101de9391507f00000000000000000000000000000000000000000000000000000000000000006080528260a052606060c460c03760206101046101203760c0608020600052602060002060e05260016102643560051b610200015261022092836102643560051b0152606060c46102406102643560051b0137611b90610c6260843593611a8e856001600160a01b03166000526001602052604060002090565b547f00000000000000000000000000000000000000000000000000000000000000006080526040608460a03760605161010052846101205260a0610144610140376101e0526101809485608020956102643560051b0190868252336101a06102643560051b015260806101c06102643560051b01526101206101e06102643560051b01527f9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f3160a4359260a061026435026101e00190a36000606052611b8760608201611b82611b5c8261165f565b96611b696080860161165f565b906001600160a01b03809916906101608701358b61565f565b61165f565b9581019061181f565b9216906147f9565b10611b9f57565b60046040517f466aa616000000000000000000000000000000000000000000000000000000008152fd5b6102643560061b6102600161024435146102406102243514602060043514161615611bf057565b60046040517f39f3e3fd000000000000000000000000000000000000000000000000000000008152fd5b507f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9015611c535790565b6104cd611c1a565b9190811015611c6c575b60061b0190565b611c74611c1a565b611c65565b919234936000915b808310611cec57505050828211611cc25781611c9c91611ee2565b808211611cb0575b50506101de6001600055565b611cbb910333611ee2565b3880611ca4565b60046040517f1a783b8d000000000000000000000000000000000000000000000000000000008152fd5b909194611cfa868385611c5b565b90813590808211611cc257611d1c82611d1760206001960161165f565b611ee2565b0395019190611c81565b818110611d31570390565b611d396117a9565b0390565b969594939190916101c4359460005b818110611d685750505095611d619596611f77565b6001600055565b80611da989898d99611d7d600196888a611c5b565b9a6001600160a01b0360208d358481809610611daf575b039d0135611da1816101c2565b16908a611f77565b01611d4c565b611db76117a9565b611d94565b909196959493966101e4359460005b818110611ddf575050611d61969750611f77565b80611e148989611df36001958f8890611c5b565b6001600160a01b03602082013591611e0a836101c2565b3591168989611f77565b01611dcb565b949290959391841515600014611e86576101de96604051967f4ce34aa2000000000000000000000000000000000000000000000000000000008852602060048901526001602489015260448801526064870152608486015260a485015260c484015260e483015261249d565b9291946002919450611e978161087c565b03611ed657600103611eac576101de93614f7b565b60046040517fefcc00b1000000000000000000000000000000000000000000000000000000008152fd5b9291906101de94615086565b90611eec81611f46565b600080808084865af115611efe575050565b60449250611f0a6128e5565b6001600160a01b03604051927f470c7c1d0000000000000000000000000000000000000000000000000000000084521660048301526024820152fd5b15611f4d57565b60046040517f91b3e514000000000000000000000000000000000000000000000000000000008152fd5b929193949094611f8683611f46565b611f9081836122f9565b80612102575050604051926000947f23b872dd00000000000000000000000000000000000000000000000000000000865280600452816024528260445260208660648180885af1803d15601f3d1160018a51141617163d1515811615611fff575b505050505050604052606052565b80863b151516611ff15790879596911561203f57602486887f5f15d672000000000000000000000000000000000000000000000000000000008252600452fd5b1561207957506084947f98891923000000000000000000000000000000000000000000000000000000008552600452602452604452606452fd5b3d6120b8575b5060a4947ff486bc8700000000000000000000000000000000000000000000000000000000855260045260245260445281606452608452fd5b3d60051c9060051c9080600302918082116120e9575b505060205a9101106120e0578561207f565b833d81803e3d90fd5b8080600392028380020360091c920302010186806120ce565b906101de9592949391612610565b9590929493919361212181836122f9565b80612138575050600103611eac576101de93614f7b565b9060649593916000979593975060208251146000146121f35760c0906001906040845260208401527f4ce34aa20000000000000000000000000000000000000000000000000000000060408401526020604484015280888401525b02019360027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc48601527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe48501526004840152602483015260448201520152565b5060c08682016001815101809152612193565b95909192939461221586611f46565b61221f81836122f9565b8061222f5750506101de94615086565b90606495969493929160208251146000146122e65760c0906001906040845260208401527f4ce34aa20000000000000000000000000000000000000000000000000000000060408401526020604484015280888401525b02019360037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc48601527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe48501526004840152602483015260448201520152565b5060c08682016001815101809152612286565b906020820151036123075750565b6101de905b60408082510361249957602082015160c0606484015102604401918051926123b560206001600160a01b036000938185927f00000000000000000000000000000000000000000000000000000000000000001674ff00000000000000000000000000000000000000001783528784527f000000000000000000000000000000000000000000000000000000000000000087526055600b201697865281805285890182895af11590565b61244e577fffffffff000000000000000000000000000000000000000000000000000000007f4ce34aa2000000000000000000000000000000000000000000000000000000009151160361240c5750505060209052565b517f1cf99b2600000000000000000000000000000000000000000000000000000000815260048101919091526001600160a01b03919091166024820152604490fd5b61126e848361245b6128e5565b517fd13d53d40000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201529081906024820190565b5050565b6040519161252e60206001600160a01b036101046000948286937f00000000000000000000000000000000000000000000000000000000000000001674ff00000000000000000000000000000000000000001784528785527f00000000000000000000000000000000000000000000000000000000000000006040526055600b20169760405282805282885af11590565b6125c4577fffffffff000000000000000000000000000000000000000000000000000000007f4ce34aa20000000000000000000000000000000000000000000000000000000091511603612580575050565b6040517f1cf99b2600000000000000000000000000000000000000000000000000000000815260048101919091526001600160a01b03919091166024820152604490fd5b61126e836125d06128e5565b6040517fd13d53d40000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201529081906024820190565b9060649492939160208251146000146126c75760c0906001906040845260208401527f4ce34aa20000000000000000000000000000000000000000000000000000000060408401526020604484015280878401525b02019260017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc48501527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe484015260048301526024820152600060448201520152565b5060c08582016001815101809152612665565b91909161014081018051917f0000000000000000000000000000000000000000000000000000000000000000604051604083018051928351926020809501906000915b868684106127e15750505050506040519160051b8220917f00000000000000000000000000000000000000000000000000000000000000009093606086019481865101906000915b8a83106127bd575050505050601f198660051b604051209401978851907f00000000000000000000000000000000000000000000000000000000000000008a5282519383528451958552865261018089209852525252565b838082601f19600194510180519089815260e0812087525201920192019190612765565b8082601f19600194510180519088815260c081208752520192019201919061271d565b467f00000000000000000000000000000000000000000000000000000000000000000361284f577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f000000000000000000000000000000000000000000000000000000000000000082527f000000000000000000000000000000000000000000000000000000000000000060408201527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260a081526128df81610338565b51902090565b3d6128ec57565b3d60051c60405160051c90806003029180821161291c575b505060205a91011061291257565b3d6000803e3d6000fd5b8080600392028380020360091c92030201013880612904565b919082604091031261000e576040516040810181811067ffffffffffffffff82111761296f575b6040526020808294803584520135910152565b6129776102c3565b61295c565b929192612988826103dd565b6040926129978451928361038c565b819581835260208093019160061b84019381851161000e57915b8483106129c057505050505050565b8386916129cd8486612935565b8152019201916129b1565b929190926129e5846103dd565b916129f3604051938461038c565b829480845260208094019060051b83019282841161000e5780915b848310612a1d57505050505050565b823567ffffffffffffffff811161000e57820184601f8201121561000e578691612a4d868385809535910161297c565b815201920191612a0e565b95979692612a6f612a7e9594612a76949389612c8c565b36916129d8565b9236916129d8565b8151815190612a95612a908383611813565b613615565b9660009485905b838210612b9a5750506000935b838510612b0657505050505080612afb575b50825115612ad15782612acd91613ab4565b9190565b60046040517fd5da9a1b000000000000000000000000000000000000000000000000000000008152fd5b835103835238612abb565b909192939488612b2184612b1a8986612c6a565b518a6136e3565b8051608001516001600160a01b03166001600160a01b03612b5b612b4f60208501516001600160a01b031690565b6001600160a01b031690565b911603612b755750506001809101955b0193929190612aa9565b8791612b9491612b8d85896001979c01038093612c6a565b528b612c6a565b50612b6b565b909589612bb6612baf89859996979899612c6a565b518a613671565b8051608001516001600160a01b03166001600160a01b03612be4612b4f60208501516001600160a01b031690565b911603612c005750506001809101965b01909493929194612a9c565b8891612c1d91612c16856001969c038093612c6a565b528c612c6a565b50612bf4565b90612c2d826103dd565b612c3a604051918261038c565b828152601f19612c4a82946103dd565b0190602036910137565b602090805115612c62570190565b61180f611c1a565b6020918151811015612c7f575b60051b010190565b612c87611c1a565b612c77565b612c94614f36565b805192612ca084612c23565b92600091828552825b868110612d3a575050612cbc908361321a565b838110612cc95750505050565b80612cd660019285612c6a565b5115612d3557612d2f612ce98285612c6a565b5151612cf58387612c6a565b5190612d0881516001600160a01b031690565b91612d1d60208301516001600160a01b031690565b606060408401519301519333926145b8565b01612cbc565b612d2f565b612d448186612c6a565b5191848115612ef15750612d59878585614d0f565b9091926001938486018b52888415612edd5750907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91612d99878d612c6a565b52019480519160a09283810151908160c0820151039142038b888281604082880396015193905b612e65575b5050505060608095510151888d905b612ded575b505050505050505050506001905b01612ca9565b8151811015612e605789818a8a8a8a612e438b8b8b612e0d8a9b8d612c6a565b51956080870198612e208a5188836131b2565b918801968751908b518214600014612e50575050508086525b808952855161315b565b9052015190520190612dd4565b612e59926131b2565b8652612e39565b612dd9565b878b88888751851015612ed45786956060612eb994612e84888c612c6a565b51906080820190612e9782518a836131b2565b938493019889519083518214600014612ec4575050508188525b528551613126565b905201839082612dc0565b612ecd926131b2565b8852612eb1565b50505050612dc5565b935050946001949350602091500152612de7565b6020600193929401528181018752612de7565b612f0c614f36565b805192612f1884612c23565b92600091828552825b868110612faa575050612f34908361321a565b838110612f415750505050565b80612f4e60019285612c6a565b5115612fa557612f9f612f618285612c6a565b5151612f6d8387612c6a565b5190612f8081516001600160a01b031690565b60208201516001600160a01b03169060606040840151930151936144e6565b01612f34565b612f9f565b612fb48186612c6a565b51918481156130d65750612fc9878585614e2f565b9091926001938486018b528884156130c25750907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91613009878d612c6a565b52019480519160a09283810151908160c0820151039142038b888281604082880396015193905b61308f575b5050505060608095510151888d905b61305d575b505050505050505050506001905b01612f21565b815181101561308a5789818a8a8a8a61307d8b8b8b612e0d8a9b8d612c6a565b9052015190520190613044565b613049565b878b888887518510156130b957869560606130ae94612e84888c612c6a565b905201839082613030565b50505050613035565b935050946001949350602091500152613057565b6020600193929401528181018752613057565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482118115151661311a570290565b6131226117a9565b0290565b93929093848103613138575050505090565b9161314b613151926131579596946130e9565b926130e9565b90611813565b0490565b9392909384810361316d575050505090565b916131516131836131ad936131579697956130e9565b917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8701946130e9565b611813565b9190918281146131f757828183096131cd57613157916130e9565b60046040517fc63cf089000000000000000000000000000000000000000000000000000000008152fd5b50905090565b6002111561088657565b516104cd8161087c565b6117398261087c565b815181519260005b8281106133615750505060005b82811061323b57505050565b613278613264602061324d8486612c6a565b5101516effffffffffffffffffffffffffffff1690565b6effffffffffffffffffffffffffffff1690565b15613359576132878183612c6a565b5151606081018051519060005b828110613312575050506040809101908151519160005b8381106132c057505050506001905b0161322f565b6132dd6132d76132d1838551612c6a565b51613207565b60031090565b6132e9576001016132ab565b600483517fa6cfc673000000000000000000000000000000000000000000000000000000008152fd5b6133236132d76132d1838551612c6a565b61332f57600101613294565b60046040517fff75a340000000000000000000000000000000000000000000000000000000008152fd5b6001906132ba565b61336b8183612c6a565b518051908682101561350b5760209161338b6132648461324d848b612c6a565b156135005761339a9087612c6a565b51519160409283830151918301516133b1816131fd565b6133ba816131fd565b61348b57830151805182101561346257906133d491612c6a565b519160038351936133e48561087c565b84906133fb84820191600483519814850390613211565b606085015190525b1115613439575090600192918161341e575b50505b01613222565b613432916080606083015192015191613535565b3880613415565b600490517f94eb6af6000000000000000000000000000000000000000000000000000000008152fd5b600484517fbfb3f8ce000000000000000000000000000000000000000000000000000000008152fd5b929060608094015180518210156134d7576003916134a891612c6a565b51938451946134b68661087c565b85916134cd85830192600484519914860390613211565b8501519052613403565b600483517f6088d7de000000000000000000000000000000000000000000000000000000008152fd5b505050600190613418565b60046040517f869586c4000000000000000000000000000000000000000000000000000000008152fd5b9190919060208080830192805160051b01015b808310613583575050500361355957565b60046040517f09bde339000000000000000000000000000000000000000000000000000000008152fd5b90919283518082116000146135a75760005282525b81604060002093019190613548565b906000528252613598565b604051906060820182811067ffffffffffffffff821117613608575b806040526040836135de8361031c565b6000928381528360808301528360a08301528360c08301528360e083015281528260208201520152565b6136106102c3565b6135ce565b9061361f826103dd565b61362c604051918261038c565b828152601f1961363c82946103dd565b019060005b82811061364d57505050565b6020906136586135b2565b82828501015201613641565b9060028210156117315752565b919061367b6135b2565b928151156136b25761368e91849161377f565b815160608101511561369d5750565b60806001600160a01b03602085015116910152565b60246040517f375c24c100000000000000000000000000000000000000000000000000000000815260006004820152fd5b9291906136ee6135b2565b9381511561372357613701918591613940565b3360208401526040830152815160608101511561371b5750565b608033910152565b60246040517f375c24c100000000000000000000000000000000000000000000000000000000815260016004820152fd5b507f7fda72790000000000000000000000000000000000000000000000000000000060005260206000fd5b9060209283820191848351518551811015613933575b60051b850101519384519086604083015181875101518151811015613926575b60051b010151926000958887980151613910575b6040865195336080880152805187528a8101518b88015201516040860152886060610120865196838a01978852015196604089019788522092805160051b01915b82811061386157505050505050506060905101529081600114613839575060021461383157565b6101de6117a9565b7f91b3e514000000000000000000000000000000000000000000000000000000006000526000fd5b9897980190898251518551811015613903575b60051b850101518a810151156138fa575160608b6040830151818651015181518110156138ed575b60051b01015199818b01519081158d8381011060011b17179b0199600082820152208414908751610120820151149087519051141616156138e0575b90899061380a565b6138e8613754565b6138d8565b6138f5613754565b61389c565b509796976138d8565b61390b613754565b613874565b60608501805160009091528015985096506137c9565b61392e613754565b6137b5565b61393b613754565b613795565b909160209283810192835151938151851015613aa7575b85600595861b830101519460609387858851015181855101518151811015613a9a575b841b010151916000968988990151613a85575b519483518652898401518a8701526040840151604087015260a08094015194608087019586528a888820948051851b01915b8281106139e357505050505050505001529081600114613839575060021461383157565b9a999a01908b808351518551811015613a78575b861b850101518181015115613a6e57518a015183518201518151811015613a61575b861b01015160008a82019b8d8d518091019e8f9115911060011b17179c9b52898120861490878951910151141615613a54575b908b906139bf565b613a5c613754565b613a4c565b613a69613754565b613a19565b5050999899613a4c565b613a80613754565b6139f7565b8387018051600090915280159950975061398d565b613aa2613754565b61397a565b613aaf613754565b613957565b908151613ac081612c23565b926000905b828210613b88575050503490613ad961173c565b9360005b8251811015613b5b5785613af18285612c6a565b518051908151613b008161087c565b613b098161087c565b15613b3d575b91613b3791836040613b2e60206001989701516001600160a01b031690565b91015191613c60565b01613add565b95909291506060830181815111611cc2575190039490918791613b0f565b5093613b67915061230c565b80613b78575b506104cd6001600055565b613b829033611ee2565b38613b6d565b91949093613b968584612c6a565b5193613bb761326460208701516effffffffffffffffffffffffffffff1690565b15613c5157613bcf613bc98784612c6a565b60019052565b606080955101519660005b8851811015613c3e5786613bee828b612c6a565b51015180613bff5750600101613bda565b6040517fa5f54208000000000000000000000000000000000000000000000000000000008152600481018a905260248101929092526044820152606490fd5b50939296509350936001905b0190613ac5565b93509360019095929195613c4a565b9291908351613c6e8161087c565b613c778161087c565b613ca157505050806060613c9860806101de9401516001600160a01b031690565b91015190611ee2565b60018451613cae8161087c565b613cb78161087c565b03613cff57926101de93613cd560208301516001600160a01b031690565b906001600160a01b036060613cf460808601516001600160a01b031690565b940151931691611f77565b60028451613d0c8161087c565b613d158161087c565b03613d5b5783613d3260206101de9601516001600160a01b031690565b60808201516001600160a01b0316926001600160a01b0360606040850151940151941691612110565b83613d7360206101de9601516001600160a01b031690565b60808201516001600160a01b0316926001600160a01b0360606040850151940151941691612206565b90613dae909493929482519083612f04565b613db782613615565b9160009485915b808310613deb5750505090613ddc9184829495613de0575b50613ab4565b5090565b825103825238613dd6565b909195613df9878385613e8e565b613e1f613e068280611755565b90613e1660209485810190611755565b92909189613ee7565b906001600160a01b03613e54612b4f613e4460808651016001600160a01b0390511690565b938501516001600160a01b031690565b911603613e6b57506001809101965b019190613dbe565b96613e888298600193830390613e81828a612c6a565b5287612c6a565b50613e63565b9190811015613ecf575b60051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18136030182121561000e570190565b613ed7611c1a565b613e98565b6104cd903690612935565b929190613ef26135b2565b94821580156140de575b6140b457613f086135b2565b613f1d81613f1736858961297c565b88613940565b5191613f3487613f2e36878561297c565b8861377f565b613f3e8751613207565b835190613f4a8261087c565b613f538261087c565b613f5c8161087c565b1480159061407c575b8015614069575b61403f576104cd95613ff9956080958960609586938493848a0197885186865101511060001461400c57505092613fcd613fc4613fb6613fb1602095613fda98611c4a565b613edc565b94838a519151015190611d26565b96845190612c6a565b5151015191015190612c6a565b510152818751015181525b51908651015201516001600160a01b031690565b6080835101906001600160a01b03169052565b60209350604092506140379561402b613fb1613fcd94613fc494611c4a565b95510151895190611d26565b510152613fe5565b60046040517f09cfb455000000000000000000000000000000000000000000000000000000008152fd5b5060408751015160408401511415613f6c565b508651602001516001600160a01b03166001600160a01b036140ab612b4f60208701516001600160a01b031690565b91161415613f65565b60046040517f98e9db6e000000000000000000000000000000000000000000000000000000008152fd5b508015613efc565b604051906140f38261031c565b604051608083610160830167ffffffffffffffff811184821017614170575b6040526000808452806020850152606093846040820152848082015281848201528160a08201528160c08201528160e08201528161010082015281610120820152816101408201528252806020830152604082015282808201520152565b6141786102c3565b614112565b919091614188614f45565b60026000556141978382614956565b9093604051946141a686610370565b6001865260005b6020808210156141cf57906020916141c36140e6565b90828a010152016141ad565b505090919361421693956142016142269861420693835115614235575b60208401526141fa83612c54565b508261321a565b612c54565b5151936101208501519185614242565b80516001600160a01b0316612d08565b6142306001600055565b600190565b61423d611c1a565b6141ec565b909194939460c082015160a09661426961426189860193845190611d26565b925142611d26565b946142748684611d26565b92349361427f61173c565b9a60005b8c6040808b0151805184101561435e578b8b8f938f936142c18b8b6142aa8f948c90612c6a565b5197606089019687519560808b019687519061442b565b80935233905283516142d28161087c565b6142db8161087c565b15614309575b50509160019493916142fd61430394516001600160a01b031690565b90613c60565b01614283565b9295969798999a9b935080945083915011614335575003969594939291908d908c908b816142fd6142e1565b600490517f1a783b8d000000000000000000000000000000000000000000000000000000008152fd5b5050505093985090919394959660005b6060808a01518051831015614402578d918a896143a88f9489896143938a8e94612c6a565b5196870195865195608089019687519061446b565b80925289830151905281516143bc8161087c565b6143c58161087c565b156143e2575b50916143dc91600194933390613c60565b0161436e565b809493508a925099909911611cc25791909103968c908b906143dc6143cb565b50505050505050509394915050614419915061230c565b806144215750565b6101de9033611ee2565b95919293949094858714600014614449575050506104cd93506131b2565b9291948461445f6104cd986144659497866131b2565b936131b2565b90613126565b95919293949094858714600014614489575050506104cd93506131b2565b9291948461445f6104cd9861449f9497866131b2565b9061315b565b90815180825260208080930193019160005b8281106144c5575050505090565b909192938260a0826144da600194895161088e565b019501939291016144b7565b91939290936040805193608091828601918652602090600082880152838188015285518093528160a088019601936000915b84831061456d5750505050505091614568827f9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f31948380950360608501526001600160a01b038091169716956144a5565b0390a3565b90919293949684836001928a5180516145858161087c565b8252808401516001600160a01b031684830152858101518683015260609081015190820152019801959493019190614518565b92909493916040918251946080918287019187526001600160a01b0394856020921682890152838189015286518093528160a089019701936000915b84831061463d57505050505050828285949361456893867f9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f319896036060870152169716956144a5565b90919293949784836001928b5180516146558161087c565b8252808401518c16848301528581015186830152606090810151908201520199019594930191906145f4565b9035907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffea18136030182121561000e570190565b6146bc6140e6565b506147066146d86146cd8380614681565b92602081019061181f565b6146ef604051946146e88661031c565b36906105b4565b845260016020850152600160408501523691610698565b606082015260405161471781610354565b60008152608082015290565b61472c826103dd565b9161473a604051938461038c565b808352601f19614749826103dd565b0160005b81811061479857505060005b8181106147665750505090565b8061477c6147776001938587613e8e565b6146b4565b6147868287612c6a565b526147918186612c6a565b5001614759565b6020906147a36140e6565b8282880101520161474d565b906040516147bc816102f3565b606081935460ff81161515835260ff8160081c16151560208401526effffffffffffffffffffffffffffff8160101c16604084015260881c910152565b614918916101de9382600052600260205282614866610c11604060002060405190614823826102f3565b5460ff81161515825260ff8160081c16151560208301526effffffffffffffffffffffffffffff8160101c16604083015260881c6060820152610c0a81856155aa565b614945575b6148859250610c8791506000526002602052604060002090565b6148c461489c826000526002602052604060002090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff8154169055565b6149086148db826000526002602052604060002090565b620100007fffffffffffffffffffffffffffffff000000000000000000000000000000ffff825416179055565b6000526002602052604060002090565b7101000000000000000000000000000000000070ffffffffffffffffffffffffffffffffff825416179055565b61494e9261522b565b38808261486b565b9091815192614971610c1160a086015160c0870151906151be565b614d035761499461326460208501516effffffffffffffffffffffffffffff1690565b6149b361326460408601516effffffffffffffffffffffffffffff1690565b948582118015614cfb575b614cd15785821080614cb9575b614c8f57614a176149db82614ed7565b9360e083015160808401516149ef81611711565b84516001600160a01b03169187614a1060208801516001600160a01b031690565b948b615c8a565b614a2e610bfb846000526002602052604060002090565b94614a3c610c118786615504565b614c7f5783614a4e610c118851151590565b614c58575b505050614a946132646060614a7d61326460408901516effffffffffffffffffffffffffffff1690565b9601516effffffffffffffffffffffffffffff1690565b948515614bf95760018103614bc157505083925b83614ab38683611813565b11614bb7575b84614b5a614bb292614ad8610c87866000526002602052604060002090565b614aef61489c866000526002602052604060002090565b6effffffffffffffffffffffffffffff9283910116614b18856000526002602052604060002090565b907fffffffffffffffffffffffffffffff000000000000000000000000000000ffff70ffffffffffffffffffffffffffffff000083549260101b169116179055565b8416614b70836000526002602052604060002090565b9070ffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffff000000000000000000000000000000000083549260881b169116179055565b929190565b8084039450614ab9565b939094848103614bd2575b50614aa8565b614bec81614be687614bf2959998996130e9565b966130e9565b956130e9565b9238614bcc565b93509350614c14610c87826000526002602052604060002090565b614c2b61489c826000526002602052604060002090565b614bb26effffffffffffffffffffffffffffff614b5a818716614b18856000526002602052604060002090565b6060614c6e614c7794516001600160a01b031690565b9201519161522b565b388083614a53565b5050509150915090600090600090565b60046040517fa11b63ff000000000000000000000000000000000000000000000000000000008152fd5b5060016080820151614cca81611711565b16156149cb565b60046040517f5a052b32000000000000000000000000000000000000000000000000000000008152fd5b5081156149be565b50600092508291508190565b919290928251614d2b610c1160a083015160c084015190615207565b614e1f57614d4e61326460208601516effffffffffffffffffffffffffffff1690565b90614d6e61326460408701516effffffffffffffffffffffffffffff1690565b958683118015614e17575b614cd15786831080614dff575b614c8f57614dda90614d9783614ed7565b9460e0840151608085015190614dac82611711565b87614dbe87516001600160a01b031690565b93614dd360208901516001600160a01b031690565b958c615d5d565b614df1610bfb846000526002602052604060002090565b94614a3c610c118786615604565b5060016080830151614e1081611711565b1615614d86565b508215614d79565b5050915050600090600090600090565b919290928251614e4b610c1160a083015160c0840151906151be565b614e1f57614e6e61326460208601516effffffffffffffffffffffffffffff1690565b90614e8e61326460408701516effffffffffffffffffffffffffffff1690565b958683118015614ecf575b614cd15786831080614eb7575b614c8f57614a1790614d9783614ed7565b5060016080830151614ec881611711565b1615614ea6565b508215614e99565b6104cd90614ef060608201515161014083015190611b98565b80516001600160a01b0316600090815260016020526040902054906126da565b90916104cd92811015614f29575b60051b810190614681565b614f31611c1a565b614f1e565b614f3e614f45565b6002600055565b600160005403614f5157565b60046040517f7fa8a987000000000000000000000000000000000000000000000000000000008152fd5b9092813b1561505857604051926000947f23b872dd000000000000000000000000000000000000000000000000000000008652806004528160245282604452858060648180885af115614fd45750505050604052606052565b8593943d615017575b5060a4947ff486bc870000000000000000000000000000000000000000000000000000000085526004526024526044526064526001608452fd5b3d60051c9060051c90806003029180821161503f575b505060205a9101106120e05785614fdd565b8080600392028380020360091c9203020101868061502d565b507f5f15d6720000000000000000000000000000000000000000000000000000000060005260045260246000fd5b929093833b1561519057604051936080519160a0519360c051956000987ff242432a000000000000000000000000000000000000000000000000000000008a528060045281602452826044528360645260a06084528960a452898060c48180895af11561510357505050505060805260a05260c052604052606052565b89949550883d615146575b5060a4957ff486bc87000000000000000000000000000000000000000000000000000000008652600452602452604452606452608452fd5b3d60051c9060051c908060030291808211615177575b505060205a91011061516e578661510e565b843d81803e3d90fd5b8080600392028380020360091c9203020101878061515c565b837f5f15d6720000000000000000000000000000000000000000000000000000000060005260045260246000fd5b42109081156151fc575b506151d257600190565b60046040517f6f7eac26000000000000000000000000000000000000000000000000000000008152fd5b9050421015386151c8565b4210908115615220575b5061521b57600190565b600090565b905042101538615211565b919091336001600160a01b03821614615284576101de9261524a612804565b7f19010000000000000000000000000000000000000000000000000000000000006000526002526022526042600020906000602252615296565b505050565b506040513d6000823e3d90fd5b825160409391929084810361537e5750602060008184015186850151615307601b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83169260ff1c01915b895193849388859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15615371575b6001600160a01b03806000511690811560001461535657600486517f8baa579f000000000000000000000000000000000000000000000000000000008152fd5b90919293809550160361536857505050565b6101de926153fb565b615379615289565b615316565b6041036153f357602082015184830151606084015160001a90601b821415806153e8575b6153b557916000916153076020946152e1565b86517f1f003d0a00000000000000000000000000000000000000000000000000000000815260ff83166004820152602490fd5b50601c8214156153a2565b90916101de93505b90916040516154558161544760208201947f1626ba7e00000000000000000000000000000000000000000000000000000000978887526024840152604060448401526064830190610148565b03601f19810183528261038c565b6000928392839251915afa156154d2577fffffffff0000000000000000000000000000000000000000000000000000000090803d6020146154c4575b50160361549a57565b60046040517f815e1d64000000000000000000000000000000000000000000000000000000008152fd5b9050602081803e5138615491565b6154da6128e5565b60046040517f4f7fb80d000000000000000000000000000000000000000000000000000000008152fd5b906020810151615579576effffffffffffffffffffffffffffff806040830151169182615535575b50505050600190565b606001511611156155485780808061552c565b602490604051907f10fda3e10000000000000000000000000000000000000000000000000000000082526004820152fd5b602482604051907f1a5155740000000000000000000000000000000000000000000000000000000082526004820152fd5b90602081015161557957604001516effffffffffffffffffffffffffffff166155d35750600190565b602490604051907fee9e0e630000000000000000000000000000000000000000000000000000000082526004820152fd5b906000906020810151615656576effffffffffffffffffffffffffffff806040830151169182615639575b5050505050600190565b6060015116111561564c5780808061562f565b6155485750600090565b50905050600090565b90929160019060048110156156bf575b11806156ac575b80615699575b615687575b50505050565b615690936156cc565b38808080615681565b506001600160a01b03821633141561567c565b506001600160a01b038416331415615676565b6156c761084c565b61566f565b600091929082916101de95604051906001600160a01b0360208301937f0e1d31dc00000000000000000000000000000000000000000000000000000000855288602485015233604485015216606483015260848201526084815261572f81610338565b51915afa615e33565b90815180825260208080930193019160005b828110615758575050505090565b909192938260a06001928751805161576f8161087c565b8252808401516001600160a01b0316848301526040808201519083015260608082015190830152608090810151908201520195019392910161574a565b90815180825260208080930193019160005b8281106157cc575050505090565b909192938260c0600192875180516157e38161087c565b8252808401516001600160a01b039081168584015260408083015190840152606080830151908401526080808301519084015260a0918201511690820152019501939291016157be565b9060048210156117315752565b6060519081815260208091019160809160005b82811061585b575050505090565b83518552938101939281019260010161584d565b90815180825260208080930193019160005b82811061588f575050505090565b835185529381019392810192600101615881565b908082519081815260208091019281808460051b8301019501936000915b8483106158d15750505050505090565b909192939495848061592783601f1986600196030187528a51805182526158fe8482015185840190613664565b60408082015190830152606080820151908301526080809101519160a08092820152019061586f565b98019301930191949392906158c1565b92615acb906001600160a01b036104cd9694615ad894875216602086015260a06040860152805160a0808701526101409061597d82880182516001600160a01b03169052565b6080615aba6159f16159bc8a6159a56020870151610160809301906001600160a01b03169052565b6040860151906101808d01526102a08c0190615738565b60608501517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec08c8303016101a08d01526157ac565b615a03838501516101c08c019061582d565b60a08401516101e08b015260c08401516102008b015260e08401516102208b015261010094858501516102408c015261012094858101516102608d015201516102808b0152615a6a602087015160c08c01906effffffffffffffffffffffffffffff169052565b60408601516effffffffffffffffffffffffffffff1660e08b015260608601517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6095868c840301908c0152610148565b930151918784030190870152610148565b838103606085015261583a565b9160808184039101526158a3565b93906104cd95936001600160a01b03615ad894615c7c93885216602087015260a06040870152805160a08088015261014090615b2d82890182516001600160a01b03169052565b6080615c6b615ba1615b6c8b6020860151615b5661016091828401906001600160a01b03169052565b61018060408801519201526102a08d0190615738565b60608501518c82037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec0016101a08e01526157ac565b615bb3838501516101c08d019061582d565b60a08401516101e08c015260c08401516102008c015260e08401516102208c015261010094858501516102408d0152610120948c6102608783015191015201516102808c0152615c1b602087015160c08d01906effffffffffffffffffffffffffffff169052565b60408601516effffffffffffffffffffffffffffff1660e08c015260608601517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6095868d840301908d0152610148565b930151918884030190880152610148565b90848203606086015261586f565b909591929493600190615c9c81611711565b1180615d4a575b80615d37575b615cb6575b505050505050565b6080810151511580615d2e575b15615cde5750615cd394506156cc565b388080808080615cae565b600093508392945061544761572f615d299760405192839160208301957f33131570000000000000000000000000000000000000000000000000000000008752338b60248601615937565b615cd3565b50855115615cc3565b506001600160a01b038416331415615ca9565b506001600160a01b038216331415615ca3565b919692939594600190615d6f81611711565b1180615e20575b80615e0d575b615d8a575b50505050505050565b6080820151511580615e04575b15615db4575050615da894506156cc565b38808080808080615d81565b600094508493955061572f615dff9761544760405193849260208401967f33131570000000000000000000000000000000000000000000000000000000008852338c60248701615ae6565b615da8565b50805115615d97565b506001600160a01b038516331415615d7c565b506001600160a01b038316331415615d76565b15615eca577f0e1d31dc000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000600060203d14615ebf575b1603615e8e5750565b602490604051907ffb5014fc0000000000000000000000000000000000000000000000000000000082526004820152fd5b602081803e51615e85565b602490615ed56128e5565b604051907ffb5014fc0000000000000000000000000000000000000000000000000000000082526004820152fdfea2646970667358221220172d3cee2d5e82e6527b51be3ef04a08b90aaf51e21707f9aaae262b4770c3c664736f6c634300080d003300000000000000000000000000000000006ce100a8b5ed8edf18ceef9e500697
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000006cE100a8b5eD8eDf18ceeF9e500697
-----Decoded View---------------
Arg [0] : conduitController (address): 0x00000000006ce100a8b5ed8edf18ceef9e500697
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000006cE100a8b5eD8eDf18ceeF9e500697
Deployed ByteCode Sourcemap
771:1277:1:-:0;;;;;;;;;-1:-1:-1;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;771:1277:1;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;771:1277:1;;;;;1530:121;771:1277;1530:121;;;;771:1277;;1530:121;771:1277;-1:-1:-1;;;;;771:1277:1;;;;;:::o;:::-;;;;;;:::i;:::-;:::o;:::-;;;;;;-1:-1:-1;;771:1277:1;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;771:1277:1;-1:-1:-1;771:1277:1;1777:7:30;771:1277:1;;;-1:-1:-1;771:1277:1;;26772:215:0;;771:1277:1;;;;;;;;;;;;;-1:-1:-1;;771:1277:1;;;;;;;-1:-1:-1;771:1277:1;17233:12:33;771:1277:1;;;-1:-1:-1;771:1277:1;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;771:1277:1;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;-1:-1:-1;771:1277:1;;;:::o;:::-;;;;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;-1:-1:-1;;771:1277:1;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;-1:-1:-1;771:1277:1;;;;;;:::o;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;-1:-1:-1;771:1277:1;;;:::o;:::-;;;:::i;:::-;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;-1:-1:-1;771:1277:1;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;-1:-1:-1;;;;;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;771:1277:1;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;22139:131:0;771:1277:1;;;;;;:::i;:::-;;;;;;;:::i;:::-;22139:131:0;;:::i;:::-;771:1277:1;;;;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;771:1277:1;;;;;912:16:30;;:::i;:::-;1228:10;771:1277:1;;1220:7:30;771:1277:1;;;;;;1220:7:30;771:1277:1;;;;;;;;;;;1316:38:30;1228:10;;1316:38;;771:1277:1;;;;;;;;;;;-1:-1:-1;;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;;;24947:13:0;;;:::i;:::-;24978:10;;;;;;:::i;:::-;25006:11;;;;;;;:::i;:::-;25035:19;;;;;;;;;:::i;:::-;25072:15;;;;;;;;;:::i;:::-;25263:19;;;;:::i;:::-;771:1277:1;;;;;:::i;:::-;-1:-1:-1;;;;;771:1277:1;;;;;-1:-1:-1;;;;;771:1277:1;;24914:389:0;;771:1277:1;;;;;;:::i;:::-;25006:11:0;24914:389;;771:1277:1;;;;;;:::i;:::-;25035:19:0;24914:389;;771:1277:1;24914:389:0;;25072:15;24914:389;;;:::i;:::-;25105:15;;;771:1277:1;25105:15:0;24914:389;;771:1277:1;25138:13:0;;;771:1277:1;25138:13:0;24914:389;;771:1277:1;25169:14:0;;;771:1277:1;25169:14:0;24914:389;;771:1277:1;25201:10:0;;;771:1277:1;25201:10:0;24914:389;;771:1277:1;25229:16:0;;;771:1277:1;25229:16:0;24914:389;;771:1277:1;24914:389:0;;;771:1277:1;25317:11:0;;771:1277:1;24884:454:0;;;:::i;:::-;25006:11;771:1277:1;;;;;;;;;-1:-1:-1;;771:1277:1;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;:::i;:::-;13529:14:33;;:::i;:::-;-1:-1:-1;14045:15:33;;;;;;771:1277:1;;15033:4:33;771:1277:1;;;;;14030:13:33;14144:9;;15033:4;14144:9;;;;:::i;:::-;14265:16;;;;:::i;:::-;14368:23;;;;:::i;:::-;771:1277:1;14502:102:33;771:1277:1;;;;:::i;:::-;14502:102:33;:::i;:::-;14731:23;15192:24;771:1277:1;;14731:23:33;;771:1277:1;;14731:12:33;771:1277:1;;;;;;;14731:23:33;771:1277:1;:::i;:::-;14849:254:33;;;;:::i;:::-;;771:1277:1;;;;;;15192:24:33;;771:1277:1;15192:24:33;15188:570;;14030:13;771:1277:1;;;;;14030:13:33;;15188:570;15697:20;15589:150;15331:15;15589:150;15331:15;15294:53;771:1277:1;15331:15:33;;;;;;;;:::i;:::-;771:1277:1;;;:::i;:::-;15294:53:33;;;:::i;:::-;15441:42;:23;;771:1277:1;;14731:12:33;771:1277:1;;;;;;;15441:23:33;15033:4;771:1277:1;;;;;;;;15441:42:33;15697:20;;:::i;:::-;771:1277:1;;;;;-1:-1:-1;;;;;771:1277:1;;;;;;;;;;;;;;15589:150:33;;;;15188:570;;;;;;771:1277:1;;;-1:-1:-1;;771:1277:1;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;19188:32:0;771:1277:1;19150:192:0;771:1277:1;;;;;;:::i;:::-;19188:32:0;;;;:::i;:::-;771:1277:1;;;;;;:::i;:::-;-1:-1:-1;771:1277:1;;19150:192:0;:::i;771:1277:1:-;;-1:-1:-1;;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;5202:193:0;5248:30;771:1277:1;;;;5248:30:0;:::i;:::-;771:1277:1;;;;;:::i;:::-;-1:-1:-1;771:1277:1;;;;5202:193:0;;:::i;:::-;771:1277:1;;;;;;;;;;-1:-1:-1;;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8173:133:0;771:1277:1;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;8173:133:0;;:::i;771:1277:1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;771:1277:1;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;11872:32:0;771:1277:1;11823:353:0;771:1277:1;;;;;;:::i;11872:32:0:-;771:1277:1;;;;;;;:::i;:::-;-1:-1:-1;771:1277:1;;;;;;;11823:353:0;;:::i;:::-;771:1277:1;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;771:1277:1;;;;;;12001:18:28;;:::i;:::-;771:1277:1;;;;;;:::i;:::-;2250:1:22;13283:4;;12335:82:28;2250:1:22;;;12335:82:28;771:1277:1;;;;;;;;;;;;;:::i;:::-;;2250:1:22;771:1277:1;;;-1:-1:-1;;;;;12136:19:28;771:1277:1;;;;;;;;;;-1:-1:-1;;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;;;;3328:459:20;;;;;;;;;3994:254;;;;;4412:93;;4793:1188;3328:459;4793:1188;;;;3328:459;4793:1188;;;6276:15;4793:1188;3328:459;4793:1188;;;;;;;;;;3328:459;4793:1188;;;;;3328:459;4793:1188;;;;;;;3328:459;4793:1188;;;;;;3328:459;;6276:15;;:::i;:::-;771:1277:1;6400:18:20;;;;;:::i;:::-;6601:235;;;;;;771:1277:1;;:::i;:::-;6897:47:20;;;7043:21;;;;6960:283;7380:30;7043:21;;7453:31;7043:21;;;7453:31;7043:21;;;:::i;:::-;7179:22;;;;771:1277:1;7135:26:20;;;;771:1277:1;7107:10:20;;771:1277:1;-1:-1:-1;;;;;771:1277:1;;6960:283:20;;:::i;:::-;7453:31;;;;;:::i;:::-;7380:30;;;;771:1277:1;7453:31:20;:::i;:::-;771:1277:1;;3328:459:20;771:1277:1;;;;;6893:4956:20;7926:30;11826:11;7926:30;;;;;;;;:::i;:::-;771:1277:1;;;;;;:::i;:::-;7975:44:20;;;8157:21;;;;8120:294;8157:21;8664:30;8157:21;-1:-1:-1;;;;;8157:21:20;;8505:374;8157:21;;;:::i;:::-;771:1277:1;;8309:22:20;;;;771:1277:1;8261:26:20;;;;771:1277:1;8229:10:20;;;8120:294;;:::i;:::-;8716:31;8613:29;;;:::i;:::-;8716:31;;;;;;:::i;:::-;8664:30;;;;771:1277:1;8229:10:20;;8505:374;:::i;:::-;11826:11;:::i;:::-;6893:4956;;7971:3745;771:1277:1;;;:::i;:::-;3328:459:20;8904:45;;3328:459;;9088:21;;;;9050:295;9088:21;9595:30;9088:21;-1:-1:-1;;;;;9088:21:20;;9436:374;9088:21;;;:::i;:::-;771:1277:1;;9240:22:20;;;;771:1277:1;9192:26:20;;;;771:1277:1;9160:10:20;;;9050:295;;:::i;8900:2816::-;771:1277:1;;;;;:::i;:::-;9835:44:20;771:1277:1;;10017:29:20;;9980:318;10017:29;10540:22;10017:29;-1:-1:-1;;;;;10017:29:20;10389:358;10017:29;;;:::i;:::-;771:1277:1;;10185:30:20;;;;771:1277:1;10129:34:20;;4793:1188;10129:34;;771:1277:1;10068:10:20;;9980:318;;:::i;:::-;10584:31;10497:21;;;;;:::i;10584:31::-;10540:22;;;;771:1277:1;10068:10:20;;10389:358;;:::i;9831:1885::-;10971:29;;10933:319;10971:29;11494:22;10971:29;-1:-1:-1;;;;;10971:29:20;11343:358;10971:29;;;:::i;:::-;771:1277:1;;11139:30:20;;;;771:1277:1;11083:34:20;;4793:1188;11083:34;;771:1277:1;11022:10:20;;10933:319;;:::i;4412:93::-;771:1277:1;;4464:26:20;;;3994:254;771:1277:1;4464:26:20;;771:1277:1;;;4464:26:20;;;;;771:1277:1;;;-1:-1:-1;;771:1277:1;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;10504:14:33;;:::i;:::-;-1:-1:-1;10965:15:33;;;;;;11626:11;771:1277:1;15033:4:33;771:1277:1;;;;;10950:13:33;11074:9;;;;;:::i;:::-;11112:13;;;:::i;:::-;11150:10;;;;;;;:::i;:::-;-1:-1:-1;;;;;771:1277:1;;;;11256:10:33;;;:21;;:43;;;10950:13;11252:115;;11626:11;;;;;;;;:::i;:::-;11663:19;;;;;;;;;:::i;:::-;11708:15;;;;;;;;;;;:::i;:::-;11947:19;;;;;:::i;:::-;771:1277:1;;;;;:::i;:::-;-1:-1:-1;;;;;771:1277:1;;;;;-1:-1:-1;;;;;771:1277:1;;;11522:473:33;;;771:1277:1;;;;;;:::i;:::-;11522:473:33;;;771:1277:1;;;;;;:::i;:::-;11522:473:33;;;771:1277:1;11522:473:33;;;;;;:::i;:::-;11749:15;;;;771:1277:1;11522:473:33;;;771:1277:1;11790:13:33;;;;771:1277:1;11522:473:33;;;771:1277:1;11829:14:33;;;;771:1277:1;11522:473:33;;;771:1277:1;11869:10:33;;;;771:1277:1;11522:473:33;;;771:1277:1;11905:16:33;;;;771:1277:1;11522:473:33;;;771:1277:1;11522:473:33;;;;;771:1277:1;12017:11:33;771:1277:1;11484:562:33;;;:::i;:::-;12136:23;;;771:1277:1;;14731:12:33;771:1277:1;;;;;;;12136:23:33;771:1277:1;;;;;;12197:23:33;;771:1277:1;;14731:12:33;771:1277:1;;;;;;;12197:23:33;771:1277:1;;;;;;;;;;;;;;12342:40:33;;771:1277:1;;12342:40:33;12235:4;771:1277:1;10950:13:33;;11252:115;771:1277:1;11626:11:33;771:1277:1;11330:18:33;;;;11256:43;771:1277:1;;;;11256:10:33;11281:18;;11256:43;;771:1277:1;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;16550:820:0;;771:1277:1;16550:820:0;17102:261;16550:820;;;;;;;771:1277:1;;;:::i;:::-;17102:261:0;;:::i;771:1277:1:-;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;-1:-1:-1;771:1277:1;;;:::o;:::-;;;;;:::i;:::-;;;;;;;;:::o;:::-;;;:::i;:::-;;:::o;13283:4:22:-;771:1277:1;;;;;;:::i;:::-;;13283:4:22;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;771:1277:1:-;;;;;;;;;;;;14288:4:20;771:1277:1;;;;;;;;:::o;:::-;;;:::i;:::-;;;:::o;:::-;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;13735:24830:20:-;;;;;;:::i;:::-;14234:59;14268:18;;;771:1277:1;14246:20:20;;;771:1277:1;14234:59:20;:::i;:::-;;;;:::i;:::-;14846:44;14790:42;:31;;;;;;:::i;:::-;:42;;;:::i;:::-;14846:44;;;771:1277:1;14846:44:20;;:::i;:::-;16115:28;16280:11851;;;;;;;;;;;14246:20;16280:11851;;;;;;;;14288:4;16280:11851;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;16280:11851:20;;-1:-1:-1;16280:11851:20;;;;;;;;;;;;;14288:4;16280:11851;;;;;;;;;;;;;;;;;14246:20;16280:11851;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14288:4;16280:11851;;;;;;;;;;;;;;;;;;;;;14288:4;16280:11851;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;38425:133;16280:11851;;;28644:20;16280:11851;28760:3007;;16280:11851;28760:3007;16280:11851;28760:3007;16280:11851;28760:3007;16280:11851;28760:3007;14246:20;28760:3007;16280:11851;;28760:3007;-1:-1:-1;28760:3007:20;16280:11851;-1:-1:-1;28760:3007:20;16280:11851;28760:3007;14288:4;16280:11851;;;;14790:31;28760:3007;;;16280:11851;;;;;;28760:3007;;16280:11851;28760:3007;;16280:11851;;;;28760:3007;;771:1277:1;38528:20:20;32830:90;;1777:16:30;;;-1:-1:-1;;;;;771:1277:1;;;14288:4:20;771:1277:1;;;;;;;1777:16:30;771:1277:1;33156:15:20;16280:11851;33186:1441;16280:11851;32830:90;16280:11851;33186:1441;16280:11851;33186:1441;16280:11851;33186:1441;;14246:20;33186:1441;16280:11851;33186:1441;14268:18;33186:1441;14846:44;33186:1441;;;;16280:11851;33186:1441;16280:11851;;;;;34647:3431;;;;;;;16280:11851;;;;34647:3431;;16280:11851;34647:3431;16280:11851;;;;34647:3431;;14246:20;14846:44;16280:11851;;;;34647:3431;;;;;16280:11851;;;;34647:3431;14846:44;34647:3431;;;-1:-1:-1;16280:11851:20;34647:3431;38496:18;16280:11851;38295:18;;38167:185;38295:18;;;:::i;:::-;38327:15;;16280:11851;38327:15;;;:::i;:::-;771:1277:1;-1:-1:-1;;;;;771:1277:1;;;38239:19:20;16280:11851;38239:19;;771:1277:1;38167:185:20;;:::i;:::-;38496:18;:::i;:::-;38528:20;;;;;:::i;771:1277:1:-;;;38425:133:20;;:::i;2782:425:19:-;3069:63;3065:136;;2782:425::o;3065:136::-;3155:35;771:1277:1;;3155:35:19;;;;3968:2077;4231:1633;;;;;;;;;;;;;;;;;;;5956:13;5952:87;;3968:2077::o;5952:87::-;4231:1633;771:1277:1;;5992:36:19;;;;771:1277:1;;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;39084:2289:20;;;39344:9;39572:13;39584:1;39567:1131;39587:29;;;;;;40772:23;;;;;;40768:88;;40925:6;;;;:::i;:::-;41021:23;;;41017:277;;39567:1131;41017:277;;;2250:1:22;1322:31:34;771:1277:1;1231:129:34;41017:277:20;41245:23;771:1277:1;;41232:10:20;41245:23;:::i;:::-;41017:277;;;;40768:88;40818:27;771:1277:1;;40818:27:20;;;;39572:13;39753:23;;;;;;;;:::i;:::-;771:1277:1;;;40022:42:20;;;;40018:115;;40283:25;40236:29;;;771:1277:1;40236:29:20;;;:::i;:::-;40283:25;:::i;:::-;771:1277:1;;;39572:13:20;;;;771:1277:1;;;;;;;;:::o;:::-;;;:::i;:::-;;;:::o;42041:2122:20:-;;;;;;;;42478:294;;42990:13;-1:-1:-1;43005:29:20;;;;;;44071:11;;;;;;;;:::i;:::-;3328:459;-1:-1:-1;771:1277:1;42041:2122:20:o;42990:13::-;43171:23;43551:225;43171:23;;;;;3328:459;43171:23;;;;:::i;:::-;771:1277:1;-1:-1:-1;;;;;42478:294:20;771:1277:1;;;;;;;;;42990:13:20;771:1277:1;43633:29:20;;771:1277:1;;;;:::i;:::-;;43551:225:20;;;:::i;:::-;771:1277:1;42990:13:20;;771:1277:1;;;:::i;:::-;;;42041:2122:20;;;;;;;;42478:294;;42990:13;-1:-1:-1;43005:29:20;;;;;;44071:11;;;;;;;:::i;42990:13::-;43171:23;43551:225;43171:23;;;771:1277:1;43171:23:20;;;;;:::i;:::-;-1:-1:-1;;;;;42478:294:20;43633:29;;771:1277:1;;;;;:::i;:::-;;;;43551:225:20;;;:::i;:::-;771:1277:1;42990:13:20;;4486:3517:26;;;;;;;4800:24;;;4796:3201;4800:24;;;7303:22;5028:2111;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7303:22;:::i;4796:3201::-;771:1277:1;;;7463:15:26;771:1277:1;;;;;;:::i;:::-;7451:27:26;7463:15;;7586:1;7576:11;7572:94;;7793:10;;;:::i;7572:94::-;7618:29;771:1277:1;;7618:29:26;;;;7447:540;7965:6;;;;;;:::i;8234:742::-;;8388:6;;;:::i;:::-;-1:-1:-1;8510:145:26;;;;;;;8701:8;8697:273;;8234:742;;:::o;8697:273::-;771:1277:1;8697:273:26;;;;:::i;:::-;-1:-1:-1;;;;;771:1277:1;;8920:39:26;;;;771:1277:1;8920:39:26;;;771:1277:1;;;;;8920:39:26;3373:202:19;3505:11;3501:68;;3373:202::o;3501:68::-;3539:19;771:1277:1;;3539:19:19;;;;9912:958:26;;;;;;;10189:6;;;:::i;:::-;10320:10;;;;:::i;:::-;10393:24;;;982:8760:36;;;;10415:1:26;;982:8760:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10389:475:26;982:8760:36;;;;;;;;;;9912:958:26:o;982:8760:36:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10389:475:26;10833:6;;;;;;;;:::i;11871:1080::-;;;;;;;;12213:10;;;;:::i;:::-;12286:24;;;12400:11;;12410:1;12400:11;12396:86;;12601:10;;;:::i;12282:663::-;22900:16;24117:671;22900:16;;;-1:-1:-1;22900:16:26;;;;771:1277:1;13283:4:22;771:1277:1;;23074:41:26;23070:1009;13283:4:22;;;24117:671:26;23131:12;23142:1;23222:498;;;;13283:4:22;23222:498:26;;;23175:33;23222:498;;;;13283:4:22;23222:498:26;;;;;;;;;23070:1009;24117:671;;;12801:1;24117:671;;;;;;;;;;;;;;;;;;;;;;11871:1080::o;23070:1009::-;23816:253;24117:671;23816:253;;;;;;;;;;23070:1009;;13918:1015;;;;;;;14225:6;;;:::i;:::-;14356:10;;;;:::i;:::-;14429:24;;;14587:6;;;;;:::i;14425:502::-;22900:16;24117:671;22900:16;;;;;;13283:4:22;771:1277:1;;23074:41:26;23070:1009;13283:4:22;;;24117:671:26;23131:12;23142:1;23222:498;;;;13283:4:22;23222:498:26;;;23175:33;23222:498;;;;13283:4:22;23222:498:26;;;;;;;;;23070:1009;24117:671;;;14783:1;24117:671;;;;;;;;;;;;;;;;;;;;;;13918:1015::o;23070:1009::-;23816:253;24117:671;23816:253;;;;;;;;;;23070:1009;;15684:458;;21507:139;;;;16046:35;16042:94;;15684:458;:::o;16042:94::-;16113:11;;16506:423;16653:2;771:1277:1;;;16631:24:26;16627:61;;21507:139;;;;17925:502;;;;;;;;9618:1318:28;;;771:1277:1;20190:8:26;21507:139;-1:-1:-1;;;;;;9371:19:28;;;;;771:1277:1;9618:1318:28;;;;;;;9516:27;9618:1318;;;;;;;;;19741:402:26;;;17925:502;;;19741:402;;;;20190:8;;771:1277:1;20190:8:26;20186:254;;771:1277:1;20762:33:26;20542:123;;771:1277:1;20752:43:26;20748:116;;18668:73;;;21507:139;18668:73;;16506:423::o;20748:116::-;771:1277:1;20818:35:26;;;;;;771:1277:1;;;;-1:-1:-1;;;;;771:1277:1;;;;;;;;;;4464:26:20;20186:254:26;20400:29;20186:254;;;;:::i;:::-;771:1277:1;20400:29:26;;;-1:-1:-1;;;;;771:1277:1;;;20400:29:26;;;771:1277:1;;;;;;;;;16627:61:26;16671:7;;:::o;19417:1453::-;9618:1318:28;;771:1277:1;20190:8:26;9618:1318:28;-1:-1:-1;;;;;13163:5:22;-1:-1:-1;9371:19:28;;;;;771:1277:1;9618:1318:28;;;;;;;9516:27;9618:1318;;;;;;;;;19741:402:26;;;;;;;20190:8;;771:1277:1;20190:8:26;20186:254;;771:1277:1;20762:33:26;20542:123;;771:1277:1;20752:43:26;20748:116;;19417:1453;;:::o;20748:116::-;9618:1318:28;771:1277:1;20818:35:26;;;;;;771:1277:1;;;;-1:-1:-1;;;;;771:1277:1;;;;;;;;;;4464:26:20;20186:254:26;20400:29;20186:254;;;:::i;:::-;9618:1318:28;771:1277:1;20400:29:26;;;-1:-1:-1;;;;;771:1277:1;;;20400:29:26;;;771:1277:1;;;;;;;;;22648:2146:26;;24117:671;22648:2146;;;;13283:4:22;771:1277:1;;23074:41:26;23070:1009;13283:4:22;;;24117:671:26;23131:12;10720:1;23222:498;;;;13283:4:22;23222:498:26;;;23175:33;23222:498;;;;13283:4:22;23222:498:26;;;;;;;;;23070:1009;24117:671;;;10720:1;24117:671;;;;;;;;;;;;;;;;10415:1;24117:671;;;;;;22648:2146::o;23070:1009::-;23816:253;24117:671;23816:253;;;10720:1;23816:253;;;;;;23070:1009;;1366:7177:28;;;;1654:47;;;771:1277:1;;2230:20:28;;2341:1623;;;;;;;;;;;;;;;;-1:-1:-1;2341:1623:28;;;;;;;;;;;;;;;;;;;;4180:28;;4299:1761;;;;;;;;;;;-1:-1:-1;4299:1761:28;;;;;;;;;;;;-1:-1:-1;;4299:1761:28;2341:1623;4299:1761;2341:1623;4299:1761;;6268:2269;;;;;6161:15;;6268:2269;;;;;;;;;;;;;;;;;;;;;;1366:7177::o;4299:1761::-;;;;-1:-1:-1;;2341:1623:28;4299:1761;;;;;;;;;;;;;;;;;;;;;;;;2341:1623;;;-1:-1:-1;;2341:1623:28;;;;;;;;;;;;;;;;;;;;;;;;;11216:181;11293:13;11310:9;11293:26;11310:9;;11334:17;11216:181;:::o;11293:97::-;771:1277:1;;2696:187:21;;;2724:24;;771:1277:1;;2766:10:21;771:1277:1;;;;2794:13:21;771:1277:1;;;;11293:13:28;771:1277:1;;;;2864:4:21;771:1277:1;;;;;2696:187:21;;;;;:::i;:::-;771:1277:1;2673:220:21;;11216:181:28;:::o;1346:2159:29:-;1414:2085;;;1346:2159::o;1414:2085::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;1346:2159::o;1414:2085::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;5673:1149:31;;;;;6390:16;771:1277:1;5673:1149:31;;771:1277:1;5673:1149:31;;6390:16;;:::i;:::-;771:1277:1;;;:::i;:::-;;;;;:::i;:::-;;;;;22159:55:31;22130:94;22159:55;;;;:::i;:::-;22130:94;:::i;:::-;22390:35;6319:5;22497:13;;22492:1022;22512:26;;;;;;23593:13;;6319:5;23588:1121;23608:34;;;;;;24793:28;;;;;;24789:320;;23588:1121;771:1277:1;;;25179:22:31;25175:88;;25335:97;;;;:::i;:::-;6779:36;5673:1149;:::o;25175:88::-;25224:28;771:1277:1;;25224:28:31;;;;24789:320;24909:186;;;;;24789:320;;;23644:3;23811:28;;;;;;23984:186;23811:28;;;;;:::i;:::-;;23984:186;;:::i;:::-;24270:14;;23146:24;24270;771:1277:1;-1:-1:-1;;;;;771:1277:1;-1:-1:-1;;;;;24270:45:31;771:1277:1;23174:17:31;24298;;771:1277:1;-1:-1:-1;;;;;771:1277:1;;;;-1:-1:-1;;;;;771:1277:1;;;24270:45:31;771:1277:1;;24270:45:31;23174:17;;771:1277:1;;;;;;24266:429:31;;771:1277:1;23593:13:31;;;;;;24266:429;771:1277:1;;24554:122:31;771:1277:1;24554:122:31;771:1277:1;;;;;;;24554:122:31;;;:::i;:::-;;;;:::i;:::-;;24266:429;;22540:3;22703:20;;;5978:1908:27;22703:20:31;;;;;;;;;:::i;:::-;;5978:1908:27;;:::i;:::-;23146:14:31;;:24;;771:1277:1;-1:-1:-1;;;;;771:1277:1;-1:-1:-1;;;;;23146:45:31;771:1277:1;23174:17:31;;;771:1277:1;-1:-1:-1;;;;;771:1277:1;;;23146:45:31;771:1277:1;;23146:45:31;23174:17;;771:1277:1;;;;;;23142:358:31;;771:1277:1;22497:13:31;;;;;;;;23142:358;771:1277:1;;23430:51:31;771:1277:1;23430:51:31;771:1277:1;;;;;23430:51:31;;;:::i;:::-;;;;:::i;:::-;;23142:358;;771:1277:1;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;-1:-1:-1;;771:1277:1;;;;:::i;:::-;;13283:4:22;771:1277:1;13283:4:22;771:1277:1;;13283:4:22;771:1277:1:o;:::-;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;8128:9851:31;;;:::i;:::-;771:1277:1;;8682:26:31;;;;:::i;:::-;6319:5;;8799:55;;;;9012:13;9027:15;;;;;;16577:17;;;;;;:::i;:::-;17205:15;;;;;8128:9851;;;;:::o;17222:3::-;17318:14;;771:1277:1;17318:14:31;;;:::i;:::-;771:1277:1;17318:28:31;17314:83;;17901:29;17544:17;;;;:::i;:::-;;:28;17704:14;;;;:::i;:::-;771:1277:1;;;;;-1:-1:-1;;;;;771:1277:1;;;;17785:20:31;771:1277:1;17785:20:31;;;771:1277:1;-1:-1:-1;;;;;771:1277:1;;;;12251:21:31;11615:30;17858:21;;;17901:29;;;16795:158;;17901:29;;:::i;:::-;771:1277:1;17190:13:31;;17314:83;17370:8;;9044:3;9151:17;;;;:::i;:::-;;9270:21;;;;9266:455;;9958:211;;;;;;:::i;:::-;771:1277:1;;;;10251:79:31;;;;;;10433:14;;;10429:272;;10783:26;;771:1277:1;10783:26:31;;;;;:::i;:::-;771:1277:1;;11014:24:31;;;:34;;;;;;771:1277:1;11166:32:31;;;;;771:1277:1;;11328:15:31;;771:1277:1;;;;;11615:30:31;771:1277:1;;;11615:30:31;;;11731:13;11726:1615;771:1277:1;;;11726:1615:31;12251:21;;;;;13504:24;;;:38;;13654:13;;13649:2789;771:1277:1;;;13649:2789:31;9044:3;;;;;;;;;;771:1277:1;9044:3:31;9012:13;771:1277:1;9012:13:31;;13695:3;771:1277:1;;13669:24:31;;;;;13849:16;;;;;;15212:322;13849:16;;;;;;;;:::i;:::-;;14112:27;12104:19;14112:27;;771:1277:1;14002:159:31;771:1277:1;;14002:159:31;;;:::i;:::-;14292:29;;;771:1277:1;;;;;;14292:84:31;;14263:646;14349:27;;;771:1277:1;;;;;;14263:646:31;771:1277:1;;;;;15212:322:31;:::i;:::-;771:1277:1;;15660:760:31;;;;771:1277:1;13654:13:31;;;14263:646;14709:177;;;:::i;:::-;771:1277:1;;14263:646:31;;13669:24;;;11764:3;771:1277:1;;;;;;11746:16:31;;;;;11868:8;;12251:21;13041:281;11868:8;;;;;:::i;:::-;;12104:19;;;;771:1277:1;11994:151:31;771:1277:1;;11994:151:31;;;:::i;:::-;12251:21;;;;771:1277:1;;;;;;12251:44:31;;12247:539;12276:19;;;771:1277:1;;;;;;12247:539:31;771:1277:1;;;13041:281:31;:::i;:::-;771:1277:1;;;11731:13:31;;;;;12247:539;12594:169;;;:::i;:::-;771:1277:1;;12247:539:31;;11746:16;;;;;;;10429:272;10552:23;;;;771:1277:1;10552:23:31;;;;;;;771:1277:1;10674:8:31;;9266:455;9396:23;771:1277:1;9396:23:31;;;;771:1277:1;9513:87:31;;;;;9694:8;;8128:9851;;;:::i;:::-;771:1277:1;;8682:26:31;;;;:::i;:::-;8799:55;;;;;;9012:13;9027:15;;;;;;16577:17;;;;;;:::i;:::-;17205:15;;;;;8128:9851;;;;:::o;17222:3::-;17318:14;;33365:4;17318:14;;;:::i;:::-;771:1277:1;17318:28:31;17314:83;;17901:29;17544:17;;;;:::i;:::-;;:28;17704:14;;;;:::i;:::-;771:1277:1;;;;;-1:-1:-1;;;;;771:1277:1;;;;17785:20:31;;;771:1277:1;-1:-1:-1;;;;;771:1277:1;17858:21:31;12251;11615:30;17858:21;;;17901:29;;;;;:::i;:::-;771:1277:1;17190:13:31;;17314:83;17370:8;;9044:3;9151:17;;;;:::i;:::-;;9270:21;;;;9266:455;;9958:211;;;;;;:::i;:::-;33365:4;;;;10251:79;;;;;;10433:14;;;10429:272;;10783:26;;771:1277:1;10783:26:31;;;;;:::i;:::-;771:1277:1;;11014:24:31;;;:34;;;;;;771:1277:1;11166:32:31;;;;;771:1277:1;;11328:15:31;;771:1277:1;;;;;11615:30:31;771:1277:1;;;11615:30:31;;;11731:13;11726:1615;33365:4;;;11726:1615;12251:21;;;;;13504:24;;;:38;;13654:13;;13649:2789;33365:4;;;13649:2789;9044:3;;;;;;;;;;33365:4;9044:3;9012:13;771:1277:1;9012:13:31;;13695:3;771:1277:1;;13669:24:31;;;;;13849:16;;;;;;15212:322;13849:16;;;;;;;;:::i;15212:322::-;771:1277:1;;15660:760:31;;;;771:1277:1;13654:13:31;;;13669:24;;;11764:3;771:1277:1;;;;;;11746:16:31;;;;;11868:8;;12251:21;13041:281;11868:8;;;;;:::i;13041:281::-;771:1277:1;;;11731:13:31;;;;;11746:16;;;;;;;10429:272;10552:23;;;;33365:4;10552:23;;;;;;;771:1277:1;10674:8:31;;9266:455;9396:23;33365:4;9396:23;;;;771:1277:1;9513:87:31;;;;;9694:8;;771:1277:1;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;:::o;1271:1405:18:-;;;;;1585:24;;;1581:983;;2653:16;;;;1271:1405;:::o;1581:983::-;2153:23;;2181:19;2153:23;2152:49;2153:23;;;;:::i;:::-;2181:19;;:::i;:::-;2152:49;;:::i;:::-;2357:88;2537:16;:::o;1271:1405::-;;;;;1585:24;;;1581:983;;2653:16;;;;1271:1405;:::o;1581:983::-;2153:23;2181:19;2153:23;2152:49;2153:23;2152:64;2153:23;;;;:::i;:::-;771:1277:1;;;;2181:19:18;;:::i;2152:49::-;:64;:::i;3484:1206::-;;;;3719:24;;;3715:67;;3939:242;;;;4262:61;;4441:17;;;:::i;4262:61::-;4295:17;771:1277:1;;4295:17:18;;;;3715:67;3759:12;;;;:::o;771:1277:1:-;;-1:-1:-1;771:1277:1;;;:::o;:::-;;;;;:::i;:::-;;;;:::i;1497:7144:25:-;771:1277:1;;;;2104:13:25;2116:1;2119:26;;;;;;6878:13;;;2116:1;6893:23;;;;;;1497:7144;;;:::o;6918:3::-;7138:28;:23;2763:36;7026:17;;;;:::i;:::-;;7138:23;771:1277:1;;;;;7138:23:25;771:1277:1;;;;7138:28:25;;7134:83;;7356:17;;;;:::i;:::-;;:28;7519:29;;;;;771:1277:1;7649:13:25;2116:1;7664:14;;;;;;3172:22;;;;8158:21;;;;;;771:1277:1;8272:13:25;2116:1;8287:14;;;;;;6918:3;;;;771:1277:1;6918:3:25;6878:13;771:1277:1;6878:13:25;;8303:3;8435:54;8455:33;:24;:21;;;:24;:::i;:::-;;:33;:::i;:::-;9348:64;-1:-1:-1;9140:278:25;;8435:54;8406:187;;771:1277:1;;8272:13:25;;8406:187;8545:25;771:1277:1;;8545:25:25;;;;7680:3;7812:116;7861:41;:32;:29;;;:32;:::i;7812:116::-;7783:257;;771:1277:1;;7649:13:25;;7783:257;7984:33;3172:22;771:1277:1;7984:33:25;;;;7134:83;771:1277:1;7190:8:25;;;2147:3;2286:20;;;;:::i;:::-;;771:1277:1;;2553:33:25;;;;;2549:120;;2763:36;:26;:41;:36;:26;;;;;:::i;:41::-;;2759:96;;2994:26;;;;:::i;:::-;;:37;3172:22;;;;;;771:1277:1;3277:17:25;3434:21;;771:1277:1;;;;:::i;:::-;;;;:::i;:::-;3434:35:25;;3563:21;;;771:1277:1;;3679:30:25;;;3675:125;;3924:21;;;;:::i;:::-;;771:1277:1;9348:64:25;771:1277:1;;;;;;:::i;:::-;4049:29:25;4123:30;4415:32;4123:30;;;771:1277:1;4299:95:25;771:1277:1;;4299:95:25;;;;4415:32;;:::i;:::-;4583:52;;;771:1277:1;;;3430:2718:25;9348:64;6246:30;6242:111;;6449:34;;771:1277:1;6449:34:25;;;6445:351;;3430:2718;2147:3;;2104:13;771:1277:1;2104:13:25;;6445:351;6725:30;6626:27;6725:30;6626:27;;;771:1277:1;6725:30:25;;;;;:::i;:::-;6445:351;;;;6242:111;6307:27;771:1277:1;;6307:27:25;;;;3675:125;3744:33;771:1277:1;;3744:33:25;;;;3430:2718;4830:29;;;;;;;771:1277:1;;4976:38:25;;;4972:141;;9348:64;5285:29;;;;:::i;:::-;;771:1277:1;;;;;;;:::i;:::-;5440:37:25;5548:38;5870:40;5548:38;;;771:1277:1;5754:95:25;771:1277:1;;5754:95:25;;;;5870:40;;:::i;:::-;6080:27;;771:1277:1;;;3430:2718:25;;4972:141;5049:41;771:1277:1;;5049:41:25;;;;2759:96;2828:8;;;771:1277:1;2828:8:25;;;2549:120;2617:33;3172:22;771:1277:1;2617:33:25;;;;9752:1564;;;;9903:1272;;;;;;;;;;;;;;;;;;;;;;;11250:60;;9752:1564::o;11250:60::-;11285:14;9903:1272;771:1277:1;11285:14:25;;;;9903:1272;;;;;;;;;;;;;-1:-1:-1;9903:1272:25;;;;;;-1:-1:-1;9903:1272:25;;;;;;;;;-1:-1:-1;9903:1272:25;;;;;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;-1:-1:-1;;771:1277:1;;;;:::i;:::-;;;-1:-1:-1;771:1277:1;;;;;;;;;:::o;:::-;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;:::o;5978:1908:27:-;;;771:1277:1;;:::i;:::-;;;;6502:33:27;6498:125;;6963:9;;;;;:::i;:::-;7756:14;;:21;;;771:1277:1;7756:26:27;7752:118;;5978:1908;:::o;7752:118::-;7802:24;-1:-1:-1;;;;;7837:17:27;;;771:1277:1;;7802:24:27;;771:1277:1;5978:1908:27:o;6498:125::-;771:1277:1;;;6562:46:27;;;6319:5:31;6562:46:27;;;771:1277:1;6562:46:27;5978:1908;;;;771:1277:1;;:::i;:::-;;;;6502:33:27;6498:125;;7360:9;;;;;:::i;:::-;7493:10;7473:17;;;771:1277:1;7600:20:27;;;771:1277:1;7756:14:27;;:21;;;771:1277:1;7756:26:27;7752:118;;5978:1908;:::o;7752:118::-;7802:24;7493:10;7802:24;;771:1277:1;5978:1908:27:o;6498:125::-;771:1277:1;;;6562:46:27;;;24061:18:31;6562:46:27;;;771:1277:1;6562:46:27;8720:10637;;;;;;;;8506:10857;;8720:10637;;;;;;;;;;;;;;;;;8506:10857;8720:10637;;;;;;;;;;;;;;;;;;;;;;;;;;;8506:10857;8720:10637;;;;;;;;;;;;;;;8506:10857;8720:10637;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8506:10857::o;8720:10637::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;8720:10637:27;-1:-1:-1;8720:10637:27;;;;;:::i;:::-;;;;;;:::i;:::-;;;20115:10440;;;20418:10131;;;;;;;;;;;;;;;;;20115:10440;20418:10131;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20115:10440;20418:10131;;;;;;;;;;;;;;;20115:10440;20418:10131;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20115:10440::o;20418:10131::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;20418:10131:27;-1:-1:-1;20418:10131:27;;;;;:::i;:::-;;;;;;:::i;:::-;;;26271:4230:31;;771:1277:1;;26678:23:31;;;:::i;:::-;26893:13;26905:1;26888:1427;26908:15;;;;;;28424:9;;;;28821:30;;;:::i;:::-;28907:13;26905:1;28907:13;771:1277:1;;28922:21:31;;;;;29062:13;;;;;:::i;:::-;;29116:14;;771:1277:1;;;;;;:::i;:::-;;;;:::i;:::-;29226:32:31;29222:434;;28907:13;29780:17;29853:11;29780:17;;29815:20;771:1277:1;27154:23:31;771:1277:1;29780:17:31;;;771:1277:1;-1:-1:-1;;;;;771:1277:1;;;;29815:20:31;;771:1277:1;29853:11:31;;:::i;:::-;771:1277:1;28907:13:31;;29222:434;29359:11;;;;;27726:38;29359:11;;771:1277:1;;;29359:28:31;29355:109;;771:1277:1;;;;29222:434:31;;771:1277:1;;29222:434:31;;28922:21;;;30131:11;28922:21;;30131:11;:::i;:::-;30235:19;30231:99;;28902:1123;30231:99;;2250:1:22;1322:31:34;771:1277:1;1231:129:34;30231:99:31;30304:14;30291:10;;30304:14;:::i;:::-;30231:99;;;26925:3;27036:17;;;;;;;;:::i;:::-;;27154:23;:28;771:1277:1;27154:23:31;;;771:1277:1;;;;;27154:28:31;;27150:323;;27539:25;;;;;:::i;:::-;27560:4;771:1277:1;;;27539:25:31;27726:38;:24;;;:38;;27883:13;26905:1;27924:3;771:1277:1;;27898:24:31;;;;;28049:16;;;;;:::i;:::-;;:28;771:1277:1;28171:16:31;28167:116;;27924:3;771:1277:1;;27883:13:31;;28167:116;771:1277:1;;28222:38:31;;;;;;771:1277:1;;;;;;;;;;;;;;;;4464:26:20;27898:24:31;;;;;;;;;771:1277:1;27898:24:31;26893:13;771:1277:1;26893:13:31;;;27150:323;27446:8;;;771:1277:1;27446:8:31;;;;;;;1939:1436:26;;;;771:1277:1;;;;;:::i;:::-;;;;:::i;:::-;2170:32:26;;2291:14;;;;2307:11;771:1277:1;2291:14:26;2307:11;2291:14;;771:1277:1;-1:-1:-1;;;;;771:1277:1;;;;2307:11:26;;771:1277:1;2307:11:26;;:::i;2166:1203::-;2357:14;771:1277:1;;;;;:::i;:::-;;;;:::i;:::-;2340:31:26;2357:14;;2490:10;2458:196;2490:10;771:1277:1;2490:10:26;;;771:1277:1;-1:-1:-1;;;;;771:1277:1;;;;2540:14:26;-1:-1:-1;;;;;2572:11:26;771:1277:1;2540:14:26;;;771:1277:1;-1:-1:-1;;;;;771:1277:1;;;;2572:11:26;;771:1277:1;;;2458:196:26;;:::i;2336:1033::-;2692:15;771:1277:1;;;;;:::i;:::-;;;;:::i;:::-;2675:32:26;2692:15;;2827:10;771:1277:1;2827:10:26;2794:230;2827:10;;771:1277:1;-1:-1:-1;;;;;771:1277:1;;;;2877:14:26;;;771:1277:1;-1:-1:-1;;;;;771:1277:1;2909:15:26;-1:-1:-1;;;;;2942:11:26;2909:15;;;771:1277:1;2942:11:26;;771:1277:1;;;2794:230:26;;:::i;2671:698::-;3161:10;771:1277:1;3161:10:26;3127:231;3161:10;;771:1277:1;-1:-1:-1;;;;;771:1277:1;;;;3211:14:26;;;771:1277:1;-1:-1:-1;;;;;771:1277:1;3243:15:26;-1:-1:-1;;;;;3276:11:26;3243:15;;;771:1277:1;3276:11:26;;771:1277:1;;;3127:231:26;;:::i;32941:661:31:-;;33431:21;32941:661;;;;;771:1277:1;;33431:21:31;;;:::i;:::-;34926:34;;;:::i;:::-;35126:35;-1:-1:-1;35227:13:31;;35222:943;35242:21;;;;;;36249:28;;;;36637:63;36249:28;;;;;36245:320;;35222:943;36637:63;;:::i;:::-;;32941:661;:::o;36245:320::-;36365:186;;;;;36245:320;;;35265:3;35381:15;;;;;;;;:::i;:::-;35520:177;35595:27;;;;:::i;:::-;35644:35;;;;;;;;;:::i;:::-;35520:177;;;;;:::i;:::-;35797:14;-1:-1:-1;;;;;35797:45:31;771:1277:1;35797:24:31;;:14;;:24;-1:-1:-1;;;;;771:1277:1;;;;;35797:24:31;35825:17;;;771:1277:1;-1:-1:-1;;;;;771:1277:1;;;35797:45:31;771:1277:1;;35797:45:31;35644:35;;771:1277:1;33365:4:31;771:1277:1;;;35793:358:31;;771:1277:1;35227:13:31;;;;35793:358;771:1277:1;36081:51:31;771:1277:1;;33365:4:31;771:1277:1;;;36081:51:31;;;;;:::i;:::-;;;;:::i;:::-;;35793:358;;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;;;;;;;:::i;1692:3201:27:-;;;;771:1277:1;;:::i;:::-;2050:27:27;;;:66;;;;1692:3201;2033:170;;771:1277:1;;:::i;:::-;2383:155:27;771:1277:1;;;;;;:::i;:::-;2383:155:27;;:::i;:::-;2659:27;771:1277:1;2762:126:27;771:1277:1;;;;;;:::i;:::-;2762:126:27;;:::i;:::-;2995:23;:14;;:23;:::i;:::-;771:1277:1;;;;;;:::i;:::-;;;;:::i;:::-;;;;:::i;:::-;2995:53:27;;;:116;;;1692:3201;2995:189;;;;1692:3201;2978:303;;4670:54;3364:24;771:1277:1;3364:24:27;4697:27;3364:24;;;;;;;;;;;771:1277:1;;;3391:14:27;;;:21;771:1277:1;-1:-1:-1;3360:1167:27;3364:24;;;3572:26;;;3708:42;3868:48;3508:104;3572:26;3810:25;3572:26;3708:128;3572:26;;:::i;:::-;3508:104;:::i;:::-;771:1277:1;;;;3895:14:27;;:21;771:1277:1;3868:48:27;;:::i;:::-;771:1277:1;;;3708:42:27;;:::i;:::-;;:70;:101;;3810:25;;771:1277:1;3708:128:27;;:::i;:::-;;:157;771:1277:1;4034:14:27;;;:21;771:1277:1;;;3360:1167:27;771:1277:1;4612:14:27;;;:21;771:1277:1;4697:27:27;771:1277:1;-1:-1:-1;;;;;771:1277:1;;;;4697:27:27;4670:14;;:24;771:1277:1;-1:-1:-1;;;;;771:1277:1;;;;3360:1167:27;4410:25;4205:18;;4316:93;4205:18;;4316:120;4205:18;4158:66;4205:18;4316:42;4205:18;4468:48;4205:18;;:::i;4158:66::-;4468:14;;:21;771:1277:1;;;4468:48:27;;:::i;4316:120::-;;:149;771:1277:1;3360:1167:27;;2978:303;3216:54;771:1277:1;;3216:54:27;;;;2995:189;3127:14;:25;:14;;:25;771:1277:1;3127:25:27;3156:28;;771:1277:1;3127:57:27;;2995:189;;:116;-1:-1:-1;3064:14:27;;:20;;771:1277:1;-1:-1:-1;;;;;771:1277:1;-1:-1:-1;;;;;3064:47:27;771:1277:1;3064:20:27;3088:23;;771:1277:1;-1:-1:-1;;;;;771:1277:1;;;3064:47:27;771:1277:1;;3064:47:27;;2995:116;;2033:170;2148:44;771:1277:1;;2148:44:27;;;;2050:66;2081:35;;;2050:66;;771:1277:1;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;:::i;:::-;;;2927:2055:32;;;;916:217:34;;:::i;:::-;2317:1:22;1099:27:34;771:1277:1;3554:165:32;;;;:::i;:::-;771:1277:1;;;;;;;;:::i;:::-;3667:4:32;771:1277:1;;1099:27:34;771:1277:1;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;4539:19:32;771:1277:1;;4107:17:32;4841:29;771:1277:1;4253:17:32;771:1277:1;;;;;;;;;;3944:33:32;;;;:::i;:::-;;4107:17;;:::i;:::-;4253;:::i;:::-;;:28;4499:26;;;;771:1277:1;4539:19:32;;;:::i;:::-;771:1277:1;;-1:-1:-1;;;;;771:1277:1;;;4841:29:32;;2250:1:22;1322:31:34;771:1277:1;1231:129:34;4841:29:32;3667:4;2927:2055;:::o;771:1277:1:-;;;:::i;:::-;;;6214:9703:32;;;;;;6542:23;;;771:1277:1;6568:25:32;;6621:43;6542:51;6568:25;;;771:1277:1;;;6542:51:32;;:::i;:::-;771:1277:1;;6621:15:32;:43;:::i;:::-;6694:18;;;;;:::i;:::-;6812:9;;7209:30;;;:::i;:::-;9289:13;-1:-1:-1;9289:13:32;9308:21;;;;;;771:1277:1;;9304:32:32;;;;;9431:24;;;;;;9571:297;9431:24;;;;;;;;:::i;:::-;;9607:21;;;;771:1277:1;;;9650:19:32;;;;771:1277:1;;;9571:297:32;;:::i;:::-;9962:422;;;;;;771:1277:1;;;;;:::i;:::-;;;;:::i;:::-;10486:37:32;10482:461;;9289:13;771:1277:1;;;8929:9:32;771:1277:1;;;;;;;-1:-1:-1;;;;;771:1277:1;;;;;;:::i;:::-;;9289:13:32;;10482:461;10632:23;;;;;;;;;;;;;;;;;10628:112;;-1:-1:-1;771:1277:1;;;;;;;;;;;;;;;10482:461:32;;10628:112;10690:27;771:1277:1;;10690:27:32;;;;9304:32;;;;;;;;;;;;;;-1:-1:-1;13075:13:32;9607:21;13094:29;;;;771:1277:1;;13090:40:32;;;;;13271:32;;;;13438:312;13271:32;;;;;;;;;:::i;:::-;;13474:29;;;771:1277:1;;;13525:27:32;9650:19;13525:27;;771:1277:1;;;13438:312:32;;:::i;:::-;13848:709;;;;;;;;;771:1277:1;;;;;:::i;:::-;;;;:::i;:::-;14659:45:32;14655:469;;13075:13;9962:422;;771:1277:1;9962:422:32;8929:9;9962:422;;;771:1277:1;;:::i;:::-;;13075:13:32;;14655:469;14813:23;;;;;;;;;;;14809:112;;771:1277:1;;;;;;;;;;14655:469:32;;13090:40;;;;;;;;;;;;;;15695:11;13090:40;;15695:11;:::i;:::-;15776:19;15772:139;;6214:9703;:::o;15772:139::-;15885:14;9962:422;;15885:14;:::i;5438:917:18:-;;;;;;;;5809:24;;;5805:544;5809:24;;;5903:47;;;;;;;:::i;5805:544::-;6107:49;;;;;6069:269;6107:49;6174:47;6107:49;;;;:::i;:::-;6174:47;;:::i;:::-;6069:269;;:::i;5438:917::-;;;;;;;;5809:24;;;5805:544;5809:24;;;5903:47;;;;;;;:::i;5805:544::-;6107:49;;;;;6069:269;6107:49;6174:47;6107:49;;;;:::i;6174:47::-;6069:269;;:::i;771:1277:1:-;;;;;;;;;;;;;;;-1:-1:-1;771:1277:1;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;16561:855:32;;;;;;771:1277:1;;;;;;;;;;;;;;8799:55:31;771:1277:1;;;;;;;;;;;;;;;;;;;;;8799:55:31;771:1277:1;;;;;;;;;;;;;;;;17249:160:32;771:1277:1;;;;;;;;;-1:-1:-1;;;;;771:1277:1;;;;;;;:::i;:::-;17249:160:32;;;16561:855::o;771:1277:1:-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;16561:855:32;;;;;;771:1277:1;;;;;;;;;;;;;-1:-1:-1;;;;;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;771:1277:1;;;;;;;;;;;;;;;;;;;;;17249:160:32;771:1277:1;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;17692:380:32:-;771:1277:1;;:::i;:::-;;;18024:15:32;17964:16;;;;:::i;:::-;18024:15;;;;;;:::i;:::-;771:1277:1;;;;;;;:::i;:::-;;;;:::i;:::-;;;17994:1:32;18024:15;17937:128;;771:1277:1;17994:1:32;771:1277:1;17937:128:32;;771:1277:1;;;;:::i;:::-;17937:128:32;;;771:1277:1;;;;;;:::i;:::-;-1:-1:-1;13283:4:22;;17937:128:32;;;771:1277:1;17692:380:32;:::o;18360:859::-;771:1277:1;;;:::i;:::-;;;;;;;;:::i;:::-;;;;-1:-1:-1;;771:1277:1;;;:::i;:::-;;-1:-1:-1;771:1277:1;;;;;;18918:13:32;;-1:-1:-1;18933:15:32;;;;;;19191:21;;;18360:859;:::o;18950:3::-;19098:9;19074:34;19098:9;771:1277:1;19098:9:32;;;;:::i;:::-;19074:34;:::i;:::-;19054:54;;;;:::i;:::-;;;;;;:::i;:::-;;771:1277:1;18918:13:32;;771:1277:1;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;1483:1032:33:-;2469:23;1483:1032;2469:39;1483:1032;771:1277:1;-1:-1:-1;771:1277:1;1732:12:33;771:1277:1;;;2138:24:33;771:1277:1;;-1:-1:-1;771:1277:1;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1824:218:33;;;;:::i;2138:24::-;2134:102;;1483:1032;2317:42;:23;;;;;771:1277:1;;14731:12:33;771:1277:1;;;;;;;2317:42:33;2369:43;:23;;771:1277:1;;14731:12:33;771:1277:1;;;;;;;2369:23:33;771:1277:1;;;;;;;2369:43:33;2422:37;:23;;771:1277:1;;14731:12:33;771:1277:1;;;;;;;2422:23:33;771:1277:1;;;;;;;;;2422:37:33;771:1277:1;;14731:12:33;771:1277:1;;;;;;;2469:23:33;771:1277:1;;;;;;;;;2134:102:33;2215:9;;;:::i;:::-;2134:102;;;;;4331:5564;;;4796:24;;4959:25;4929:143;4930:142;4959:25;;;771:1277:1;5002:23:33;;;771:1277:1;4930:142:33;;:::i;4929:143::-;4912:302;;5322:32;771:1277:1;5330:23:33;;;771:1277:1;;;;;5322:32:33;5386:34;771:1277:1;5394:25:33;;;771:1277:1;;;;;5386:34:33;5508:23;;;;:41;;;;4331:5564;5504:92;;5704:23;;;:93;;;4331:5564;5687:262;;6507:20;6052:86;;;:::i;:::-;6393:24;;;;771:1277:1;6431:25:33;;;771:1277:1;;;;:::i;:::-;;;-1:-1:-1;;;;;771:1277:1;6507:20:33;;771:1277:1;5330:23:33;6507:20;;771:1277:1;-1:-1:-1;;;;;771:1277:1;;;;6507:20:33;;;:::i;:::-;771:1277:1;6648:23:33;;771:1277:1;;14731:12:33;771:1277:1;;;;;;;;6758:189:33;6757:190;6758:189;;;;:::i;6757:190::-;6740:348;;771:1277:1;7183:24:33;771:1277:1;;;;;;;7183:24:33;7179:194;;4331:5564;7490:21;;;7521:51;771:1277:1;;7464:47:33;771:1277:1;5394:25:33;7490:21;;771:1277:1;;;;;7464:47:33;7549:23;;771:1277:1;;;;;7521:51:33;7668:22;;;;;3667:4:32;7791:16:33;;3667:4:32;;7906:29:33;;;7787:668;;8554:27;;;;;:::i;:::-;:41;8550:329;;7787:668;9079:23;9200:110;9328:58;9079:23;:42;:23;;771:1277:1;;14731:12:33;771:1277:1;;;;;;;9079:42:33;9139:43;:23;;771:1277:1;;14731:12:33;771:1277:1;;;;;;;9139:43:33;771:1277:1;;;;;;9200:23:33;;771:1277:1;;14731:12:33;771:1277:1;;;;;;;9200:23:33;771:1277:1;;;;;;;;;;;;;;;9200:110:33;771:1277:1;;9328:23:33;;771:1277:1;;14731:12:33;771:1277:1;;;;;;;9328:23:33;771:1277:1;;;;;;;;;;;;;;;9328:58:33;9846:42;;4331:5564;:::o;8550:329::-;771:1277:1;;;;-1:-1:-1;8550:329:33;;7787:668;8099:32;;;;;;8095:360;;7787:668;;;;8095:360;8360:30;8231;;;8408:32;8231:30;;;;;:::i;:::-;8360;;:::i;:::-;8408:32;;:::i;:::-;8095:360;;;;7664:2092;9506:23;;;;:42;:23;;771:1277:1;;14731:12:33;771:1277:1;;;;;;;9506:42:33;9562:43;:23;;771:1277:1;;14731:12:33;771:1277:1;;;;;;;9562:43:33;9687:58;771:1277:1;9619:54:33;771:1277:1;;;9619:23:33;;771:1277:1;;14731:12:33;771:1277:1;;;;;;;7179:194:33;771:1277:1;;7325:23:33;771:1277:1;;-1:-1:-1;;;;;771:1277:1;;;;7325:23:33;;;;;:::i;:::-;7179:194;;;;;6740:348;7053:24;;;;;;;;-1:-1:-1;7053:24:33;-1:-1:-1;7053:24:33;:::o;5687:262::-;5906:32;5394:25;771:1277:1;5906:32:33;;;;5704:93;5771:25;3667:4:32;5771:25:33;;;771:1277:1;;;;:::i;:::-;18200:133:33;;5704:93;;5504:92;5572:13;5394:25;771:1277:1;5572:13:33;;;;5508:41;5535:14;;;5508:41;;4912:302;-1:-1:-1;;;;;;;;;5178:25:33:o;4331:5564::-;;;;;4796:24;;4929:143;4930:142;4959:25;;;771:1277:1;5002:23:33;;;771:1277:1;4930:142:33;;:::i;4929:143::-;4912:302;;5322:32;771:1277:1;5330:23:33;;;771:1277:1;;;;;5322:32:33;5394:25;5386:34;771:1277:1;5394:25:33;;;771:1277:1;;;;;5386:34:33;5508:23;;;;:41;;;;4331:5564;5504:92;;5704:23;;;:93;;;4331:5564;5687:262;;6507:20;6052:86;;;;:::i;:::-;6393:24;;;;771:1277:1;6431:25:33;;;771:1277:1;;;;;:::i;:::-;;;;;-1:-1:-1;;;;;771:1277:1;;;;6507:20:33;771:1277:1;5330:23:33;6507:20;;771:1277:1;-1:-1:-1;;;;;771:1277:1;;;;6507:20:33;;;:::i;:::-;771:1277:1;6648:23:33;;771:1277:1;;14731:12:33;771:1277:1;;;;;;;;6758:189:33;6757:190;6758:189;;;;:::i;5704:93::-;5771:25;18200:133;5771:25;;;771:1277:1;;;;:::i;:::-;18200:133:33;;5704:93;;5508:41;5535:14;;;5508:41;;4912:302;5178:25;;;;;6319:5:31;5178:25:33;6319:5:31;5178:25:33;6319:5:31;5178:25:33;:::o;4331:5564::-;;;;;4796:24;;4929:143;4930:142;4959:25;;;771:1277:1;5002:23:33;;;771:1277:1;4930:142:33;;:::i;4929:143::-;4912:302;;5322:32;771:1277:1;5330:23:33;;;771:1277:1;;;;;5322:32:33;5394:25;5386:34;771:1277:1;5394:25:33;;;771:1277:1;;;;;5386:34:33;5508:23;;;;:41;;;;4331:5564;5504:92;;5704:23;;;:93;;;4331:5564;5687:262;;6507:20;6052:86;;;;:::i;5704:93::-;5771:25;33365:4:31;5771:25:33;;;771:1277:1;;;;:::i;:::-;18200:133:33;;5704:93;;5508:41;5535:14;;;5508:41;;1567:650:19;2095:115;1567:650;1931:47;1881:29;;;;771:1277:1;1931:47:19;;;771:1277:1;1931:47:19;;:::i;:::-;771:1277:1;;-1:-1:-1;;;;;771:1277:1;-1:-1:-1;771:1277:1;;;1777:7:30;771:1277:1;;;;;;2095:115:19;;:::i;771:1277:1:-;;;;;;;;;;;;;;;;;:::i;:::-;;;:::i;:::-;;;916:217:34;;;:::i;:::-;2317:1:22;1099:27:34;771:1277:1;916:217:34:o;1510:215::-;2250:1:22;1635:16:34;771:1277:1;1635:32:34;1631:88;;1510:215::o;1631:88::-;1690:18;771:1277:1;;1690:18:34;;;;10197:4678:36;;;10422:4447;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10197:4678::o;10422:4447::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15499:5338;;;;15750:5081;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15499:5338::o;15750:5081::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1337:627:38;1586:15;-1:-1:-1;1574:57:38;;;;;1337:627;1570:314;;;14288:4:20;1337:627:38;:::o;1570:314::-;1766:13;771:1277:1;;1766:13:38;;;;1574:57;1586:15;;;-1:-1:-1;1605:26:38;1574:57;;;1337:627;1586:15;-1:-1:-1;1574:57:38;;;;;1337:627;1570:314;;;1953:4;1337:627;:::o;1570:314::-;-1:-1:-1;1861:12:38;:::o;1574:57::-;1586:15;;;-1:-1:-1;1605:26:38;1574:57;;;2639:569;;;;2863:10;-1:-1:-1;;;;;771:1277:1;;2852:21:38;2848:58;;3191:9;3033:18;;;:::i;:::-;12929:843:28;-1:-1:-1;12929:843:28;;;;;;-1:-1:-1;12929:843:28;;-1:-1:-1;12929:843:28;;3191:9:38;:::i;2848:58::-;2889:7;;;:::o;771:1277:1:-;;;;;;;;;;;1234:2726:35;771:1277:1;;1588:2:35;;1234:2726;;;1568:22;;;1588:2;;1785:546;3519:26;-1:-1:-1;1785:546:35;;;;;;;;3519:26;1785:546;;;;;;;;1564:1839;;771:1277:1;;3519:26:35;;;;;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;;3519:26:35;;;;;;;;;;;;1564:1839;-1:-1:-1;;;;;3519:26:35;-1:-1:-1;3519:26:35;771:1277:1;3597:29:35;;;3593:361;3597:29;;;3649:18;771:1277:1;;3649:18:35;;;;3593:361;771:1277:1;;;;;;;;3768:25:35;3764:190;;3593:361;;;1234:2726::o;3764:190::-;3933:9;;;:::i;3519:26::-;;;:::i;:::-;;;1564:1839;2371:2;2351:22;2371:2;;2549:361;;;;;;;;;;;;-1:-1:-1;2549:361:35;2981:7;2986:2;2981:7;;;:18;;;2347:1056;2977:80;;2347:1056;-1:-1:-1;2347:1056:35;3519:26;;2347:1056;1564:1839;;2977:80;771:1277:1;;3026:16:35;;;771:1277:1;;;3026:16:35;;;771:1277:1;;;4464:26:20;2981:18:35;2992:7;2997:2;2992:7;;;2981:18;;2347:1056;3290:9;;;;;4683:914;;;771:1277:1;;4948:147:35;;771:1277:1;4948:147:35;;;4988:42;;4948:147;;;;;;;771:1277:1;;;;;;;;;;;:::i;:::-;4948:147:35;-1:-1:-1;;4948:147:35;;;;;;:::i;:::-;-1:-1:-1;829:265:29;;;;;;;;;5152:8:35;5148:245;;771:1277:1;;4010:13:29;4112:394;4948:147:35;4112:394:29;;;4683:914:35;771:1277:1;;4604:18:29;5476:115:35;;4683:914::o;5476:115::-;4948:147;771:1277:1;;5565:15:35;;;;4112:394:29;;;4948:147:35;4112:394:29;;;;;;;5148:245:35;;;:::i;:::-;4948:147;771:1277:1;;5360:22:35;;;;3992:1454:38;;4259:23;;;771:1277:1;4255:301:38;;771:1277:1;4620:21:38;;;;771:1277:1;;4620:26:38;;4616:748;;3992:1454;5427:12;;;;15033:4:33;3992:1454:38;:::o;4616:748::-;5027:23;;771:1277:1;;-1:-1:-1;5002:48:38;4998:356;;4616:748;;;;;4998:356;771:1277:1;;4620:21:38;771:1277:1;5197:29:38;;;;;;;771:1277:1;5197:29:38;4255:301;771:1277:1;;;;4417:27:38;;;;;;;771:1277:1;4417:27:38;3992:1454;;4259:23;;;771:1277:1;4255:301:38;;4620:21;;771:1277:1;;;4616:748:38;;5427:12;1904:4:33;3992:1454:38;:::o;4616:748::-;771:1277:1;;4620:21:38;771:1277:1;4868:31:38;;;;;;;771:1277:1;4868:31:38;3992:1454;;6319:5:31;4259:23:38;;;;771:1277:1;4255:301:38;;771:1277:1;4620:21:38;;;;771:1277:1;;4620:26:38;;4616:748;;3992:1454;5427:12;;;;;5435:4;3992:1454;:::o;4616:748::-;5027:23;;771:1277:1;;-1:-1:-1;5002:48:38;4998:356;;4616:748;;;;;4998:356;5147:98;;5327:12;6319:5:31;5327:12:38;:::o;4255:301::-;4371:88;;;4533:12;6319:5:31;4533:12:38;:::o;1239:544:39:-;;;;1561:1;1239:544;771:1277:1;;;;;;1239:544:39;1540:22;:56;;;1239:544;1540:93;;;1239:544;1523:254;;1239:544;;;;;:::o;1523:254::-;1757:8;;;:::i;:::-;1523:254;;;;;;1540:93;771:1277:1;-1:-1:-1;;;;;771:1277:1;;1612:10:39;:21;;1540:93;;:56;771:1277:1;-1:-1:-1;;;;;771:1277:1;;1578:10:39;:18;;1540:56;;771:1277:1;;;:::i;:::-;;;1789:621:39;-1:-1:-1;1789:621:39;;;;;2393:9;1789:621;771:1277:1;;2055:195:39;-1:-1:-1;;;;;2055:195:39;;;;2095:35;2055:195;;;;;;771:1277:1;2175:10:39;771:1277:1;;;;;;;;;;;;;;2055:195:39;;;;;:::i;:::-;829:265:29;;;;2393:9:39;:::i;771:1277:1:-;;;;;;;;;;;;;;;-1:-1:-1;771:1277:1;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;771:1277:1;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;-1:-1:-1;771:1277:1;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;771:1277:1;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;771:1277:1;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;771:1277:1;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;771:1277:1;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;;;771:1277:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;771:1277:1;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;771:1277:1;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;4120:1675:39:-;;;;;;;4585:1;4120:1675;771:1277:1;;;:::i;:::-;4564:22:39;:56;;;4120:1675;4564:93;;;4120:1675;4547:1242;;4120:1675;;;;;;;:::o;4547:1242::-;4772:23;;;;771:1277:1;4772:35:39;:84;;;4547:1242;4751:1028;;;4992:8;;;;;:::i;:::-;4547:1242;;;;;;;;4751:1028;-1:-1:-1;771:1277:1;;;;;;5273:318:39;;5754:9;771:1277:1;;;5273:318:39;;;;;;;5321:53;5273:318;;5435:10;5273:318;;;;;:::i;5754:9::-;4751:1028;;4772:84;771:1277:1;;;4827:29:39;4772:84;;4564:93;771:1277:1;-1:-1:-1;;;;;771:1277:1;;4636:10:39;:21;;4564:93;;:56;771:1277:1;-1:-1:-1;;;;;771:1277:1;;4602:10:39;:18;;4564:56;;4120:1675;;;;;;;4585:1;4120:1675;771:1277:1;;;:::i;:::-;4564:22:39;:56;;;4120:1675;4564:93;;;4120:1675;4547:1242;;4120:1675;;;;;;;;:::o;4547:1242::-;4772:23;;;;771:1277:1;4772:35:39;:84;;;4547:1242;4751:1028;;;4992:8;;;;;;:::i;:::-;4547:1242;;;;;;;;;4751:1028;-1:-1:-1;771:1277:1;;;;;;5273:318:39;5754:9;771:1277:1;5273:318:39;771:1277:1;;5273:318:39;;;;;;;5321:53;5273:318;;5435:10;5273:318;;;;;:::i;5754:9::-;4751:1028;;4772:84;771:1277:1;;;4827:29:39;4772:84;;4564:93;771:1277:1;-1:-1:-1;;;;;771:1277:1;;4636:10:39;:21;;4564:93;;:56;771:1277:1;-1:-1:-1;;;;;771:1277:1;;4602:10:39;:18;;4564:56;;6264:633;6426:8;6422:256;;6788:35;771:1277:1;-1:-1:-1;4112:394:29;;;;;6264:633:39;771:1277:1;4604:18:29;6765:126:39;;6264:633;:::o;6765:126::-;771:1277:1;;;;6847:33:39;;;;;;;771:1277:1;6847:33:39;4112:394:29;;;;;;;;6422:256:39;771:1277:1;6422:256:39;;;:::i;:::-;771:1277:1;;6634:33:39;;;;;;;771:1277:1;6634:33:39
Swarm Source
ipfs://172d3cee2d5e82e6527b51be3ef04a08b90aaf51e21707f9aaae262b4770c3c6
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.
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.