Contract
0xf75194740067d6e4000000003b350688dd770000
11
Contract Overview
Balance:
0 ETH
ETH Value:
$0.00
My Name Tag:
Not Available
Latest 1 internal transaction
Parent Txn Hash | Block | From | To | Value | |||
---|---|---|---|---|---|---|---|
0xdfc8aba5c55239aa40613450909e64b84b67e1b2b8326826761cb0a113782bf0 | 20428034 | 170 days 2 hrs ago | 0x0000000000ffe8b47b3e2130213b802212439497 | Contract Creation | 0 ETH |
[ Download CSV Export ]
Contract Name:
SeaportValidator
Compiler Version
v0.8.14+commit.80d49f37
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import { ItemType } from "./ConsiderationEnums.sol"; import { Order, OrderParameters, BasicOrderParameters, OfferItem, ConsiderationItem } from "./ConsiderationStructs.sol"; import { ConsiderationTypeHashes } from "./ConsiderationTypeHashes.sol"; import { ConsiderationInterface } from "../interfaces/ConsiderationInterface.sol"; import { ConduitControllerInterface } from "../interfaces/ConduitControllerInterface.sol"; import { SeaportValidatorInterface } from "../interfaces/SeaportValidatorInterface.sol"; import { ZoneInterface } from "../interfaces/ZoneInterface.sol"; import { IERC721 } from "@openzeppelin/contracts/interfaces/IERC721.sol"; import { IERC1155 } from "@openzeppelin/contracts/interfaces/IERC1155.sol"; import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol"; import { IERC2981 } from "@openzeppelin/contracts/interfaces/IERC2981.sol"; import { ErrorsAndWarnings, ErrorsAndWarningsLib } from "./ErrorsAndWarnings.sol"; import { SafeStaticCall } from "./SafeStaticCall.sol"; import { Murky } from "./Murky.sol"; import { CreatorFeeEngineInterface } from "../interfaces/CreatorFeeEngineInterface.sol"; import { IssueParser, ValidationConfiguration, TimeIssue, StatusIssue, OfferIssue, ConsiderationIssue, PrimaryFeeIssue, ERC721Issue, ERC1155Issue, ERC20Issue, NativeIssue, ZoneIssue, ConduitIssue, CreatorFeeIssue, SignatureIssue, GenericIssue } from "./SeaportValidatorTypes.sol"; import { SignatureVerification } from "./SignatureVerification.sol"; /** * @title SeaportValidator * @notice SeaportValidator provides advanced validation to seaport orders. */ contract SeaportValidator is SeaportValidatorInterface, ConsiderationTypeHashes, SignatureVerification, Murky { using ErrorsAndWarningsLib for ErrorsAndWarnings; using SafeStaticCall for address; using IssueParser for *; /// @notice Cross-chain seaport address ConsiderationInterface public constant seaport = ConsiderationInterface(0x00000000006c3852cbEf3e08E8dF289169EdE581); /// @notice Cross-chain conduit controller Address ConduitControllerInterface public constant conduitController = ConduitControllerInterface(0x00000000F9490004C11Cef243f5400493c00Ad63); /// @notice Ethereum creator fee engine address CreatorFeeEngineInterface public immutable creatorFeeEngine; constructor() { address creatorFeeEngineAddress; if (block.chainid == 1) { creatorFeeEngineAddress = 0x0385603ab55642cb4Dd5De3aE9e306809991804f; } else if (block.chainid == 3) { // Ropsten creatorFeeEngineAddress = 0xFf5A6F7f36764aAD301B7C9E85A5277614Df5E26; } else if (block.chainid == 4) { // Rinkeby creatorFeeEngineAddress = 0x8d17687ea9a6bb6efA24ec11DcFab01661b2ddcd; } else if (block.chainid == 5) { // Goerli creatorFeeEngineAddress = 0xe7c9Cb6D966f76f3B5142167088927Bf34966a1f; } else if (block.chainid == 42) { // Kovan creatorFeeEngineAddress = 0x54D88324cBedfFe1e62c9A59eBb310A11C295198; } else if (block.chainid == 137) { // Polygon creatorFeeEngineAddress = 0x28EdFcF0Be7E86b07493466e7631a213bDe8eEF2; } else if (block.chainid == 80001) { // Mumbai creatorFeeEngineAddress = 0x0a01E11887f727D1b1Cd81251eeEE9BEE4262D07; } else { // No creator fee engine for this chain creatorFeeEngineAddress = address(0); } creatorFeeEngine = CreatorFeeEngineInterface(creatorFeeEngineAddress); } /** * @notice Conduct a comprehensive validation of the given order. * `isValidOrder` validates simple orders that adhere to a set of rules defined below: * - The order is either a listing or an offer order (one NFT to buy or one NFT to sell). * - The first consideration is the primary consideration. * - The order pays up to two fees in the fungible token currency. First fee is primary fee, second is creator fee. * - In private orders, the last consideration specifies a recipient for the offer item. * - Offer items must be owned and properly approved by the offerer. * - There must be one offer item * - Consideration items must exist. * - The signature must be valid, or the order must be already validated on chain * @param order The order to validate. * @return errorsAndWarnings The errors and warnings found in the order. */ function isValidOrder(Order calldata order) external view returns (ErrorsAndWarnings memory errorsAndWarnings) { return isValidOrderWithConfiguration( ValidationConfiguration( address(0), 0, false, false, 30 minutes, 26 weeks ), order ); } /** * @notice Same as `isValidOrder` but allows for more configuration related to fee validation. * If `skipStrictValidation` is set order logic validation is not carried out: fees are not * checked and there may be more than one offer item as well as any number of consideration items. */ function isValidOrderWithConfiguration( ValidationConfiguration memory validationConfiguration, Order memory order ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) { errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0)); // Concatenates errorsAndWarnings with the returned errorsAndWarnings errorsAndWarnings.concat( validateTime( order.parameters, validationConfiguration.shortOrderDuration, validationConfiguration.distantOrderExpiration ) ); errorsAndWarnings.concat(validateOrderStatus(order.parameters)); errorsAndWarnings.concat(validateOfferItems(order.parameters)); errorsAndWarnings.concat(validateConsiderationItems(order.parameters)); errorsAndWarnings.concat(isValidZone(order.parameters)); errorsAndWarnings.concat(validateSignature(order)); // Skip strict validation if requested if (!validationConfiguration.skipStrictValidation) { errorsAndWarnings.concat( validateStrictLogic( order.parameters, validationConfiguration.primaryFeeRecipient, validationConfiguration.primaryFeeBips, validationConfiguration.checkCreatorFee ) ); } } /** * @notice Checks if a conduit key is valid. * @param conduitKey The conduit key to check. * @return errorsAndWarnings The errors and warnings */ function isValidConduit(bytes32 conduitKey) external view returns (ErrorsAndWarnings memory errorsAndWarnings) { (, errorsAndWarnings) = getApprovalAddress(conduitKey); } /** * @notice Gets the approval address for the given conduit key * @param conduitKey Conduit key to get approval address for * @return errorsAndWarnings An ErrorsAndWarnings structs with results */ function getApprovalAddress(bytes32 conduitKey) public view returns (address, ErrorsAndWarnings memory errorsAndWarnings) { errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0)); // Zero conduit key corresponds to seaport if (conduitKey == 0) return (address(seaport), errorsAndWarnings); // Pull conduit info from conduitController (address conduitAddress, bool exists) = conduitController.getConduit( conduitKey ); // Conduit does not exist if (!exists) { errorsAndWarnings.addError(ConduitIssue.KeyInvalid.parseInt()); conduitAddress = address(0); // Don't return invalid conduit } return (conduitAddress, errorsAndWarnings); } /** * @notice Validates the signature for the order using the offerer's current counter * @dev Will also check if order is validated on chain. */ function validateSignature(Order memory order) public view returns (ErrorsAndWarnings memory errorsAndWarnings) { // Pull current counter from seaport uint256 currentCounter = seaport.getCounter(order.parameters.offerer); return validateSignatureWithCounter(order, currentCounter); } /** * @notice Validates the signature for the order using the given counter * @dev Will also check if order is validated on chain. */ function validateSignatureWithCounter(Order memory order, uint256 counter) public view returns (ErrorsAndWarnings memory errorsAndWarnings) { errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0)); // Get current counter for context uint256 currentCounter = seaport.getCounter(order.parameters.offerer); if (currentCounter > counter) { // Counter strictly increases errorsAndWarnings.addError(SignatureIssue.LowCounter.parseInt()); return errorsAndWarnings; } else if (counter > 2 && currentCounter < counter - 2) { // Will require significant input from offerer to validate, warn errorsAndWarnings.addWarning(SignatureIssue.HighCounter.parseInt()); } bytes32 orderHash = _deriveOrderHash(order.parameters, counter); // Check if order is validated on chain (bool isValid, , , ) = seaport.getOrderStatus(orderHash); if (isValid) { // Shortcut success, valid on chain return errorsAndWarnings; } // Get signed digest bytes32 eip712Digest = _deriveEIP712Digest(orderHash); if ( // Checks EIP712 and EIP1271 !_isValidSignature( order.parameters.offerer, eip712Digest, order.signature ) ) { if ( order.parameters.consideration.length != order.parameters.totalOriginalConsiderationItems ) { // May help diagnose signature issues errorsAndWarnings.addWarning( SignatureIssue.OriginalConsiderationItems.parseInt() ); } // Signature is invalid errorsAndWarnings.addError(SignatureIssue.Invalid.parseInt()); } } /** * @notice Check the time validity of an order * @param orderParameters The parameters for the order to validate * @param shortOrderDuration The duration of which an order is considered short * @param distantOrderExpiration Distant order expiration delta in seconds. * @return errorsAndWarnings The Issues and warnings */ function validateTime( OrderParameters memory orderParameters, uint256 shortOrderDuration, uint256 distantOrderExpiration ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) { errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0)); if (orderParameters.endTime <= orderParameters.startTime) { // Order duration is zero errorsAndWarnings.addError( TimeIssue.EndTimeBeforeStartTime.parseInt() ); return errorsAndWarnings; } if (orderParameters.endTime < block.timestamp) { // Order is expired errorsAndWarnings.addError(TimeIssue.Expired.parseInt()); return errorsAndWarnings; } else if ( orderParameters.endTime > block.timestamp + distantOrderExpiration ) { // Order expires in a long time errorsAndWarnings.addWarning( TimeIssue.DistantExpiration.parseInt() ); } if (orderParameters.startTime > block.timestamp) { // Order is not active errorsAndWarnings.addWarning(TimeIssue.NotActive.parseInt()); } if ( orderParameters.endTime - ( orderParameters.startTime > block.timestamp ? orderParameters.startTime : block.timestamp ) < shortOrderDuration ) { // Order has a short duration errorsAndWarnings.addWarning(TimeIssue.ShortOrder.parseInt()); } } /** * @notice Validate the status of an order * @param orderParameters The parameters for the order to validate * @return errorsAndWarnings The errors and warnings */ function validateOrderStatus(OrderParameters memory orderParameters) public view returns (ErrorsAndWarnings memory errorsAndWarnings) { errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0)); // Pull current counter from seaport uint256 currentOffererCounter = seaport.getCounter( orderParameters.offerer ); // Derive order hash using orderParameters and currentOffererCounter bytes32 orderHash = _deriveOrderHash( orderParameters, currentOffererCounter ); // Get order status from seaport (, bool isCancelled, uint256 totalFilled, uint256 totalSize) = seaport .getOrderStatus(orderHash); if (isCancelled) { // Order is cancelled errorsAndWarnings.addError(StatusIssue.Cancelled.parseInt()); } if (totalSize > 0 && totalFilled == totalSize) { // Order is fully filled errorsAndWarnings.addError(StatusIssue.FullyFilled.parseInt()); } } /** * @notice Validate all offer items for an order. Ensures that * offerer has sufficient balance and approval for each item. * @dev Amounts are not summed and verified, just the individual amounts. * @param orderParameters The parameters for the order to validate * @return errorsAndWarnings The errors and warnings */ function validateOfferItems(OrderParameters memory orderParameters) public view returns (ErrorsAndWarnings memory errorsAndWarnings) { errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0)); // Iterate over each offer item and validate it for (uint256 i = 0; i < orderParameters.offer.length; i++) { errorsAndWarnings.concat(validateOfferItem(orderParameters, i)); // Check for duplicate offer item OfferItem memory offerItem1 = orderParameters.offer[i]; for (uint256 j = i + 1; j < orderParameters.offer.length; j++) { // Iterate over each remaining offer item // (previous items already check with this item) OfferItem memory offerItem2 = orderParameters.offer[j]; // Check if token and id are the same if ( offerItem1.token == offerItem2.token && offerItem1.identifierOrCriteria == offerItem2.identifierOrCriteria ) { errorsAndWarnings.addError( OfferIssue.DuplicateItem.parseInt() ); } } } // You must have an offer item if (orderParameters.offer.length == 0) { errorsAndWarnings.addError(OfferIssue.ZeroItems.parseInt()); } // Warning if there is more than one offer item if (orderParameters.offer.length > 1) { errorsAndWarnings.addWarning(OfferIssue.MoreThanOneItem.parseInt()); } } /** * @notice Validates an offer item * @param orderParameters The parameters for the order to validate * @param offerItemIndex The index of the offerItem in offer array to validate * @return errorsAndWarnings An ErrorsAndWarnings structs with results */ function validateOfferItem( OrderParameters memory orderParameters, uint256 offerItemIndex ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) { // First validate the parameters (correct amount, contract, etc) errorsAndWarnings = validateOfferItemParameters( orderParameters, offerItemIndex ); if (errorsAndWarnings.hasErrors()) { // Only validate approvals and balances if parameters are valid return errorsAndWarnings; } // Validate approvals and balances for the offer item errorsAndWarnings.concat( validateOfferItemApprovalAndBalance(orderParameters, offerItemIndex) ); } /** * @notice Validates the OfferItem parameters. This includes token contract validation * @dev OfferItems with criteria are currently not allowed * @param orderParameters The parameters for the order to validate * @param offerItemIndex The index of the offerItem in offer array to validate * @return errorsAndWarnings An ErrorsAndWarnings structs with results */ function validateOfferItemParameters( OrderParameters memory orderParameters, uint256 offerItemIndex ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) { errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0)); OfferItem memory offerItem = orderParameters.offer[offerItemIndex]; // Check if start amount and end amount are zero if (offerItem.startAmount == 0 && offerItem.endAmount == 0) { errorsAndWarnings.addError(OfferIssue.AmountZero.parseInt()); return errorsAndWarnings; } // Check that amount velocity is not too high. if ( offerItem.startAmount != offerItem.endAmount && orderParameters.endTime > orderParameters.startTime ) { // Assign larger and smaller amount values (uint256 maxAmount, uint256 minAmount) = offerItem.startAmount > offerItem.endAmount ? (offerItem.startAmount, offerItem.endAmount) : (offerItem.endAmount, offerItem.startAmount); uint256 amountDelta = maxAmount - minAmount; // delta of time that order exists for uint256 timeDelta = orderParameters.endTime - orderParameters.startTime; // Velocity scaled by 1e10 for precision uint256 velocity = (amountDelta * 1e10) / timeDelta; // gives velocity percentage in hundredth of a basis points per second in terms of larger value uint256 velocityPercentage = velocity / (maxAmount * 1e4); // 278 * 60 * 30 ~= 500,000 if (velocityPercentage > 278) { // Over 50% change per 30 min errorsAndWarnings.addError( OfferIssue.AmountVelocityHigh.parseInt() ); } // Over 50% change per 30 min else if (velocityPercentage > 28) { // Over 5% change per 30 min errorsAndWarnings.addWarning( OfferIssue.AmountVelocityHigh.parseInt() ); } // Check for large amount steps if (minAmount <= 1e15) { errorsAndWarnings.addWarning( OfferIssue.AmountStepLarge.parseInt() ); } } if (offerItem.itemType == ItemType.ERC721) { // ERC721 type requires amounts to be 1 if (offerItem.startAmount != 1 || offerItem.endAmount != 1) { errorsAndWarnings.addError(ERC721Issue.AmountNotOne.parseInt()); } // Check the EIP165 token interface if (!checkInterface(offerItem.token, type(IERC721).interfaceId)) { errorsAndWarnings.addError(ERC721Issue.InvalidToken.parseInt()); } } else if (offerItem.itemType == ItemType.ERC721_WITH_CRITERIA) { // Check the EIP165 token interface if (!checkInterface(offerItem.token, type(IERC721).interfaceId)) { errorsAndWarnings.addError(ERC721Issue.InvalidToken.parseInt()); } if (offerItem.startAmount > 1 || offerItem.endAmount > 1) { // Require partial fill enabled. Even orderTypes are full if (uint8(orderParameters.orderType) % 2 == 0) { errorsAndWarnings.addError( ERC721Issue.CriteriaNotPartialFill.parseInt() ); } } } else if ( offerItem.itemType == ItemType.ERC1155 || offerItem.itemType == ItemType.ERC1155_WITH_CRITERIA ) { // Check the EIP165 token interface if (!checkInterface(offerItem.token, type(IERC1155).interfaceId)) { errorsAndWarnings.addError( ERC1155Issue.InvalidToken.parseInt() ); } } else if (offerItem.itemType == ItemType.ERC20) { // ERC20 must have `identifierOrCriteria` be zero if (offerItem.identifierOrCriteria != 0) { errorsAndWarnings.addError( ERC20Issue.IdentifierNonZero.parseInt() ); } // Validate contract, should return an uint256 if its an ERC20 if ( !offerItem.token.safeStaticCallUint256( abi.encodeWithSelector( IERC20.allowance.selector, address(seaport), address(seaport) ), 0 ) ) { errorsAndWarnings.addError(ERC20Issue.InvalidToken.parseInt()); } } else { // Must be native // NATIVE must have `token` be zero address if (offerItem.token != address(0)) { errorsAndWarnings.addError(NativeIssue.TokenAddress.parseInt()); } // NATIVE must have `identifierOrCriteria` be zero if (offerItem.identifierOrCriteria != 0) { errorsAndWarnings.addError( NativeIssue.IdentifierNonZero.parseInt() ); } } } /** * @notice Validates the OfferItem approvals and balances * @param orderParameters The parameters for the order to validate * @param offerItemIndex The index of the offerItem in offer array to validate * @return errorsAndWarnings An ErrorsAndWarnings structs with results */ function validateOfferItemApprovalAndBalance( OrderParameters memory orderParameters, uint256 offerItemIndex ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) { // Note: If multiple items are of the same token, token amounts are not summed for validation errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0)); // Get the approval address for the given conduit key ( address approvalAddress, ErrorsAndWarnings memory ew ) = getApprovalAddress(orderParameters.conduitKey); errorsAndWarnings.concat(ew); if (ew.hasErrors()) { // Approval address is invalid return errorsAndWarnings; } OfferItem memory offerItem = orderParameters.offer[offerItemIndex]; if (offerItem.itemType == ItemType.ERC721) { IERC721 token = IERC721(offerItem.token); // Check that offerer owns token if ( !address(token).safeStaticCallAddress( abi.encodeWithSelector( IERC721.ownerOf.selector, offerItem.identifierOrCriteria ), orderParameters.offerer ) ) { errorsAndWarnings.addError(ERC721Issue.NotOwner.parseInt()); } // Check for approval via `getApproved` if ( !address(token).safeStaticCallAddress( abi.encodeWithSelector( IERC721.getApproved.selector, offerItem.identifierOrCriteria ), approvalAddress ) ) { // Fallback to `isApprovalForAll` if ( !address(token).safeStaticCallBool( abi.encodeWithSelector( IERC721.isApprovedForAll.selector, orderParameters.offerer, approvalAddress ), true ) ) { // Not approved errorsAndWarnings.addError( ERC721Issue.NotApproved.parseInt() ); } } } else if ( offerItem.itemType == ItemType.ERC721_WITH_CRITERIA ) {} else if (offerItem.itemType == ItemType.ERC1155) { IERC1155 token = IERC1155(offerItem.token); // Check for approval if ( !address(token).safeStaticCallBool( abi.encodeWithSelector( IERC721.isApprovedForAll.selector, orderParameters.offerer, approvalAddress ), true ) ) { errorsAndWarnings.addError(ERC1155Issue.NotApproved.parseInt()); } // Get min required balance (max(startAmount, endAmount)) uint256 minBalance = offerItem.startAmount < offerItem.endAmount ? offerItem.startAmount : offerItem.endAmount; // Check for sufficient balance if ( !address(token).safeStaticCallUint256( abi.encodeWithSelector( IERC1155.balanceOf.selector, orderParameters.offerer, offerItem.identifierOrCriteria ), minBalance ) ) { // Insufficient balance errorsAndWarnings.addError( ERC1155Issue.InsufficientBalance.parseInt() ); } } else if ( offerItem.itemType == ItemType.ERC1155_WITH_CRITERIA ) {} else if (offerItem.itemType == ItemType.ERC20) { IERC20 token = IERC20(offerItem.token); // Get min required balance and approval (max(startAmount, endAmount)) uint256 minBalanceAndAllowance = offerItem.startAmount < offerItem.endAmount ? offerItem.startAmount : offerItem.endAmount; // Check allowance if ( !address(token).safeStaticCallUint256( abi.encodeWithSelector( IERC20.allowance.selector, orderParameters.offerer, approvalAddress ), minBalanceAndAllowance ) ) { errorsAndWarnings.addError( ERC20Issue.InsufficientAllowance.parseInt() ); } // Check balance if ( !address(token).safeStaticCallUint256( abi.encodeWithSelector( IERC20.balanceOf.selector, orderParameters.offerer ), minBalanceAndAllowance ) ) { errorsAndWarnings.addError( ERC20Issue.InsufficientBalance.parseInt() ); } } else { // Must be native // Get min required balance (max(startAmount, endAmount)) uint256 minBalance = offerItem.startAmount < offerItem.endAmount ? offerItem.startAmount : offerItem.endAmount; // Check for sufficient balance if (orderParameters.offerer.balance < minBalance) { errorsAndWarnings.addError( NativeIssue.InsufficientBalance.parseInt() ); } // Native items can not be pulled so warn errorsAndWarnings.addWarning(OfferIssue.NativeItem.parseInt()); } } /** * @notice Validate all consideration items for an order * @param orderParameters The parameters for the order to validate * @return errorsAndWarnings The errors and warnings */ function validateConsiderationItems(OrderParameters memory orderParameters) public view returns (ErrorsAndWarnings memory errorsAndWarnings) { errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0)); if (orderParameters.consideration.length == 0) { errorsAndWarnings.addWarning( ConsiderationIssue.ZeroItems.parseInt() ); return errorsAndWarnings; } // Iterate over each consideration item for (uint256 i = 0; i < orderParameters.consideration.length; i++) { // Validate consideration item errorsAndWarnings.concat( validateConsiderationItem(orderParameters, i) ); ConsiderationItem memory considerationItem1 = orderParameters .consideration[i]; for ( uint256 j = i + 1; j < orderParameters.consideration.length; j++ ) { // Iterate over each remaining offer item // (previous items already check with this item) ConsiderationItem memory considerationItem2 = orderParameters .consideration[j]; // Check if itemType, token, id, and recipient are the same if ( considerationItem2.itemType == considerationItem1.itemType && considerationItem2.token == considerationItem1.token && considerationItem2.identifierOrCriteria == considerationItem1.identifierOrCriteria && considerationItem2.recipient == considerationItem1.recipient ) { errorsAndWarnings.addWarning( // Duplicate consideration item, warning ConsiderationIssue.DuplicateItem.parseInt() ); } } } } /** * @notice Validate a consideration item * @param orderParameters The parameters for the order to validate * @param considerationItemIndex The index of the consideration item to validate * @return errorsAndWarnings The errors and warnings */ function validateConsiderationItem( OrderParameters memory orderParameters, uint256 considerationItemIndex ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) { errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0)); errorsAndWarnings.concat( validateConsiderationItemParameters( orderParameters, considerationItemIndex ) ); } /** * @notice Validates the parameters of a consideration item including contract validation * @param orderParameters The parameters for the order to validate * @param considerationItemIndex The index of the consideration item to validate * @return errorsAndWarnings The errors and warnings */ function validateConsiderationItemParameters( OrderParameters memory orderParameters, uint256 considerationItemIndex ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) { errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0)); ConsiderationItem memory considerationItem = orderParameters .consideration[considerationItemIndex]; // Check if startAmount and endAmount are zero if ( considerationItem.startAmount == 0 && considerationItem.endAmount == 0 ) { errorsAndWarnings.addError( ConsiderationIssue.AmountZero.parseInt() ); return errorsAndWarnings; } // Check if the recipient is the null address if (considerationItem.recipient == address(0)) { errorsAndWarnings.addError( ConsiderationIssue.NullRecipient.parseInt() ); } if ( considerationItem.startAmount != considerationItem.endAmount && orderParameters.endTime > orderParameters.startTime ) { // Check that amount velocity is not too high. // Assign larger and smaller amount values (uint256 maxAmount, uint256 minAmount) = considerationItem .startAmount > considerationItem.endAmount ? (considerationItem.startAmount, considerationItem.endAmount) : (considerationItem.endAmount, considerationItem.startAmount); uint256 amountDelta = maxAmount - minAmount; // delta of time that order exists for uint256 timeDelta = orderParameters.endTime - orderParameters.startTime; // Velocity scaled by 1e10 for precision uint256 velocity = (amountDelta * 1e10) / timeDelta; // gives velocity percentage in hundredth of a basis points per second in terms of larger value uint256 velocityPercentage = velocity / (maxAmount * 1e4); // 278 * 60 * 30 ~= 500,000 if (velocityPercentage > 278) { // Over 50% change per 30 min errorsAndWarnings.addError( ConsiderationIssue.AmountVelocityHigh.parseInt() ); } // 28 * 60 * 30 ~= 50,000 else if (velocityPercentage > 28) { // Over 5% change per 30 min errorsAndWarnings.addWarning( ConsiderationIssue.AmountVelocityHigh.parseInt() ); } // Check for large amount steps if (minAmount <= 1e15) { errorsAndWarnings.addWarning( ConsiderationIssue.AmountStepLarge.parseInt() ); } } if (considerationItem.itemType == ItemType.ERC721) { // ERC721 type requires amounts to be 1 if ( considerationItem.startAmount != 1 || considerationItem.endAmount != 1 ) { errorsAndWarnings.addError(ERC721Issue.AmountNotOne.parseInt()); } // Check EIP165 interface if ( !checkInterface( considerationItem.token, type(IERC721).interfaceId ) ) { errorsAndWarnings.addError(ERC721Issue.InvalidToken.parseInt()); return errorsAndWarnings; } // Check that token exists if ( !considerationItem.token.safeStaticCallUint256( abi.encodeWithSelector( IERC721.ownerOf.selector, considerationItem.identifierOrCriteria ), 1 ) ) { // Token does not exist errorsAndWarnings.addError( ERC721Issue.IdentifierDNE.parseInt() ); } } else if ( considerationItem.itemType == ItemType.ERC721_WITH_CRITERIA ) { // Check EIP165 interface if ( !checkInterface( considerationItem.token, type(IERC721).interfaceId ) ) { // Does not implement required interface errorsAndWarnings.addError(ERC721Issue.InvalidToken.parseInt()); } } else if ( considerationItem.itemType == ItemType.ERC1155 || considerationItem.itemType == ItemType.ERC1155_WITH_CRITERIA ) { // Check EIP165 interface if ( !checkInterface( considerationItem.token, type(IERC1155).interfaceId ) ) { // Does not implement required interface errorsAndWarnings.addError( ERC1155Issue.InvalidToken.parseInt() ); } } else if (considerationItem.itemType == ItemType.ERC20) { // ERC20 must have `identifierOrCriteria` be zero if (considerationItem.identifierOrCriteria != 0) { errorsAndWarnings.addError( ERC20Issue.IdentifierNonZero.parseInt() ); } // Check that it is an ERC20 token. ERC20 will return a uint256 if ( !considerationItem.token.safeStaticCallUint256( abi.encodeWithSelector( IERC20.allowance.selector, address(seaport), address(seaport) ), 0 ) ) { // Not an ERC20 token errorsAndWarnings.addError(ERC20Issue.InvalidToken.parseInt()); } } else { // Must be native // NATIVE must have `token` be zero address if (considerationItem.token != address(0)) { errorsAndWarnings.addError(NativeIssue.TokenAddress.parseInt()); } // NATIVE must have `identifierOrCriteria` be zero if (considerationItem.identifierOrCriteria != 0) { errorsAndWarnings.addError( NativeIssue.IdentifierNonZero.parseInt() ); } } } /** * @notice Strict validation operates under tight assumptions. It validates primary * fee, creator fee, private sale consideration, and overall order format. * @dev Only checks first fee recipient provided by CreatorFeeEngine. * Order of consideration items must be as follows: * 1. Primary consideration * 2. Primary fee * 3. Creator Fee * 4. Private sale consideration * @param orderParameters The parameters for the order to validate. * @param primaryFeeRecipient The primary fee recipient. Set to null address for no primary fee. * @param primaryFeeBips The primary fee in BIPs. * @param checkCreatorFee Should check for creator fee. If true, creator fee must be present as * according to creator fee engine. If false, must not have creator fee. * @return errorsAndWarnings The errors and warnings. */ function validateStrictLogic( OrderParameters memory orderParameters, address primaryFeeRecipient, uint256 primaryFeeBips, bool checkCreatorFee ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) { errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0)); // Check that order matches the required format (listing or offer) { bool canCheckFee = true; // Single offer item and at least one consideration if ( orderParameters.offer.length != 1 || orderParameters.consideration.length == 0 ) { // Not listing or offer, can't check fees canCheckFee = false; } else if ( // Can't have both items be fungible isPaymentToken(orderParameters.offer[0].itemType) && isPaymentToken(orderParameters.consideration[0].itemType) ) { // Not listing or offer, can't check fees canCheckFee = false; } else if ( // Can't have both items be non-fungible !isPaymentToken(orderParameters.offer[0].itemType) && !isPaymentToken(orderParameters.consideration[0].itemType) ) { // Not listing or offer, can't check fees canCheckFee = false; } if (!canCheckFee) { // Does not match required format errorsAndWarnings.addError( GenericIssue.InvalidOrderFormat.parseInt() ); return errorsAndWarnings; } } // Validate secondary consideration items (fees) ( uint256 tertiaryConsiderationIndex, ErrorsAndWarnings memory errorsAndWarningsLocal ) = _validateSecondaryConsiderationItems( orderParameters, primaryFeeRecipient, primaryFeeBips, checkCreatorFee ); errorsAndWarnings.concat(errorsAndWarningsLocal); // Validate tertiary consideration items if not 0 (0 indicates error). // Only if no prior errors if (tertiaryConsiderationIndex != 0) { errorsAndWarnings.concat( _validateTertiaryConsiderationItems( orderParameters, tertiaryConsiderationIndex ) ); } } function _validateSecondaryConsiderationItems( OrderParameters memory orderParameters, address primaryFeeRecipient, uint256 primaryFeeBips, bool checkCreatorFee ) internal view returns ( uint256 tertiaryConsiderationIndex, ErrorsAndWarnings memory errorsAndWarnings ) { errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0)); // non-fungible item address address itemAddress; // non-fungible item identifier uint256 itemIdentifier; // fungible item start amount uint256 transactionAmountStart; // fungible item end amount uint256 transactionAmountEnd; // Consideration item to hold expected creator fee info ConsiderationItem memory creatorFeeConsideration; if (isPaymentToken(orderParameters.offer[0].itemType)) { // Offer is an offer. oOffer item is fungible and used for fees creatorFeeConsideration.itemType = orderParameters .offer[0] .itemType; creatorFeeConsideration.token = orderParameters.offer[0].token; transactionAmountStart = orderParameters.offer[0].startAmount; transactionAmountEnd = orderParameters.offer[0].endAmount; // Set non-fungible information for calculating creator fee itemAddress = orderParameters.consideration[0].token; itemIdentifier = orderParameters .consideration[0] .identifierOrCriteria; } else { // Offer is an offer. Consideration item is fungible and used for fees creatorFeeConsideration.itemType = orderParameters .consideration[0] .itemType; creatorFeeConsideration.token = orderParameters .consideration[0] .token; transactionAmountStart = orderParameters .consideration[0] .startAmount; transactionAmountEnd = orderParameters.consideration[0].endAmount; // Set non-fungible information for calculating creator fees itemAddress = orderParameters.offer[0].token; itemIdentifier = orderParameters.offer[0].identifierOrCriteria; } // Store flag if primary fee is present bool primaryFeePresent = false; { // Calculate primary fee start and end amounts uint256 primaryFeeStartAmount = (transactionAmountStart * primaryFeeBips) / 10000; uint256 primaryFeeEndAmount = (transactionAmountEnd * primaryFeeBips) / 10000; // Check if primary fee check is desired. Skip if calculated amount is zero. if ( primaryFeeRecipient != address(0) && (primaryFeeStartAmount > 0 || primaryFeeEndAmount > 0) ) { // Ensure primary fee is present if (orderParameters.consideration.length < 2) { errorsAndWarnings.addError( PrimaryFeeIssue.Missing.parseInt() ); return (0, errorsAndWarnings); } primaryFeePresent = true; ConsiderationItem memory primaryFeeItem = orderParameters .consideration[1]; // Check item type if ( primaryFeeItem.itemType != creatorFeeConsideration.itemType ) { errorsAndWarnings.addError( PrimaryFeeIssue.ItemType.parseInt() ); return (0, errorsAndWarnings); } // Check token if (primaryFeeItem.token != creatorFeeConsideration.token) { errorsAndWarnings.addError( PrimaryFeeIssue.Token.parseInt() ); } // Check start amount if (primaryFeeItem.startAmount < primaryFeeStartAmount) { errorsAndWarnings.addError( PrimaryFeeIssue.StartAmount.parseInt() ); } // Check end amount if (primaryFeeItem.endAmount < primaryFeeEndAmount) { errorsAndWarnings.addError( PrimaryFeeIssue.EndAmount.parseInt() ); } // Check recipient if (primaryFeeItem.recipient != primaryFeeRecipient) { errorsAndWarnings.addError( PrimaryFeeIssue.Recipient.parseInt() ); } } } // Check creator fee ( creatorFeeConsideration.recipient, creatorFeeConsideration.startAmount, creatorFeeConsideration.endAmount ) = getCreatorFeeInfo( itemAddress, itemIdentifier, transactionAmountStart, transactionAmountEnd ); // Flag indicating if creator fee is present in considerations bool creatorFeePresent = false; // Determine if should check for creator fee if ( creatorFeeConsideration.recipient != address(0) && checkCreatorFee && (creatorFeeConsideration.startAmount > 0 || creatorFeeConsideration.endAmount > 0) ) { // Calculate index of creator fee consideration item uint16 creatorFeeConsiderationIndex = primaryFeePresent ? 2 : 1; // 2 if primary fee, ow 1 // Check that creator fee consideration item exists if ( orderParameters.consideration.length - 1 < creatorFeeConsiderationIndex ) { errorsAndWarnings.addError(CreatorFeeIssue.Missing.parseInt()); return (0, errorsAndWarnings); } ConsiderationItem memory creatorFeeItem = orderParameters .consideration[creatorFeeConsiderationIndex]; creatorFeePresent = true; // Check type if (creatorFeeItem.itemType != creatorFeeConsideration.itemType) { errorsAndWarnings.addError(CreatorFeeIssue.ItemType.parseInt()); return (0, errorsAndWarnings); } // Check token if (creatorFeeItem.token != creatorFeeConsideration.token) { errorsAndWarnings.addError(CreatorFeeIssue.Token.parseInt()); } // Check start amount if ( creatorFeeItem.startAmount < creatorFeeConsideration.startAmount ) { errorsAndWarnings.addError( CreatorFeeIssue.StartAmount.parseInt() ); } // Check end amount if (creatorFeeItem.endAmount < creatorFeeConsideration.endAmount) { errorsAndWarnings.addError( CreatorFeeIssue.EndAmount.parseInt() ); } // Check recipient if (creatorFeeItem.recipient != creatorFeeConsideration.recipient) { errorsAndWarnings.addError( CreatorFeeIssue.Recipient.parseInt() ); } } // Calculate index of first tertiary consideration item tertiaryConsiderationIndex = 1 + (primaryFeePresent ? 1 : 0) + (creatorFeePresent ? 1 : 0); } function getCreatorFeeInfo( address token, uint256 tokenId, uint256 transactionAmountStart, uint256 transactionAmountEnd ) public view returns ( address payable recipient, uint256 creatorFeeAmountStart, uint256 creatorFeeAmountEnd ) { // Check if creator fee engine is on this chain if (address(creatorFeeEngine) != address(0)) { // Creator fee engine may revert if no creator fees are present. try creatorFeeEngine.getRoyaltyView( token, tokenId, transactionAmountStart ) returns ( address payable[] memory creatorFeeRecipients, uint256[] memory creatorFeeAmountsStart ) { if (creatorFeeRecipients.length != 0) { // Use first recipient and amount recipient = creatorFeeRecipients[0]; creatorFeeAmountStart = creatorFeeAmountsStart[0]; } } catch { // Creator fee not found } // If fees found for start amount, check end amount if (recipient != address(0)) { // Creator fee engine may revert if no creator fees are present. try creatorFeeEngine.getRoyaltyView( token, tokenId, transactionAmountEnd ) returns ( address payable[] memory, uint256[] memory creatorFeeAmountsEnd ) { creatorFeeAmountEnd = creatorFeeAmountsEnd[0]; } catch {} } } else { // Fallback to ERC2981 { // Static call to token using ERC2981 (bool success, bytes memory res) = token.staticcall( abi.encodeWithSelector( IERC2981.royaltyInfo.selector, tokenId, transactionAmountStart ) ); // Check if call succeeded if (success) { // Ensure 64 bytes returned if (res.length == 64) { // Decode result and assign recipient and start amount (recipient, creatorFeeAmountStart) = abi.decode( res, (address, uint256) ); } } } // Only check end amount if start amount found if (recipient != address(0)) { // Static call to token using ERC2981 (bool success, bytes memory res) = token.staticcall( abi.encodeWithSelector( IERC2981.royaltyInfo.selector, tokenId, transactionAmountEnd ) ); // Check if call succeeded if (success) { // Ensure 64 bytes returned if (res.length == 64) { // Decode result and assign end amount (, creatorFeeAmountEnd) = abi.decode( res, (address, uint256) ); } } } } } /** * @notice Internal function for validating all consideration items after the fee items. * Only additional acceptable consideration is private sale. */ function _validateTertiaryConsiderationItems( OrderParameters memory orderParameters, uint256 considerationItemIndex ) internal pure returns (ErrorsAndWarnings memory errorsAndWarnings) { errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0)); if (orderParameters.consideration.length <= considerationItemIndex) { // No more consideration items return errorsAndWarnings; } ConsiderationItem memory privateSaleConsideration = orderParameters .consideration[considerationItemIndex]; // Check if offer is payment token. Private sale not possible if so. if (isPaymentToken(orderParameters.offer[0].itemType)) { errorsAndWarnings.addError( ConsiderationIssue.ExtraItems.parseInt() ); return errorsAndWarnings; } // Check if private sale to self if (privateSaleConsideration.recipient == orderParameters.offerer) { errorsAndWarnings.addError( ConsiderationIssue.PrivateSaleToSelf.parseInt() ); return errorsAndWarnings; } // Ensure that private sale parameters match offer item. if ( privateSaleConsideration.itemType != orderParameters.offer[0].itemType || privateSaleConsideration.token != orderParameters.offer[0].token || orderParameters.offer[0].startAmount != privateSaleConsideration.startAmount || orderParameters.offer[0].endAmount != privateSaleConsideration.endAmount || orderParameters.offer[0].identifierOrCriteria != privateSaleConsideration.identifierOrCriteria ) { // Invalid private sale, say extra consideration item errorsAndWarnings.addError( ConsiderationIssue.ExtraItems.parseInt() ); return errorsAndWarnings; } errorsAndWarnings.addWarning(ConsiderationIssue.PrivateSale.parseInt()); // Should not be any additional consideration items if (orderParameters.consideration.length - 1 > considerationItemIndex) { // Extra consideration items errorsAndWarnings.addError( ConsiderationIssue.ExtraItems.parseInt() ); return errorsAndWarnings; } } /** * @notice Validates the zone call for an order * @param orderParameters The parameters for the order to validate * @return errorsAndWarnings An ErrorsAndWarnings structs with results */ function isValidZone(OrderParameters memory orderParameters) public view returns (ErrorsAndWarnings memory errorsAndWarnings) { errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0)); // If not restricted, zone isn't checked if (uint8(orderParameters.orderType) < 2) { return errorsAndWarnings; } if (orderParameters.zone == address(0)) { // Zone is not set errorsAndWarnings.addError(ZoneIssue.NotSet.parseInt()); return errorsAndWarnings; } // EOA zone is always valid if (address(orderParameters.zone).code.length == 0) { // Address is EOA. Valid order return errorsAndWarnings; } // Get counter to derive order hash uint256 currentOffererCounter = seaport.getCounter( orderParameters.offerer ); // Call zone function `isValidOrder` with `msg.sender` as the caller if ( !orderParameters.zone.safeStaticCallBytes4( abi.encodeWithSelector( ZoneInterface.isValidOrder.selector, _deriveOrderHash(orderParameters, currentOffererCounter), msg.sender, orderParameters.offerer, orderParameters.zoneHash ), ZoneInterface.isValidOrder.selector ) ) { errorsAndWarnings.addWarning(ZoneIssue.RejectedOrder.parseInt()); } } /** * @notice Safely check that a contract implements an interface * @param token The token address to check * @param interfaceHash The interface hash to check */ function checkInterface(address token, bytes4 interfaceHash) public view returns (bool) { return token.safeStaticCallBool( abi.encodeWithSelector( IERC165.supportsInterface.selector, interfaceHash ), true ); } function isPaymentToken(ItemType itemType) public pure returns (bool) { return itemType == ItemType.NATIVE || itemType == ItemType.ERC20; } /*////////////////////////////////////////////////////////////// Merkle Helpers //////////////////////////////////////////////////////////////*/ /** * @notice Sorts an array of token ids by the keccak256 hash of the id. Required ordering of ids * for other merkle operations. * @param includedTokens An array of included token ids. * @return sortedTokens The sorted `includedTokens` array. */ function sortMerkleTokens(uint256[] memory includedTokens) public pure returns (uint256[] memory sortedTokens) { // Sort token ids by the keccak256 hash of the id return _sortUint256ByHash(includedTokens); } /** * @notice Creates a merkle root for includedTokens. * @dev `includedTokens` must be sorting in strictly ascending order according to the keccak256 hash of the value. * @return merkleRoot The merkle root * @return errorsAndWarnings Errors and warnings from the operation */ function getMerkleRoot(uint256[] memory includedTokens) public pure returns (bytes32 merkleRoot, ErrorsAndWarnings memory errorsAndWarnings) { (merkleRoot, errorsAndWarnings) = _getRoot(includedTokens); } /** * @notice Creates a merkle proof for the the targetIndex contained in includedTokens. * @dev `targetIndex` is referring to the index of an element in `includedTokens`. * `includedTokens` must be sorting in ascending order according to the keccak256 hash of the value. * @return merkleProof The merkle proof * @return errorsAndWarnings Errors and warnings from the operation */ function getMerkleProof( uint256[] memory includedTokens, uint256 targetIndex ) public pure returns ( bytes32[] memory merkleProof, ErrorsAndWarnings memory errorsAndWarnings ) { (merkleProof, errorsAndWarnings) = _getProof( includedTokens, targetIndex ); } function verifyMerkleProof( bytes32 merkleRoot, bytes32[] memory merkleProof, uint256 valueToProve ) public pure returns (bool) { bytes32 hashedValue = keccak256(abi.encode(valueToProve)); return _verifyProof(merkleRoot, merkleProof, hashedValue); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; // prettier-ignore 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 } // prettier-ignore 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 } // prettier-ignore 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 } // prettier-ignore 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 } // prettier-ignore enum Side { // 0: Items that can be spent OFFER, // 1: Items that must be received CONSIDERATION }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; // prettier-ignore import { OrderType, BasicOrderType, ItemType, Side, BasicOrderRouteType } 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 counter, and an arbitrary number of * offer items that can be spent along with consideration items that must * be received by their respective recipient. */ struct OrderComponents { address offerer; address zone; OfferItem[] offer; ConsiderationItem[] consideration; OrderType orderType; uint256 startTime; uint256 endTime; bytes32 zoneHash; uint256 salt; bytes32 conduitKey; uint256 counter; } /** * @dev An offer item has five components: an item type (ETH or other native * tokens, ERC20, ERC721, and ERC1155, as well as criteria-based ERC721 and * ERC1155), a token address, a dual-purpose "identifierOrCriteria" * component that will either represent a tokenId or a merkle root * depending on the item type, and a start and end amount that support * increasing or decreasing amounts over the duration of the respective * order. */ struct OfferItem { ItemType itemType; address token; uint256 identifierOrCriteria; uint256 startAmount; uint256 endAmount; } /** * @dev A consideration item has the same five components as an offer item and * an additional sixth component designating the required recipient of the * item. */ struct ConsiderationItem { ItemType itemType; address token; uint256 identifierOrCriteria; uint256 startAmount; uint256 endAmount; address payable recipient; } /** * @dev A spent item is translated from a utilized offer item and has four * components: an item type (ETH or other native tokens, ERC20, ERC721, and * ERC1155), a token address, a tokenId, and an amount. */ struct SpentItem { ItemType itemType; address token; uint256 identifier; uint256 amount; } /** * @dev A received item is translated from a utilized consideration item and has * the same four components as a spent item, as well as an additional fifth * component designating the required recipient of the item. */ struct ReceivedItem { ItemType itemType; address token; uint256 identifier; uint256 amount; address payable recipient; } /** * @dev For basic orders involving ETH / native / ERC20 <=> ERC721 / ERC1155 * matching, a group of six functions may be called that only requires a * subset of the usual order arguments. Note the use of a "basicOrderType" * enum; this represents both the usual order type as well as the "route" * of the basic order (a simple derivation function for the basic order * type is `basicOrderType = orderType + (4 * basicOrderRoute)`.) */ struct BasicOrderParameters { // calldata offset address considerationToken; // 0x24 uint256 considerationIdentifier; // 0x44 uint256 considerationAmount; // 0x64 address payable offerer; // 0x84 address zone; // 0xa4 address offerToken; // 0xc4 uint256 offerIdentifier; // 0xe4 uint256 offerAmount; // 0x104 BasicOrderType basicOrderType; // 0x124 uint256 startTime; // 0x144 uint256 endTime; // 0x164 bytes32 zoneHash; // 0x184 uint256 salt; // 0x1a4 bytes32 offererConduitKey; // 0x1c4 bytes32 fulfillerConduitKey; // 0x1e4 uint256 totalOriginalAdditionalRecipients; // 0x204 AdditionalRecipient[] additionalRecipients; // 0x224 bytes signature; // 0x244 // Total length, excluding dynamic array data: 0x264 (580) } /** * @dev Basic orders can supply any number of additional recipients, with the * implied assumption that they are supplied from the offered ETH (or other * native token) or ERC20 token for the order. */ struct AdditionalRecipient { uint256 amount; address payable recipient; } /** * @dev The full set of order components, with the exception of the counter, * must be supplied when fulfilling more sophisticated orders or groups of * orders. The total number of original consideration items must also be * supplied, as the caller may specify additional consideration items. */ struct OrderParameters { address offerer; // 0x00 address zone; // 0x20 OfferItem[] offer; // 0x40 ConsiderationItem[] consideration; // 0x60 OrderType orderType; // 0x80 uint256 startTime; // 0xa0 uint256 endTime; // 0xc0 bytes32 zoneHash; // 0xe0 uint256 salt; // 0x100 bytes32 conduitKey; // 0x120 uint256 totalOriginalConsiderationItems; // 0x140 // offer.length // 0x160 } /** * @dev Orders require a signature in addition to the other order parameters. */ struct Order { OrderParameters parameters; bytes signature; } /** * @dev Advanced orders include a numerator (i.e. a fraction to attempt to fill) * and a denominator (the total size of the order) in addition to the * signature and other order parameters. It also supports an optional field * for supplying extra data; this data will be 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 counter), and * partially or fully filled (with the fraction filled represented by a * numerator and denominator). */ struct OrderStatus { bool isValidated; bool isCancelled; uint120 numerator; uint120 denominator; } /** * @dev A criteria resolver specifies an order, side (offer vs. consideration), * and item index. It then provides a chosen identifier (i.e. tokenId) * alongside a merkle proof demonstrating the identifier meets the required * criteria. */ struct CriteriaResolver { uint256 orderIndex; Side side; uint256 index; uint256 identifier; bytes32[] criteriaProof; } /** * @dev A fulfillment is applied to a group of orders. It decrements a series of * offer and consideration items, then generates a single execution * element. A given fulfillment can be applied to as many offer and * consideration items as desired, but must contain at least one offer and * at least one consideration that match. The fulfillment must also remain * consistent on all key parameters across all offer items (same offerer, * token, type, tokenId, and conduit preference) as well as across all * consideration items (token, type, tokenId, and recipient). */ struct Fulfillment { FulfillmentComponent[] offerComponents; FulfillmentComponent[] considerationComponents; } /** * @dev Each fulfillment component contains one index referencing a specific * order and another referencing a specific offer or consideration item. */ struct FulfillmentComponent { uint256 orderIndex; uint256 itemIndex; } /** * @dev An execution is triggered once all consideration items have been zeroed * out. It sends the item in question from the offerer to the item's * recipient, optionally sourcing approvals from either this contract * directly or from the offerer's chosen conduit if one is specified. An * execution is not provided as an argument, but rather is derived via * orders, criteria resolvers, and fulfillments (where the total number of * executions will be less than or equal to the total number of indicated * fulfillments) and returned as part of `matchOrders`. */ struct Execution { ReceivedItem item; address offerer; bytes32 conduitKey; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import "./ConsiderationStructs.sol"; uint256 constant EIP712_Order_size = 0x180; uint256 constant EIP712_OfferItem_size = 0xc0; uint256 constant EIP712_ConsiderationItem_size = 0xe0; uint256 constant EIP712_DomainSeparator_offset = 0x02; uint256 constant EIP712_OrderHash_offset = 0x22; uint256 constant EIP712_DigestPayload_size = 0x42; uint256 constant EIP_712_PREFIX = ( 0x1901000000000000000000000000000000000000000000000000000000000000 ); contract ConsiderationTypeHashes { 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; bytes32 internal immutable _DOMAIN_SEPARATOR; address internal constant seaportAddress = address(0x00000000006c3852cbEf3e08E8dF289169EdE581); constructor() { // Derive hash of the name of the contract. _NAME_HASH = keccak256(bytes("Seaport")); // Derive hash of the version string of the contract. _VERSION_HASH = keccak256(bytes("1.1")); bytes memory offerItemTypeString = abi.encodePacked( "OfferItem(", "uint8 itemType,", "address token,", "uint256 identifierOrCriteria,", "uint256 startAmount,", "uint256 endAmount", ")" ); // Construct the ConsiderationItem type string. // prettier-ignore 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. // prettier-ignore 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 counter", ")" ); // Derive the OfferItem type hash using the corresponding type string. bytes32 offerItemTypehash = keccak256(offerItemTypeString); // Derive ConsiderationItem type hash using corresponding type string. bytes32 considerationItemTypehash = keccak256( considerationItemTypeString ); // Construct the primary EIP-712 domain type string. // prettier-ignore _EIP_712_DOMAIN_TYPEHASH = keccak256( abi.encodePacked( "EIP712Domain(", "string name,", "string version,", "uint256 chainId,", "address verifyingContract", ")" ) ); _OFFER_ITEM_TYPEHASH = offerItemTypehash; _CONSIDERATION_ITEM_TYPEHASH = considerationItemTypehash; // Derive OrderItem type hash via combination of relevant type strings. _ORDER_TYPEHASH = keccak256( abi.encodePacked( orderComponentsPartialTypeString, considerationItemTypeString, offerItemTypeString ) ); _DOMAIN_SEPARATOR = _deriveDomainSeparator(); } /** * @dev Internal view function to derive the EIP-712 domain separator. * * @return The derived domain separator. */ function _deriveDomainSeparator() internal view returns (bytes32) { // prettier-ignore return keccak256( abi.encode( _EIP_712_DOMAIN_TYPEHASH, _NAME_HASH, _VERSION_HASH, block.chainid, seaportAddress ) ); } /** * @dev Internal pure function to efficiently derive an digest to sign for * an order in accordance with EIP-712. * * @param orderHash The order hash. * * @return value The hash. */ function _deriveEIP712Digest(bytes32 orderHash) internal view returns (bytes32 value) { bytes32 domainSeparator = _DOMAIN_SEPARATOR; // 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) } } /** * @dev Internal view function to derive the EIP-712 hash for an offer item. * * @param offerItem The offered item to hash. * * @return The hash. */ function _hashOfferItem(OfferItem memory offerItem) internal view returns (bytes32) { return keccak256( abi.encode( _OFFER_ITEM_TYPEHASH, offerItem.itemType, offerItem.token, offerItem.identifierOrCriteria, offerItem.startAmount, offerItem.endAmount ) ); } /** * @dev Internal view function to derive the EIP-712 hash for a consideration item. * * @param considerationItem The consideration item to hash. * * @return The hash. */ function _hashConsiderationItem(ConsiderationItem memory considerationItem) internal view returns (bytes32) { return keccak256( abi.encode( _CONSIDERATION_ITEM_TYPEHASH, considerationItem.itemType, considerationItem.token, considerationItem.identifierOrCriteria, considerationItem.startAmount, considerationItem.endAmount, considerationItem.recipient ) ); } /** * @dev Internal view function to derive the order hash for a given order. * Note that only the original consideration items are included in the * order hash, as additional consideration items may be supplied by the * caller. * * @param orderParameters The parameters of the order to hash. * @param counter The counter of the order to hash. * * @return orderHash The hash. */ function _deriveOrderHash( OrderParameters memory orderParameters, uint256 counter ) internal view returns (bytes32 orderHash) { // Designate new memory regions for offer and consideration item hashes. bytes32[] memory offerHashes = new bytes32[]( orderParameters.offer.length ); bytes32[] memory considerationHashes = new bytes32[]( orderParameters.totalOriginalConsiderationItems ); // Iterate over each offer on the order. for (uint256 i = 0; i < orderParameters.offer.length; ++i) { // Hash the offer and place the result into memory. offerHashes[i] = _hashOfferItem(orderParameters.offer[i]); } // Iterate over each consideration on the order. for ( uint256 i = 0; i < orderParameters.totalOriginalConsiderationItems; ++i ) { // Hash the consideration and place the result into memory. considerationHashes[i] = _hashConsiderationItem( orderParameters.consideration[i] ); } // Derive and return the order hash as specified by EIP-712. return keccak256( abi.encode( _ORDER_TYPEHASH, orderParameters.offerer, orderParameters.zone, keccak256(abi.encodePacked(offerHashes)), keccak256(abi.encodePacked(considerationHashes)), orderParameters.orderType, orderParameters.startTime, orderParameters.endTime, orderParameters.zoneHash, orderParameters.salt, orderParameters.conduitKey, counter ) ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; // prettier-ignore import { BasicOrderParameters, OrderComponents, Fulfillment, FulfillmentComponent, Execution, Order, AdvancedOrder, OrderStatus, CriteriaResolver } from "../lib/ConsiderationStructs.sol"; /** * @title ConsiderationInterface * @author 0age * @custom:version 1.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 * (transferable) token identifier on the token * in question is valid and that no associated * proof needs to be supplied. * @param fulfillerConduitKey A bytes32 value indicating what conduit, if * any, to source the fulfiller's token approvals * from. The zero hash signifies that no conduit * should be used, with direct approvals set on * Consideration. * @param recipient The intended recipient for all received items, * with `address(0)` indicating that the caller * should receive the items. * * @return fulfilled A boolean indicating whether the order has been * successfully fulfilled. */ function fulfillAdvancedOrder( AdvancedOrder calldata advancedOrder, CriteriaResolver[] calldata criteriaResolvers, bytes32 fulfillerConduitKey, address recipient ) external payable returns (bool fulfilled); /** * @notice Attempt to fill a group of orders, each with an arbitrary number * of items for offer and consideration. Any order that is not * currently active, has already been fully filled, or has been * cancelled will be omitted. Remaining offer and consideration * items will then be aggregated where possible as indicated by the * supplied offer and consideration component arrays and aggregated * items will be transferred to the fulfiller or to each intended * recipient, respectively. Note that a failing item transfer or an * issue with order formatting will cause the entire batch to fail. * Note that this function does not support criteria-based orders or * partial filling of orders (though filling the remainder of a * partially-filled order is supported). * * @param orders The orders to fulfill. Note that both * the offerer and the fulfiller must first * approve this contract (or the * corresponding conduit if indicated) to * transfer any relevant tokens on their * behalf and that contracts must implement * `onERC1155Received` to receive ERC1155 * tokens as consideration. * @param offerFulfillments An array of FulfillmentComponent arrays * indicating which offer items to attempt * to aggregate when preparing executions. * @param considerationFulfillments An array of FulfillmentComponent arrays * indicating which consideration items to * attempt to aggregate when preparing * executions. * @param fulfillerConduitKey A bytes32 value indicating what conduit, * if any, to source the fulfiller's token * approvals from. The zero hash signifies * that no conduit should be used, with * direct approvals set on this contract. * @param maximumFulfilled The maximum number of orders to fulfill. * * @return availableOrders An array of booleans indicating if each order * with an index corresponding to the index of the * returned boolean was fulfillable or not. * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function fulfillAvailableOrders( Order[] calldata orders, FulfillmentComponent[][] calldata offerFulfillments, FulfillmentComponent[][] calldata considerationFulfillments, bytes32 fulfillerConduitKey, uint256 maximumFulfilled ) external payable returns (bool[] memory availableOrders, Execution[] memory executions); /** * @notice Attempt to fill a group of orders, fully or partially, with an * arbitrary number of items for offer and consideration per order * alongside criteria resolvers containing specific token * identifiers and associated proofs. Any order that is not * currently active, has already been fully filled, or has been * cancelled will be omitted. Remaining offer and consideration * items will then be aggregated where possible as indicated by the * supplied offer and consideration component arrays and aggregated * items will be transferred to the fulfiller or to each intended * recipient, respectively. Note that a failing item transfer or an * issue with order formatting will cause the entire batch to fail. * * @param advancedOrders The orders to fulfill along with the * fraction of those orders to attempt to * fill. Note that both the offerer and the * fulfiller must first approve this * contract (or their preferred conduit if * indicated by the order) to transfer any * relevant tokens on their behalf and that * contracts must implement * `onERC1155Received` to enable receipt of * ERC1155 tokens as consideration. Also * note that all offer and consideration * components must have no remainder after * multiplication of the respective amount * with the supplied fraction for an * order's partial fill amount to be * considered valid. * @param criteriaResolvers An array where each element contains a * reference to a specific offer or * consideration, a token identifier, and a * proof that the supplied token identifier * is contained in the merkle root held by * the item in question's criteria element. * Note that an empty criteria indicates * that any (transferable) token * identifier on the token in question is * valid and that no associated proof needs * to be supplied. * @param offerFulfillments An array of FulfillmentComponent arrays * indicating which offer items to attempt * to aggregate when preparing executions. * @param considerationFulfillments An array of FulfillmentComponent arrays * indicating which consideration items to * attempt to aggregate when preparing * executions. * @param fulfillerConduitKey A bytes32 value indicating what conduit, * if any, to source the fulfiller's token * approvals from. The zero hash signifies * that no conduit should be used, with * direct approvals set on this contract. * @param recipient The intended recipient for all received * items, with `address(0)` indicating that * the caller should receive the items. * @param maximumFulfilled The maximum number of orders to fulfill. * * @return availableOrders An array of booleans indicating if each order * with an index corresponding to the index of the * returned boolean was fulfillable or not. * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function fulfillAvailableAdvancedOrders( AdvancedOrder[] calldata advancedOrders, CriteriaResolver[] calldata criteriaResolvers, FulfillmentComponent[][] calldata offerFulfillments, FulfillmentComponent[][] calldata considerationFulfillments, bytes32 fulfillerConduitKey, address recipient, uint256 maximumFulfilled ) external payable returns (bool[] memory availableOrders, Execution[] memory executions); /** * @notice Match an arbitrary number of orders, each with an arbitrary * number of items for offer and consideration along with as set of * fulfillments allocating offer components to consideration * components. Note that this function does not support * criteria-based or partial filling of orders (though filling the * remainder of a partially-filled order is supported). * * @param orders The orders to match. Note that both the offerer and * fulfiller on each order must first approve this * contract (or their conduit if indicated by the order) * to transfer any relevant tokens on their behalf and * each consideration recipient must implement * `onERC1155Received` to enable ERC1155 token receipt. * @param fulfillments An array of elements allocating offer components to * consideration components. Note that each * consideration component must be fully met for the * match operation to be valid. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function matchOrders( Order[] calldata orders, Fulfillment[] calldata fulfillments ) external payable returns (Execution[] memory executions); /** * @notice Match an arbitrary number of full or partial orders, each with an * arbitrary number of items for offer and consideration, supplying * criteria resolvers containing specific token identifiers and * associated proofs as well as fulfillments allocating offer * components to consideration components. * * @param orders The advanced orders to match. Note that both the * offerer and fulfiller on each order must first * approve this contract (or a preferred conduit if * indicated by the order) to transfer any relevant * tokens on their behalf and each consideration * recipient must implement `onERC1155Received` in * order to receive ERC1155 tokens. Also note that * the offer and consideration components for each * order must have no remainder after multiplying * the respective amount with the supplied fraction * in order for the group of partial fills to be * considered valid. * @param criteriaResolvers An array where each element contains a reference * to a specific order as well as that order's * offer or consideration, a token identifier, and * a proof that the supplied token identifier is * contained in the order's merkle root. Note that * an empty root indicates that any (transferable) * token identifier is valid and that no associated * proof needs to be supplied. * @param fulfillments An array of elements allocating offer components * to consideration components. Note that each * consideration component must be fully met in * order for the match operation to be valid. * * @return executions An array of elements indicating the sequence of * transfers performed as part of matching the given * orders. */ function matchAdvancedOrders( AdvancedOrder[] calldata orders, CriteriaResolver[] calldata criteriaResolvers, Fulfillment[] calldata fulfillments ) external payable returns (Execution[] memory executions); /** * @notice Cancel an arbitrary number of orders. Note that only the offerer * or the zone of a given order may cancel it. Callers should ensure * that the intended order was cancelled by calling `getOrderStatus` * and confirming that `isCancelled` returns `true`. * * @param orders The orders to cancel. * * @return cancelled A boolean indicating whether the supplied orders have * been successfully cancelled. */ function cancel(OrderComponents[] calldata orders) external returns (bool cancelled); /** * @notice Validate an arbitrary number of orders, thereby registering their * signatures as valid and allowing the fulfiller to skip signature * verification on fulfillment. Note that validated orders may still * be unfulfillable due to invalid item amounts or other factors; * callers should determine whether validated orders are fulfillable * by simulating the fulfillment call prior to execution. Also note * that anyone can validate a signed order, but only the offerer can * validate an order without supplying a signature. * * @param orders The orders to validate. * * @return validated A boolean indicating whether the supplied orders have * been successfully validated. */ function validate(Order[] calldata orders) external returns (bool validated); /** * @notice Cancel all orders from a given offerer with a given zone in bulk * by incrementing a counter. Note that only the offerer may * increment the counter. * * @return newCounter The new counter. */ function incrementCounter() external returns (uint256 newCounter); /** * @notice Retrieve the order hash for a given order. * * @param order The components of the order. * * @return orderHash The order hash. */ function getOrderHash(OrderComponents calldata order) external view returns (bytes32 orderHash); /** * @notice Retrieve the status of a given order by hash, including whether * the order has been cancelled or validated and the fraction of the * order that has been filled. * * @param orderHash The order hash in question. * * @return isValidated A boolean indicating whether the order in question * has been validated (i.e. previously approved or * partially filled). * @return isCancelled A boolean indicating whether the order in question * has been cancelled. * @return totalFilled The total portion of the order that has been filled * (i.e. the "numerator"). * @return totalSize The total size of the order that is either filled or * unfilled (i.e. the "denominator"). */ function getOrderStatus(bytes32 orderHash) external view returns ( bool isValidated, bool isCancelled, uint256 totalFilled, uint256 totalSize ); /** * @notice Retrieve the current counter for a given offerer. * * @param offerer The offerer in question. * * @return counter The current counter. */ function getCounter(address offerer) external view returns (uint256 counter); /** * @notice Retrieve configuration information for this contract. * * @return version The contract version. * @return domainSeparator The domain separator for this contract. * @return conduitController The conduit Controller set for this contract. */ function information() external view returns ( string memory version, bytes32 domainSeparator, address conduitController ); /** * @notice Retrieve the name of this contract. * * @return contractName The name of this contract. */ function name() external view returns (string memory contractName); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; /** * @title ConduitControllerInterface * @author 0age * @notice ConduitControllerInterface contains all external function interfaces, * structs, events, and errors for the conduit controller. */ interface ConduitControllerInterface { /** * @dev Track the conduit key, current owner, new potential owner, and open * channels for each deployed conduit. */ struct ConduitProperties { bytes32 key; address owner; address potentialOwner; address[] channels; mapping(address => uint256) channelIndexesPlusOne; } /** * @dev Emit an event whenever a new conduit is created. * * @param conduit The newly created conduit. * @param conduitKey The conduit key used to create the new conduit. */ event NewConduit(address conduit, bytes32 conduitKey); /** * @dev Emit an event whenever conduit ownership is transferred. * * @param conduit The conduit for which ownership has been * transferred. * @param previousOwner The previous owner of the conduit. * @param newOwner The new owner of the conduit. */ event OwnershipTransferred( address indexed conduit, address indexed previousOwner, address indexed newOwner ); /** * @dev Emit an event whenever a conduit owner registers a new potential * owner for that conduit. * * @param newPotentialOwner The new potential owner of the conduit. */ event PotentialOwnerUpdated(address indexed newPotentialOwner); /** * @dev Revert with an error when attempting to create a new conduit using a * conduit key where the first twenty bytes of the key do not match the * address of the caller. */ error InvalidCreator(); /** * @dev Revert with an error when attempting to create a new conduit when no * initial owner address is supplied. */ error InvalidInitialOwner(); /** * @dev Revert with an error when attempting to set a new potential owner * that is already set. */ error NewPotentialOwnerAlreadySet( address conduit, address newPotentialOwner ); /** * @dev Revert with an error when attempting to cancel ownership transfer * when no new potential owner is currently set. */ error NoPotentialOwnerCurrentlySet(address conduit); /** * @dev Revert with an error when attempting to interact with a conduit that * does not yet exist. */ error NoConduit(); /** * @dev Revert with an error when attempting to create a conduit that * already exists. */ error ConduitAlreadyExists(address conduit); /** * @dev Revert with an error when attempting to update channels or transfer * ownership of a conduit when the caller is not the owner of the * conduit in question. */ error CallerIsNotOwner(address conduit); /** * @dev Revert with an error when attempting to register a new potential * owner and supplying the null address. */ error NewPotentialOwnerIsZeroAddress(address conduit); /** * @dev Revert with an error when attempting to claim ownership of a conduit * with a caller that is not the current potential owner for the * conduit in question. */ error CallerIsNotNewPotentialOwner(address conduit); /** * @dev Revert with an error when attempting to retrieve a channel using an * index that is out of range. */ error ChannelOutOfRange(address conduit); /** * @notice Deploy a new conduit using a supplied conduit key and assigning * an initial owner for the deployed conduit. Note that the first * twenty bytes of the supplied conduit key must match the caller * and that a new conduit cannot be created if one has already been * deployed using the same conduit key. * * @param conduitKey The conduit key used to deploy the conduit. Note that * the first twenty bytes of the conduit key must match * the caller of this contract. * @param initialOwner The initial owner to set for the new conduit. * * @return conduit The address of the newly deployed conduit. */ function createConduit(bytes32 conduitKey, address initialOwner) external returns (address conduit); /** * @notice Open or close a channel on a given conduit, thereby allowing the * specified account to execute transfers against that conduit. * Extreme care must be taken when updating channels, as malicious * or vulnerable channels can transfer any ERC20, ERC721 and ERC1155 * tokens where the token holder has granted the conduit approval. * Only the owner of the conduit in question may call this function. * * @param conduit The conduit for which to open or close the channel. * @param channel The channel to open or close on the conduit. * @param isOpen A boolean indicating whether to open or close the channel. */ function updateChannel( address conduit, address channel, bool isOpen ) external; /** * @notice Initiate conduit ownership transfer by assigning a new potential * owner for the given conduit. Once set, the new potential owner * may call `acceptOwnership` to claim ownership of the conduit. * Only the owner of the conduit in question may call this function. * * @param conduit The conduit for which to initiate ownership transfer. * @param newPotentialOwner The new potential owner of the conduit. */ function transferOwnership(address conduit, address newPotentialOwner) external; /** * @notice Clear the currently set potential owner, if any, from a conduit. * Only the owner of the conduit in question may call this function. * * @param conduit The conduit for which to cancel ownership transfer. */ function cancelOwnershipTransfer(address conduit) external; /** * @notice Accept ownership of a supplied conduit. Only accounts that the * current owner has set as the new potential owner may call this * function. * * @param conduit The conduit for which to accept ownership. */ function acceptOwnership(address conduit) external; /** * @notice Retrieve the current owner of a deployed conduit. * * @param conduit The conduit for which to retrieve the associated owner. * * @return owner The owner of the supplied conduit. */ function ownerOf(address conduit) external view returns (address owner); /** * @notice Retrieve the conduit key for a deployed conduit via reverse * lookup. * * @param conduit The conduit for which to retrieve the associated conduit * key. * * @return conduitKey The conduit key used to deploy the supplied conduit. */ function getKey(address conduit) external view returns (bytes32 conduitKey); /** * @notice Derive the conduit associated with a given conduit key and * determine whether that conduit exists (i.e. whether it has been * deployed). * * @param conduitKey The conduit key used to derive the conduit. * * @return conduit The derived address of the conduit. * @return exists A boolean indicating whether the derived conduit has been * deployed or not. */ function getConduit(bytes32 conduitKey) external view returns (address conduit, bool exists); /** * @notice Retrieve the potential owner, if any, for a given conduit. The * current owner may set a new potential owner via * `transferOwnership` and that owner may then accept ownership of * the conduit in question via `acceptOwnership`. * * @param conduit The conduit for which to retrieve the potential owner. * * @return potentialOwner The potential owner, if any, for the conduit. */ function getPotentialOwner(address conduit) external view returns (address potentialOwner); /** * @notice Retrieve the status (either open or closed) of a given channel on * a conduit. * * @param conduit The conduit for which to retrieve the channel status. * @param channel The channel for which to retrieve the status. * * @return isOpen The status of the channel on the given conduit. */ function getChannelStatus(address conduit, address channel) external view returns (bool isOpen); /** * @notice Retrieve the total number of open channels for a given conduit. * * @param conduit The conduit for which to retrieve the total channel count. * * @return totalChannels The total number of open channels for the conduit. */ function getTotalChannels(address conduit) external view returns (uint256 totalChannels); /** * @notice Retrieve an open channel at a specific index for a given conduit. * Note that the index of a channel can change as a result of other * channels being closed on the conduit. * * @param conduit The conduit for which to retrieve the open channel. * @param channelIndex The index of the channel in question. * * @return channel The open channel, if any, at the specified channel index. */ function getChannel(address conduit, uint256 channelIndex) external view returns (address channel); /** * @notice Retrieve all open channels for a given conduit. Note that calling * this function for a conduit with many channels will revert with * an out-of-gas error. * * @param conduit The conduit for which to retrieve open channels. * * @return channels An array of open channels on the given conduit. */ function getChannels(address conduit) external view returns (address[] memory channels); /** * @dev Retrieve the conduit creation code and runtime code hashes. */ function getConduitCodeHashes() external view returns (bytes32 creationCodeHash, bytes32 runtimeCodeHash); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import { ItemType } from "../lib/ConsiderationEnums.sol"; import { Order, OrderParameters } from "../lib/ConsiderationStructs.sol"; import { ErrorsAndWarnings } from "../lib/ErrorsAndWarnings.sol"; import { ValidationConfiguration } from "../lib/SeaportValidatorTypes.sol"; /** * @title SeaportValidator * @notice SeaportValidator validates simple orders that adhere to a set of rules defined below: * - The order is either a listing or an offer order (one NFT to buy or one NFT to sell). * - The first consideration is the primary consideration. * - The order pays up to two fees in the fungible token currency. First fee is primary fee, second is creator fee. * - In private orders, the last consideration specifies a recipient for the offer item. * - Offer items must be owned and properly approved by the offerer. * - Consideration items must exist. */ interface SeaportValidatorInterface { /** * @notice Conduct a comprehensive validation of the given order. * @param order The order to validate. * @return errorsAndWarnings The errors and warnings found in the order. */ function isValidOrder(Order calldata order) external view returns (ErrorsAndWarnings memory errorsAndWarnings); /** * @notice Same as `isValidOrder` but allows for more configuration related to fee validation. */ function isValidOrderWithConfiguration( ValidationConfiguration memory validationConfiguration, Order memory order ) external view returns (ErrorsAndWarnings memory errorsAndWarnings); /** * @notice Checks if a conduit key is valid. * @param conduitKey The conduit key to check. * @return errorsAndWarnings The errors and warnings */ function isValidConduit(bytes32 conduitKey) external view returns (ErrorsAndWarnings memory errorsAndWarnings); function validateSignature(Order memory order) external view returns (ErrorsAndWarnings memory errorsAndWarnings); function validateSignatureWithCounter(Order memory order, uint256 counter) external view returns (ErrorsAndWarnings memory errorsAndWarnings); /** * @notice Check the time validity of an order * @param orderParameters The parameters for the order to validate * @param shortOrderDuration The duration of which an order is considered short * @param distantOrderExpiration Distant order expiration delta in seconds. * @return errorsAndWarnings The Issues and warnings */ function validateTime( OrderParameters memory orderParameters, uint256 shortOrderDuration, uint256 distantOrderExpiration ) external view returns (ErrorsAndWarnings memory errorsAndWarnings); /** * @notice Validate the status of an order * @param orderParameters The parameters for the order to validate * @return errorsAndWarnings The errors and warnings */ function validateOrderStatus(OrderParameters memory orderParameters) external view returns (ErrorsAndWarnings memory errorsAndWarnings); /** * @notice Validate all offer items for an order * @param orderParameters The parameters for the order to validate * @return errorsAndWarnings The errors and warnings */ function validateOfferItems(OrderParameters memory orderParameters) external view returns (ErrorsAndWarnings memory errorsAndWarnings); /** * @notice Validate all consideration items for an order * @param orderParameters The parameters for the order to validate * @return errorsAndWarnings The errors and warnings */ function validateConsiderationItems(OrderParameters memory orderParameters) external view returns (ErrorsAndWarnings memory errorsAndWarnings); /** * @notice Strict validation operates under tight assumptions. It validates primary * fee, creator fee, private sale consideration, and overall order format. * @dev Only checks first fee recipient provided by CreatorFeeRegistry. * Order of consideration items must be as follows: * 1. Primary consideration * 2. Primary fee * 3. Creator Fee * 4. Private sale consideration * @param orderParameters The parameters for the order to validate. * @param primaryFeeRecipient The primary fee recipient. Set to null address for no primary fee. * @param primaryFeeBips The primary fee in BIPs. * @param checkCreatorFee Should check for creator fee. If true, creator fee must be present as * according to creator fee engine. If false, must not have creator fee. * @return errorsAndWarnings The errors and warnings. */ function validateStrictLogic( OrderParameters memory orderParameters, address primaryFeeRecipient, uint256 primaryFeeBips, bool checkCreatorFee ) external view returns (ErrorsAndWarnings memory errorsAndWarnings); /** * @notice Validate a consideration item * @param orderParameters The parameters for the order to validate * @param considerationItemIndex The index of the consideration item to validate * @return errorsAndWarnings The errors and warnings */ function validateConsiderationItem( OrderParameters memory orderParameters, uint256 considerationItemIndex ) external view returns (ErrorsAndWarnings memory errorsAndWarnings); /** * @notice Validates the parameters of a consideration item including contract validation * @param orderParameters The parameters for the order to validate * @param considerationItemIndex The index of the consideration item to validate * @return errorsAndWarnings The errors and warnings */ function validateConsiderationItemParameters( OrderParameters memory orderParameters, uint256 considerationItemIndex ) external view returns (ErrorsAndWarnings memory errorsAndWarnings); /** * @notice Validates an offer item * @param orderParameters The parameters for the order to validate * @param offerItemIndex The index of the offerItem in offer array to validate * @return errorsAndWarnings An ErrorsAndWarnings structs with results */ function validateOfferItem( OrderParameters memory orderParameters, uint256 offerItemIndex ) external view returns (ErrorsAndWarnings memory errorsAndWarnings); /** * @notice Validates the OfferItem parameters. This includes token contract validation * @dev OfferItems with criteria are currently not allowed * @param orderParameters The parameters for the order to validate * @param offerItemIndex The index of the offerItem in offer array to validate * @return errorsAndWarnings An ErrorsAndWarnings structs with results */ function validateOfferItemParameters( OrderParameters memory orderParameters, uint256 offerItemIndex ) external view returns (ErrorsAndWarnings memory errorsAndWarnings); /** * @notice Validates the OfferItem approvals and balances * @param orderParameters The parameters for the order to validate * @param offerItemIndex The index of the offerItem in offer array to validate * @return errorsAndWarnings An ErrorsAndWarnings structs with results */ function validateOfferItemApprovalAndBalance( OrderParameters memory orderParameters, uint256 offerItemIndex ) external view returns (ErrorsAndWarnings memory errorsAndWarnings); // TODO: Need to add support for order with extra data /** * @notice Validates the zone call for an order * @param orderParameters The parameters for the order to validate * @return errorsAndWarnings An ErrorsAndWarnings structs with results */ function isValidZone(OrderParameters memory orderParameters) external view returns (ErrorsAndWarnings memory errorsAndWarnings); /** * @notice Gets the approval address for the given conduit key * @param conduitKey Conduit key to get approval address for * @return errorsAndWarnings An ErrorsAndWarnings structs with results */ function getApprovalAddress(bytes32 conduitKey) external view returns (address, ErrorsAndWarnings memory errorsAndWarnings); /** * @notice Safely check that a contract implements an interface * @param token The token address to check * @param interfaceHash The interface hash to check */ function checkInterface(address token, bytes4 interfaceHash) external view returns (bool); function isPaymentToken(ItemType itemType) external pure returns (bool); /*////////////////////////////////////////////////////////////// Merkle Helpers //////////////////////////////////////////////////////////////*/ /** * @notice Sorts an array of token ids by the keccak256 hash of the id. Required ordering of ids * for other merkle operations. * @param includedTokens An array of included token ids. * @return sortedTokens The sorted `includedTokens` array. */ function sortMerkleTokens(uint256[] memory includedTokens) external view returns (uint256[] memory sortedTokens); /** * @notice Creates a merkle root for includedTokens. * @dev `includedTokens` must be sorting in strictly ascending order according to the keccak256 hash of the value. * @return merkleRoot The merkle root * @return errorsAndWarnings Errors and warnings from the operation */ function getMerkleRoot(uint256[] memory includedTokens) external view returns ( bytes32 merkleRoot, ErrorsAndWarnings memory errorsAndWarnings ); /** * @notice Creates a merkle proof for the the targetIndex contained in includedTokens. * @dev `targetIndex` is referring to the index of an element in `includedTokens`. * `includedTokens` must be sorting in ascending order according to the keccak256 hash of the value. * @return merkleProof The merkle proof * @return errorsAndWarnings Errors and warnings from the operation */ function getMerkleProof( uint256[] memory includedTokens, uint256 targetIndex ) external view returns ( bytes32[] memory merkleProof, ErrorsAndWarnings memory errorsAndWarnings ); function verifyMerkleProof( bytes32 merkleRoot, bytes32[] memory merkleProof, uint256 valueToProve ) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; 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 // OpenZeppelin Contracts v4.4.1 (interfaces/IERC721.sol) pragma solidity ^0.8.0; import "../token/ERC721/IERC721.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC1155.sol) pragma solidity ^0.8.0; import "../token/ERC1155/IERC1155.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165.sol"; /** * @dev Interface for the NFT Royalty Standard. * * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal * support for royalty payments across all NFT marketplaces and ecosystem participants. * * _Available since v4.5._ */ interface IERC2981 is IERC165 { /** * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. */ function royaltyInfo(uint256 tokenId, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; struct ErrorsAndWarnings { uint16[] errors; uint16[] warnings; } library ErrorsAndWarningsLib { function concat(ErrorsAndWarnings memory ew1, ErrorsAndWarnings memory ew2) internal pure { ew1.errors = concatMemory(ew1.errors, ew2.errors); ew1.warnings = concatMemory(ew1.warnings, ew2.warnings); } function addError(ErrorsAndWarnings memory ew, uint16 err) internal pure { ew.errors = pushMemory(ew.errors, err); } function addWarning(ErrorsAndWarnings memory ew, uint16 warn) internal pure { ew.warnings = pushMemory(ew.warnings, warn); } function hasErrors(ErrorsAndWarnings memory ew) internal pure returns (bool) { return ew.errors.length != 0; } function hasWarnings(ErrorsAndWarnings memory ew) internal pure returns (bool) { return ew.warnings.length != 0; } // Helper Functions function concatMemory(uint16[] memory array1, uint16[] memory array2) private pure returns (uint16[] memory) { if (array1.length == 0) { return array2; } else if (array2.length == 0) { return array1; } uint16[] memory returnValue = new uint16[]( array1.length + array2.length ); for (uint256 i = 0; i < array1.length; i++) { returnValue[i] = array1[i]; } for (uint256 i = 0; i < array2.length; i++) { returnValue[i + array1.length] = array2[i]; } return returnValue; } function pushMemory(uint16[] memory uint16Array, uint16 newValue) internal pure returns (uint16[] memory) { uint16[] memory returnValue = new uint16[](uint16Array.length + 1); for (uint256 i = 0; i < uint16Array.length; i++) { returnValue[i] = uint16Array[i]; } returnValue[uint16Array.length] = newValue; return returnValue; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; library SafeStaticCall { function safeStaticCallBool( address target, bytes memory callData, bool expectedReturn ) internal view returns (bool) { (bool success, bytes memory res) = target.staticcall(callData); if (!success) return false; if (res.length != 32) return false; if ( bytes32(res) & 0x0000000000000000000000000000000000000000000000000000000000000001 != bytes32(res) ) { return false; } return expectedReturn ? res[31] == 0x01 : res[31] == 0; } function safeStaticCallAddress( address target, bytes memory callData, address expectedReturn ) internal view returns (bool) { (bool success, bytes memory res) = target.staticcall(callData); if (!success) return false; if (res.length != 32) return false; if ( bytes32(res) & 0x000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF != bytes32(res) ) { // Ensure only 20 bytes used return false; } return abi.decode(res, (address)) == expectedReturn; } function safeStaticCallUint256( address target, bytes memory callData, uint256 minExpectedReturn ) internal view returns (bool) { (bool success, bytes memory res) = target.staticcall(callData); if (!success) return false; if (res.length != 32) return false; return abi.decode(res, (uint256)) >= minExpectedReturn; } function safeStaticCallBytes4( address target, bytes memory callData, bytes4 expectedReturn ) internal view returns (bool) { (bool success, bytes memory res) = target.staticcall(callData); if (!success) return false; if (res.length != 32) return false; if ( bytes32(res) & 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 != bytes32(res) ) { // Ensure only 4 bytes used return false; } return abi.decode(res, (bytes4)) == expectedReturn; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import { ErrorsAndWarnings, ErrorsAndWarningsLib } from "./ErrorsAndWarnings.sol"; import { IssueParser, MerkleIssue } from "./SeaportValidatorTypes.sol"; contract Murky { using ErrorsAndWarningsLib for ErrorsAndWarnings; using IssueParser for MerkleIssue; bool internal constant HASH_ODD_WITH_ZERO = false; function _verifyProof( bytes32 root, bytes32[] memory proof, bytes32 valueToProve ) internal pure returns (bool) { // proof length must be less than max array size bytes32 rollingHash = valueToProve; uint256 length = proof.length; unchecked { for (uint256 i = 0; i < length; ++i) { rollingHash = _hashLeafPairs(rollingHash, proof[i]); } } return root == rollingHash; } /******************** * HASHING FUNCTION * ********************/ /// ascending sort and concat prior to hashing function _hashLeafPairs(bytes32 left, bytes32 right) internal pure returns (bytes32 _hash) { assembly { switch lt(left, right) case 0 { mstore(0x0, right) mstore(0x20, left) } default { mstore(0x0, left) mstore(0x20, right) } _hash := keccak256(0x0, 0x40) } } /******************** * PROOF GENERATION * ********************/ function _getRoot(uint256[] memory data) internal pure returns (bytes32 result, ErrorsAndWarnings memory errorsAndWarnings) { errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0)); if (data.length < 2) { errorsAndWarnings.addError(MerkleIssue.SingleLeaf.parseInt()); return (0, errorsAndWarnings); } bool hashOddWithZero = HASH_ODD_WITH_ZERO; if (!_processInput(data)) { errorsAndWarnings.addError(MerkleIssue.Unsorted.parseInt()); return (0, errorsAndWarnings); } assembly { function hashLeafPairs(left, right) -> _hash { switch lt(left, right) case 0 { mstore(0x0, right) mstore(0x20, left) } default { mstore(0x0, left) mstore(0x20, right) } _hash := keccak256(0x0, 0x40) } function hashLevel(_data, length, _hashOddWithZero) -> newLength { // we will be modifying data in-place, so set result pointer to data pointer let _result := _data // get length of original data array // let length := mload(_data) // bool to track if we need to hash the last element of an odd-length array with zero let oddLength // if length is odd, we need to hash the last element with zero switch and(length, 1) case 1 { // if length is odd, add 1 so division by 2 will round up newLength := add(1, div(length, 2)) oddLength := 1 } default { newLength := div(length, 2) } // todo: necessary? // mstore(_data, newLength) let resultIndexPointer := add(0x20, _data) let dataIndexPointer := resultIndexPointer // stop iterating over for loop at length-1 let stopIteration := add(_data, mul(length, 0x20)) // write result array in-place over data array for { } lt(dataIndexPointer, stopIteration) { } { // get next two elements from data, hash them together let data1 := mload(dataIndexPointer) let data2 := mload(add(dataIndexPointer, 0x20)) let hashedPair := hashLeafPairs(data1, data2) // overwrite an element of data array with mstore(resultIndexPointer, hashedPair) // increment result pointer by 1 slot resultIndexPointer := add(0x20, resultIndexPointer) // increment data pointer by 2 slot dataIndexPointer := add(0x40, dataIndexPointer) } // we did not yet hash last index if odd-length if oddLength { let data1 := mload(dataIndexPointer) let nextValue switch _hashOddWithZero case 0 { nextValue := data1 } default { nextValue := hashLeafPairs(data1, 0) } mstore(resultIndexPointer, nextValue) } } let dataLength := mload(data) for { } gt(dataLength, 1) { } { dataLength := hashLevel(data, dataLength, hashOddWithZero) } result := mload(add(0x20, data)) } } function _getProof(uint256[] memory data, uint256 node) internal pure returns ( bytes32[] memory result, ErrorsAndWarnings memory errorsAndWarnings ) { errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0)); if (data.length < 2) { errorsAndWarnings.addError(MerkleIssue.SingleLeaf.parseInt()); return (new bytes32[](0), errorsAndWarnings); } bool hashOddWithZero = HASH_ODD_WITH_ZERO; if (!_processInput(data)) { errorsAndWarnings.addError(MerkleIssue.Unsorted.parseInt()); return (new bytes32[](0), errorsAndWarnings); } // The size of the proof is equal to the ceiling of log2(numLeaves) // Two overflow risks: node, pos // node: max array size is 2**256-1. Largest index in the array will be 1 less than that. Also, // for dynamic arrays, size is limited to 2**64-1 // pos: pos is bounded by log2(data.length), which should be less than type(uint256).max assembly { function hashLeafPairs(left, right) -> _hash { switch lt(left, right) case 0 { mstore(0x0, right) mstore(0x20, left) } default { mstore(0x0, left) mstore(0x20, right) } _hash := keccak256(0x0, 0x40) } function hashLevel(_data, length, _hashOddWithZero) -> newLength { // we will be modifying data in-place, so set result pointer to data pointer let _result := _data // get length of original data array // let length := mload(_data) // bool to track if we need to hash the last element of an odd-length array with zero let oddLength // if length is odd, we'll need to hash the last element with zero switch and(length, 1) case 1 { // if length is odd, add 1 so division by 2 will round up newLength := add(1, div(length, 2)) oddLength := 1 } default { newLength := div(length, 2) } // todo: necessary? // mstore(_data, newLength) let resultIndexPointer := add(0x20, _data) let dataIndexPointer := resultIndexPointer // stop iterating over for loop at length-1 let stopIteration := add(_data, mul(length, 0x20)) // write result array in-place over data array for { } lt(dataIndexPointer, stopIteration) { } { // get next two elements from data, hash them together let data1 := mload(dataIndexPointer) let data2 := mload(add(dataIndexPointer, 0x20)) let hashedPair := hashLeafPairs(data1, data2) // overwrite an element of data array with mstore(resultIndexPointer, hashedPair) // increment result pointer by 1 slot resultIndexPointer := add(0x20, resultIndexPointer) // increment data pointer by 2 slot dataIndexPointer := add(0x40, dataIndexPointer) } // we did not yet hash last index if odd-length if oddLength { let data1 := mload(dataIndexPointer) let nextValue switch _hashOddWithZero case 0 { nextValue := data1 } default { nextValue := hashLeafPairs(data1, 0) } mstore(resultIndexPointer, nextValue) } } // set result pointer to free memory result := mload(0x40) // get pointer to first index of result let resultIndexPtr := add(0x20, result) // declare so we can use later let newLength // put length of data onto stack let dataLength := mload(data) for { // repeat until only one element is left } gt(dataLength, 1) { } { // bool if node is odd let oddNodeIndex := and(node, 1) // bool if node is last let lastNodeIndex := eq(dataLength, add(1, node)) // store both bools in one value so we can switch on it let switchVal := or(shl(1, lastNodeIndex), oddNodeIndex) switch switchVal // 00 - neither odd nor last case 0 { // store data[node+1] at result[i] // get pointer to result[node+1] by adding 2 to node and multiplying by 0x20 // to account for the fact that result points to array length, not first index mstore( resultIndexPtr, mload(add(data, mul(0x20, add(2, node)))) ) } // 10 - node is last case 2 { // store 0 at result[i] mstore(resultIndexPtr, 0) } // 01 or 11 - node is odd (and possibly also last) default { // store data[node-1] at result[i] mstore(resultIndexPtr, mload(add(data, mul(0x20, node)))) } // increment result index resultIndexPtr := add(0x20, resultIndexPtr) // get new node index node := div(node, 2) // keep track of how long result array is newLength := add(1, newLength) // compute the next hash level, overwriting data, and get the new length dataLength := hashLevel(data, dataLength, hashOddWithZero) } // store length of result array at pointer mstore(result, newLength) // set free mem pointer to word after end of result array mstore(0x40, resultIndexPtr) } } /** * Hashes each element of the input array in place using keccak256 */ function _processInput(uint256[] memory data) private pure returns (bool sorted) { sorted = true; // Hash inputs with keccak256 for (uint256 i = 0; i < data.length; ++i) { assembly { mstore( add(data, mul(0x20, add(1, i))), keccak256(add(data, mul(0x20, add(1, i))), 0x20) ) // for every element after the first, hashed value must be greater than the last one if and( gt(i, 0), iszero( gt( mload(add(data, mul(0x20, add(1, i)))), mload(add(data, mul(0x20, add(1, sub(i, 1))))) ) ) ) { sorted := 0 // Elements not ordered by hash } } } } // Sort uint256 in order of the keccak256 hashes struct HashAndIntTuple { uint256 num; bytes32 hash; } function _sortUint256ByHash(uint256[] memory values) internal pure returns (uint256[] memory sortedValues) { HashAndIntTuple[] memory toSort = new HashAndIntTuple[](values.length); for (uint256 i = 0; i < values.length; i++) { toSort[i] = HashAndIntTuple( values[i], keccak256(abi.encode(values[i])) ); } _quickSort(toSort, 0, int256(toSort.length - 1)); sortedValues = new uint256[](values.length); for (uint256 i = 0; i < values.length; i++) { sortedValues[i] = toSort[i].num; } } function _quickSort( HashAndIntTuple[] memory arr, int256 left, int256 right ) internal pure { int256 i = left; int256 j = right; if (i == j) return; bytes32 pivot = arr[uint256(left + (right - left) / 2)].hash; while (i <= j) { while (arr[uint256(i)].hash < pivot) i++; while (pivot < arr[uint256(j)].hash) j--; if (i <= j) { (arr[uint256(i)], arr[uint256(j)]) = ( arr[uint256(j)], arr[uint256(i)] ); i++; j--; } } if (left < j) _quickSort(arr, left, j); if (i < right) _quickSort(arr, i, right); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; interface CreatorFeeEngineInterface { function getRoyaltyView( address tokenAddress, uint256 tokenId, uint256 value ) external view returns (address payable[] memory recipients, uint256[] memory amounts); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; struct ValidationConfiguration { /// @notice Recipient for primary fee payments. address primaryFeeRecipient; /// @notice Bips for primary fee payments. uint256 primaryFeeBips; /// @notice Should creator fees be checked? bool checkCreatorFee; /// @notice Should strict validation be skipped? bool skipStrictValidation; /// @notice Short order duration in seconds uint256 shortOrderDuration; /// @notice Distant order expiration delta in seconds. Warning if order expires in longer than this. uint256 distantOrderExpiration; } enum TimeIssue { EndTimeBeforeStartTime, Expired, DistantExpiration, NotActive, ShortOrder } enum StatusIssue { Cancelled, FullyFilled } enum OfferIssue { ZeroItems, AmountZero, MoreThanOneItem, NativeItem, DuplicateItem, AmountVelocityHigh, AmountStepLarge } enum ConsiderationIssue { AmountZero, NullRecipient, ExtraItems, PrivateSaleToSelf, ZeroItems, DuplicateItem, PrivateSale, AmountVelocityHigh, AmountStepLarge } enum PrimaryFeeIssue { Missing, ItemType, Token, StartAmount, EndAmount, Recipient } enum ERC721Issue { AmountNotOne, InvalidToken, IdentifierDNE, NotOwner, NotApproved, CriteriaNotPartialFill } enum ERC1155Issue { InvalidToken, NotApproved, InsufficientBalance } enum ERC20Issue { IdentifierNonZero, InvalidToken, InsufficientAllowance, InsufficientBalance } enum NativeIssue { TokenAddress, IdentifierNonZero, InsufficientBalance } enum ZoneIssue { RejectedOrder, NotSet } enum ConduitIssue { KeyInvalid } enum CreatorFeeIssue { Missing, ItemType, Token, StartAmount, EndAmount, Recipient } enum SignatureIssue { Invalid, LowCounter, HighCounter, OriginalConsiderationItems } enum GenericIssue { InvalidOrderFormat } enum MerkleIssue { SingleLeaf, Unsorted } /** * @title IssueParser - parse issues into integers * @notice Implements a `parseInt` function for each issue type. * offsets the enum value to place within the issue range. */ library IssueParser { function parseInt(GenericIssue err) internal pure returns (uint16) { return uint16(err) + 100; } function parseInt(ERC20Issue err) internal pure returns (uint16) { return uint16(err) + 200; } function parseInt(ERC721Issue err) internal pure returns (uint16) { return uint16(err) + 300; } function parseInt(ERC1155Issue err) internal pure returns (uint16) { return uint16(err) + 400; } function parseInt(ConsiderationIssue err) internal pure returns (uint16) { return uint16(err) + 500; } function parseInt(OfferIssue err) internal pure returns (uint16) { return uint16(err) + 600; } function parseInt(PrimaryFeeIssue err) internal pure returns (uint16) { return uint16(err) + 700; } function parseInt(StatusIssue err) internal pure returns (uint16) { return uint16(err) + 800; } function parseInt(TimeIssue err) internal pure returns (uint16) { return uint16(err) + 900; } function parseInt(ConduitIssue err) internal pure returns (uint16) { return uint16(err) + 1000; } function parseInt(SignatureIssue err) internal pure returns (uint16) { return uint16(err) + 1100; } function parseInt(CreatorFeeIssue err) internal pure returns (uint16) { return uint16(err) + 1200; } function parseInt(NativeIssue err) internal pure returns (uint16) { return uint16(err) + 1300; } function parseInt(ZoneIssue err) internal pure returns (uint16) { return uint16(err) + 1400; } function parseInt(MerkleIssue err) internal pure returns (uint16) { return uint16(err) + 1500; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import "./ConsiderationConstants.sol"; import { IERC1271 } from "@openzeppelin/contracts/interfaces/IERC1271.sol"; import { SafeStaticCall } from "./SafeStaticCall.sol"; /** * @title SignatureVerification * @author 0age * @notice SignatureVerification contains logic for verifying signatures. */ abstract contract SignatureVerification { using SafeStaticCall for address; /** * @dev Internal view function to verify the signature of an order. An * ERC-1271 fallback will be attempted if either the signature length * is not 64 or 65 bytes or if the recovered signer does not match the * supplied signer. Note that in cases where a 64 or 65 byte signature * is supplied, only standard ECDSA signatures that recover to a * non-zero address are supported. * * @param 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 _isValidSignature( address signer, bytes32 digest, bytes memory signature ) internal view returns (bool) { // Declare r, s, and v signature parameters. bytes32 r; bytes32 s; uint8 v; if (signer.code.length > 0) { // If signer is a contract, try verification via EIP-1271. return _isValidEIP1271Signature(signer, digest, signature); } else if (signature.length == 64) { // If signature contains 64 bytes, parse as EIP-2098 signature. (r+s&v) // Declare temporary vs that will be decomposed into s and v. bytes32 vs; (r, vs) = abi.decode(signature, (bytes32, bytes32)); s = vs & EIP2098_allButHighestBitMask; v = uint8(uint256(vs >> 255)) + 27; } else if (signature.length == 65) { (r, s) = abi.decode(signature, (bytes32, bytes32)); v = uint8(signature[64]); // Ensure v value is properly formatted. if (v != 27 && v != 28) { return false; } } else { return false; } // Attempt to recover signer using the digest and signature parameters. address recoveredSigner = ecrecover(digest, v, r, s); // Disallow invalid signers. if (recoveredSigner == address(0) || recoveredSigner != signer) { return false; // Should a signer be recovered, but it doesn't match the signer... } return true; } /** * @dev Internal view function to verify the signature of an order using * ERC-1271 (i.e. contract signatures via `isValidSignature`). * * @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 _isValidEIP1271Signature( address signer, bytes32 digest, bytes memory signature ) internal view returns (bool) { if ( !signer.safeStaticCallBytes4( abi.encodeWithSelector( IERC1271.isValidSignature.selector, digest, signature ), IERC1271.isValidSignature.selector ) ) { return false; } return true; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[EIP]. * * _Available since v3.1._ */ interface IERC1155 is IERC165 { /** * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the amount of tokens of token type `id` owned by `account`. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the caller. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.7; /* * -------------------------- 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.14/abi-spec.html#argument-encoding * - Note that the length of an array is separate from and precedes the * head of the array. * * - The term "body" is used in place of the term "head" used in the ABI * documentation. It refers to the start of the data for a dynamic type, * e.g. the first word of a struct or the first word of the first element * in an array. * * - The term "pointer" is used to describe the absolute position of a value * and never an offset relative to another value. * - The suffix "_ptr" refers to a memory pointer. * - The suffix "_cdPtr" refers to a calldata pointer. * * - The term "offset" is used to describe the position of a value relative * to some parent value. For example, OrderParameters_conduit_offset is the * offset to the "conduit" value in the OrderParameters struct relative to * the start of the body. * - Note: Offsets are used to derive pointers. * * - Some structs have pointers defined for all of their fields in this file. * Lines which are commented out are fields that are not used in the * codebase but have been left in for readability. */ // Declare constants for name, version, and reentrancy sentinel values. // Name is right padded, so it touches the length which is left padded. This // enables writing both values at once. Length goes at byte 95 in memory, and // name fills bytes 96-109, so both values can be written left-padded to 77. uint256 constant NameLengthPtr = 77; uint256 constant NameWithLength = 0x0d436F6E73696465726174696F6E; uint256 constant Version = 0x312e31; uint256 constant Version_length = 3; uint256 constant Version_shift = 0xe8; 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 = 0x04; 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 = 0x04; uint256 constant OrderParameters_offer_head_offset = 0x40; uint256 constant OrderParameters_consideration_head_offset = 0x60; uint256 constant OrderParameters_conduit_offset = 0x120; uint256 constant OrderParameters_counter_offset = 0x140; uint256 constant Fulfillment_itemIndex_offset = 0x20; uint256 constant AdvancedOrder_numerator_offset = 0x20; uint256 constant AlmostOneWord = 0x1f; 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_common_params_size = 0xa0; 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; uint256 constant BasicOrder_basicOrderType_range = 0x18; // 24 values /* * Memory layout in _prepareBasicFulfillmentFromCalldata of * EIP712 data for ConsiderationItem * - 0x80: ConsiderationItem EIP-712 typehash (constant) * - 0xa0: itemType * - 0xc0: token * - 0xe0: identifier * - 0x100: startAmount * - 0x120: endAmount * - 0x140: recipient */ uint256 constant BasicOrder_considerationItem_typeHash_ptr = 0x80; // memoryPtr uint256 constant BasicOrder_considerationItem_itemType_ptr = 0xa0; uint256 constant BasicOrder_considerationItem_token_ptr = 0xc0; uint256 constant BasicOrder_considerationItem_identifier_ptr = 0xe0; uint256 constant BasicOrder_considerationItem_startAmount_ptr = 0x100; uint256 constant BasicOrder_considerationItem_endAmount_ptr = 0x120; // uint256 constant BasicOrder_considerationItem_recipient_ptr = 0x140; /* * Memory layout in _prepareBasicFulfillmentFromCalldata of * EIP712 data for OfferItem * - 0x80: OfferItem EIP-712 typehash (constant) * - 0xa0: itemType * - 0xc0: token * - 0xe0: identifier (reused for offeredItemsHash) * - 0x100: startAmount * - 0x120: endAmount */ uint256 constant BasicOrder_offerItem_typeHash_ptr = 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: _counters[orderParameters.offerer] (from storage) */ uint256 constant BasicOrder_order_typeHash_ptr = 0x80; uint256 constant BasicOrder_order_offerer_ptr = 0xa0; // uint256 constant BasicOrder_order_zone_ptr = 0xc0; uint256 constant BasicOrder_order_offerHashes_ptr = 0xe0; uint256 constant BasicOrder_order_considerationHashes_ptr = 0x100; uint256 constant BasicOrder_order_orderType_ptr = 0x120; uint256 constant BasicOrder_order_startTime_ptr = 0x140; // uint256 constant BasicOrder_order_endTime_ptr = 0x160; // uint256 constant BasicOrder_order_zoneHash_ptr = 0x180; // uint256 constant BasicOrder_order_salt_ptr = 0x1a0; // uint256 constant BasicOrder_order_conduitKey_ptr = 0x1c0; uint256 constant BasicOrder_order_counter_ptr = 0x1e0; uint256 constant BasicOrder_additionalRecipients_head_ptr = 0x240; uint256 constant BasicOrder_signature_ptr = 0x260; // Signature-related bytes32 constant EIP2098_allButHighestBitMask = ( 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ); bytes32 constant ECDSA_twentySeventhAndTwentyEighthBytesSet = ( 0x0000000000000000000000000000000000000000000000000000000101000000 ); uint256 constant ECDSA_MaxLength = 65; uint256 constant ECDSA_signature_s_offset = 0x40; uint256 constant ECDSA_signature_v_offset = 0x60; bytes32 constant EIP1271_isValidSignature_selector = ( 0x1626ba7e00000000000000000000000000000000000000000000000000000000 ); uint256 constant EIP1271_isValidSignature_signatureHead_negativeOffset = 0x20; uint256 constant EIP1271_isValidSignature_digest_negativeOffset = 0x40; uint256 constant EIP1271_isValidSignature_selector_negativeOffset = 0x44; uint256 constant EIP1271_isValidSignature_calldata_baseLength = 0x64; uint256 constant EIP1271_isValidSignature_signature_head_offset = 0x40; // 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; // 512 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 MaxUint8 = 0xff; uint256 constant MaxUint120 = 0xffffffffffffffffffffffffffffff; uint256 constant Conduit_execute_ConduitTransfer_ptr = 0x20; uint256 constant Conduit_execute_ConduitTransfer_length = 0x01; uint256 constant Conduit_execute_ConduitTransfer_offset_ptr = 0x04; uint256 constant Conduit_execute_ConduitTransfer_length_ptr = 0x24; uint256 constant Conduit_execute_transferItemType_ptr = 0x44; uint256 constant Conduit_execute_transferToken_ptr = 0x64; uint256 constant Conduit_execute_transferFrom_ptr = 0x84; uint256 constant Conduit_execute_transferTo_ptr = 0xa4; uint256 constant Conduit_execute_transferIdentifier_ptr = 0xc4; uint256 constant Conduit_execute_transferAmount_ptr = 0xe4; uint256 constant OneConduitExecute_size = 0x104; // Sentinel value to indicate that the conduit accumulator is not armed. uint256 constant AccumulatorDisarmed = 0x20; uint256 constant AccumulatorArmed = 0x40; uint256 constant Accumulator_conduitKey_ptr = 0x20; uint256 constant Accumulator_selector_ptr = 0x40; uint256 constant Accumulator_array_offset_ptr = 0x44; uint256 constant Accumulator_array_length_ptr = 0x64; uint256 constant Accumulator_itemSizeOffsetDifference = 0x3c; uint256 constant Accumulator_array_offset = 0x20; uint256 constant Conduit_transferItem_size = 0xc0; uint256 constant Conduit_transferItem_token_ptr = 0x20; uint256 constant Conduit_transferItem_from_ptr = 0x40; uint256 constant Conduit_transferItem_to_ptr = 0x60; uint256 constant Conduit_transferItem_identifier_ptr = 0x80; uint256 constant Conduit_transferItem_amount_ptr = 0xa0; // Declare constant for errors related to amount derivation. // error InexactFraction() @ AmountDerivationErrors.sol uint256 constant InexactFraction_error_signature = ( 0xc63cf08900000000000000000000000000000000000000000000000000000000 ); uint256 constant InexactFraction_error_len = 0x04; // Declare constant for errors related to signature verification. uint256 constant Ecrecover_precompile = 1; uint256 constant Ecrecover_args_size = 0x80; uint256 constant Signature_lower_v = 27; // error BadSignatureV(uint8) @ SignatureVerificationErrors.sol uint256 constant BadSignatureV_error_signature = ( 0x1f003d0a00000000000000000000000000000000000000000000000000000000 ); uint256 constant BadSignatureV_error_offset = 0x04; uint256 constant BadSignatureV_error_length = 0x24; // error InvalidSigner() @ SignatureVerificationErrors.sol uint256 constant InvalidSigner_error_signature = ( 0x815e1d6400000000000000000000000000000000000000000000000000000000 ); uint256 constant InvalidSigner_error_length = 0x04; // error InvalidSignature() @ SignatureVerificationErrors.sol uint256 constant InvalidSignature_error_signature = ( 0x8baa579f00000000000000000000000000000000000000000000000000000000 ); uint256 constant InvalidSignature_error_length = 0x04; // error BadContractSignature() @ SignatureVerificationErrors.sol uint256 constant BadContractSignature_error_signature = ( 0x4f7fb80d00000000000000000000000000000000000000000000000000000000 ); uint256 constant BadContractSignature_error_length = 0x04; uint256 constant NumBitsAfterSelector = 0xe0; // 69 is the lowest modulus for which the remainder // of every selector other than the two match functions // is greater than those of the match functions. uint256 constant NonMatchSelector_MagicModulus = 69; // Of the two match function selectors, the highest // remainder modulo 69 is 29. uint256 constant NonMatchSelector_MagicRemainder = 0x1d;
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. * * _Available since v4.1._ */ interface IERC1271 { /** * @dev Should return whether the signature provided is valid for the provided data * @param hash Hash of the data to be signed * @param signature Signature byte array associated with _data */ function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bytes4","name":"interfaceHash","type":"bytes4"}],"name":"checkInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"conduitController","outputs":[{"internalType":"contract ConduitControllerInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creatorFeeEngine","outputs":[{"internalType":"contract CreatorFeeEngineInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"conduitKey","type":"bytes32"}],"name":"getApprovalAddress","outputs":[{"internalType":"address","name":"","type":"address"},{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"transactionAmountStart","type":"uint256"},{"internalType":"uint256","name":"transactionAmountEnd","type":"uint256"}],"name":"getCreatorFeeInfo","outputs":[{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"uint256","name":"creatorFeeAmountStart","type":"uint256"},{"internalType":"uint256","name":"creatorFeeAmountEnd","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"includedTokens","type":"uint256[]"},{"internalType":"uint256","name":"targetIndex","type":"uint256"}],"name":"getMerkleProof","outputs":[{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"},{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"includedTokens","type":"uint256[]"}],"name":"getMerkleRoot","outputs":[{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"}],"name":"isPaymentToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"conduitKey","type":"bytes32"}],"name":"isValidConduit","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"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":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Order","name":"order","type":"tuple"}],"name":"isValidOrder","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"primaryFeeRecipient","type":"address"},{"internalType":"uint256","name":"primaryFeeBips","type":"uint256"},{"internalType":"bool","name":"checkCreatorFee","type":"bool"},{"internalType":"bool","name":"skipStrictValidation","type":"bool"},{"internalType":"uint256","name":"shortOrderDuration","type":"uint256"},{"internalType":"uint256","name":"distantOrderExpiration","type":"uint256"}],"internalType":"struct ValidationConfiguration","name":"validationConfiguration","type":"tuple"},{"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"}],"name":"isValidOrderWithConfiguration","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"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":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"}],"name":"isValidZone","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"seaport","outputs":[{"internalType":"contract ConsiderationInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"includedTokens","type":"uint256[]"}],"name":"sortMerkleTokens","outputs":[{"internalType":"uint256[]","name":"sortedTokens","type":"uint256[]"}],"stateMutability":"pure","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":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"internalType":"uint256","name":"considerationItemIndex","type":"uint256"}],"name":"validateConsiderationItem","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"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":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"internalType":"uint256","name":"considerationItemIndex","type":"uint256"}],"name":"validateConsiderationItemParameters","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"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":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"}],"name":"validateConsiderationItems","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"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":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"internalType":"uint256","name":"offerItemIndex","type":"uint256"}],"name":"validateOfferItem","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"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":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"internalType":"uint256","name":"offerItemIndex","type":"uint256"}],"name":"validateOfferItemApprovalAndBalance","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"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":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"internalType":"uint256","name":"offerItemIndex","type":"uint256"}],"name":"validateOfferItemParameters","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"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":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"}],"name":"validateOfferItems","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"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":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"}],"name":"validateOrderStatus","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"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":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Order","name":"order","type":"tuple"}],"name":"validateSignature","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"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":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Order","name":"order","type":"tuple"},{"internalType":"uint256","name":"counter","type":"uint256"}],"name":"validateSignatureWithCounter","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"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":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"internalType":"address","name":"primaryFeeRecipient","type":"address"},{"internalType":"uint256","name":"primaryFeeBips","type":"uint256"},{"internalType":"bool","name":"checkCreatorFee","type":"bool"}],"name":"validateStrictLogic","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"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":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"internalType":"uint256","name":"shortOrderDuration","type":"uint256"},{"internalType":"uint256","name":"distantOrderExpiration","type":"uint256"}],"name":"validateTime","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"},{"internalType":"uint256","name":"valueToProve","type":"uint256"}],"name":"verifyMerkleProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"}]
Contract Creation Code
6101806040523480156200001257600080fd5b50604080518082018252600781526614d9585c1bdc9d60ca1b6020918201527f32b5c112df393a49218d7552f96b2eeb829dfb4272f4f24eef510a586b85feef608052815180830183526003815262312e3160e81b908201527f722c0e0c80487266e8c6a45e3a1a803aab23378a9c32e6ebe029d4fad7bfc96560a05290516000916200014f91016909ecccccae492e8cada560b31b81526e1d5a5b9d0e081a5d195b551e5c194b608a1b600a8201526d1859191c995cdcc81d1bdad95b8b60921b60198201527f75696e74323536206964656e7469666965724f7243726974657269612c00000060278201527f75696e74323536207374617274416d6f756e742c0000000000000000000000006044820152701d5a5b9d0c8d4d88195b99105b5bdd5b9d607a1b6058820152602960f81b6069820152606a0190565b60408051601f1981840301815282825271086dedce6d2c8cae4c2e8d2dedc92e8cada560731b60208401526e1d5a5b9d0e081a5d195b551e5c194b608a1b60328401526d1859191c995cdcc81d1bdad95b8b60921b60418401527f75696e74323536206964656e7469666965724f7243726974657269612c000000604f8401527f75696e74323536207374617274416d6f756e742c000000000000000000000000606c840152711d5a5b9d0c8d4d88195b99105b5bdd5b9d0b60721b6080840152701859191c995cdcc81c9958da5c1a595b9d607a1b6092840152602960f81b60a384018190528251808503608401815260a485019093526f09ee4c8cae486dedae0dedccadce8e6560831b60c48501526f1859191c995cdcc81bd999995c995c8b60821b60d48501526c1859191c995cdcc81e9bdb994b609a1b60e48501527113d999995c925d195b56d7481bd999995c8b60721b60f18501527f436f6e73696465726174696f6e4974656d5b5d20636f6e73696465726174696f610103850152611b8b60f21b6101238501526f1d5a5b9d0e081bdc99195c951e5c194b60821b610125850152711d5a5b9d0c8d4d881cdd185c9d151a5b594b60721b6101358501526f1d5a5b9d0c8d4d88195b99151a5b594b60821b61014785015270189e5d195ccccc881e9bdb9952185cda0b607a1b6101578501526c1d5a5b9d0c8d4d881cd85b1d0b609a1b6101688501527f6279746573333220636f6e647569744b65792c000000000000000000000000006101758501526e3ab4b73a191a9b1031b7bab73a32b960891b6101888501526101978401529250906000906101980160408051601f19818403018152908290528451602086810191909120855186830120929450926200046a91016c08a92a06e626488dedac2d2dc5609b1b81526b1cdd1c9a5b99c81b985b594b60a21b600d8201526e1cdd1c9a5b99c81d995c9cda5bdb8b608a1b60198201526f1d5a5b9d0c8d4d8818da185a5b92590b60821b60288201527f6164647265737320766572696679696e67436f6e7472616374000000000000006038820152602960f81b605182015260520190565b60408051601f1981840301815290829052805160209182012060c05260e0849052610100839052620004a3918591879189910162000676565b60408051808303601f1901815282825280516020918201206101205260c080516080805160a080518689019490945287870191909152606087019290925246908601526e6c3852cbef3e08e8df289169ede581818601528351808603909101815293019091528151910120610140525060009350504660010391506200054190505750730385603ab55642cb4dd5de3ae9e306809991804f62000625565b4660030362000566575073ff5a6f7f36764aad301b7c9e85a5277614df5e2662000625565b466004036200058b5750738d17687ea9a6bb6efa24ec11dcfab01661b2ddcd62000625565b46600503620005b0575073e7c9cb6d966f76f3b5142167088927bf34966a1f62000625565b46602a03620005d557507354d88324cbedffe1e62c9a59ebb310a11c29519862000625565b46608903620005fa57507328edfcf0be7e86b07493466e7631a213bde8eef262000625565b466201388103620006215750730a01e11887f727d1b1cd81251eeee9bee4262d0762000625565b5060005b6001600160a01b031661016052620006a3565b6000815160005b818110156200065b57602081850181015186830152016200063f565b818111156200066b576000828601525b509290920192915050565b60006200069a620006936200068c848862000638565b8662000638565b8462000638565b95945050505050565b60805160a05160c05160e05161010051610120516101405161016051614ff2620007156000396000818161042c0152818161063b01528181610695015261078301526000610edc015260006123e4015260006139a5015260006139370152600050506000505060005050614ff26000f3fe608060405234801561001057600080fd5b50600436106101a95760003560e01c806350f9cb63116100f9578063b0cedcb411610097578063de6fe09011610071578063de6fe09014610401578063df48c75014610414578063f11deea614610427578063f5c7bd701461044e57600080fd5b8063b0cedcb4146103c8578063b7f1667d146103db578063d023ff2c146103ee57600080fd5b8063713532a6116100d3578063713532a61461036e57806383f4127a14610381578063acfdf2ac146103a2578063b0517ff2146103b557600080fd5b806350f9cb63146103355780635c199be91461034857806361af055d1461035b57600080fd5b80632df7ec571161016657806339dad9071161014057806339dad907146102bf5780634534fe04146102d25780634710042e146102e55780634bd6aafd1461030657600080fd5b80632df7ec57146102795780632f5d94d71461028c57806334773ca3146102ac57600080fd5b80630a959489146101ae5780630f5aa50f146101d757806310941e95146101ea57806326a1ccaf1461022257806326affb001461023557806328e5252814610258575b600080fd5b6101c16101bc366004614296565b610464565b6040516101ce9190614337565b60405180910390f35b6101c16101e536600461434a565b6105ec565b6101fd6101f836600461438e565b610635565b604080516001600160a01b0390941684526020840192909252908201526060016101ce565b6101c16102303660046143c9565b6109bf565b6102486102433660046143e2565b6109e3565b60405190151581526020016101ce565b61026b6102663660046143c9565b610a25565b6040516101ce929190614486565b6101c161028736600461434a565b610b2b565b61029f61029a366004614510565b610b6f565b6040516101ce9190614544565b6101c16102ba366004614296565b610b7a565b6101c16102cd366004614644565b610d2b565b6101c16102e0366004614687565b610f61565b6102f86102f3366004614734565b611027565b6040516101ce929190614769565b61031d6ff9490004c11cef243f5400493c00ad6381565b6040516001600160a01b0390911681526020016101ce565b6101c16103433660046147b6565b61105b565b6101c161035636600461434a565b611148565b610248610369366004614819565b61152f565b6101c161037c366004614852565b61158c565b61039461038f366004614510565b61162a565b6040516101ce929190614886565b6101c16103b0366004614296565b61165c565b6102486103c336600461489f565b6117b5565b6101c16103d6366004614296565b6117ec565b6101c16103e936600461434a565b6119a7565b6101c16103fc36600461434a565b611c62565b6101c161040f3660046148ba565b6120d9565b6101c1610422366004614925565b612231565b61031d7f000000000000000000000000000000000000000000000000000000000000000081565b61031d6e6c3852cbef3e08e8df289169ede58181565b6040805180820182526060808252602091820181905282516000818501818152928201855291815283518281528084018552818401528451845163f07ec37360e01b81526001600160a01b0390911660048201529351909391926e6c3852cbef3e08e8df289169ede5819263f07ec37392602480830193928290030181865afa1580156104f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610519919061495f565b905060006105278483612283565b6040516346423aa760e01b815260048101829052909150600090819081906e6c3852cbef3e08e8df289169ede581906346423aa790602401608060405180830381865afa15801561057c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a09190614978565b9350935093505082156105c1576105c16105ba60006124b7565b87906124d7565b6000811180156105d057508082145b156105e2576105e26105ba60016124b7565b5050505050919050565b604080518082019091526060808252602082015261060a8383611148565b9050610617815151151590565b61062f5761062f6106288484611c62565b82906124e9565b92915050565b600080807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161561081557604051630f84100560e21b81526001600160a01b03888116600483015260248201889052604482018790527f00000000000000000000000000000000000000000000000000000000000000001690633e10401490606401600060405180830381865afa9250505080156106fd57506040513d6000823e601f3d908101601f191682016040526106fa9190810190614a31565b60015b1561074757815115610744578160008151811061071c5761071c614aeb565b602002602001015194508060008151811061073957610739614aeb565b602002602001015193505b50505b6001600160a01b0383161561081057604051630f84100560e21b81526001600160a01b03888116600483015260248201889052604482018690527f00000000000000000000000000000000000000000000000000000000000000001690633e10401490606401600060405180830381865afa9250505080156107eb57506040513d6000823e601f3d908101601f191682016040526107e89190810190614a31565b60015b15610810578060008151811061080357610803614aeb565b6020026020010151925050505b6109b5565b6040805160248101889052604480820188905282518083039091018152606490910182526020810180516001600160e01b031663152a902d60e11b179052905160009182916001600160a01b038b169161086e91614b31565b600060405180830381855afa9150503d80600081146108a9576040519150601f19603f3d011682016040523d82523d6000602084013e6108ae565b606091505b509150915081156108dc5780516040036108dc57808060200190518101906108d69190614b4d565b90955093505b50506001600160a01b038316156109b5576040805160248101889052604480820187905282518083039091018152606490910182526020810180516001600160e01b031663152a902d60e11b179052905160009182916001600160a01b038b169161094691614b31565b600060405180830381855afa9150503d8060008114610981576040519150601f19603f3d011682016040523d82523d6000602084013e610986565b606091505b509150915081156109b25780516040036109b257808060200190518101906109ae9190614b4d565b9350505b50505b9450945094915050565b60408051808201909152606080825260208201526109dc82610a25565b9392505050565b600080826040516020016109f991815260200190565b604051602081830303815290604052805190602001209050610a1c858583612519565b95945050505050565b6000610a44604051806040016040528060608152602001606081525090565b506040805160008183018181526060830184528252825181815260208082019094529282019290925290839003610a8c576e6c3852cbef3e08e8df289169ede5819150915091565b604051636e9bfd9f60e01b81526004810184905260009081906ff9490004c11cef243f5400493c00ad6390636e9bfd9f906024016040805180830381865afa158015610adc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b009190614b7b565b9150915080610b2257610b1d610b166000612563565b84906124d7565b600091505b50939092509050565b6040805180820182526060808252602091820181905282516000818501818152928201855291815283519182528183019093529082015261062f61062884846119a7565b606061062f82612580565b604080518082018252606080825260209182018190528251600081850181815282840186528252845181815280850190955292810193909352830151519003610bd657610bd1610bca600461274f565b829061276f565b919050565b60005b826060015151811015610d2557610bfa610bf38483610b2b565b83906124e9565b600083606001518281518110610c1257610c12614aeb565b602002602001015190506000826001610c2b9190614bc0565b90505b846060015151811015610d1057600085606001518281518110610c5357610c53614aeb565b6020026020010151905082600001516005811115610c7357610c736149c0565b81516005811115610c8657610c866149c0565b148015610cac575082602001516001600160a01b031681602001516001600160a01b0316145b8015610cbf575082604001518160400151145b8015610ce457508260a001516001600160a01b03168160a001516001600160a01b0316145b15610cfd57610cfd610cf6600561274f565b869061276f565b5080610d0881614bd8565b915050610c2e565b50508080610d1d90614bd8565b915050610bd9565b50919050565b604080518082018252606080825260209182018190528251600081850181815292820185529181528351828152808401855281840152855151845163f07ec37360e01b81526001600160a01b0390911660048201529351909391926e6c3852cbef3e08e8df289169ede5819263f07ec37392602480830193928290030181865afa158015610dbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de1919061495f565b905082811115610e0557610dff610df8600161277d565b83906124d7565b5061062f565b600283118015610e1e5750610e1b600284614bf1565b81105b15610e3757610e37610e30600261277d565b839061276f565b6000610e47856000015185612283565b6040516346423aa760e01b8152600481018290529091506000906e6c3852cbef3e08e8df289169ede581906346423aa790602401608060405180830381865afa158015610e98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ebc9190614978565b50505090508015610ecf5750505061062f565b61190160f01b60009081527f00000000000000000000000000000000000000000000000000000000000000006002526022838152604282209190528651516020880151610f1e9190839061279d565b610f575786516101408101516060909101515114610f4357610f43610cf6600361277d565b610f57610f50600061277d565b86906124d7565b5050505092915050565b604080518082018252606080825260209182018190528251600081850181815292820185529181528351918252818301909352908201528151608084015160a0850151610fb39261062892909161105b565b610fc36106288360000151610464565b610fd3610628836000015161165c565b610fe36106288360000151610b7a565b610ff361062883600001516117ec565b610fff6106288361158c565b826060015161062f5761062f61062883600001518560000151866020015187604001516120d9565b6060611046604051806040016040528060608152602001606081525090565b611050848461292f565b909590945092505050565b6040805180820182526060808252602091820181905282516000818501818152928201855291815283519182528183019093529082015260a084015160c0850151116110ba576110b56110ae6000612b30565b82906124d7565b6109dc565b428460c0015110156110d3576110b56110ae6001612b30565b6110dd8242614bc0565b8460c0015111156110f5576110f5610bca6002612b30565b428460a00151111561110e5761110e610bca6003612b30565b82428560a00151116111205742611126565b8460a001515b8560c001516111359190614bf1565b10156109dc576109dc610bca6004612b30565b6040805180820182526060808252602091820181905282516000818501818152928201855291815283518281528084018552928101929092529184015180519192918490811061119a5761119a614aeb565b60200260200101519050806060015160001480156111ba57506080810151155b156111cc57610dff610df86001612b50565b80608001518160600151141580156111eb57508360a001518460c00151115b156112e1576000808260800151836060015111611211578260800151836060015161121c565b826060015183608001515b9092509050600061122d8284614bf1565b905060008760a001518860c001516112459190614bf1565b9050600081611259846402540be400614c08565b6112639190614c3d565b9050600061127386612710614c08565b61127d9083614c3d565b90506101168111156112a25761129d6112966005612b50565b89906124d7565b6112bf565b601c8111156112bf576112bf6112b86005612b50565b899061276f565b66038d7ea4c6800085116112da576112da6112b86006612b50565b5050505050505b6002815160058111156112f6576112f66149c0565b03611351578060600151600114158061131457508060800151600114155b1561132657611326610df86000612b70565b61133b81602001516380ac58cd60e01b61152f565b61134c5761134c610df86001612b70565b611528565b600481516005811115611366576113666149c0565b036113e65761138081602001516380ac58cd60e01b61152f565b61139157611391610df86001612b70565b6001816060015111806113a8575060018160800151115b1561134c576002846080015160038111156113c5576113c56149c0565b6113cf9190614c51565b60ff1660000361134c5761134c610df86005612b70565b6003815160058111156113fb576113fb6149c0565b14806114195750600581516005811115611417576114176149c0565b145b15611444576114338160200151636cdb3d1360e11b61152f565b61134c5761134c610df86000612b90565b600181516005811115611459576114596149c0565b036114f15760408101511561147557611475610df86000612bb0565b604080516e6c3852cbef3e08e8df289169ede58160248201819052604480830191909152825180830390910181526064909101909152602080820180516001600160e01b0316636eb1769f60e11b1790528201516114e0916001600160a01b03909116906000612bcf565b61134c5761134c610df86001612bb0565b60208101516001600160a01b03161561151157611511610df86000612c76565b60408101511561152857611528610df86001612c76565b5092915050565b604080516001600160e01b031983166024808301919091528251808303909101815260449091019091526020810180516001600160e01b03166301ffc9a760e01b1790526000906109dc906001600160a01b038516906001612c96565b604080518082019091526060808252602082015281515160405163f07ec37360e01b81526001600160a01b0390911660048201526000906e6c3852cbef3e08e8df289169ede5819063f07ec37390602401602060405180830381865afa1580156115fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161e919061495f565b90506109dc8382610d2b565b6000611649604051806040016040528060608152602001606081525090565b61165283612da2565b9094909350915050565b60408051808201825260608082526020918201819052825160008185018181529282018552918152835182815280840190945291820192909252905b82604001515181101561177f576116b2610bf384836105ec565b6000836040015182815181106116ca576116ca614aeb565b6020026020010151905060008260016116e39190614bc0565b90505b84604001515181101561176a5760008560400151828151811061170b5761170b614aeb565b6020026020010151905080602001516001600160a01b031683602001516001600160a01b0316148015611745575080604001518360400151145b1561175757611757610f506004612b50565b508061176281614bd8565b9150506116e6565b5050808061177790614bd8565b915050611698565b5081604001515160000361179a5761179a6110ae6000612b50565b60018260400151511115610bd157610bd1610bca6002612b50565b6000808260058111156117ca576117ca6149c0565b148061062f575060018260058111156117e5576117e56149c0565b1492915050565b604080518082018252606080825260209182018190528251600081850181815292820185529181528351918252818301909352908201526080820151600290600381111561183c5761183c6149c0565b60ff16101561184a57919050565b60208201516001600160a01b031661186957610bd16110ae6001612ec5565b81602001516001600160a01b03163b60000361188457919050565b815160405163f07ec37360e01b81526001600160a01b0390911660048201526000906e6c3852cbef3e08e8df289169ede5819063f07ec37390602401602060405180830381865afa1580156118dd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611901919061495f565b90506119966303874c7760e21b6119188584612283565b855160e087015160405160248101939093523360448401526001600160a01b039091166064830152608482015260a40160408051601f19818403018152919052602080820180516001600160e01b03166001600160e01b031990941693909317909252908501516001600160a01b0316906303874c7760e21b612ee5565b610d2557610d25610e306000612ec5565b6040805180820182526060808252602091820181905282516000818501818152828401865282528451818152808501909552928101939093528401518051849081106119f5576119f5614aeb565b6020026020010151905080606001516000148015611a1557506080810151155b15611a2757610dff610df8600061274f565b60a08101516001600160a01b0316611a4657611a46610df8600161274f565b8060800151816060015114158015611a6557508360a001518460c00151115b15611b4d576000808260800151836060015111611a8b5782608001518360600151611a96565b826060015183608001515b90925090506000611aa78284614bf1565b905060008760a001518860c00151611abf9190614bf1565b9050600081611ad3846402540be400614c08565b611add9190614c3d565b90506000611aed86612710614c08565b611af79083614c3d565b9050610116811115611b1557611b10611296600761274f565b611b2b565b601c811115611b2b57611b2b6112b8600761274f565b66038d7ea4c680008511611b4657611b466112b8600861274f565b5050505050505b600281516005811115611b6257611b626149c0565b03611c335780606001516001141580611b8057508060800151600114155b15611b9257611b92610df86000612b70565b611ba781602001516380ac58cd60e01b61152f565b611bb857610dff610df86001612b70565b611c22636352211e60e01b8260400151604051602401611bda91815260200190565b60408051601f19818403018152919052602080820180516001600160e01b03166001600160e01b031990941693909317909252908301516001600160a01b0316906001612bcf565b61134c5761134c610df86002612b70565b600481516005811115611c4857611c486149c0565b036113e65761133b81602001516380ac58cd60e01b61152f565b604080518082018252606080825260209182018190528251600081850181815292820185529181528351828152808401909452918201929092526101208401519091908190611cb090610a25565b9092509050611cbf83826124e9565b80515115611cce57505061062f565b600085604001518581518110611ce657611ce6614aeb565b6020026020010151905060026005811115611d0357611d036149c0565b81516005811115611d1657611d166149c0565b03611e775760208181015160408084015181516024808201929092528251808203909201825260440190915291820180516001600160e01b03166331a9108f60e11b17905287519091611d74916001600160a01b0384169190612fcb565b611d8557611d85610f506003612b70565b611dea63081812fc60e01b8360400151604051602401611da791815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526001600160a01b0383169086612fcb565b611e715786516040516001600160a01b0391821660248201529085166044820152611e609063e985e9c560e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526001600160a01b038316906001612c96565b611e7157611e71610f506004612b70565b506120d0565b600481516005811115611e8c57611e8c6149c0565b146120d057600381516005811115611ea657611ea66149c0565b03611fa157602081015186516040516001600160a01b0391821660248201529085166044820152611ee29063e985e9c560e01b90606401611e1c565b611ef357611ef3610f506001612b90565b60008260800151836060015110611f0e578260800151611f14565b82606001515b885160408086015190516001600160a01b0390921660248301526044820152909150611f8990627eeac760e11b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526001600160a01b0384169083612bcf565b611f9a57611f9a6105ba6002612b90565b50506120d0565b600581516005811115611fb657611fb66149c0565b146120d057600181516005811115611fd057611fd06149c0565b0361207d5760208101516080820151606083015160009111611ff6578260800151611ffc565b82606001515b88516040516001600160a01b039182166024820152908716604482015290915061203190636eb1769f60e11b90606401611f46565b612042576120426105ba6002612bb0565b87516040516001600160a01b03909116602482015261206c906370a0823160e01b90604401611f46565b611f9a57611f9a6105ba6003612bb0565b6000816080015182606001511061209857816080015161209e565b81606001515b90508087600001516001600160a01b03163110156120c3576120c3610f506002612c76565b610f57610cf66003612b50565b50505092915050565b6040805180820182526060808252602091820181905282516000818501818152928201855291815283519182528183018452918201529085015151600190811415806121285750606086015151155b15612135575060006121d5565b612160866040015160008151811061214f5761214f614aeb565b6020026020010151600001516117b5565b80156121815750612181866060015160008151811061214f5761214f614aeb565b1561218e575060006121d5565b6121a8866040015160008151811061214f5761214f614aeb565b1580156121cc57506121ca866060015160008151811061214f5761214f614aeb565b155b156121d5575060005b806121ed576121e7610df860006130ae565b50612229565b506000806121fd878787876130ca565b909250905061220c83826124e9565b81156122265761222661221f888461370e565b84906124e9565b50505b949350505050565b60408051808201825260608082526020808301829052835160c081018552600080825291810182905293840181905290830152610708608083015262eff10060a08301529061062f906102e084614c73565b6000808360400151516001600160401b038111156122a3576122a3613efe565b6040519080825280602002602001820160405280156122cc578160200160208202803683370190505b50905060008461014001516001600160401b038111156122ee576122ee613efe565b604051908082528060200260200182016040528015612317578160200160208202803683370190505b50905060005b85604001515181101561237d576123508660400151828151811061234357612343614aeb565b6020026020010151613933565b83828151811061236257612362614aeb565b602090810291909101015261237681614bd8565b905061231d565b5060005b8561014001518110156123e1576123b4866060015182815181106123a7576123a7614aeb565b60200260200101516139a1565b8282815181106123c6576123c6614aeb565b60209081029190910101526123da81614bd8565b9050612381565b507f0000000000000000000000000000000000000000000000000000000000000000856000015186602001518460405160200161241e9190614c7f565b60405160208183030381529060405280519060200120846040516020016124459190614c7f565b6040516020818303038152906040528051906020012089608001518a60a001518b60c001518c60e001518d61010001518e61012001518e6040516020016124979c9b9a99989796959493929190614cb5565b604051602081830303815290604052805190602001209250505092915050565b60008160018111156124cb576124cb6149c0565b61062f90610320614d2f565b81516124e390826139f8565b90915250565b815181516124f79190613ada565b82526020808301519082015161250d9190613ada565b82602001819052505050565b81516000908290825b818110156125575761254d8387838151811061254057612540614aeb565b6020026020010151613c1e565b9250600101612522565b50509093149392505050565b6000818015612574576125746149c0565b61062f906103e8614d2f565b6060600082516001600160401b0381111561259d5761259d613efe565b6040519080825280602002602001820160405280156125e257816020015b60408051808201909152600080825260208201528152602001906001900390816125bb5790505b50905060005b835181101561269057604051806040016040528085838151811061260e5761260e614aeb565b6020026020010151815260200185838151811061262d5761262d614aeb565b602002602001015160405160200161264791815260200190565b6040516020818303038152906040528051906020012081525082828151811061267257612672614aeb565b6020026020010181905250808061268890614bd8565b9150506125e8565b506126aa816000600184516126a59190614bf1565b613c4b565b82516001600160401b038111156126c3576126c3613efe565b6040519080825280602002602001820160405280156126ec578160200160208202803683370190505b50915060005b83518110156127485781818151811061270d5761270d614aeb565b60200260200101516000015183828151811061272b5761272b614aeb565b60209081029190910101528061274081614bd8565b9150506126f2565b5050919050565b6000816008811115612763576127636149c0565b61062f906101f4614d2f565b61250d8260200151826139f8565b6000816003811115612791576127916149c0565b61062f9061044c614d2f565b60008080806001600160a01b0387163b156127c7576127bd878787613dd8565b93505050506109dc565b845160400361280e576000858060200190518101906127e69190614d55565b9094506001600160ff1b0381169350905061280660ff82901c601b614d79565b915050612886565b845160410361287a578480602001905181019061282b9190614d55565b865191945092508590604090811061284557612845614aeb565b016020015160f81c9050601b811480159061286457508060ff16601c14155b1561287557600093505050506109dc565b612886565b600093505050506109dc565b6040805160008082526020820180845289905260ff841692820192909252606081018590526080810184905260019060a0016020604051602081039080840390855afa1580156128da573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158061290f5750876001600160a01b0316816001600160a01b031614155b156129215760009450505050506109dc565b506001979650505050505050565b606061294e604051806040016040528060608152602001606081525090565b50604080516000818301818152606083018452825282519081526020808201909352918101919091528351600211156129a45761298e6110ae6000613e58565b6040805160008152602081019091529150612b29565b60006129af85613e78565b6129d7576129c0610df86001613e58565b506040805160008152602081019091529150612b29565b612aa4565b600082821080156129f45782600052836020526129fd565b83600052826020525b5050604060002092915050565b6000806001841660018114612a2457600285049250612a32565b600285046001019250600191505b5082602001806020860285015b80821015612a6d5781516020830151612a5881836129dc565b85525050602090920191604090910190612a3f565b508215612a9a5780516000888015612a9157612a8a6000846129dc565b9150612a95565b8291505b508352505b5050509392505050565b604051925082602001600086515b6001811115612b215760018781018214811b90881617808015612ae55760028114612af657886020028a01518552612afb565b886002016020028a01518552612afb565b600085525b5050826020019250600287049650816001019150612b1a84828a612a0a565b9050612ab2565b508452604052505b9250929050565b6000816004811115612b4457612b446149c0565b61062f90610384614d2f565b6000816006811115612b6457612b646149c0565b61062f90610258614d2f565b6000816005811115612b8457612b846149c0565b61062f9061012c614d2f565b6000816002811115612ba457612ba46149c0565b61062f90610190614d2f565b6000816003811115612bc457612bc46149c0565b61062f9060c8614d2f565b6000806000856001600160a01b031685604051612bec9190614b31565b600060405180830381855afa9150503d8060008114612c27576040519150601f19603f3d011682016040523d82523d6000602084013e612c2c565b606091505b509150915081612c41576000925050506109dc565b8051602014612c55576000925050506109dc565b8381806020019051810190612c6a919061495f565b10159695505050505050565b6000816002811115612c8a57612c8a6149c0565b61062f90610514614d2f565b6000806000856001600160a01b031685604051612cb39190614b31565b600060405180830381855afa9150503d8060008114612cee576040519150601f19603f3d011682016040523d82523d6000602084013e612cf3565b606091505b509150915081612d08576000925050506109dc565b8051602014612d1c576000925050506109dc565b612d2581614d9e565b612d2e82614d9e565b60011614612d41576000925050506109dc565b83612d6e5780601f81518110612d5957612d59614aeb565b01602001516001600160f81b03191615612d98565b80601f81518110612d8157612d81614aeb565b6020910101516001600160f81b031916600160f81b145b9695505050505050565b6000612dc1604051806040016040528060608152602001606081525090565b5060408051600081830181815260608301845282528251908152602080820190935291810191909152825160021115612e0b57612e016110ae6000613e58565b6000939092509050565b6000612e1684613e78565b612e3257612e27610df86001613e58565b506000939092509050565b612e9a565b6000806001841660018114612e5157600285049250612e5f565b600285046001019250600191505b5082602001806020860285015b80821015612a6d5781516020830151612e8581836129dc565b85525050602090920191604090910190612e6c565b83515b6001811115612eb857612eb1828287612e37565b9050612e9d565b5050602090920151929050565b6000816001811115612ed957612ed96149c0565b61062f90610578614d2f565b6000806000856001600160a01b031685604051612f029190614b31565b600060405180830381855afa9150503d8060008114612f3d576040519150601f19603f3d011682016040523d82523d6000602084013e612f42565b606091505b509150915081612f57576000925050506109dc565b8051602014612f6b576000925050506109dc565b612f7481614d9e565b612f7d82614d9e565b6001600160e01b03191614612f97576000925050506109dc565b836001600160e01b03191681806020019051810190612fb69190614dc2565b6001600160e01b031916149695505050505050565b6000806000856001600160a01b031685604051612fe89190614b31565b600060405180830381855afa9150503d8060008114613023576040519150601f19603f3d011682016040523d82523d6000602084013e613028565b606091505b50915091508161303d576000925050506109dc565b8051602014613051576000925050506109dc565b61305a81614d9e565b61306382614d9e565b6001600160a01b03161461307c576000925050506109dc565b836001600160a01b03168180602001905181019061309a9190614ddf565b6001600160a01b0316149695505050505050565b60008180156130bf576130bf6149c0565b61062f906064614d2f565b60006130e9604051806040016040528060608152602001606081525090565b506040805160008183018181526060808401855290835283518281526020808201865280850191909152845160c08101865283815290810183905293840182905283018190526080830181905260a08301819052909181908190819061315f8b6040015160008151811061214f5761214f614aeb565b1561327f578a6040015160008151811061317b5761317b614aeb565b6020026020010151600001518160000190600581111561319d5761319d6149c0565b908160058111156131b0576131b06149c0565b815250508a604001516000815181106131cb576131cb614aeb565b6020908102919091018101518101516001600160a01b03169082015260408b015180516000906131fd576131fd614aeb565b60200260200101516060015192508a6040015160008151811061322257613222614aeb565b60200260200101516080015191508a6060015160008151811061324757613247614aeb565b60200260200101516020015194508a6060015160008151811061326c5761326c614aeb565b6020026020010151604001519350613396565b8a6060015160008151811061329657613296614aeb565b602002602001015160000151816000019060058111156132b8576132b86149c0565b908160058111156132cb576132cb6149c0565b815250508a606001516000815181106132e6576132e6614aeb565b6020908102919091018101518101516001600160a01b03169082015260608b0151805160009061331857613318614aeb565b60200260200101516060015192508a6060015160008151811061333d5761333d614aeb565b60200260200101516080015191508a6040015160008151811061336257613362614aeb565b60200260200101516020015194508a6040015160008151811061338757613387614aeb565b60200260200101516040015193505b6000806127106133a68c87614c08565b6133b09190614c3d565b905060006127106133c18d87614c08565b6133cb9190614c3d565b90506001600160a01b038d16158015906133ef575060008211806133ef5750600081115b1561352e5760028e606001515110156134275761341661340f6000613ebe565b8a906124d7565b600099505050505050505050613705565b6001925060008e6060015160018151811061344457613444614aeb565b6020026020010151905084600001516005811115613464576134646149c0565b81516005811115613477576134776149c0565b146134a2576134906134896001613ebe565b8b906124d7565b60009a50505050505050505050613705565b84602001516001600160a01b031681602001516001600160a01b0316146134d0576134d06134896002613ebe565b82816060015110156134e9576134e96134896003613ebe565b8181608001511015613502576135026134896004613ebe565b8d6001600160a01b03168160a001516001600160a01b03161461352c5761352c6134896005613ebe565b505b505061353c86868686610635565b608085015260608401526001600160a01b031660a08301819052600090158015906135645750895b80156135825750600083606001511180613582575060008360800151115b156136c557600082613595576001613598565b60025b60ff1690508061ffff1660018f60600151516135b49190614bf1565b10156135c75761341661340f6000613ede565b60008e606001518261ffff16815181106135e3576135e3614aeb565b602002602001015190506001925084600001516005811115613607576136076149c0565b8151600581111561361a5761361a6149c0565b1461362c576134906134896001613ede565b84602001516001600160a01b031681602001516001600160a01b03161461365a5761365a6134896002613ede565b846060015181606001511015613677576136776134896003613ede565b846080015181608001511015613694576136946134896004613ede565b8460a001516001600160a01b03168160a001516001600160a01b0316146136c2576136c26134896005613ede565b50505b806136d15760006136d4565b60015b826136e05760006136e3565b60015b6136ee906001614d79565b6136f89190614d79565b60ff169850505050505050505b94509492505050565b604080518082018252606080825260209182018190528251600081850181815282840186528252845190815280840190945291820192909252908301515182101561062f5760008360600151838151811061376b5761376b614aeb565b6020026020010151905061378f846040015160008151811061214f5761214f614aeb565b156137a157610dff610df8600261274f565b83600001516001600160a01b03168160a001516001600160a01b0316036137cf57610dff610df8600361274f565b83604001516000815181106137e6576137e6614aeb565b6020026020010151600001516005811115613803576138036149c0565b81516005811115613816576138166149c0565b14158061385b5750836040015160008151811061383557613835614aeb565b6020026020010151602001516001600160a01b031681602001516001600160a01b031614155b8061388c57508060600151846040015160008151811061387d5761387d614aeb565b60200260200101516060015114155b806138bd5750806080015184604001516000815181106138ae576138ae614aeb565b60200260200101516080015114155b806138ee5750806040015184604001516000815181106138df576138df614aeb565b60200260200101516040015114155b1561390057610dff610df8600261274f565b61390d610e30600661274f565b8260018560600151516139209190614bf1565b111561152857610dff610df8600261274f565b60007f00000000000000000000000000000000000000000000000000000000000000008260000151836020015184604001518560600151866080015160405160200161398496959493929190614e10565b604051602081830303815290604052805190602001209050919050565b60007f0000000000000000000000000000000000000000000000000000000000000000826000015183602001518460400151856060015186608001518760a001516040516020016139849796959493929190614e51565b6060600083516001613a0a9190614bc0565b6001600160401b03811115613a2157613a21613efe565b604051908082528060200260200182016040528015613a4a578160200160208202803683370190505b50905060005b8451811015613aaa57848181518110613a6b57613a6b614aeb565b6020026020010151828281518110613a8557613a85614aeb565b61ffff9092166020928302919091019091015280613aa281614bd8565b915050613a50565b508281855181518110613abf57613abf614aeb565b61ffff90921660209283029190910190910152905092915050565b60608251600003613aec57508061062f565b8151600003613afc57508161062f565b600082518451613b0c9190614bc0565b6001600160401b03811115613b2357613b23613efe565b604051908082528060200260200182016040528015613b4c578160200160208202803683370190505b50905060005b8451811015613bac57848181518110613b6d57613b6d614aeb565b6020026020010151828281518110613b8757613b87614aeb565b61ffff9092166020928302919091019091015280613ba481614bd8565b915050613b52565b5060005b8351811015613c1657838181518110613bcb57613bcb614aeb565b602002602001015182865183613be19190614bc0565b81518110613bf157613bf1614aeb565b61ffff9092166020928302919091019091015280613c0e81614bd8565b915050613bb0565b509392505050565b60008183108015613c365783600052826020526129fd565b82600052836020525050604060002092915050565b8181808203613c5b575050505050565b6000856002613c6a8787614e9f565b613c749190614ede565b613c7e9087614f0c565b81518110613c8e57613c8e614aeb565b60200260200101516020015190505b818313613daa575b80868481518110613cb857613cb8614aeb565b6020026020010151602001511015613cdc5782613cd481614f4d565b935050613ca5565b858281518110613cee57613cee614aeb565b602002602001015160200151811015613d135781613d0b81614f65565b925050613cdc565b818313613da557858281518110613d2c57613d2c614aeb565b6020026020010151868481518110613d4657613d46614aeb565b6020026020010151878581518110613d6057613d60614aeb565b60200260200101888581518110613d7957613d79614aeb565b6020026020010182905282905250508280613d9390614f4d565b9350508180613da190614f65565b9250505b613c9d565b81851215613dbd57613dbd868684613c4b565b83831215613dd057613dd0868486613c4b565b505050505050565b6000613e42631626ba7e60e01b8484604051602401613df8929190614f82565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526001600160a01b03861690630b135d3f60e11b612ee5565b613e4e575060006109dc565b5060019392505050565b6000816001811115613e6c57613e6c6149c0565b61062f906105dc614d2f565b600160005b8251811015610d255760206001820181028401818120908190529082028401518215159111151615613eae57600091505b613eb781614bd8565b9050613e7d565b6000816005811115613ed257613ed26149c0565b61062f906102bc614d2f565b6000816005811115613ef257613ef26149c0565b61062f906104b0614d2f565b634e487b7160e01b600052604160045260246000fd5b60405160a081016001600160401b0381118282101715613f3657613f36613efe565b60405290565b60405160c081016001600160401b0381118282101715613f3657613f36613efe565b60405161016081016001600160401b0381118282101715613f3657613f36613efe565b604080519081016001600160401b0381118282101715613f3657613f36613efe565b604051601f8201601f191681016001600160401b0381118282101715613fcb57613fcb613efe565b604052919050565b6001600160a01b0381168114613fe857600080fd5b50565b8035610bd181613fd3565b60006001600160401b0382111561400f5761400f613efe565b5060051b60200190565b803560068110610bd157600080fd5b600082601f83011261403957600080fd5b8135602061404e61404983613ff6565b613fa3565b82815260a0928302850182019282820191908785111561406d57600080fd5b8387015b858110156140d85781818a0312156140895760008081fd5b614091613f14565b61409a82614019565b8152858201356140a981613fd3565b818701526040828101359082015260608083013590820152608080830135908201528452928401928101614071565b5090979650505050505050565b600082601f8301126140f657600080fd5b8135602061410661404983613ff6565b82815260c0928302850182019282820191908785111561412557600080fd5b8387015b858110156140d85781818a0312156141415760008081fd5b614149613f3c565b61415282614019565b81528582013561416181613fd3565b8187015260408281013590820152606080830135908201526080808301359082015260a08083013561419281613fd3565b908201528452928401928101614129565b803560048110610bd157600080fd5b600061016082840312156141c557600080fd5b6141cd613f5e565b90506141d882613feb565b81526141e660208301613feb565b602082015260408201356001600160401b038082111561420557600080fd5b61421185838601614028565b6040840152606084013591508082111561422a57600080fd5b50614237848285016140e5565b606083015250614249608083016141a3565b608082015260a082013560a082015260c082013560c082015260e082013560e082015261010080830135818301525061012080830135818301525061014080830135818301525092915050565b6000602082840312156142a857600080fd5b81356001600160401b038111156142be57600080fd5b612229848285016141b2565b600081518084526020808501945080840160005b838110156142fe57815161ffff16875295820195908201906001016142de565b509495945050505050565b600081516040845261431e60408501826142ca565b905060208301518482036020860152610a1c82826142ca565b6020815260006109dc6020830184614309565b6000806040838503121561435d57600080fd5b82356001600160401b0381111561437357600080fd5b61437f858286016141b2565b95602094909401359450505050565b600080600080608085870312156143a457600080fd5b84356143af81613fd3565b966020860135965060408601359560600135945092505050565b6000602082840312156143db57600080fd5b5035919050565b6000806000606084860312156143f757600080fd5b833592506020808501356001600160401b0381111561441557600080fd5b8501601f8101871361442657600080fd5b803561443461404982613ff6565b81815260059190911b8201830190838101908983111561445357600080fd5b928401925b8284101561447157833582529284019290840190614458565b96999698505050506040949094013593505050565b6001600160a01b038316815260406020820181905260009061222990830184614309565b600082601f8301126144bb57600080fd5b813560206144cb61404983613ff6565b82815260059290921b840181019181810190868411156144ea57600080fd5b8286015b8481101561450557803583529183019183016144ee565b509695505050505050565b60006020828403121561452257600080fd5b81356001600160401b0381111561453857600080fd5b612229848285016144aa565b6020808252825182820181905260009190848201906040850190845b8181101561457c57835183529284019291840191600101614560565b50909695505050505050565b60006040828403121561459a57600080fd5b6145a2613f81565b905081356001600160401b03808211156145bb57600080fd5b6145c7858386016141b2565b83526020915081840135818111156145de57600080fd5b8401601f810186136145ef57600080fd5b80358281111561460157614601613efe565b614613601f8201601f19168501613fa3565b9250808352868482840101111561462957600080fd5b80848301858501376000908301840152509082015292915050565b6000806040838503121561465757600080fd5b82356001600160401b0381111561466d57600080fd5b61437f85828601614588565b8015158114613fe857600080fd5b60008082840360e081121561469b57600080fd5b60c08112156146a957600080fd5b506146b2613f3c565b83356146bd81613fd3565b81526020848101359082015260408401356146d781614679565b604082015260608401356146ea81614679565b60608201526080848101359082015260a08085013590820152915060c08301356001600160401b0381111561471e57600080fd5b61472a85828601614588565b9150509250929050565b6000806040838503121561474757600080fd5b82356001600160401b0381111561475d57600080fd5b61437f858286016144aa565b604080825283519082018190526000906020906060840190828701845b828110156147a257815184529284019290840190600101614786565b50505083810382850152612d988186614309565b6000806000606084860312156147cb57600080fd5b83356001600160401b038111156147e157600080fd5b6147ed868287016141b2565b9660208601359650604090950135949350505050565b6001600160e01b031981168114613fe857600080fd5b6000806040838503121561482c57600080fd5b823561483781613fd3565b9150602083013561484781614803565b809150509250929050565b60006020828403121561486457600080fd5b81356001600160401b0381111561487a57600080fd5b61222984828501614588565b8281526040602082015260006122296040830184614309565b6000602082840312156148b157600080fd5b6109dc82614019565b600080600080608085870312156148d057600080fd5b84356001600160401b038111156148e657600080fd5b6148f2878288016141b2565b945050602085013561490381613fd3565b925060408501359150606085013561491a81614679565b939692955090935050565b60006020828403121561493757600080fd5b81356001600160401b0381111561494d57600080fd5b8201604081850312156109dc57600080fd5b60006020828403121561497157600080fd5b5051919050565b6000806000806080858703121561498e57600080fd5b845161499981614679565b60208601519094506149aa81614679565b6040860151606090960151949790965092505050565b634e487b7160e01b600052602160045260246000fd5b600082601f8301126149e757600080fd5b815160206149f761404983613ff6565b82815260059290921b84018101918181019086841115614a1657600080fd5b8286015b848110156145055780518352918301918301614a1a565b60008060408385031215614a4457600080fd5b82516001600160401b0380821115614a5b57600080fd5b818501915085601f830112614a6f57600080fd5b81516020614a7f61404983613ff6565b82815260059290921b84018101918181019089841115614a9e57600080fd5b948201945b83861015614ac5578551614ab681613fd3565b82529482019490820190614aa3565b91880151919650909350505080821115614ade57600080fd5b5061472a858286016149d6565b634e487b7160e01b600052603260045260246000fd5b60005b83811015614b1c578181015183820152602001614b04565b83811115614b2b576000848401525b50505050565b60008251614b43818460208701614b01565b9190910192915050565b60008060408385031215614b6057600080fd5b8251614b6b81613fd3565b6020939093015192949293505050565b60008060408385031215614b8e57600080fd5b8251614b9981613fd3565b602084015190925061484781614679565b634e487b7160e01b600052601160045260246000fd5b60008219821115614bd357614bd3614baa565b500190565b600060018201614bea57614bea614baa565b5060010190565b600082821015614c0357614c03614baa565b500390565b6000816000190483118215151615614c2257614c22614baa565b500290565b634e487b7160e01b600052601260045260246000fd5b600082614c4c57614c4c614c27565b500490565b600060ff831680614c6457614c64614c27565b8060ff84160691505092915050565b600061062f3683614588565b815160009082906020808601845b83811015614ca957815185529382019390820190600101614c8d565b50929695505050505050565b8c81526001600160a01b038c811660208301528b166040820152606081018a905260808101899052610180810160048910614cf257614cf26149c0565b60a082019890985260c081019690965260e08601949094526101008501929092526101208401526101408301526101609091015295945050505050565b600061ffff808316818516808303821115614d4c57614d4c614baa565b01949350505050565b60008060408385031215614d6857600080fd5b505080516020909101519092909150565b600060ff821660ff84168060ff03821115614d9657614d96614baa565b019392505050565b80516020808301519190811015610d255760001960209190910360031b1b16919050565b600060208284031215614dd457600080fd5b81516109dc81614803565b600060208284031215614df157600080fd5b81516109dc81613fd3565b60068110614e0c57614e0c6149c0565b9052565b86815260c08101614e246020830188614dfc565b6001600160a01b039590951660408201526060810193909352608083019190915260a09091015292915050565b87815260e08101614e656020830189614dfc565b6001600160a01b0396871660408301526060820195909552608081019390935260a083019190915290921660c09092019190915292915050565b60008083128015600160ff1b850184121615614ebd57614ebd614baa565b6001600160ff1b0384018313811615614ed857614ed8614baa565b50500390565b600082614eed57614eed614c27565b600160ff1b821460001984141615614f0757614f07614baa565b500590565b600080821280156001600160ff1b0384900385131615614f2e57614f2e614baa565b600160ff1b8390038412811615614f4757614f47614baa565b50500190565b60006001600160ff1b018201614bea57614bea614baa565b6000600160ff1b8201614f7a57614f7a614baa565b506000190190565b8281526040602082015260008251806040840152614fa7816060850160208701614b01565b601f01601f191691909101606001939250505056fea26469706673582212207b9adabd316d13e7345e5bd51166dea71dc67a4734557ca4320fc1bffeda06d264736f6c634300080e0033
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.