Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multi Chain
Multichain Addresses
N/ALatest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
0x60a08060 | 8515500 | 220 days 16 hrs ago | IN | Create: FlowOrderBookComplication | 0 ETH | 0.26535439 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Txn Hash | Block | From | To | Value | ||
---|---|---|---|---|---|---|
8896189 | 153 days 20 hrs ago | 0 ETH | ||||
8896189 | 153 days 20 hrs ago | 0 ETH | ||||
8896189 | 153 days 20 hrs ago | 0 ETH | ||||
8896189 | 153 days 20 hrs ago | 0 ETH | ||||
8896189 | 153 days 20 hrs ago | 0 ETH | ||||
8896189 | 153 days 20 hrs ago | 0 ETH | ||||
8896189 | 153 days 20 hrs ago | 0 ETH | ||||
8896189 | 153 days 20 hrs ago | 0 ETH | ||||
8896189 | 153 days 20 hrs ago | 0 ETH | ||||
8896189 | 153 days 20 hrs ago | 0 ETH | ||||
8896189 | 153 days 20 hrs ago | 0 ETH | ||||
8896189 | 153 days 20 hrs ago | 0 ETH | ||||
8851074 | 161 days 22 hrs ago | 0 ETH | ||||
8851074 | 161 days 22 hrs ago | 0 ETH | ||||
8851074 | 161 days 22 hrs ago | 0 ETH | ||||
8851074 | 161 days 22 hrs ago | 0 ETH | ||||
8851074 | 161 days 22 hrs ago | 0 ETH | ||||
8851074 | 161 days 22 hrs ago | 0 ETH | ||||
8850989 | 161 days 22 hrs ago | 0 ETH | ||||
8850989 | 161 days 22 hrs ago | 0 ETH | ||||
8850989 | 161 days 22 hrs ago | 0 ETH | ||||
8850989 | 161 days 22 hrs ago | 0 ETH | ||||
8850989 | 161 days 22 hrs ago | 0 ETH | ||||
8850989 | 161 days 22 hrs ago | 0 ETH | ||||
8850989 | 161 days 22 hrs ago | 0 ETH |
Loading...
Loading
Contract Name:
FlowOrderBookComplication
Compiler Version
v0.8.14+commit.80d49f37
Optimization Enabled:
Yes with 99999999 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT // solhint-disable not-rely-on-time pragma solidity 0.8.14; // external imports import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; // internal imports import { OrderTypes, SignatureChecker } from "../libs/SignatureChecker.sol"; import { IFlowComplication } from "../interfaces/IFlowComplication.sol"; /** * @title FlowOrderBookComplication * @author nneverlander. Twitter @nneverlander * @notice Complication to execute orderbook orders */ contract FlowOrderBookComplication is IFlowComplication, Ownable, SignatureChecker { using EnumerableSet for EnumerableSet.AddressSet; uint256 public constant PRECISION = 1e4; // precision for division; similar to bps /// @dev WETH address of the chain being used // solhint-disable-next-line var-name-mixedcase address public constant WETH = 0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6; // keccak256('Order(bool isSellOrder,address signer,uint256[] constraints,OrderItem[] nfts,address[] execParams,bytes extraParams)OrderItem(address collection,TokenInfo[] tokens)TokenInfo(uint256 tokenId,uint256 numTokens)') bytes32 public constant ORDER_HASH = 0x7bcfb5a29031e6b8d34ca1a14dd0a1f5cb11b20f755bb2a31ee3c4b143477e4a; // keccak256('OrderItem(address collection,TokenInfo[] tokens)TokenInfo(uint256 tokenId,uint256 numTokens)') bytes32 public constant ORDER_ITEM_HASH = 0xf73f37e9f570369ceaab59cef16249ae1c0ad1afd592d656afac0be6f63b87e0; // keccak256('TokenInfo(uint256 tokenId,uint256 numTokens)') bytes32 public constant TOKEN_INFO_HASH = 0x88f0bd19d14f8b5d22c0605a15d9fffc285ebc8c86fb21139456d305982906f1; /// @dev Used in order signing with EIP-712 // solhint-disable-next-line var-name-mixedcase bytes32 public immutable DOMAIN_SEPARATOR; /// @dev Storage variable that keeps track of valid currencies used for payment (tokens) EnumerableSet.AddressSet private _currencies; bool public trustedExecEnabled = false; event CurrencyAdded(address currency); event CurrencyRemoved(address currency); event TrustedExecutionChanged(bool oldVal, bool newVal); constructor() { // Calculate the domain separator DOMAIN_SEPARATOR = keccak256( abi.encode( keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ), keccak256("FlowComplication"), keccak256(bytes("1")), // for versionId = 1 block.chainid, address(this) ) ); // add default currencies _currencies.add(WETH); _currencies.add(address(0)); // ETH } // ======================================================= EXTERNAL FUNCTIONS ================================================== /** * @notice Checks whether one to one matches can be executed * @dev This function is called by the main exchange to check whether one to one matches can be executed. It checks whether orders have the right constraints - i.e they have one specific NFT only, whether time is still valid, prices are valid and whether the nfts intersect. * @param makerOrder1 first makerOrder * @param makerOrder2 second makerOrder * @return returns whether the order can be executed, orderHashes and the execution price */ function canExecMatchOneToOne( OrderTypes.MakerOrder calldata makerOrder1, OrderTypes.MakerOrder calldata makerOrder2 ) external view override returns (bool, bytes32, bytes32, uint256) { // check if the orders are valid bool _isPriceValid; uint256 makerOrder1Price = _getCurrentPrice(makerOrder1); uint256 makerOrder2Price = _getCurrentPrice(makerOrder2); uint256 execPrice; if (makerOrder1.isSellOrder) { _isPriceValid = makerOrder2Price >= makerOrder1Price; execPrice = makerOrder1Price; } else { _isPriceValid = makerOrder1Price >= makerOrder2Price; execPrice = makerOrder2Price; } bytes32 sellOrderHash = _hash(makerOrder1); bytes32 buyOrderHash = _hash(makerOrder2); if (trustedExecEnabled) { bool trustedExec = makerOrder2.constraints.length == 8 && makerOrder2.constraints[7] == 1 && makerOrder1.constraints.length == 8 && makerOrder1.constraints[7] == 1; if (trustedExec) { bool sigValid = SignatureChecker.verify( sellOrderHash, makerOrder1.signer, makerOrder1.sig, DOMAIN_SEPARATOR ) && SignatureChecker.verify( buyOrderHash, makerOrder2.signer, makerOrder2.sig, DOMAIN_SEPARATOR ); return (sigValid, sellOrderHash, buyOrderHash, execPrice); } } require( verifyMatchOneToOneOrders( sellOrderHash, buyOrderHash, makerOrder1, makerOrder2 ), "order not verified" ); // check constraints bool numItemsValid = makerOrder2.constraints[0] == makerOrder1.constraints[0] && makerOrder2.constraints[0] == 1 && makerOrder2.nfts.length == 1 && makerOrder2.nfts[0].tokens.length == 1 && makerOrder1.nfts.length == 1 && makerOrder1.nfts[0].tokens.length == 1; bool _isTimeValid = makerOrder2.constraints[3] <= block.timestamp && makerOrder2.constraints[4] >= block.timestamp && makerOrder1.constraints[3] <= block.timestamp && makerOrder1.constraints[4] >= block.timestamp; return ( numItemsValid && _isTimeValid && doItemsIntersect(makerOrder1.nfts, makerOrder2.nfts) && _isPriceValid, sellOrderHash, buyOrderHash, execPrice ); } /** * @dev This function is called by an offline checker to verify whether matches can be executed * irrespective of the trusted execution constraint */ function verifyCanExecMatchOneToOne( OrderTypes.MakerOrder calldata makerOrder1, OrderTypes.MakerOrder calldata makerOrder2 ) external view returns (bool, bytes32, bytes32, uint256) { // check if the orders are valid bool _isPriceValid; uint256 makerOrder1Price = _getCurrentPrice(makerOrder1); uint256 makerOrder2Price = _getCurrentPrice(makerOrder2); uint256 execPrice; if (makerOrder1.isSellOrder) { _isPriceValid = makerOrder2Price >= makerOrder1Price; execPrice = makerOrder1Price; } else { _isPriceValid = makerOrder1Price >= makerOrder2Price; execPrice = makerOrder2Price; } bytes32 sellOrderHash = _hash(makerOrder1); bytes32 buyOrderHash = _hash(makerOrder2); require( verifyMatchOneToOneOrders( sellOrderHash, buyOrderHash, makerOrder1, makerOrder2 ), "order not verified" ); // check constraints bool numItemsValid = makerOrder2.constraints[0] == makerOrder1.constraints[0] && makerOrder2.constraints[0] == 1 && makerOrder2.nfts.length == 1 && makerOrder2.nfts[0].tokens.length == 1 && makerOrder1.nfts.length == 1 && makerOrder1.nfts[0].tokens.length == 1; bool _isTimeValid = makerOrder2.constraints[3] <= block.timestamp && makerOrder2.constraints[4] >= block.timestamp && makerOrder1.constraints[3] <= block.timestamp && makerOrder1.constraints[4] >= block.timestamp; return ( numItemsValid && _isTimeValid && doItemsIntersect(makerOrder1.nfts, makerOrder2.nfts) && _isPriceValid, sellOrderHash, buyOrderHash, execPrice ); } /** * @notice Checks whether one to many matches can be executed * @dev This function is called by the main exchange to check whether one to many matches can be executed. It checks whether orders have the right constraints - i.e they have the right number of items, whether time is still valid, prices are valid and whether the nfts intersect. All orders are expected to contain specific items. * @param makerOrder the one makerOrder * @param manyMakerOrders many maker orders * @return returns whether the order can be executed and orderHash of the one side order */ function canExecMatchOneToMany( OrderTypes.MakerOrder calldata makerOrder, OrderTypes.MakerOrder[] calldata manyMakerOrders ) external view override returns (bool, bytes32) { bytes32 makerOrderHash = _hash(makerOrder); if (trustedExecEnabled) { bool isTrustedExec = makerOrder.constraints.length == 8 && makerOrder.constraints[7] == 1; for (uint256 i; i < manyMakerOrders.length; ) { isTrustedExec = isTrustedExec && manyMakerOrders[i].constraints.length == 8 && manyMakerOrders[i].constraints[7] == 1; if (!isTrustedExec) { break; // short circuit } unchecked { ++i; } } if (isTrustedExec) { bool sigValid = SignatureChecker.verify( makerOrderHash, makerOrder.signer, makerOrder.sig, DOMAIN_SEPARATOR ); return (sigValid, makerOrderHash); } } require( isOrderValid(makerOrder, makerOrderHash), "invalid maker order" ); // check the constraints of the 'one' maker order uint256 numNftsInOneOrder; for (uint256 i; i < makerOrder.nfts.length; ) { numNftsInOneOrder = numNftsInOneOrder + makerOrder.nfts[i].tokens.length; unchecked { ++i; } } // check the constraints of many maker orders uint256 totalNftsInManyOrders; bool numNftsPerManyOrderValid = true; bool isOrdersTimeValid = true; bool itemsIntersect = true; for (uint256 i; i < manyMakerOrders.length; ) { uint256 nftsLength = manyMakerOrders[i].nfts.length; uint256 numNftsPerOrder; for (uint256 j; j < nftsLength; ) { numNftsPerOrder = numNftsPerOrder + manyMakerOrders[i].nfts[j].tokens.length; unchecked { ++j; } } numNftsPerManyOrderValid = numNftsPerManyOrderValid && manyMakerOrders[i].constraints[0] == numNftsPerOrder; totalNftsInManyOrders = totalNftsInManyOrders + numNftsPerOrder; isOrdersTimeValid = isOrdersTimeValid && manyMakerOrders[i].constraints[3] <= block.timestamp && manyMakerOrders[i].constraints[4] >= block.timestamp; itemsIntersect = itemsIntersect && doItemsIntersect(makerOrder.nfts, manyMakerOrders[i].nfts); if (!numNftsPerManyOrderValid) { return (false, makerOrderHash); // short circuit } unchecked { ++i; } } bool _isTimeValid = isOrdersTimeValid && makerOrder.constraints[3] <= block.timestamp && makerOrder.constraints[4] >= block.timestamp; uint256 currentMakerOrderPrice = _getCurrentPrice(makerOrder); uint256 sumCurrentOrderPrices = _sumCurrentPrices(manyMakerOrders); bool _isPriceValid; if (makerOrder.isSellOrder) { _isPriceValid = sumCurrentOrderPrices >= currentMakerOrderPrice; } else { _isPriceValid = sumCurrentOrderPrices <= currentMakerOrderPrice; } return ( numNftsInOneOrder == makerOrder.constraints[0] && numNftsInOneOrder == totalNftsInManyOrders && _isTimeValid && itemsIntersect && _isPriceValid, makerOrderHash ); } /** * @dev This function is called by an offline checker to verify whether matches can be executed * irrespective of the trusted execution constraint */ function verifyCanExecMatchOneToMany( OrderTypes.MakerOrder calldata makerOrder, OrderTypes.MakerOrder[] calldata manyMakerOrders ) external view returns (bool, bytes32) { bytes32 makerOrderHash = _hash(makerOrder); require( isOrderValid(makerOrder, makerOrderHash), "invalid maker order" ); // check the constraints of the 'one' maker order uint256 numNftsInOneOrder; for (uint256 i; i < makerOrder.nfts.length; ) { numNftsInOneOrder = numNftsInOneOrder + makerOrder.nfts[i].tokens.length; unchecked { ++i; } } // check the constraints of many maker orders uint256 totalNftsInManyOrders; bool numNftsPerManyOrderValid = true; bool isOrdersTimeValid = true; bool itemsIntersect = true; for (uint256 i; i < manyMakerOrders.length; ) { uint256 nftsLength = manyMakerOrders[i].nfts.length; uint256 numNftsPerOrder; for (uint256 j; j < nftsLength; ) { numNftsPerOrder = numNftsPerOrder + manyMakerOrders[i].nfts[j].tokens.length; unchecked { ++j; } } numNftsPerManyOrderValid = numNftsPerManyOrderValid && manyMakerOrders[i].constraints[0] == numNftsPerOrder; totalNftsInManyOrders = totalNftsInManyOrders + numNftsPerOrder; isOrdersTimeValid = isOrdersTimeValid && manyMakerOrders[i].constraints[3] <= block.timestamp && manyMakerOrders[i].constraints[4] >= block.timestamp; itemsIntersect = itemsIntersect && doItemsIntersect(makerOrder.nfts, manyMakerOrders[i].nfts); if (!numNftsPerManyOrderValid) { return (false, makerOrderHash); // short circuit } unchecked { ++i; } } bool _isTimeValid = isOrdersTimeValid && makerOrder.constraints[3] <= block.timestamp && makerOrder.constraints[4] >= block.timestamp; uint256 currentMakerOrderPrice = _getCurrentPrice(makerOrder); uint256 sumCurrentOrderPrices = _sumCurrentPrices(manyMakerOrders); bool _isPriceValid; if (makerOrder.isSellOrder) { _isPriceValid = sumCurrentOrderPrices >= currentMakerOrderPrice; } else { _isPriceValid = sumCurrentOrderPrices <= currentMakerOrderPrice; } return ( numNftsInOneOrder == makerOrder.constraints[0] && numNftsInOneOrder == totalNftsInManyOrders && _isTimeValid && itemsIntersect && _isPriceValid, makerOrderHash ); } /** * @notice Checks whether match orders with a higher level intent can be executed * @dev This function is called by the main exchange to check whether one to one matches can be executed. It checks whether orders have the right constraints - i.e they have the right number of items, whether time is still valid, prices are valid and whether the nfts intersect * @param sell sell order * @param buy buy order * @param constructedNfts - nfts constructed by the off chain matching engine * @return returns whether the order can be execute, orderHashes and the execution price */ function canExecMatchOrder( OrderTypes.MakerOrder calldata sell, OrderTypes.MakerOrder calldata buy, OrderTypes.OrderItem[] calldata constructedNfts ) external view override returns (bool, bytes32, bytes32, uint256) { // check if orders are valid (bool _isPriceValid, uint256 execPrice) = isPriceValid(sell, buy); bytes32 sellOrderHash = _hash(sell); bytes32 buyOrderHash = _hash(buy); if (trustedExecEnabled) { bool trustedExec = sell.constraints.length == 8 && sell.constraints[7] == 1 && buy.constraints.length == 8 && buy.constraints[7] == 1; if (trustedExec) { bool sigValid = SignatureChecker.verify( sellOrderHash, sell.signer, sell.sig, DOMAIN_SEPARATOR ) && SignatureChecker.verify( buyOrderHash, buy.signer, buy.sig, DOMAIN_SEPARATOR ); return (sigValid, sellOrderHash, buyOrderHash, execPrice); } } require( verifyMatchOrders(sellOrderHash, buyOrderHash, sell, buy), "order not verified" ); return ( isTimeValid(sell, buy) && _isPriceValid && areNumMatchItemsValid(sell, buy, constructedNfts) && doItemsIntersect(sell.nfts, constructedNfts) && doItemsIntersect(buy.nfts, constructedNfts), sellOrderHash, buyOrderHash, execPrice ); } /** * @dev This function is called by an offline checker to verify whether matches can be executed * irrespective of the trusted execution constraint */ function verifyCanExecMatchOrder( OrderTypes.MakerOrder calldata sell, OrderTypes.MakerOrder calldata buy, OrderTypes.OrderItem[] calldata constructedNfts ) external view returns (bool, bytes32, bytes32, uint256) { // check if orders are valid (bool _isPriceValid, uint256 execPrice) = isPriceValid(sell, buy); bytes32 sellOrderHash = _hash(sell); bytes32 buyOrderHash = _hash(buy); require( verifyMatchOrders(sellOrderHash, buyOrderHash, sell, buy), "order not verified" ); return ( isTimeValid(sell, buy) && _isPriceValid && areNumMatchItemsValid(sell, buy, constructedNfts) && doItemsIntersect(sell.nfts, constructedNfts) && doItemsIntersect(buy.nfts, constructedNfts), sellOrderHash, buyOrderHash, execPrice ); } /** * @notice Checks whether one to one taker orders can be executed * @dev This function is called by the main exchange to check whether one to one taker orders can be executed. It checks whether orders have the right constraints - i.e they have one NFT only and whether time is still valid * @param makerOrder the makerOrder * @return returns whether the order can be executed and makerOrderHash */ function canExecTakeOneOrder( OrderTypes.MakerOrder calldata makerOrder ) external view override returns (bool, bytes32) { // check if makerOrder is valid bytes32 makerOrderHash = _hash(makerOrder); require( isOrderValid(makerOrder, makerOrderHash), "invalid maker order" ); bool numItemsValid = makerOrder.constraints[0] == 1 && makerOrder.nfts.length == 1 && makerOrder.nfts[0].tokens.length == 1; bool _isTimeValid = makerOrder.constraints[3] <= block.timestamp && makerOrder.constraints[4] >= block.timestamp; return (numItemsValid && _isTimeValid, makerOrderHash); } /** * @notice Checks whether take orders with a higher level intent can be executed * @dev This function is called by the main exchange to check whether take orders with a higher level intent can be executed. It checks whether orders have the right constraints - i.e they have the right number of items, whether time is still valid and whether the nfts intersect * @param makerOrder the maker order * @param takerItems the taker items specified by the taker * @return returns whether order can be executed and the makerOrderHash */ function canExecTakeOrder( OrderTypes.MakerOrder calldata makerOrder, OrderTypes.OrderItem[] calldata takerItems ) external view override returns (bool, bytes32) { // check if makerOrder is valid bytes32 makerOrderHash = _hash(makerOrder); require( isOrderValid(makerOrder, makerOrderHash), "invalid maker order" ); return ( makerOrder.constraints[3] <= block.timestamp && makerOrder.constraints[4] >= block.timestamp && areNumTakerItemsValid(makerOrder, takerItems) && doItemsIntersect(makerOrder.nfts, takerItems), makerOrderHash ); } // ======================================================= PUBLIC FUNCTIONS ================================================== /** * @notice Checks whether orders are valid * @dev Checks whether currencies match, sides match, complications match and if each order is valid (see isOrderValid) * @param sellOrderHash hash of the sell order * @param buyOrderHash hash of the buy order * @param sell the sell order * @param buy the buy order * @return whether orders are valid */ function verifyMatchOneToOneOrders( bytes32 sellOrderHash, bytes32 buyOrderHash, OrderTypes.MakerOrder calldata sell, OrderTypes.MakerOrder calldata buy ) public view returns (bool) { bool currenciesMatch = sell.execParams[1] == buy.execParams[1] || (sell.execParams[1] == address(0) && buy.execParams[1] == WETH); return (sell.isSellOrder && !buy.isSellOrder && sell.execParams[0] == buy.execParams[0] && sell.signer != buy.signer && currenciesMatch && isOrderValid(sell, sellOrderHash) && isOrderValid(buy, buyOrderHash)); } /** * @notice Checks whether orders are valid * @dev Checks whether currencies match, sides match, complications match and if each order is valid (see isOrderValid) * @param sell the sell order * @param buy the buy order * @return whether orders are valid and orderHash */ function verifyMatchOneToManyOrders( bool verifySellOrder, OrderTypes.MakerOrder calldata sell, OrderTypes.MakerOrder calldata buy ) public view override returns (bool, bytes32) { bool currenciesMatch = sell.execParams[1] == buy.execParams[1] || (sell.execParams[1] == address(0) && buy.execParams[1] == WETH); bool _orderValid; bytes32 orderHash; if (verifySellOrder) { orderHash = _hash(sell); _orderValid = isOrderValid(sell, orderHash); } else { orderHash = _hash(buy); _orderValid = isOrderValid(buy, orderHash); } return ( sell.isSellOrder && !buy.isSellOrder && sell.execParams[0] == buy.execParams[0] && sell.signer != buy.signer && currenciesMatch && _orderValid, orderHash ); } /** * @notice Checks whether orders are valid * @dev Checks whether currencies match, sides match, complications match and if each order is valid (see isOrderValid) Also checks if the given complication can execute this order * @param sellOrderHash hash of the sell order * @param buyOrderHash hash of the buy order * @param sell the sell order * @param buy the buy order * @return whether orders are valid */ function verifyMatchOrders( bytes32 sellOrderHash, bytes32 buyOrderHash, OrderTypes.MakerOrder calldata sell, OrderTypes.MakerOrder calldata buy ) public view returns (bool) { bool currenciesMatch = sell.execParams[1] == buy.execParams[1] || (sell.execParams[1] == address(0) && buy.execParams[1] == WETH); return (sell.isSellOrder && !buy.isSellOrder && sell.execParams[0] == buy.execParams[0] && sell.signer != buy.signer && currenciesMatch && isOrderValid(sell, sellOrderHash) && isOrderValid(buy, buyOrderHash)); } /** * @notice Verifies the validity of the order * @dev checks if signature is valid and if the complication and currency are valid * @param order the order * @param orderHash computed hash of the order * @return whether the order is valid */ function isOrderValid( OrderTypes.MakerOrder calldata order, bytes32 orderHash ) public view returns (bool) { // Verify the validity of the signature bool sigValid = SignatureChecker.verify( orderHash, order.signer, order.sig, DOMAIN_SEPARATOR ); return (sigValid && order.execParams[0] == address(this) && _currencies.contains(order.execParams[1])); } /// @dev checks whether the orders are expired function isTimeValid( OrderTypes.MakerOrder calldata sell, OrderTypes.MakerOrder calldata buy ) public view returns (bool) { return sell.constraints[3] <= block.timestamp && sell.constraints[4] >= block.timestamp && buy.constraints[3] <= block.timestamp && buy.constraints[4] >= block.timestamp; } /// @dev checks whether the price is valid; a buy order should always have a higher price than a sell order function isPriceValid( OrderTypes.MakerOrder calldata sell, OrderTypes.MakerOrder calldata buy ) public view returns (bool, uint256) { (uint256 currentSellPrice, uint256 currentBuyPrice) = ( _getCurrentPrice(sell), _getCurrentPrice(buy) ); return (currentBuyPrice >= currentSellPrice, currentSellPrice); } /// @dev sanity check to make sure the constructed nfts conform to the user signed constraints function areNumMatchItemsValid( OrderTypes.MakerOrder calldata sell, OrderTypes.MakerOrder calldata buy, OrderTypes.OrderItem[] calldata constructedNfts ) public pure returns (bool) { uint256 numConstructedItems; for (uint256 i; i < constructedNfts.length; ) { unchecked { numConstructedItems = numConstructedItems + constructedNfts[i].tokens.length; ++i; } } return numConstructedItems >= buy.constraints[0] && numConstructedItems <= sell.constraints[0]; } /// @dev sanity check to make sure that a taker is specifying the right number of items function areNumTakerItemsValid( OrderTypes.MakerOrder calldata makerOrder, OrderTypes.OrderItem[] calldata takerItems ) public pure returns (bool) { uint256 numTakerItems; for (uint256 i; i < takerItems.length; ) { unchecked { numTakerItems = numTakerItems + takerItems[i].tokens.length; ++i; } } return makerOrder.constraints[0] == numTakerItems; } /** * @notice Checks whether nfts intersect * @dev This function checks whether there are intersecting nfts between two orders * @param order1Nfts nfts in the first order * @param order2Nfts nfts in the second order * @return returns whether items intersect */ function doItemsIntersect( OrderTypes.OrderItem[] calldata order1Nfts, OrderTypes.OrderItem[] calldata order2Nfts ) public pure returns (bool) { uint256 order1NftsLength = order1Nfts.length; uint256 order2NftsLength = order2Nfts.length; // case where maker/taker didn't specify any items if (order1NftsLength == 0 || order2NftsLength == 0) { return true; } uint256 numCollsMatched; unchecked { for (uint256 i; i < order2NftsLength; ) { for (uint256 j; j < order1NftsLength; ) { if (order1Nfts[j].collection == order2Nfts[i].collection) { // increment numCollsMatched ++numCollsMatched; // check if tokenIds intersect bool tokenIdsIntersect = doTokenIdsIntersect( order1Nfts[j], order2Nfts[i] ); require(tokenIdsIntersect, "tokenIds dont intersect"); // short circuit break; } ++j; } ++i; } } return numCollsMatched == order2NftsLength; } /** * @notice Checks whether tokenIds intersect * @dev This function checks whether there are intersecting tokenIds between two order items * @param item1 first item * @param item2 second item * @return returns whether tokenIds intersect */ function doTokenIdsIntersect( OrderTypes.OrderItem calldata item1, OrderTypes.OrderItem calldata item2 ) public pure returns (bool) { uint256 item1TokensLength = item1.tokens.length; uint256 item2TokensLength = item2.tokens.length; // case where maker/taker didn't specify any tokenIds for this collection if (item1TokensLength == 0 || item2TokensLength == 0) { return true; } uint256 numTokenIdsPerCollMatched; unchecked { for (uint256 k; k < item2TokensLength; ) { // solhint-disable-next-line use-forbidden-name for (uint256 l; l < item1TokensLength; ) { if (item1.tokens[l].tokenId == item2.tokens[k].tokenId) { // increment numTokenIdsPerCollMatched ++numTokenIdsPerCollMatched; // short circuit break; } ++l; } ++k; } } return numTokenIdsPerCollMatched == item2TokensLength; } // ======================================================= UTILS ============================================================ /// @dev hashes the given order with the help of _nftsHash and _tokensHash function _hash( OrderTypes.MakerOrder calldata order ) internal pure returns (bytes32) { return keccak256( abi.encode( ORDER_HASH, order.isSellOrder, order.signer, keccak256(abi.encodePacked(order.constraints)), _nftsHash(order.nfts), keccak256(abi.encodePacked(order.execParams)), keccak256(order.extraParams) ) ); } function _nftsHash( OrderTypes.OrderItem[] calldata nfts ) internal pure returns (bytes32) { bytes32[] memory hashes = new bytes32[](nfts.length); for (uint256 i; i < nfts.length; ) { bytes32 hash = keccak256( abi.encode( ORDER_ITEM_HASH, nfts[i].collection, _tokensHash(nfts[i].tokens) ) ); hashes[i] = hash; unchecked { ++i; } } bytes32 nftsHash = keccak256(abi.encodePacked(hashes)); return nftsHash; } function _tokensHash( OrderTypes.TokenInfo[] calldata tokens ) internal pure returns (bytes32) { bytes32[] memory hashes = new bytes32[](tokens.length); for (uint256 i; i < tokens.length; ) { bytes32 hash = keccak256( abi.encode( TOKEN_INFO_HASH, tokens[i].tokenId, tokens[i].numTokens ) ); hashes[i] = hash; unchecked { ++i; } } bytes32 tokensHash = keccak256(abi.encodePacked(hashes)); return tokensHash; } /// @dev returns the sum of current order prices; used in match one to many orders function _sumCurrentPrices( OrderTypes.MakerOrder[] calldata orders ) internal view returns (uint256) { uint256 sum; uint256 ordersLength = orders.length; for (uint256 i; i < ordersLength; ) { sum = sum + _getCurrentPrice(orders[i]); unchecked { ++i; } } return sum; } /// @dev Gets current order price for orders that vary in price over time (dutch and reverse dutch auctions) function _getCurrentPrice( OrderTypes.MakerOrder calldata order ) internal view returns (uint256) { (uint256 startPrice, uint256 endPrice) = ( order.constraints[1], order.constraints[2] ); if (startPrice == endPrice) { return startPrice; } uint256 duration = order.constraints[4] - order.constraints[3]; if (duration == 0) { return startPrice; } uint256 elapsedTime = block.timestamp - order.constraints[3]; unchecked { uint256 portionBps = elapsedTime > duration ? PRECISION : ((elapsedTime * PRECISION) / duration); if (startPrice > endPrice) { uint256 priceDiff = ((startPrice - endPrice) * portionBps) / PRECISION; return startPrice - priceDiff; } else { uint256 priceDiff = ((endPrice - startPrice) * portionBps) / PRECISION; return startPrice + priceDiff; } } } // ======================================================= VIEW FUNCTIONS ============================================================ /// @notice returns the number of currencies supported by the exchange function numCurrencies() external view returns (uint256) { return _currencies.length(); } /// @notice returns the currency at the given index function getCurrencyAt(uint256 index) external view returns (address) { return _currencies.at(index); } /// @notice returns whether a given currency is valid function isValidCurrency(address currency) external view returns (bool) { return _currencies.contains(currency); } // ======================================================= OWNER FUNCTIONS ============================================================ /// @dev adds a new transaction currency to the exchange function addCurrency(address _currency) external onlyOwner { _currencies.add(_currency); emit CurrencyAdded(_currency); } /// @dev removes a transaction currency from the exchange function removeCurrency(address _currency) external onlyOwner { _currencies.remove(_currency); emit CurrencyRemoved(_currency); } /// @dev enables/diables trusted execution function setTrustedExecStatus(bool newVal) external onlyOwner { bool oldVal = trustedExecEnabled; require(oldVal != newVal, "no value change"); trustedExecEnabled = newVal; emit TrustedExecutionChanged(oldVal, newVal); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// 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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/structs/EnumerableSet.sol) pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { return _values(set._inner); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; import { OrderTypes } from "../libs/OrderTypes.sol"; /** * @title IFlowComplication * @author nneverlander. Twitter @nneverlander * @notice Complication interface that must be implemented by all complications (execution strategies) */ interface IFlowComplication { function canExecMatchOneToOne( OrderTypes.MakerOrder calldata makerOrder1, OrderTypes.MakerOrder calldata makerOrder2 ) external view returns (bool, bytes32, bytes32, uint256); function canExecMatchOneToMany( OrderTypes.MakerOrder calldata makerOrder, OrderTypes.MakerOrder[] calldata manyMakerOrders ) external view returns (bool, bytes32); function canExecMatchOrder( OrderTypes.MakerOrder calldata sell, OrderTypes.MakerOrder calldata buy, OrderTypes.OrderItem[] calldata constructedNfts ) external view returns (bool, bytes32, bytes32, uint256); function canExecTakeOneOrder( OrderTypes.MakerOrder calldata makerOrder ) external view returns (bool, bytes32); function canExecTakeOrder( OrderTypes.MakerOrder calldata makerOrder, OrderTypes.OrderItem[] calldata takerItems ) external view returns (bool, bytes32); function verifyMatchOneToManyOrders( bool verifySellOrder, OrderTypes.MakerOrder calldata sell, OrderTypes.MakerOrder calldata buy ) external view returns (bool, bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.14; uint256 constant FreeMemoryPointerSlot = 0x40; uint256 constant OneWord = 0x20; uint256 constant OneWordShift = 0x5; uint256 constant ThirtyOneBytes = 0x1f; bytes32 constant EIP2098_allButHighestBitMask = ( 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ); uint256 constant ExtraGasBuffer = 0x20; uint256 constant CostPerWord = 0x3; uint256 constant MemoryExpansionCoefficientShift = 0x9; uint256 constant BulkOrder_Typehash_Height_One = ( 0x25f1d312acdce9bb5f11c5585e941709b8456695fe5aacf9998bd3acadfd7fec ); uint256 constant BulkOrder_Typehash_Height_Two = ( 0xb7870d22600c57d01e7ff46f87ea8741898e43ce73f7d5bfb269c715ea8d4242 ); uint256 constant BulkOrder_Typehash_Height_Three = ( 0xe9ccc656222762d6d2e94ef74311f23818493f907cde851440e6d8773f56c5fe ); uint256 constant BulkOrder_Typehash_Height_Four = ( 0x14300c4bb2d1850e661a7bb2347e8ac0fa0736fa434a6d0ae1017cb485ce1a7c ); uint256 constant BulkOrder_Typehash_Height_Five = ( 0xd2a9fdbc6e34ad83660cd4ad49310a663134bbdaea7c34c7c6a95cf9aa8618b1 ); uint256 constant BulkOrder_Typehash_Height_Six = ( 0x4c2c782f8c9daf12d0ec87e76fc496ffeed835292ca7ff04ac92375bbc0f4cc7 ); uint256 constant BulkOrder_Typehash_Height_Seven = ( 0xab5bd2a739337f6f3d8743b51df07f176805bae22da4b25be5d8cdd688498382 ); uint256 constant BulkOrder_Typehash_Height_Eight = ( 0x96596fb6c680230945bae686c1776a9920c438436a98dba61ca767f370b6ef0c ); uint256 constant BulkOrder_Typehash_Height_Nine = ( 0x40d250b9c55bcc275a49429cae143a873752d755dfa1072e47e10d5252fb8d3b ); uint256 constant BulkOrder_Typehash_Height_Ten = ( 0xeaf49b43e05b65ffed9bd664ee39555b22fa8ba157aa058f19fc7fee92d386f4 ); uint256 constant BulkOrder_Typehash_Height_Eleven = ( 0x9d5d1c872408322fe8c431a1b66583d09e5dd77e0ac5f99b55131b3fe8363ffb ); uint256 constant BulkOrder_Typehash_Height_Twelve = ( 0xdb50e721ad63671fc79a925f372d22d69adfe998243b341129c4ef29a20c7a74 ); uint256 constant BulkOrder_Typehash_Height_Thirteen = ( 0x908c5a945faf8d6b1d5aba44fc097fb8c22cca14f60bf75bf680224813809637 ); uint256 constant BulkOrder_Typehash_Height_Fourteen = ( 0x7968127d641eabf208fbdc9d69f10fed718855c94a809679d41b7bcf18104b74 ); uint256 constant BulkOrder_Typehash_Height_Fifteen = ( 0x814b44e912b2ccd234edcf03da0b9d37c459baf9d512034ed96bc93032c37bab ); uint256 constant BulkOrder_Typehash_Height_Sixteen = ( 0x3a8ceb52e9851a307cf6bd49c73a2ec0d37712e6c4d68c4dcf84df0ad574f59a ); uint256 constant BulkOrder_Typehash_Height_Seventeen = ( 0xdd2197b5843051f931afa0a534e25a1d824e11ccb5e100c716e9e40406c68b3a ); uint256 constant BulkOrder_Typehash_Height_Eighteen = ( 0x84b50d02c0d7ec2a815ec27a71290ad861c7cd3addd94f5f7c0736df33fe1827 ); uint256 constant BulkOrder_Typehash_Height_Nineteen = ( 0xdaa31608975cb535532462ce63bbb075b6d81235cd756da2117e745baed067c1 ); uint256 constant BulkOrder_Typehash_Height_Twenty = ( 0x5089f7eef268ce27189a0f19e64dd8210ecadff4be5176a5bd4fd1f176f483a1 ); uint256 constant BulkOrder_Typehash_Height_TwentyOne = ( 0x907e1899005168c54e8279a0e7fc8f890b1de622a79e1ea1447bde837732da56 ); uint256 constant BulkOrder_Typehash_Height_TwentyTwo = ( 0x73ea6321c43a7d88f2d0f797219c7dd3405b1208e89c6d00c6df5c2cc833aa1d ); uint256 constant BulkOrder_Typehash_Height_TwentyThree = ( 0xb2036d7869c41d1588416aba4ce6e52b45a330fd934c05995b14653db5db9293 ); uint256 constant BulkOrder_Typehash_Height_TwentyFour = ( 0x99e8d8ff7ddc6198258cce0fe5930c7fe7799405517eca81dbf14c1707c163ad );
// SPDX-License-Identifier: MIT // solhint-disable no-inline-assembly pragma solidity 0.8.14; import { CostPerWord, ExtraGasBuffer, FreeMemoryPointerSlot, MemoryExpansionCoefficientShift, OneWord, OneWordShift, ThirtyOneBytes } from "./Constants.sol"; /** * @title LowLevelHelpers * @author 0age * @notice LowLevelHelpers contains logic for performing various low-level * operations. */ contract LowLevelHelpers { /** * @dev Internal view function to revert and pass along the revert reason if * data was returned by the last call and that the size of that data * does not exceed the currently allocated memory size. */ function _revertWithReasonIfOneIsReturned() internal view { assembly { // If it returned a message, bubble it up as long as sufficient gas // remains to do so: if returndatasize() { // Ensure that sufficient gas is available to copy returndata // while expanding memory where necessary. Start by computing // the word size of returndata and allocated memory. let returnDataWords := shr( OneWordShift, add(returndatasize(), ThirtyOneBytes) ) // Note: use the free memory pointer in place of msize() to work // around a Yul warning that prevents accessing msize directly // when the IR pipeline is activated. let msizeWords := shr( OneWordShift, mload(FreeMemoryPointerSlot) ) // Next, compute the cost of the returndatacopy. let cost := mul(CostPerWord, returnDataWords) // Then, compute cost of new memory allocation. if gt(returnDataWords, msizeWords) { cost := add( cost, add( mul(sub(returnDataWords, msizeWords), CostPerWord), shr( MemoryExpansionCoefficientShift, sub( mul(returnDataWords, returnDataWords), mul(msizeWords, msizeWords) ) ) ) ) } // Finally, add a small constant and compare to gas remaining; // bubble up the revert data if enough gas is still available. if lt(add(cost, ExtraGasBuffer), gas()) { // Copy returndata to memory; overwrite existing memory. returndatacopy(0, 0, returndatasize()) // Revert, specifying memory region with copied returndata. revert(0, returndatasize()) } } } } /** * @dev Internal view function to branchlessly select either the caller (if * a supplied recipient is equal to zero) or the supplied recipient (if * that recipient is a nonzero value). * * @param recipient The supplied recipient. * * @return updatedRecipient The updated recipient. */ function _substituteCallerForEmptyRecipient( address recipient ) internal view returns (address updatedRecipient) { // Utilize assembly to perform a branchless operation on the recipient. assembly { // Add caller to recipient if recipient equals 0; otherwise add 0. updatedRecipient := add(recipient, mul(iszero(recipient), caller())) } } /** * @dev Internal pure function to cast a `bool` value to a `uint256` value. * * @param b The `bool` value to cast. * * @return u The `uint256` value. */ function _cast(bool b) internal pure returns (uint256 u) { assembly { u := b } } /** * @dev Internal pure function to compare two addresses without first * masking them. Note that dirty upper bits will cause otherwise equal * addresses to be recognized as unequal. * * @param a The first address. * @param b The second address * * @return areEqual A boolean representing whether the addresses are equal. */ function _unmaskedAddressComparison( address a, address b ) internal pure returns (bool areEqual) { // Utilize assembly to perform the comparison without masking. assembly { areEqual := eq(a, b) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.14; /** * @title OrderTypes * @author nneverlander. Twitter @nneverlander * @notice This library contains the order types used by the main exchange and complications */ library OrderTypes { /// @dev the tokenId and numTokens (==1 for ERC721) struct TokenInfo { uint256 tokenId; uint256 numTokens; } /// @dev an order item is a collection address and tokens from that collection struct OrderItem { address collection; TokenInfo[] tokens; } struct MakerOrder { ///@dev is order sell or buy bool isSellOrder; ///@dev signer of the order (maker address) address signer; ///@dev Constraints array contains the order constraints. Total constraints: 7. In order: // numItems - min (for buy orders) / max (for sell orders) number of items in the order // start price in wei // end price in wei // start time in block.timestamp // end time in block.timestamp // nonce of the order // max tx.gasprice in wei that a user is willing to pay for gas // 1 for trustedExecution, 0 or non-existent for not trustedExecution uint256[] constraints; ///@dev nfts array contains order items where each item is a collection and its tokenIds OrderItem[] nfts; ///@dev address of complication for trade execution (e.g. FlowOrderBookComplication), address of the currency (e.g., WETH) address[] execParams; ///@dev additional parameters like traits for trait orders, private sale buyer for OTC orders etc bytes extraParams; ///@dev the order signature uint8 v: parameter (27 or 28), bytes32 r, bytes32 s bytes sig; } }
// SPDX-License-Identifier: MIT // solhint-disable no-inline-assembly pragma solidity 0.8.14; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { LowLevelHelpers } from "./LowLevelHelpers.sol"; import { IERC1271 } from "@openzeppelin/contracts/interfaces/IERC1271.sol"; import { OrderTypes } from "../libs/OrderTypes.sol"; import { EIP2098_allButHighestBitMask, OneWord, OneWordShift, BulkOrder_Typehash_Height_One, BulkOrder_Typehash_Height_Two, BulkOrder_Typehash_Height_Three, BulkOrder_Typehash_Height_Four, BulkOrder_Typehash_Height_Five, BulkOrder_Typehash_Height_Six, BulkOrder_Typehash_Height_Seven, BulkOrder_Typehash_Height_Eight, BulkOrder_Typehash_Height_Nine, BulkOrder_Typehash_Height_Ten, BulkOrder_Typehash_Height_Eleven, BulkOrder_Typehash_Height_Twelve, BulkOrder_Typehash_Height_Thirteen, BulkOrder_Typehash_Height_Fourteen, BulkOrder_Typehash_Height_Fifteen, BulkOrder_Typehash_Height_Sixteen, BulkOrder_Typehash_Height_Seventeen, BulkOrder_Typehash_Height_Eighteen, BulkOrder_Typehash_Height_Nineteen, BulkOrder_Typehash_Height_Twenty, BulkOrder_Typehash_Height_TwentyOne, BulkOrder_Typehash_Height_TwentyTwo, BulkOrder_Typehash_Height_TwentyThree, BulkOrder_Typehash_Height_TwentyFour } from "./Constants.sol"; /** * @title SignatureChecker * @notice This library allows verification of signatures for both EOAs and contracts */ contract SignatureChecker is LowLevelHelpers { /** * @dev Revert with an error when a signature that does not contain a v * value of 27 or 28 has been supplied. * * @param v The invalid v value. */ error BadSignatureV(uint8 v); /** * @dev Revert with an error when the signer recovered by the supplied * signature does not match the offerer or an allowed EIP-1271 signer * as specified by the offerer in the event they are a contract. */ error InvalidSigner(); /** * @dev Revert with an error when a signer cannot be recovered from the * supplied signature. */ error InvalidSignature(); /** * @dev Revert with an error when an EIP-1271 call to an account fails. */ error BadContractSignature(); /** * @notice Returns whether the signer matches the signed message * @param orderHash the hash containing the signed message * @param signer the signer address to confirm message validity * @param sig the signature * @param domainSeparator parameter to prevent signature being executed in other chains and environments * @return true --> if valid // false --> if invalid */ function verify( bytes32 orderHash, address signer, bytes calldata sig, bytes32 domainSeparator ) internal view returns (bool) { bytes32 originalDigest = keccak256( abi.encodePacked("\x19\x01", domainSeparator, orderHash) ); bytes32 digest; bytes memory extractedSignature; if (_isValidBulkOrderSize(sig)) { (orderHash, extractedSignature) = _computeBulkOrderProof( sig, orderHash ); digest = keccak256( abi.encodePacked("\x19\x01", domainSeparator, orderHash) ); } else { digest = originalDigest; extractedSignature = sig; } _assertValidSignature( signer, digest, originalDigest, sig, extractedSignature ); return true; } /** * @dev Determines whether the specified bulk order size is valid. * * @param signature The signature of the bulk order to check. * * @return validLength True if bulk order size is valid, false otherwise. */ function _isValidBulkOrderSize( bytes memory signature ) internal pure returns (bool validLength) { validLength = signature.length < 837 && signature.length > 98 && ((signature.length - 67) % 32) < 2; } /** * @dev Computes the bulk order hash for the specified proof and leaf. Note * that if an index that exceeds the number of orders in the bulk order * payload will instead "wrap around" and refer to an earlier index. * * @param proofAndSignature The proof and signature of the bulk order. * @param leaf The leaf of the bulk order tree. * * @return bulkOrderHash The bulk order hash. * @return signature The signature of the bulk order. */ function _computeBulkOrderProof( bytes memory proofAndSignature, bytes32 leaf ) internal pure returns (bytes32 bulkOrderHash, bytes memory signature) { bytes32 root = leaf; // proofAndSignature with odd length is a compact signature (64 bytes). uint256 length = proofAndSignature.length % 2 == 0 ? 65 : 64; // Create a new array of bytes equal to the length of the signature. signature = new bytes(length); // Iterate over each byte in the signature. for (uint256 i = 0; i < length; ++i) { // Assign the byte from the proofAndSignature to the signature. signature[i] = proofAndSignature[i]; } // Compute the key by extracting the next three bytes from the // proofAndSignature. uint256 key = (((uint256(uint8(proofAndSignature[length])) << 16) | ((uint256(uint8(proofAndSignature[length + 1]))) << 8)) | (uint256(uint8(proofAndSignature[length + 2])))); uint256 height = (proofAndSignature.length - length) / 32; // Create an array of bytes32 to hold the proof elements. bytes32[] memory proofElements = new bytes32[](height); // Iterate over each proof element. for (uint256 elementIndex = 0; elementIndex < height; ++elementIndex) { // Compute the starting index for the current proof element. uint256 start = (length + 3) + (elementIndex * 32); // Create a new array of bytes to hold the current proof element. bytes memory buffer = new bytes(32); // Iterate over each byte in the proof element. for (uint256 i = 0; i < 32; ++i) { // Assign the byte from the proofAndSignature to the buffer. buffer[i] = proofAndSignature[start + i]; } // Decode the current proof element from the buffer and assign it to // the proofElements array. proofElements[elementIndex] = abi.decode(buffer, (bytes32)); } // Iterate over each proof element. for (uint256 i = 0; i < proofElements.length; ++i) { // Retrieve the proof element. bytes32 proofElement = proofElements[i]; // Check if the current bit of the key is set. if ((key >> i) % 2 == 0) { // If the current bit is not set, then concatenate the root and // the proof element, and compute the keccak256 hash of the // concatenation to assign it to the root. root = keccak256(abi.encodePacked(root, proofElement)); } else { // If the current bit is set, then concatenate the proof element // and the root, and compute the keccak256 hash of the // concatenation to assign it to the root. root = keccak256(abi.encodePacked(proofElement, root)); } } // Compute the bulk order hash and return it. bulkOrderHash = keccak256( abi.encodePacked(_lookupBulkOrderTypehash(height), root) ); // Return the signature. return (bulkOrderHash, signature); } /** * @dev Internal pure function to look up one of twenty-four potential bulk * order typehash constants based on the height of the bulk order tree. * Note that values between one and twenty-four are supported, which is * enforced by _isValidBulkOrderSize. * * @param _treeHeight The height of the bulk order tree. The value must be * between one and twenty-four. * * @return _typeHash The EIP-712 typehash for the bulk order type with the * given height. */ function _lookupBulkOrderTypehash(uint256 _treeHeight) internal pure returns (bytes32 _typeHash) { // Utilize assembly to efficiently retrieve correct bulk order typehash. assembly { // Use a Yul function to enable use of the `leave` keyword // to stop searching once the appropriate type hash is found. function lookupTypeHash(treeHeight) -> typeHash { // Handle tree heights one through eight. if lt(treeHeight, 9) { // Handle tree heights one through four. if lt(treeHeight, 5) { // Handle tree heights one and two. if lt(treeHeight, 3) { // Utilize branchless logic to determine typehash. typeHash := ternary( eq(treeHeight, 1), BulkOrder_Typehash_Height_One, BulkOrder_Typehash_Height_Two ) // Exit the function once typehash has been located. leave } // Handle height three and four via branchless logic. typeHash := ternary( eq(treeHeight, 3), BulkOrder_Typehash_Height_Three, BulkOrder_Typehash_Height_Four ) // Exit the function once typehash has been located. leave } // Handle tree height five and six. if lt(treeHeight, 7) { // Utilize branchless logic to determine typehash. typeHash := ternary( eq(treeHeight, 5), BulkOrder_Typehash_Height_Five, BulkOrder_Typehash_Height_Six ) // Exit the function once typehash has been located. leave } // Handle height seven and eight via branchless logic. typeHash := ternary( eq(treeHeight, 7), BulkOrder_Typehash_Height_Seven, BulkOrder_Typehash_Height_Eight ) // Exit the function once typehash has been located. leave } // Handle tree height nine through sixteen. if lt(treeHeight, 17) { // Handle tree height nine through twelve. if lt(treeHeight, 13) { // Handle tree height nine and ten. if lt(treeHeight, 11) { // Utilize branchless logic to determine typehash. typeHash := ternary( eq(treeHeight, 9), BulkOrder_Typehash_Height_Nine, BulkOrder_Typehash_Height_Ten ) // Exit the function once typehash has been located. leave } // Handle height eleven and twelve via branchless logic. typeHash := ternary( eq(treeHeight, 11), BulkOrder_Typehash_Height_Eleven, BulkOrder_Typehash_Height_Twelve ) // Exit the function once typehash has been located. leave } // Handle tree height thirteen and fourteen. if lt(treeHeight, 15) { // Utilize branchless logic to determine typehash. typeHash := ternary( eq(treeHeight, 13), BulkOrder_Typehash_Height_Thirteen, BulkOrder_Typehash_Height_Fourteen ) // Exit the function once typehash has been located. leave } // Handle height fifteen and sixteen via branchless logic. typeHash := ternary( eq(treeHeight, 15), BulkOrder_Typehash_Height_Fifteen, BulkOrder_Typehash_Height_Sixteen ) // Exit the function once typehash has been located. leave } // Handle tree height seventeen through twenty. if lt(treeHeight, 21) { // Handle tree height seventeen and eighteen. if lt(treeHeight, 19) { // Utilize branchless logic to determine typehash. typeHash := ternary( eq(treeHeight, 17), BulkOrder_Typehash_Height_Seventeen, BulkOrder_Typehash_Height_Eighteen ) // Exit the function once typehash has been located. leave } // Handle height nineteen and twenty via branchless logic. typeHash := ternary( eq(treeHeight, 19), BulkOrder_Typehash_Height_Nineteen, BulkOrder_Typehash_Height_Twenty ) // Exit the function once typehash has been located. leave } // Handle tree height twenty-one and twenty-two. if lt(treeHeight, 23) { // Utilize branchless logic to determine typehash. typeHash := ternary( eq(treeHeight, 21), BulkOrder_Typehash_Height_TwentyOne, BulkOrder_Typehash_Height_TwentyTwo ) // Exit the function once typehash has been located. leave } // Handle height twenty-three & twenty-four w/ branchless logic. typeHash := ternary( eq(treeHeight, 23), BulkOrder_Typehash_Height_TwentyThree, BulkOrder_Typehash_Height_TwentyFour ) // Exit the function once typehash has been located. leave } // Implement ternary conditional using branchless logic. function ternary(cond, ifTrue, ifFalse) -> c { c := xor(ifFalse, mul(cond, xor(ifFalse, ifTrue))) } // Look up the typehash using the supplied tree height. _typeHash := lookupTypeHash(_treeHeight) } } /** * @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 signature against. * @param originalDigest The original digest to verify signature against. * @param originalSignature The original signature. * @param signature A signature from the signer indicating that the * order has been approved. */ function _assertValidSignature( address signer, bytes32 digest, bytes32 originalDigest, bytes memory originalSignature, bytes memory signature ) internal view { if (signer.code.length > 0) { // If signer is a contract, try verification via EIP-1271. if ( IERC1271(signer).isValidSignature( originalDigest, originalSignature ) != 0x1626ba7e ) { revert BadContractSignature(); } // Return early if the ERC-1271 signature check succeeded. return; } else { _assertValidSignatureHelper(signer, digest, signature); } } function _assertValidSignatureHelper( address signer, bytes32 digest, bytes memory signature ) internal pure { // Declare r, s, and v signature parameters. bytes32 r; bytes32 s; uint8 v; if (signature.length == 64) { // If signature contains 64 bytes, parse as EIP-2098 sig. (r+s&v) // Declare temporary vs that will be decomposed into s and v. bytes32 vs; // Decode signature into r, vs. (r, vs) = abi.decode(signature, (bytes32, bytes32)); // Decompose vs into s and v. s = vs & EIP2098_allButHighestBitMask; // If the highest bit is set, v = 28, otherwise v = 27. 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) { revert BadSignatureV(v); } } else { revert InvalidSignature(); } // 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) { revert InvalidSigner(); } } }
{ "viaIR": true, "optimizer": { "enabled": true, "runs": 99999999 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BadContractSignature","type":"error"},{"inputs":[{"internalType":"uint8","name":"v","type":"uint8"}],"name":"BadSignatureV","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"currency","type":"address"}],"name":"CurrencyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"currency","type":"address"}],"name":"CurrencyRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"oldVal","type":"bool"},{"indexed":false,"internalType":"bool","name":"newVal","type":"bool"}],"name":"TrustedExecutionChanged","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ORDER_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ORDER_ITEM_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_INFO_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_currency","type":"address"}],"name":"addCurrency","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"sell","type":"tuple"},{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"buy","type":"tuple"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"constructedNfts","type":"tuple[]"}],"name":"areNumMatchItemsValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"makerOrder","type":"tuple"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"takerItems","type":"tuple[]"}],"name":"areNumTakerItemsValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"makerOrder","type":"tuple"},{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder[]","name":"manyMakerOrders","type":"tuple[]"}],"name":"canExecMatchOneToMany","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"makerOrder1","type":"tuple"},{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"makerOrder2","type":"tuple"}],"name":"canExecMatchOneToOne","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"sell","type":"tuple"},{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"buy","type":"tuple"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"constructedNfts","type":"tuple[]"}],"name":"canExecMatchOrder","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"makerOrder","type":"tuple"}],"name":"canExecTakeOneOrder","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"makerOrder","type":"tuple"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"takerItems","type":"tuple[]"}],"name":"canExecTakeOrder","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"order1Nfts","type":"tuple[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"order2Nfts","type":"tuple[]"}],"name":"doItemsIntersect","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem","name":"item1","type":"tuple"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem","name":"item2","type":"tuple"}],"name":"doTokenIdsIntersect","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getCurrencyAt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"order","type":"tuple"},{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"isOrderValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"sell","type":"tuple"},{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"buy","type":"tuple"}],"name":"isPriceValid","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"sell","type":"tuple"},{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"buy","type":"tuple"}],"name":"isTimeValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"currency","type":"address"}],"name":"isValidCurrency","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numCurrencies","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_currency","type":"address"}],"name":"removeCurrency","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"newVal","type":"bool"}],"name":"setTrustedExecStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trustedExecEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"makerOrder","type":"tuple"},{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder[]","name":"manyMakerOrders","type":"tuple[]"}],"name":"verifyCanExecMatchOneToMany","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"makerOrder1","type":"tuple"},{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"makerOrder2","type":"tuple"}],"name":"verifyCanExecMatchOneToOne","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"sell","type":"tuple"},{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"buy","type":"tuple"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"constructedNfts","type":"tuple[]"}],"name":"verifyCanExecMatchOrder","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"verifySellOrder","type":"bool"},{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"sell","type":"tuple"},{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"buy","type":"tuple"}],"name":"verifyMatchOneToManyOrders","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"sellOrderHash","type":"bytes32"},{"internalType":"bytes32","name":"buyOrderHash","type":"bytes32"},{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"sell","type":"tuple"},{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"buy","type":"tuple"}],"name":"verifyMatchOneToOneOrders","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"sellOrderHash","type":"bytes32"},{"internalType":"bytes32","name":"buyOrderHash","type":"bytes32"},{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"sell","type":"tuple"},{"components":[{"internalType":"bool","name":"isSellOrder","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256[]","name":"constraints","type":"uint256[]"},{"components":[{"internalType":"address","name":"collection","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"internalType":"struct OrderTypes.TokenInfo[]","name":"tokens","type":"tuple[]"}],"internalType":"struct OrderTypes.OrderItem[]","name":"nfts","type":"tuple[]"},{"internalType":"address[]","name":"execParams","type":"address[]"},{"internalType":"bytes","name":"extraParams","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct OrderTypes.MakerOrder","name":"buy","type":"tuple"}],"name":"verifyMatchOrders","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60a08060405234620001355760008054336001600160a01b0319821681178355926001600160a01b03909116917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a36200005f60ff1960035416600355565b6200006962000184565b8051602091820120604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f9381019384527f767f60897b08e93f316241ec3d323d66363c5d1e229edd7d32c34a27f468abfc9181019190915260608101919091524660808201523060a0808301919091528152620000eb60c08262000151565b519020608052620000fb620001c3565b506200010662000277565b5060405161416b9081620002ff82396080518181816107f901528181611c81015281816121a501526126c70152f35b600080fd5b50634e487b7160e01b600052604160045260246000fd5b601f909101601f19168101906001600160401b038211908210176200017557604052565b6200017f6200013a565b604052565b60408051919082016001600160401b03811183821017620001b3575b60405260018252603160f81b6020830152565b620001bd6200013a565b620001a0565b73b4fbf271143f4fbf7b91a5ded31805e42b2208d6600081815260026020527fa4e4028036a6258222c986d8dc177d59e3d7870180e9f3b76f2253cbc5db69e954909190620002735760019182546801000000000000000081101562000263575b8381018085558110156200024f57908260409285835260208320015583549281526002602052205590565b634e487b7160e01b82526032600452602482fd5b6200026d6200013a565b62000224565b5090565b600080805260026020527fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b54620002fb57600190815468010000000000000000811015620002eb575b8281018084558110156200024f57819083825260208220015560408254918080526002602052205590565b620002f56200013a565b620002c0565b9056fe60806040526004361015610013575b600080fd5b60003560e01c80630cc02a42146102b25780631d49c1ef146102a95780631dc267a9146102a05780633051b935146102465780633644e5151461029757806336ce5c7a1461028e5780633e4e4f8b146102855780634fb925581461027c57806355de2746146102735780635ce390731461026a578063715018a6146102615780637720595d146102585780637b866a1d1461024f578063829a23071461024657806383d121461461023d5780638ab234b6146102345780638da5cb5b1461022b5780638e2c7d8514610222578063950c52bb146102195780639e0daf5e14610210578063aaf5eb6814610207578063ad5c4648146101fe578063ae3aad4d146101f5578063b66948cf146101ec578063b7970741146101e3578063bf281c99146101da578063c291c1d5146101d1578063c5d3a107146101c8578063d4677527146101bf578063d9814ac5146101b6578063f1332a91146101ad578063f2fde38b146101a4578063f7a0e3f41461019b5763fd2596281461019357600080fd5b61000e6115f2565b5061000e6115d8565b5061000e6114e2565b5061000e6114ca565b5061000e6114af565b5061000e611483565b5061000e6113f5565b5061000e6113d8565b5061000e611396565b5061000e61133c565b5061000e6112c6565b5061000e6111bb565b5061000e61116d565b5061000e611131565b5061000e61100c565b5061000e610fca565b5061000e610ede565b5061000e610e8b565b5061000e610df3565b5061000e610bbc565b5061000e61073c565b5061000e610b62565b5061000e610acf565b5061000e610a27565b5061000e6109ea565b5061000e6109d0565b5061000e6108cd565b5061000e61087a565b5061000e61081c565b5061000e6107c2565b5061000e6105f9565b5061000e610595565b5061000e61032e565b908160e091031261000e5790565b9060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc83011261000e5767ffffffffffffffff60043581811161000e5783610314916004016102bb565b9260243591821161000e5761032b916004016102bb565b90565b503461000e5761033d366102c9565b60009161034981613129565b9261035383613129565b905061035e826117a4565b1561058b57831115925b61037182612ccc565b9361037b84612ccc565b9361039061038b8286888a612536565b6118f5565b60408101936103a86103a286846117ae565b90611832565b359460408201956103bc6103a288856117ae565b35149586610572575b86610558575b86610538575b8661051e575b866104ee575b6103f06103ea83866117ae565b90611843565b3542101591826104d4575b50816104b4575b81610494575b508561048c575b5084610457575b50508261044d575b5061044991926040519485948590949392606092608083019615158352602083015260408201520152565b0390f35b915061044961041e565b6104849294509061046f82606061047c9401906117ae565b92909160608101906117ae565b9290916129af565b913880610416565b94503861040f565b6104ab91506104a390836117ae565b42929161185e565b35101538610408565b90506104cb6104c382846117ae565b429291611843565b35111590610402565b6104e49192506104a390856117ae565b35101590386103fb565b9550600161051561050b61050560608601866117ae565b9061195a565b60208101906119ef565b905014956103dd565b9550600161052f60608401846117ae565b905014956103d7565b9550600161054f61050b61050560608701876117ae565b905014956103d1565b9550600161056960608501856117ae565b905014956103cb565b955060016105836103a283866117ae565b3514956103c5565b8093101592610368565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760206040517f7bcfb5a29031e6b8d34ca1a14dd0a1f5cb11b20f755bb2a31ee3c4b143477e4a8152f35b8015150361000e57565b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57600435610635816105ef565b61065873ffffffffffffffffffffffffffffffffffffffff6000541633146116d0565b6003549060ff82168115159283821515146106de577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0060ff7fa2d07ed145017e8fdeeb5ffaadae1e46bd9b24cd77169a72ca38efee2f234a4095169116176003556106d9604051928392839092916020906040830194151583521515910152565b0390a1005b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f2076616c7565206368616e676500000000000000000000000000000000006044820152fd5b503461000e5760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5767ffffffffffffffff60443581811161000e5761078d9036906004016102bb565b9060643590811161000e576020916107ac6107b89236906004016102bb565b90602435600435612536565b6040519015158152f35b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b503461000e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760043567ffffffffffffffff811161000e576107b861087160209236906004016102bb565b602435906126a4565b503461000e5760406108a0610898610891366102c9565b9190613129565b918291613129565b10159082519182526020820152f35b73ffffffffffffffffffffffffffffffffffffffff81160361000e57565b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5773ffffffffffffffffffffffffffffffffffffffff60043561091e816108af565b16600052600260205260206040600020541515604051908152f35b9181601f8401121561000e5782359167ffffffffffffffff831161000e576020808501948460051b01011161000e57565b9060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc83011261000e5767ffffffffffffffff60043581811161000e57836109b5916004016102bb565b9260243591821161000e576109cc91600401610939565b9091565b503461000e5760206107b86109e43661096a565b916128f2565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e576020600154604051908152f35b503461000e576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610acc5780547fffffffffffffffffffffffff000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff821691610a9e3384146116d0565b16825581604051917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08284a3f35b80fd5b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602073ffffffffffffffffffffffffffffffffffffffff600435600154811015610b55575b60016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6015416604051908152f35b610b5d611802565b610b24565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760206040517f88f0bd19d14f8b5d22c0605a15d9fffc285ebc8c86fb21139456d305982906f18152f35b503461000e5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57600435610bf8816105ef565b67ffffffffffffffff9060243582811161000e57610c1a9036906004016102bb565b9160443590811161000e57610c339036906004016102bb565b6080830191610c53610c4e610c4885876117ae565b9061186d565b61189a565b916080810192610c85610c6c610c4e610c4887866117ae565b73ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff80921614928315610da4575b15610d8a57610cb486612ccc565b95610cbf87826126a4565b945b610cca826117a4565b9687610d72575b87610d3f575b505085610d13575b50505082610d0b575b5081610d03575b506040805191151582526020820192909252f35b905038610cef565b915038610ce8565b610d3291929395506020610d2b81610c6c930161189a565b940161189a565b9116141591388080610cdf565b829750610c6c610c4e6103a2610d60610c4e6103a2610d67968a98996117ae565b95886117ae565b911614943880610cd7565b9650610d84610d80856117a4565b1590565b96610cd1565b610d9382612ccc565b95610d9e87846126a4565b94610cc1565b925080610db7610c4e610c48888a6117ae565b161580610dc5575b92610ca6565b5073b4fbf271143f4fbf7b91a5ded31805e42b2208d681610dec610c4e610c4888876117ae565b1614610dbf565b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e577fe0390a89516146ccfb796a9fbfc3f7646282194c554d05020484599ee992dd5a6020600435610e52816108af565b73ffffffffffffffffffffffffffffffffffffffff90610e77826000541633146116d0565b16610e8181613228565b50604051908152a1005b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b503461000e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5767ffffffffffffffff60043581811161000e57610f2f903690600401610939565b60249291923591821161000e5760209261047c6107b8933690600401610939565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261000e5767ffffffffffffffff9160043583811161000e5782610f9b916004016102bb565b9260243581811161000e5783610fb3916004016102bb565b9260443591821161000e576109cc91600401610939565b503461000e57610449610fe8610fdf36610f50565b929190916123e0565b60408051941515855260208501939093529183015260608201529081906080820190565b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760043567ffffffffffffffff811161000e5761105c9036906004016102bb565b61106581612ccc565b9061107861107383836126a4565b611d90565b6040810190600161108983836117ae565b15611124575b3514918261110a575b826110ea575b6110ab6103ea82846117ae565b3542101591826110d1575b505081610d0357506040805191151582526020820192909252f35b6110e09250906104a3916117ae565b35101538806110b6565b9150600161110161050b61050560608501856117ae565b9050149161109e565b9150600161111b60608301836117ae565b90501491611098565b61112c611802565b61108f565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760206040516127108152f35b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602060405173b4fbf271143f4fbf7b91a5ded31805e42b2208d68152f35b503461000e576111ca36610f50565b90926111d581613129565b90816111e085613129565b1015926111ec82612ccc565b956111f686612ccc565b9261120661038b8883878c612536565b61121087826127a2565b95866112b0575b508561129c575b8561127f575b5084611258575b50506104499293506040519485948590949392606092608083019615158352602083015260408201520152565b610449945061126f866060611275959801906117ae565b906129af565b915082388061122b565b8161129592965061126f826060869401906117ae565b9338611224565b94506112aa82828888612868565b9461121e565b955038611217565b9081604091031261000e5790565b503461000e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5767ffffffffffffffff60043581811161000e576113179036906004016112b8565b9060243590811161000e576020916113366107b89236906004016112b8565b90612a86565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760206040517ff73f37e9f570369ceaab59cef16249ae1c0ad1afd592d656afac0be6f63b87e08152f35b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602060ff600354166040519015158152f35b503461000e5760206107b86113ec36610f50565b92919091612868565b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e577fa40d69111be14f29022626d38310e47cc2d7f4cb728961509c2f65a4bee08c5b6020600435611454816108af565b73ffffffffffffffffffffffffffffffffffffffff90611479826000541633146116d0565b16610e818161335f565b503461000e5761149b6114953661096a565b91612250565b604080519215158352602083019190915290f35b503461000e57610449610fe86114c4366102c9565b90611a43565b503461000e5761149b6114dc3661096a565b91611ec3565b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760043561151e816108af565b73ffffffffffffffffffffffffffffffffffffffff611542816000541633146116d0565b8116156115545761155290611735565b005b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b503461000e5760206107b86115ec366102c9565b906127a2565b503461000e576116013661096a565b61160c839293612ccc565b9261161a61107385856126a4565b604083019261162984826117ae565b600310156116c3575b60604291013511159384611692575b508361167f575b83611664575b5050604080519215158352602083019390935250f35b611677935080606061126f9201906117ae565b38808061164e565b925061168c8282856128f2565b92611648565b8161169e9295506117ae565b600410156116b6575b60804291013510159238611641565b6116be611802565b6116a7565b6116cb611802565b611632565b156116d757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b6000549073ffffffffffffffffffffffffffffffffffffffff80911691827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e06000604051a3565b3561032b816105ef565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561000e570180359067ffffffffffffffff821161000e57602001918160051b3603831361000e57565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b901561183b5790565b61032b611802565b60609160031015611852570190565b61185a611802565b0190565b60809160041015611852570190565b60209160011015611852570190565b60e09160071015611852570190565b60409160021015611852570190565b3561032b816108af565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561000e570180359067ffffffffffffffff821161000e5760200191813603831361000e57565b156118fc57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6f72646572206e6f7420766572696669656400000000000000000000000000006044820152fd5b9015611994575b8035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18136030182121561000e570190565b61199c611802565b611961565b91908110156119e2575b60051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18136030182121561000e570190565b6119ea611802565b6119ab565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561000e570180359067ffffffffffffffff821161000e57602001918160061b3603831361000e57565b600092611a4f82613129565b93611a5984613129565b9050611a64836117a4565b15611d375784111593915b611a7881612ccc565b94611a8285612ccc565b94611a8f60035460ff1690565b611c33575b611aa361038b8285898b612536565b6040810192611ab56103a285846117ae565b35936040820194611ac96103a287856117ae565b35149485611c1a575b85611c00575b85611be0575b85611bc6575b85611ba6575b611af76103ea83866117ae565b354210159182611b8c575b5081611b74575b81611b5c575b5084611b54575b5083611b34575b505081611b2c575b5093929190565b905038611b25565b611b4c9293509061046f82606061047c9401906117ae565b903880611b1d565b935038611b16565b611b6b91506104a390836117ae565b35101538611b0f565b9050611b836104c382846117ae565b35111590611b09565b611b9c9192506104a390856117ae565b3510159038611b02565b94506001611bbd61050b61050560608601866117ae565b90501494611aea565b94506001611bd760608401846117ae565b90501494611ae4565b94506001611bf761050b61050560608701876117ae565b90501494611ade565b94506001611c1160608501856117ae565b90501494611ad8565b94506001611c2b6103a283866117ae565b351494611ad2565b604081016008611c4382846117ae565b9050149081611d1e575b5080611d06575b80611ce6575b15611a9457919050611caa611c7f611c746020840161189a565b9260c08101906118a4565b7f0000000000000000000000000000000000000000000000000000000000000000938492908a613495565b9182611cb9575b505093929190565b611cdf9250611cd8611ccd6020830161189a565b9160c08101906118a4565b9187613495565b3880611cb1565b506001611cff611cf960408601866117ae565b9061187c565b3514611c5a565b506008611d1660408501856117ae565b905014611c54565b60019150611cf9611d2f91846117ae565b351438611c4d565b809410159391611a6f565b9190811015611d83575b60051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff218136030182121561000e570190565b611d8b611802565b611d4c565b15611d9757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c6964206d616b6572206f72646572000000000000000000000000006044820152fd5b507f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6001907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe8111611e53570190565b61185a611df5565b6002907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd8111611e53570190565b6003907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8111611e53570190565b81198111611e53570190565b92909192611ed081612ccc565b60035460ff1661214f575b611ee861107382846126a4565b600092835b60608401611efb81866117ae565b9050861015611f3157600191611f2161050b88611f1b611f29958a6117ae565b906119a1565b919050611eb7565b940193611eed565b5093509390946000600192839284835b82811061202557505083612009575b83611fd8575b611f8c91611f706103a292611f6a89613129565b9261309a565b611f79886117a4565b15611fd0571015955b60408101906117ae565b3585149485611fc6575b505083611fbe575b5082611fb6575b5081611fb057509190565b90509190565b915038611fa5565b925038611f9e565b1493503880611f96565b111595611f82565b92506103a2611f8c91611f70611ffa611ff460408a018a6117ae565b9061185e565b35421115959250509150611f56565b925061201b6103ea60408701876117ae565b3542101592611f50565b6120358184869998979499611d42565b95612045606097888101906117ae565b6000915081905b8985888a8486106121295750505050505088612108575b61206e908994611eb7565b95806120ed575b806120d2575b96816120a0575b50961561209157600101611f41565b50505050505050505060009190565b6120cc9150806120b561047c928c018c6117ae565b9290916120c386898b611d42565b908101906117ae565b38612082565b506120e4611ff4611f82848789611d42565b3542111561207b565b506120ff6103ea611f82848789611d42565b35421015612075565b975061206e8861211f6103a2611f8286898b611d42565b3514989050612063565b85611f1b612147956120c3600198999a96611f219661050b96611d42565b92019061204c565b9291906040938482019461216386846117ae565b600897908814915081612237575b509060005b8881106121cf575b505090919293945015611edb5793506121cb9192506121a2611ccd6020830161189a565b907f00000000000000000000000000000000000000000000000000000000000000009286613495565b9190565b82612214575b826121ee575b82156121e957600101612176565b61217e565b9150600161220c611cf9612203858c8b611d42565b848101906117ae565b3514916121db565b91508661222e612225848b8a611d42565b838101906117ae565b905014916121d5565b60019150611cf961224891866117ae565b351438612171565b9290919261225d81612ccc565b61226a61107382846126a4565b600092835b6060840161227d81866117ae565b90508610156122a557600191611f2161050b88611f1b61229d958a6117ae565b94019361226f565b5093509390946000600192839284835b8281106122dc575050836120095783611fd857611f8c91611f706103a292611f6a89613129565b6122ec8184869998979499611d42565b956122fc606097888101906117ae565b6000915081905b8985888a8486106123ba5750505050505088612399575b612325908994611eb7565b958061237e575b80612363575b9681612348575b509615612091576001016122b5565b61235d9150806120b561047c928c018c6117ae565b38612339565b50612375611ff4611f82848789611d42565b35421115612332565b506123906103ea611f82848789611d42565b3542101561232c565b9750612325886123b06103a2611f8286898b611d42565b351498905061231a565b85611f1b6123d8956120c3600198999a96611f219661050b96611d42565b920190612303565b92919390936123ef858561284c565b9390916123fb86612ccc565b9661240581612ccc565b9661241260035460ff1690565b6124a8575b61242661038b83838b8d612536565b61243082826127a2565b94856124a0575b508461248c575b8461246f575b5083612454575b50505093929190565b612467935080606061126f9201906117ae565b38808061244b565b6124859194508261126f826060879401906117ae565b9238612444565b935061249a83838387612868565b9361243e565b945038612437565b6040810160086124b882846117ae565b905014908161251d575b5080612505575b806124eb575b15612417579250925050611caa611c7f611c746020840161189a565b5060016124fe611cf960408501856117ae565b35146124cf565b50600861251560408401846117ae565b9050146124c9565b60019150611cf961252e91846117ae565b3514386124c2565b6080830193919261254d610c4e610c4887846117ae565b6080840190612565610c6c610c4e610c4885896117ae565b73ffffffffffffffffffffffffffffffffffffffff80921614918215612655575b61258f846117a4565b9788612641575b8861260d575b5050866125e3575b50856125db575b50846125c8575b5050826125be57505090565b61032b92506126a4565b6125d39294506126a4565b9138806125b2565b9450386125ab565b9095506125f26020830161189a565b90612602610c6c6020870161189a565b9116141594386125a4565b829850610c6c610c4e6103a261262f610c4e6103a2612636968b9998996117ae565b958a6117ae565b91161495388061259c565b975061264f610d80876117a4565b97612596565b915080612668610c4e610c488a876117ae565b161580612676575b91612586565b5073b4fbf271143f4fbf7b91a5ded31805e42b2208d68161269d610c4e610c48868a6117ae565b1614612670565b906126ec9060208301356126b7816108af565b6126c460c08501856118a4565b917f000000000000000000000000000000000000000000000000000000000000000093613495565b9081612758575b816126fc575090565b73ffffffffffffffffffffffffffffffffffffffff915061272381608060209301906117ae565b6001101561274b575b0135612737816108af565b166000526002602052604060002054151590565b612753611802565b61272c565b905061276760808201826117ae565b15612795575b35612777816108af565b73ffffffffffffffffffffffffffffffffffffffff163014906126f3565b61279d611802565b61276d565b90604082016127b181846117ae565b6003101561283f575b6060429101351115928361280e575b5050816127f3575b816127da575090565b6127ed91508060406104a39201906117ae565b35101590565b90506128056104c360408301836117ae565b351115906127d1565b6128199293506117ae565b60041015612832575b60804291013510159038806127c9565b61283a611802565b612822565b612847611802565b6127ba565b9061285a6128629392613129565b928391613129565b10159190565b9260009283915b8083106128d1575050508060406128879201906117ae565b156128c4575b35811015918261289c57505090565b6128ac91925060408101906117ae565b156128b75735101590565b6128bf611802565b6127ed565b6128cc611802565b61288d565b9091936001906128e561050b8785876119a1565b919050019401919061286f565b909160009283915b808310612929575050508060406129129201906117ae565b1561291c57351490565b612924611802565b351490565b90919360019061293d61050b8785876119a1565b91905001940191906128fa565b1561295157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f746f6b656e49647320646f6e7420696e746572736563740000000000000000006044820152fd5b909182158015612a60575b612a5757600092835b8581106129d257505050501490565b60005b8281106129e6575b506001016129c3565b6129f4610c4e8285886119a1565b73ffffffffffffffffffffffffffffffffffffffff612a1a610c6c610c4e868c8a6119a1565b911614612a29576001016129d5565b9490612a51612a4c612a4160018095019886896119a1565b611336848b896119a1565b61294a565b906129dd565b50505050600190565b5083156129ba565b9190811015612a79575b60061b0190565b612a81611802565b612a72565b6020810190612a9582826119ef565b9190506020840193612aa785826119ef565b95905083158015612b29575b612b1e57600094855b878110612acd575050505050501490565b60005b868110612ae1575b50600101612abc565b612af581612aef85896119ef565b90612a68565b35612b0483612aef87896119ef565b3514612b1257600101612ad0565b50600196870196612ad8565b505050505050600190565b508515612ab3565b91907f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811161000e5760051b80928237016000815290565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6080810190811067ffffffffffffffff821117612bb557604052565b612bbd612b69565b604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117612bb557604052565b9060005b818110612c145750505090565b90919260019073ffffffffffffffffffffffffffffffffffffffff8535612c3a816108af565b16815260209081019401929101612c07565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f60209267ffffffffffffffff8111612c88575b01160190565b612c90612b69565b612c82565b929192612ca182612c4c565b91612caf6040519384612bc2565b82948184528183011161000e578281602093846000960137010152565b612cd5816117a4565b90612e2b612d0a612ce86020840161189a565b612e1f612cf860408601866117ae565b60405194602086019286928491612b31565b0393612d3c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe095868101835282612bc2565b51902094612d56612d5060608301836117ae565b90612ef6565b90612da5612d9e612d90612d84612d7060808601866117ae565b929060405192839160208301958691612c03565b038a8101835282612bc2565b5190209260a08101906118a4565b3691612c95565b6020815191012091604051978895602087019a8b9273ffffffffffffffffffffffffffffffffffffffff60c095929897969360e08601997f7bcfb5a29031e6b8d34ca1a14dd0a1f5cb11b20f755bb2a31ee3c4b143477e4a8752151560208701521660408501526060840152608083015260a08201520152565b03908101835282612bc2565b51902090565b60209067ffffffffffffffff8111612e4b575b60051b0190565b612e53612b69565b612e44565b90612e6282612e31565b612e6f6040519182612bc2565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612e9d8294612e31565b0190602036910137565b6020918151811015612ebc575b60051b010190565b612ec4611802565b612eb4565b805160208092019160005b828110612ee2575050505090565b835185529381019392810192600101612ed4565b90612f0081612e58565b9160005b828110612f4f57505050604051612e2b81612f23602082018095612ec9565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282612bc2565b80612f5d60019285856119a1565b35612f67816108af565b612f728286866119a1565b612fe5612f8d612f87602093848101906119ef565b90612ff9565b604080517ff73f37e9f570369ceaab59cef16249ae1c0ad1afd592d656afac0be6f63b87e094810194855273ffffffffffffffffffffffffffffffffffffffff90951660208501528301529091908160608401612f23565b519020612ff28287612ea7565b5201612f04565b9061300381612e58565b9160005b82811061302657505050604051612e2b81612f23602082018095612ec9565b806130346001928585612a68565b35602080613043848888612a68565b01356040928351928301937f88f0bd19d14f8b5d22c0605a15d9fffc285ebc8c86fb21139456d305982906f1855283015260609081830152815261308681612b99565b5190206130938287612ea7565b5201613007565b9060009182915b8083106130ae5750505090565b9091926130d06001916130ca6130c5878688611d42565b613129565b90611eb7565b930191906130a1565b8181106130e4570390565b6130ec611df5565b0390565b81156130fa570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6040810161313a610c4882846117ae565b359161314f61314983836117ae565b9061188b565b35908184146131dd5761317d613168611ff485846117ae565b356131766103ea86856117ae565b35906130d9565b9081156131d6576131976103ea6127109561319e936117ae565b35426130d9565b90808211156131c557505081905b83818111156131bd57030204900390565b900302040190565b836131d092026130f0565b906131ac565b5050505090565b50505090565b60015481101561321b575b60016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60190600090565b613223611802565b6131ee565b806000526002602052604060002054156000146132b95780600154680100000000000000008110156132ac575b600181018060015581101561329f575b7fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60155600154906000526002602052604060002055600190565b6132a7611802565b613265565b6132b4612b69565b613255565b50600090565b60015480156133305760007fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83019280841015613323575b600183520155600155565b61332b611802565b613318565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600081815260026020526040902054801561348e576000918160016133db9310613481575b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff838101928210613474575b8101908282036133e1575b505050506133cb6132bf565b6000526002602052604060002090565b55600190565b61345d927fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf5826133cb93613424951015613467575b60018a5201549283916131e3565b90919082549060031b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811b9283911b16911916179055565b55388080806133bf565b61346f611802565b613416565b61347c611df5565b6133b4565b613489611df5565b613384565b5050600090565b9091926135b094936040519460208601866134e286848490916042927f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201520190565b03966135147fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe098898101835282612bc2565b51902093613523368585612c95565b5161034581109081613617575b816135d0575b50156135b55790612e1f61359f61355b6135aa9594613556368988612c95565b61374e565b999060405193849160208301968790916042927f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201520190565b519020923691612c95565b92613e38565b600190565b50509093506135aa82916135ca368783612c95565b95612d9e565b600291507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd816043601f931061360a575b01161038613536565b613612611df5565b613601565b606281119150613530565b604051906040820182811067ffffffffffffffff82111761364d575b60405260208083523683820137565b613655612b69565b61363e565b9061366482612c4c565b6136716040519182612bc2565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612e9d8294612c4c565b6001907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611e53570190565b606090805160401015611852570190565b9060209180518210156136f057010190565b6136f8611802565b010190565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0460201181151516613732575b60051b90565b61373a611df5565b61372c565b9081602091031261000e575190565b919061375b835160011690565b6139915760ff60415b169161376f8361365a565b60005b84811061396e57506137c86137c26137bc6137b6613790888a6136de565b517fff000000000000000000000000000000000000000000000000000000000000001690565b60f81c90565b60ff1690565b60101b90565b6137ec6137e66137bc6137b66137906137e08a611e25565b8b6136de565b60081b90565b176138086137bc6137b661379061380289611e5b565b8a6136de565b179161381e6138188688516130d9565b60051c90565b9461382886612e58565b9660005b8781106138e5575050506000935b86518510156138aa57613884906138518689612ea7565b5185871c60011661388a5760408051602081019384529081019190915261387b8160608101612f23565b5190209461369f565b9361383a565b6040805160208101928352908101929092529061387b8160608101612f23565b9350936138de919550612f2392506138c19061399a565b926040519283916020830195869091604092825260208201520190565b5190209190565b6138fa6138f184611e89565b6130ca836136fd565b613902613622565b9060005b6020811061393c57505090613927613937926020808251830101910161373f565b613931828c612ea7565b5261369f565b61382c565b806139566137906139506139699486611eb7565b886136de565b60001a61396382866136de565b5361369f565b613906565b8061397f61379061398c93896136de565b60001a61396382856136de565b613772565b60ff6040613764565b60098110613c325760118110613aee5760158110613a505760178110613a055760177f2bebb58714187c8dadcda4b5a975e954a2daa4f8c232cf1880e5292ab21af13e9114027f99e8d8ff7ddc6198258cce0fe5930c7fe7799405517eca81dbf14c1707c163ad1890565b60157fe3947bb8c46b154dbc528e37c660f25a4b46f42a4f0273a182a482afbf01704b9114027f73ea6321c43a7d88f2d0f797219c7dd3405b1208e89c6d00c6df5c2cc833aa1d1890565b60138110613aa35760137f8a2ae1e665347b124bbe6dd785f66854b812cdc173241b07ac31a5aad824e4609114027f5089f7eef268ce27189a0f19e64dd8210ecadff4be5176a5bd4fd1f176f483a11890565b60117f59949ab744e7bdd3b0f162df45cb50c5e389dcf668384f986aeed2db3538931d9114027f84b50d02c0d7ec2a815ec27a71290ad861c7cd3addd94f5f7c0736df33fe18271890565b600d8110613b9457600f8110613b4957600f7fbbc7afbbfb37d6e2481b724a1d31b3f7172ea81f11c48f0316ef163ae7b78e319114027f3a8ceb52e9851a307cf6bd49c73a2ec0d37712e6c4d68c4dcf84df0ad574f59a1890565b600d7fe9e448e93bb1269915a166d995f87055b3a49fddbc8b6122229b59870b90dd439114027f7968127d641eabf208fbdc9d69f10fed718855c94a809679d41b7bcf18104b741890565b600b8110613be757600b7f460dfba6896b55302f5ea3fe8148a10604823ee62efecd8a7cd7f4164a3a458f9114027fdb50e721ad63671fc79a925f372d22d69adfe998243b341129c4ef29a20c7a741890565b60097faa26cbfa2500a9d8b7d294f8402d6fdc15a85cf4880b02a15e1d72bcc0280bcf9114027feaf49b43e05b65ffed9bd664ee39555b22fa8ba157aa058f19fc7fee92d386f41890565b60058110613cd85760078110613c8d5760077f3d02bd11ffb35c66783da533dc87158e48c182a1473c69fdf97faa25f8ff6c8e9114027f96596fb6c680230945bae686c1776a9920c438436a98dba61ca767f370b6ef0c1890565b60057f9e858593e2a90291b6e0534a26f59c99dfec8ef3c6dbcbc36a3b6ba2168954769114027f4c2c782f8c9daf12d0ec87e76fc496ffeed835292ca7ff04ac92375bbc0f4cc71890565b60038110613d2b5760037ffdfcca1d90f6e7d8b4f33545776f78f8e24e096a3f94e81ea1e7a4c3ba98df829114027f14300c4bb2d1850e661a7bb2347e8ac0fa0736fa434a6d0ae1017cb485ce1a7c1890565b60017f9276de30ccd0be6b416e3137d97e904831cb255b8dad79462be214b947703dae9114027fb7870d22600c57d01e7ff46f87ea8741898e43ce73f7d5bfb269c715ea8d42421890565b9081602091031261000e57517fffffffff000000000000000000000000000000000000000000000000000000008116810361000e5790565b90929192815260206040818301528351908160408401526000945b828610613e15575050601f817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0926060959611613e08575b0116010190565b6000858286010152613e01565b8581018201518487016060015294810194613dc9565b506040513d6000823e3d90fd5b919391929190833b15613f3e5750506020613ebb7fffffffff000000000000000000000000000000000000000000000000000000009373ffffffffffffffffffffffffffffffffffffffff936040519485809481937f1626ba7e000000000000000000000000000000000000000000000000000000009a8b845260048401613dae565b0392165afa908115613f31575b600091613f03575b501603613ed957565b60046040517f4f7fb80d000000000000000000000000000000000000000000000000000000008152fd5b613f24915060203d8111613f2a575b613f1c8183612bc2565b810190613d76565b38613ed0565b503d613f12565b613f39613e2b565b613ec8565b915091613f4b9350613f75565b565b919082604091031261000e576020825192015190565b60ff601b911660e48111611e53570190565b919081516040811460001461407a5750613ff9600091613f9f846020808097518301019101613f4d565b929092613fd17f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82169160ff1c613f63565b935b604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa1561406d575b73ffffffffffffffffffffffffffffffffffffffff8060005116908115928315614060575b50505061403657565b60046040517f815e1d64000000000000000000000000000000000000000000000000000000008152fd5b161415905038808061402d565b614075613e2b565b614008565b60410361410b576137906140a56137b661409d6020865187010160208701613f4d565b9390956136cd565b9260ff8416601b81141590816140ff575b506140cb5791613ff960209492600094613fd3565b6040517f1f003d0a00000000000000000000000000000000000000000000000000000000815260ff85166004820152602490fd5b601c91501415386140b6565b60046040517f8baa579f000000000000000000000000000000000000000000000000000000008152fdfea26469706673582212202f42f663722eafcc500d267085a617b5d6577cf27798e197b5435c48fb7c770264736f6c634300080e0033
Deployed Bytecode
0x60806040526004361015610013575b600080fd5b60003560e01c80630cc02a42146102b25780631d49c1ef146102a95780631dc267a9146102a05780633051b935146102465780633644e5151461029757806336ce5c7a1461028e5780633e4e4f8b146102855780634fb925581461027c57806355de2746146102735780635ce390731461026a578063715018a6146102615780637720595d146102585780637b866a1d1461024f578063829a23071461024657806383d121461461023d5780638ab234b6146102345780638da5cb5b1461022b5780638e2c7d8514610222578063950c52bb146102195780639e0daf5e14610210578063aaf5eb6814610207578063ad5c4648146101fe578063ae3aad4d146101f5578063b66948cf146101ec578063b7970741146101e3578063bf281c99146101da578063c291c1d5146101d1578063c5d3a107146101c8578063d4677527146101bf578063d9814ac5146101b6578063f1332a91146101ad578063f2fde38b146101a4578063f7a0e3f41461019b5763fd2596281461019357600080fd5b61000e6115f2565b5061000e6115d8565b5061000e6114e2565b5061000e6114ca565b5061000e6114af565b5061000e611483565b5061000e6113f5565b5061000e6113d8565b5061000e611396565b5061000e61133c565b5061000e6112c6565b5061000e6111bb565b5061000e61116d565b5061000e611131565b5061000e61100c565b5061000e610fca565b5061000e610ede565b5061000e610e8b565b5061000e610df3565b5061000e610bbc565b5061000e61073c565b5061000e610b62565b5061000e610acf565b5061000e610a27565b5061000e6109ea565b5061000e6109d0565b5061000e6108cd565b5061000e61087a565b5061000e61081c565b5061000e6107c2565b5061000e6105f9565b5061000e610595565b5061000e61032e565b908160e091031261000e5790565b9060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc83011261000e5767ffffffffffffffff60043581811161000e5783610314916004016102bb565b9260243591821161000e5761032b916004016102bb565b90565b503461000e5761033d366102c9565b60009161034981613129565b9261035383613129565b905061035e826117a4565b1561058b57831115925b61037182612ccc565b9361037b84612ccc565b9361039061038b8286888a612536565b6118f5565b60408101936103a86103a286846117ae565b90611832565b359460408201956103bc6103a288856117ae565b35149586610572575b86610558575b86610538575b8661051e575b866104ee575b6103f06103ea83866117ae565b90611843565b3542101591826104d4575b50816104b4575b81610494575b508561048c575b5084610457575b50508261044d575b5061044991926040519485948590949392606092608083019615158352602083015260408201520152565b0390f35b915061044961041e565b6104849294509061046f82606061047c9401906117ae565b92909160608101906117ae565b9290916129af565b913880610416565b94503861040f565b6104ab91506104a390836117ae565b42929161185e565b35101538610408565b90506104cb6104c382846117ae565b429291611843565b35111590610402565b6104e49192506104a390856117ae565b35101590386103fb565b9550600161051561050b61050560608601866117ae565b9061195a565b60208101906119ef565b905014956103dd565b9550600161052f60608401846117ae565b905014956103d7565b9550600161054f61050b61050560608701876117ae565b905014956103d1565b9550600161056960608501856117ae565b905014956103cb565b955060016105836103a283866117ae565b3514956103c5565b8093101592610368565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760206040517f7bcfb5a29031e6b8d34ca1a14dd0a1f5cb11b20f755bb2a31ee3c4b143477e4a8152f35b8015150361000e57565b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57600435610635816105ef565b61065873ffffffffffffffffffffffffffffffffffffffff6000541633146116d0565b6003549060ff82168115159283821515146106de577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0060ff7fa2d07ed145017e8fdeeb5ffaadae1e46bd9b24cd77169a72ca38efee2f234a4095169116176003556106d9604051928392839092916020906040830194151583521515910152565b0390a1005b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f2076616c7565206368616e676500000000000000000000000000000000006044820152fd5b503461000e5760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5767ffffffffffffffff60443581811161000e5761078d9036906004016102bb565b9060643590811161000e576020916107ac6107b89236906004016102bb565b90602435600435612536565b6040519015158152f35b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760206040517f49c42e8c36a4602069bb2830cb235db37e3c516a09ec9139ccd07204d14c47e28152f35b503461000e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760043567ffffffffffffffff811161000e576107b861087160209236906004016102bb565b602435906126a4565b503461000e5760406108a0610898610891366102c9565b9190613129565b918291613129565b10159082519182526020820152f35b73ffffffffffffffffffffffffffffffffffffffff81160361000e57565b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5773ffffffffffffffffffffffffffffffffffffffff60043561091e816108af565b16600052600260205260206040600020541515604051908152f35b9181601f8401121561000e5782359167ffffffffffffffff831161000e576020808501948460051b01011161000e57565b9060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc83011261000e5767ffffffffffffffff60043581811161000e57836109b5916004016102bb565b9260243591821161000e576109cc91600401610939565b9091565b503461000e5760206107b86109e43661096a565b916128f2565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e576020600154604051908152f35b503461000e576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610acc5780547fffffffffffffffffffffffff000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff821691610a9e3384146116d0565b16825581604051917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08284a3f35b80fd5b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602073ffffffffffffffffffffffffffffffffffffffff600435600154811015610b55575b60016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6015416604051908152f35b610b5d611802565b610b24565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760206040517f88f0bd19d14f8b5d22c0605a15d9fffc285ebc8c86fb21139456d305982906f18152f35b503461000e5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57600435610bf8816105ef565b67ffffffffffffffff9060243582811161000e57610c1a9036906004016102bb565b9160443590811161000e57610c339036906004016102bb565b6080830191610c53610c4e610c4885876117ae565b9061186d565b61189a565b916080810192610c85610c6c610c4e610c4887866117ae565b73ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff80921614928315610da4575b15610d8a57610cb486612ccc565b95610cbf87826126a4565b945b610cca826117a4565b9687610d72575b87610d3f575b505085610d13575b50505082610d0b575b5081610d03575b506040805191151582526020820192909252f35b905038610cef565b915038610ce8565b610d3291929395506020610d2b81610c6c930161189a565b940161189a565b9116141591388080610cdf565b829750610c6c610c4e6103a2610d60610c4e6103a2610d67968a98996117ae565b95886117ae565b911614943880610cd7565b9650610d84610d80856117a4565b1590565b96610cd1565b610d9382612ccc565b95610d9e87846126a4565b94610cc1565b925080610db7610c4e610c48888a6117ae565b161580610dc5575b92610ca6565b5073b4fbf271143f4fbf7b91a5ded31805e42b2208d681610dec610c4e610c4888876117ae565b1614610dbf565b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e577fe0390a89516146ccfb796a9fbfc3f7646282194c554d05020484599ee992dd5a6020600435610e52816108af565b73ffffffffffffffffffffffffffffffffffffffff90610e77826000541633146116d0565b16610e8181613228565b50604051908152a1005b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b503461000e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5767ffffffffffffffff60043581811161000e57610f2f903690600401610939565b60249291923591821161000e5760209261047c6107b8933690600401610939565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261000e5767ffffffffffffffff9160043583811161000e5782610f9b916004016102bb565b9260243581811161000e5783610fb3916004016102bb565b9260443591821161000e576109cc91600401610939565b503461000e57610449610fe8610fdf36610f50565b929190916123e0565b60408051941515855260208501939093529183015260608201529081906080820190565b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760043567ffffffffffffffff811161000e5761105c9036906004016102bb565b61106581612ccc565b9061107861107383836126a4565b611d90565b6040810190600161108983836117ae565b15611124575b3514918261110a575b826110ea575b6110ab6103ea82846117ae565b3542101591826110d1575b505081610d0357506040805191151582526020820192909252f35b6110e09250906104a3916117ae565b35101538806110b6565b9150600161110161050b61050560608501856117ae565b9050149161109e565b9150600161111b60608301836117ae565b90501491611098565b61112c611802565b61108f565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760206040516127108152f35b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602060405173b4fbf271143f4fbf7b91a5ded31805e42b2208d68152f35b503461000e576111ca36610f50565b90926111d581613129565b90816111e085613129565b1015926111ec82612ccc565b956111f686612ccc565b9261120661038b8883878c612536565b61121087826127a2565b95866112b0575b508561129c575b8561127f575b5084611258575b50506104499293506040519485948590949392606092608083019615158352602083015260408201520152565b610449945061126f866060611275959801906117ae565b906129af565b915082388061122b565b8161129592965061126f826060869401906117ae565b9338611224565b94506112aa82828888612868565b9461121e565b955038611217565b9081604091031261000e5790565b503461000e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5767ffffffffffffffff60043581811161000e576113179036906004016112b8565b9060243590811161000e576020916113366107b89236906004016112b8565b90612a86565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760206040517ff73f37e9f570369ceaab59cef16249ae1c0ad1afd592d656afac0be6f63b87e08152f35b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602060ff600354166040519015158152f35b503461000e5760206107b86113ec36610f50565b92919091612868565b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e577fa40d69111be14f29022626d38310e47cc2d7f4cb728961509c2f65a4bee08c5b6020600435611454816108af565b73ffffffffffffffffffffffffffffffffffffffff90611479826000541633146116d0565b16610e818161335f565b503461000e5761149b6114953661096a565b91612250565b604080519215158352602083019190915290f35b503461000e57610449610fe86114c4366102c9565b90611a43565b503461000e5761149b6114dc3661096a565b91611ec3565b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760043561151e816108af565b73ffffffffffffffffffffffffffffffffffffffff611542816000541633146116d0565b8116156115545761155290611735565b005b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b503461000e5760206107b86115ec366102c9565b906127a2565b503461000e576116013661096a565b61160c839293612ccc565b9261161a61107385856126a4565b604083019261162984826117ae565b600310156116c3575b60604291013511159384611692575b508361167f575b83611664575b5050604080519215158352602083019390935250f35b611677935080606061126f9201906117ae565b38808061164e565b925061168c8282856128f2565b92611648565b8161169e9295506117ae565b600410156116b6575b60804291013510159238611641565b6116be611802565b6116a7565b6116cb611802565b611632565b156116d757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b6000549073ffffffffffffffffffffffffffffffffffffffff80911691827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e06000604051a3565b3561032b816105ef565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561000e570180359067ffffffffffffffff821161000e57602001918160051b3603831361000e57565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b901561183b5790565b61032b611802565b60609160031015611852570190565b61185a611802565b0190565b60809160041015611852570190565b60209160011015611852570190565b60e09160071015611852570190565b60409160021015611852570190565b3561032b816108af565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561000e570180359067ffffffffffffffff821161000e5760200191813603831361000e57565b156118fc57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6f72646572206e6f7420766572696669656400000000000000000000000000006044820152fd5b9015611994575b8035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18136030182121561000e570190565b61199c611802565b611961565b91908110156119e2575b60051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18136030182121561000e570190565b6119ea611802565b6119ab565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561000e570180359067ffffffffffffffff821161000e57602001918160061b3603831361000e57565b600092611a4f82613129565b93611a5984613129565b9050611a64836117a4565b15611d375784111593915b611a7881612ccc565b94611a8285612ccc565b94611a8f60035460ff1690565b611c33575b611aa361038b8285898b612536565b6040810192611ab56103a285846117ae565b35936040820194611ac96103a287856117ae565b35149485611c1a575b85611c00575b85611be0575b85611bc6575b85611ba6575b611af76103ea83866117ae565b354210159182611b8c575b5081611b74575b81611b5c575b5084611b54575b5083611b34575b505081611b2c575b5093929190565b905038611b25565b611b4c9293509061046f82606061047c9401906117ae565b903880611b1d565b935038611b16565b611b6b91506104a390836117ae565b35101538611b0f565b9050611b836104c382846117ae565b35111590611b09565b611b9c9192506104a390856117ae565b3510159038611b02565b94506001611bbd61050b61050560608601866117ae565b90501494611aea565b94506001611bd760608401846117ae565b90501494611ae4565b94506001611bf761050b61050560608701876117ae565b90501494611ade565b94506001611c1160608501856117ae565b90501494611ad8565b94506001611c2b6103a283866117ae565b351494611ad2565b604081016008611c4382846117ae565b9050149081611d1e575b5080611d06575b80611ce6575b15611a9457919050611caa611c7f611c746020840161189a565b9260c08101906118a4565b7f49c42e8c36a4602069bb2830cb235db37e3c516a09ec9139ccd07204d14c47e2938492908a613495565b9182611cb9575b505093929190565b611cdf9250611cd8611ccd6020830161189a565b9160c08101906118a4565b9187613495565b3880611cb1565b506001611cff611cf960408601866117ae565b9061187c565b3514611c5a565b506008611d1660408501856117ae565b905014611c54565b60019150611cf9611d2f91846117ae565b351438611c4d565b809410159391611a6f565b9190811015611d83575b60051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff218136030182121561000e570190565b611d8b611802565b611d4c565b15611d9757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c6964206d616b6572206f72646572000000000000000000000000006044820152fd5b507f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6001907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe8111611e53570190565b61185a611df5565b6002907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd8111611e53570190565b6003907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8111611e53570190565b81198111611e53570190565b92909192611ed081612ccc565b60035460ff1661214f575b611ee861107382846126a4565b600092835b60608401611efb81866117ae565b9050861015611f3157600191611f2161050b88611f1b611f29958a6117ae565b906119a1565b919050611eb7565b940193611eed565b5093509390946000600192839284835b82811061202557505083612009575b83611fd8575b611f8c91611f706103a292611f6a89613129565b9261309a565b611f79886117a4565b15611fd0571015955b60408101906117ae565b3585149485611fc6575b505083611fbe575b5082611fb6575b5081611fb057509190565b90509190565b915038611fa5565b925038611f9e565b1493503880611f96565b111595611f82565b92506103a2611f8c91611f70611ffa611ff460408a018a6117ae565b9061185e565b35421115959250509150611f56565b925061201b6103ea60408701876117ae565b3542101592611f50565b6120358184869998979499611d42565b95612045606097888101906117ae565b6000915081905b8985888a8486106121295750505050505088612108575b61206e908994611eb7565b95806120ed575b806120d2575b96816120a0575b50961561209157600101611f41565b50505050505050505060009190565b6120cc9150806120b561047c928c018c6117ae565b9290916120c386898b611d42565b908101906117ae565b38612082565b506120e4611ff4611f82848789611d42565b3542111561207b565b506120ff6103ea611f82848789611d42565b35421015612075565b975061206e8861211f6103a2611f8286898b611d42565b3514989050612063565b85611f1b612147956120c3600198999a96611f219661050b96611d42565b92019061204c565b9291906040938482019461216386846117ae565b600897908814915081612237575b509060005b8881106121cf575b505090919293945015611edb5793506121cb9192506121a2611ccd6020830161189a565b907f49c42e8c36a4602069bb2830cb235db37e3c516a09ec9139ccd07204d14c47e29286613495565b9190565b82612214575b826121ee575b82156121e957600101612176565b61217e565b9150600161220c611cf9612203858c8b611d42565b848101906117ae565b3514916121db565b91508661222e612225848b8a611d42565b838101906117ae565b905014916121d5565b60019150611cf961224891866117ae565b351438612171565b9290919261225d81612ccc565b61226a61107382846126a4565b600092835b6060840161227d81866117ae565b90508610156122a557600191611f2161050b88611f1b61229d958a6117ae565b94019361226f565b5093509390946000600192839284835b8281106122dc575050836120095783611fd857611f8c91611f706103a292611f6a89613129565b6122ec8184869998979499611d42565b956122fc606097888101906117ae565b6000915081905b8985888a8486106123ba5750505050505088612399575b612325908994611eb7565b958061237e575b80612363575b9681612348575b509615612091576001016122b5565b61235d9150806120b561047c928c018c6117ae565b38612339565b50612375611ff4611f82848789611d42565b35421115612332565b506123906103ea611f82848789611d42565b3542101561232c565b9750612325886123b06103a2611f8286898b611d42565b351498905061231a565b85611f1b6123d8956120c3600198999a96611f219661050b96611d42565b920190612303565b92919390936123ef858561284c565b9390916123fb86612ccc565b9661240581612ccc565b9661241260035460ff1690565b6124a8575b61242661038b83838b8d612536565b61243082826127a2565b94856124a0575b508461248c575b8461246f575b5083612454575b50505093929190565b612467935080606061126f9201906117ae565b38808061244b565b6124859194508261126f826060879401906117ae565b9238612444565b935061249a83838387612868565b9361243e565b945038612437565b6040810160086124b882846117ae565b905014908161251d575b5080612505575b806124eb575b15612417579250925050611caa611c7f611c746020840161189a565b5060016124fe611cf960408501856117ae565b35146124cf565b50600861251560408401846117ae565b9050146124c9565b60019150611cf961252e91846117ae565b3514386124c2565b6080830193919261254d610c4e610c4887846117ae565b6080840190612565610c6c610c4e610c4885896117ae565b73ffffffffffffffffffffffffffffffffffffffff80921614918215612655575b61258f846117a4565b9788612641575b8861260d575b5050866125e3575b50856125db575b50846125c8575b5050826125be57505090565b61032b92506126a4565b6125d39294506126a4565b9138806125b2565b9450386125ab565b9095506125f26020830161189a565b90612602610c6c6020870161189a565b9116141594386125a4565b829850610c6c610c4e6103a261262f610c4e6103a2612636968b9998996117ae565b958a6117ae565b91161495388061259c565b975061264f610d80876117a4565b97612596565b915080612668610c4e610c488a876117ae565b161580612676575b91612586565b5073b4fbf271143f4fbf7b91a5ded31805e42b2208d68161269d610c4e610c48868a6117ae565b1614612670565b906126ec9060208301356126b7816108af565b6126c460c08501856118a4565b917f49c42e8c36a4602069bb2830cb235db37e3c516a09ec9139ccd07204d14c47e293613495565b9081612758575b816126fc575090565b73ffffffffffffffffffffffffffffffffffffffff915061272381608060209301906117ae565b6001101561274b575b0135612737816108af565b166000526002602052604060002054151590565b612753611802565b61272c565b905061276760808201826117ae565b15612795575b35612777816108af565b73ffffffffffffffffffffffffffffffffffffffff163014906126f3565b61279d611802565b61276d565b90604082016127b181846117ae565b6003101561283f575b6060429101351115928361280e575b5050816127f3575b816127da575090565b6127ed91508060406104a39201906117ae565b35101590565b90506128056104c360408301836117ae565b351115906127d1565b6128199293506117ae565b60041015612832575b60804291013510159038806127c9565b61283a611802565b612822565b612847611802565b6127ba565b9061285a6128629392613129565b928391613129565b10159190565b9260009283915b8083106128d1575050508060406128879201906117ae565b156128c4575b35811015918261289c57505090565b6128ac91925060408101906117ae565b156128b75735101590565b6128bf611802565b6127ed565b6128cc611802565b61288d565b9091936001906128e561050b8785876119a1565b919050019401919061286f565b909160009283915b808310612929575050508060406129129201906117ae565b1561291c57351490565b612924611802565b351490565b90919360019061293d61050b8785876119a1565b91905001940191906128fa565b1561295157565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f746f6b656e49647320646f6e7420696e746572736563740000000000000000006044820152fd5b909182158015612a60575b612a5757600092835b8581106129d257505050501490565b60005b8281106129e6575b506001016129c3565b6129f4610c4e8285886119a1565b73ffffffffffffffffffffffffffffffffffffffff612a1a610c6c610c4e868c8a6119a1565b911614612a29576001016129d5565b9490612a51612a4c612a4160018095019886896119a1565b611336848b896119a1565b61294a565b906129dd565b50505050600190565b5083156129ba565b9190811015612a79575b60061b0190565b612a81611802565b612a72565b6020810190612a9582826119ef565b9190506020840193612aa785826119ef565b95905083158015612b29575b612b1e57600094855b878110612acd575050505050501490565b60005b868110612ae1575b50600101612abc565b612af581612aef85896119ef565b90612a68565b35612b0483612aef87896119ef565b3514612b1257600101612ad0565b50600196870196612ad8565b505050505050600190565b508515612ab3565b91907f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811161000e5760051b80928237016000815290565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6080810190811067ffffffffffffffff821117612bb557604052565b612bbd612b69565b604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117612bb557604052565b9060005b818110612c145750505090565b90919260019073ffffffffffffffffffffffffffffffffffffffff8535612c3a816108af565b16815260209081019401929101612c07565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f60209267ffffffffffffffff8111612c88575b01160190565b612c90612b69565b612c82565b929192612ca182612c4c565b91612caf6040519384612bc2565b82948184528183011161000e578281602093846000960137010152565b612cd5816117a4565b90612e2b612d0a612ce86020840161189a565b612e1f612cf860408601866117ae565b60405194602086019286928491612b31565b0393612d3c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe095868101835282612bc2565b51902094612d56612d5060608301836117ae565b90612ef6565b90612da5612d9e612d90612d84612d7060808601866117ae565b929060405192839160208301958691612c03565b038a8101835282612bc2565b5190209260a08101906118a4565b3691612c95565b6020815191012091604051978895602087019a8b9273ffffffffffffffffffffffffffffffffffffffff60c095929897969360e08601997f7bcfb5a29031e6b8d34ca1a14dd0a1f5cb11b20f755bb2a31ee3c4b143477e4a8752151560208701521660408501526060840152608083015260a08201520152565b03908101835282612bc2565b51902090565b60209067ffffffffffffffff8111612e4b575b60051b0190565b612e53612b69565b612e44565b90612e6282612e31565b612e6f6040519182612bc2565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612e9d8294612e31565b0190602036910137565b6020918151811015612ebc575b60051b010190565b612ec4611802565b612eb4565b805160208092019160005b828110612ee2575050505090565b835185529381019392810192600101612ed4565b90612f0081612e58565b9160005b828110612f4f57505050604051612e2b81612f23602082018095612ec9565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282612bc2565b80612f5d60019285856119a1565b35612f67816108af565b612f728286866119a1565b612fe5612f8d612f87602093848101906119ef565b90612ff9565b604080517ff73f37e9f570369ceaab59cef16249ae1c0ad1afd592d656afac0be6f63b87e094810194855273ffffffffffffffffffffffffffffffffffffffff90951660208501528301529091908160608401612f23565b519020612ff28287612ea7565b5201612f04565b9061300381612e58565b9160005b82811061302657505050604051612e2b81612f23602082018095612ec9565b806130346001928585612a68565b35602080613043848888612a68565b01356040928351928301937f88f0bd19d14f8b5d22c0605a15d9fffc285ebc8c86fb21139456d305982906f1855283015260609081830152815261308681612b99565b5190206130938287612ea7565b5201613007565b9060009182915b8083106130ae5750505090565b9091926130d06001916130ca6130c5878688611d42565b613129565b90611eb7565b930191906130a1565b8181106130e4570390565b6130ec611df5565b0390565b81156130fa570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6040810161313a610c4882846117ae565b359161314f61314983836117ae565b9061188b565b35908184146131dd5761317d613168611ff485846117ae565b356131766103ea86856117ae565b35906130d9565b9081156131d6576131976103ea6127109561319e936117ae565b35426130d9565b90808211156131c557505081905b83818111156131bd57030204900390565b900302040190565b836131d092026130f0565b906131ac565b5050505090565b50505090565b60015481101561321b575b60016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60190600090565b613223611802565b6131ee565b806000526002602052604060002054156000146132b95780600154680100000000000000008110156132ac575b600181018060015581101561329f575b7fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60155600154906000526002602052604060002055600190565b6132a7611802565b613265565b6132b4612b69565b613255565b50600090565b60015480156133305760007fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83019280841015613323575b600183520155600155565b61332b611802565b613318565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600081815260026020526040902054801561348e576000918160016133db9310613481575b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff838101928210613474575b8101908282036133e1575b505050506133cb6132bf565b6000526002602052604060002090565b55600190565b61345d927fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf5826133cb93613424951015613467575b60018a5201549283916131e3565b90919082549060031b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811b9283911b16911916179055565b55388080806133bf565b61346f611802565b613416565b61347c611df5565b6133b4565b613489611df5565b613384565b5050600090565b9091926135b094936040519460208601866134e286848490916042927f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201520190565b03966135147fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe098898101835282612bc2565b51902093613523368585612c95565b5161034581109081613617575b816135d0575b50156135b55790612e1f61359f61355b6135aa9594613556368988612c95565b61374e565b999060405193849160208301968790916042927f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201520190565b519020923691612c95565b92613e38565b600190565b50509093506135aa82916135ca368783612c95565b95612d9e565b600291507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd816043601f931061360a575b01161038613536565b613612611df5565b613601565b606281119150613530565b604051906040820182811067ffffffffffffffff82111761364d575b60405260208083523683820137565b613655612b69565b61363e565b9061366482612c4c565b6136716040519182612bc2565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612e9d8294612c4c565b6001907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611e53570190565b606090805160401015611852570190565b9060209180518210156136f057010190565b6136f8611802565b010190565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0460201181151516613732575b60051b90565b61373a611df5565b61372c565b9081602091031261000e575190565b919061375b835160011690565b6139915760ff60415b169161376f8361365a565b60005b84811061396e57506137c86137c26137bc6137b6613790888a6136de565b517fff000000000000000000000000000000000000000000000000000000000000001690565b60f81c90565b60ff1690565b60101b90565b6137ec6137e66137bc6137b66137906137e08a611e25565b8b6136de565b60081b90565b176138086137bc6137b661379061380289611e5b565b8a6136de565b179161381e6138188688516130d9565b60051c90565b9461382886612e58565b9660005b8781106138e5575050506000935b86518510156138aa57613884906138518689612ea7565b5185871c60011661388a5760408051602081019384529081019190915261387b8160608101612f23565b5190209461369f565b9361383a565b6040805160208101928352908101929092529061387b8160608101612f23565b9350936138de919550612f2392506138c19061399a565b926040519283916020830195869091604092825260208201520190565b5190209190565b6138fa6138f184611e89565b6130ca836136fd565b613902613622565b9060005b6020811061393c57505090613927613937926020808251830101910161373f565b613931828c612ea7565b5261369f565b61382c565b806139566137906139506139699486611eb7565b886136de565b60001a61396382866136de565b5361369f565b613906565b8061397f61379061398c93896136de565b60001a61396382856136de565b613772565b60ff6040613764565b60098110613c325760118110613aee5760158110613a505760178110613a055760177f2bebb58714187c8dadcda4b5a975e954a2daa4f8c232cf1880e5292ab21af13e9114027f99e8d8ff7ddc6198258cce0fe5930c7fe7799405517eca81dbf14c1707c163ad1890565b60157fe3947bb8c46b154dbc528e37c660f25a4b46f42a4f0273a182a482afbf01704b9114027f73ea6321c43a7d88f2d0f797219c7dd3405b1208e89c6d00c6df5c2cc833aa1d1890565b60138110613aa35760137f8a2ae1e665347b124bbe6dd785f66854b812cdc173241b07ac31a5aad824e4609114027f5089f7eef268ce27189a0f19e64dd8210ecadff4be5176a5bd4fd1f176f483a11890565b60117f59949ab744e7bdd3b0f162df45cb50c5e389dcf668384f986aeed2db3538931d9114027f84b50d02c0d7ec2a815ec27a71290ad861c7cd3addd94f5f7c0736df33fe18271890565b600d8110613b9457600f8110613b4957600f7fbbc7afbbfb37d6e2481b724a1d31b3f7172ea81f11c48f0316ef163ae7b78e319114027f3a8ceb52e9851a307cf6bd49c73a2ec0d37712e6c4d68c4dcf84df0ad574f59a1890565b600d7fe9e448e93bb1269915a166d995f87055b3a49fddbc8b6122229b59870b90dd439114027f7968127d641eabf208fbdc9d69f10fed718855c94a809679d41b7bcf18104b741890565b600b8110613be757600b7f460dfba6896b55302f5ea3fe8148a10604823ee62efecd8a7cd7f4164a3a458f9114027fdb50e721ad63671fc79a925f372d22d69adfe998243b341129c4ef29a20c7a741890565b60097faa26cbfa2500a9d8b7d294f8402d6fdc15a85cf4880b02a15e1d72bcc0280bcf9114027feaf49b43e05b65ffed9bd664ee39555b22fa8ba157aa058f19fc7fee92d386f41890565b60058110613cd85760078110613c8d5760077f3d02bd11ffb35c66783da533dc87158e48c182a1473c69fdf97faa25f8ff6c8e9114027f96596fb6c680230945bae686c1776a9920c438436a98dba61ca767f370b6ef0c1890565b60057f9e858593e2a90291b6e0534a26f59c99dfec8ef3c6dbcbc36a3b6ba2168954769114027f4c2c782f8c9daf12d0ec87e76fc496ffeed835292ca7ff04ac92375bbc0f4cc71890565b60038110613d2b5760037ffdfcca1d90f6e7d8b4f33545776f78f8e24e096a3f94e81ea1e7a4c3ba98df829114027f14300c4bb2d1850e661a7bb2347e8ac0fa0736fa434a6d0ae1017cb485ce1a7c1890565b60017f9276de30ccd0be6b416e3137d97e904831cb255b8dad79462be214b947703dae9114027fb7870d22600c57d01e7ff46f87ea8741898e43ce73f7d5bfb269c715ea8d42421890565b9081602091031261000e57517fffffffff000000000000000000000000000000000000000000000000000000008116810361000e5790565b90929192815260206040818301528351908160408401526000945b828610613e15575050601f817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0926060959611613e08575b0116010190565b6000858286010152613e01565b8581018201518487016060015294810194613dc9565b506040513d6000823e3d90fd5b919391929190833b15613f3e5750506020613ebb7fffffffff000000000000000000000000000000000000000000000000000000009373ffffffffffffffffffffffffffffffffffffffff936040519485809481937f1626ba7e000000000000000000000000000000000000000000000000000000009a8b845260048401613dae565b0392165afa908115613f31575b600091613f03575b501603613ed957565b60046040517f4f7fb80d000000000000000000000000000000000000000000000000000000008152fd5b613f24915060203d8111613f2a575b613f1c8183612bc2565b810190613d76565b38613ed0565b503d613f12565b613f39613e2b565b613ec8565b915091613f4b9350613f75565b565b919082604091031261000e576020825192015190565b60ff601b911660e48111611e53570190565b919081516040811460001461407a5750613ff9600091613f9f846020808097518301019101613f4d565b929092613fd17f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82169160ff1c613f63565b935b604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa1561406d575b73ffffffffffffffffffffffffffffffffffffffff8060005116908115928315614060575b50505061403657565b60046040517f815e1d64000000000000000000000000000000000000000000000000000000008152fd5b161415905038808061402d565b614075613e2b565b614008565b60410361410b576137906140a56137b661409d6020865187010160208701613f4d565b9390956136cd565b9260ff8416601b81141590816140ff575b506140cb5791613ff960209492600094613fd3565b6040517f1f003d0a00000000000000000000000000000000000000000000000000000000815260ff85166004820152602490fd5b601c91501415386140b6565b60046040517f8baa579f000000000000000000000000000000000000000000000000000000008152fdfea26469706673582212202f42f663722eafcc500d267085a617b5d6577cf27798e197b5435c48fb7c770264736f6c634300080e0033
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.