More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 893,612 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Cancel Order | 21388448 | 10 days ago | IN | 0 ETH | 0.00210262 | ||||
Fill Or Kill Ord... | 21336009 | 17 days ago | IN | 0 ETH | 0.00480798 | ||||
Fill Or Kill Ord... | 21325844 | 19 days ago | IN | 0 ETH | 0.00475622 | ||||
Fill Or Kill Ord... | 21320193 | 20 days ago | IN | 0 ETH | 0.00404959 | ||||
Fill Or Kill Ord... | 21309673 | 21 days ago | IN | 0 ETH | 0.00656253 | ||||
Fill Or Kill Ord... | 21268118 | 27 days ago | IN | 0 ETH | 0.00129359 | ||||
Fill Or Kill Ord... | 21233177 | 32 days ago | IN | 0 ETH | 0.0025721 | ||||
Fill Or Kill Ord... | 21197185 | 37 days ago | IN | 0 ETH | 0.0025499 | ||||
Fill Or Kill Ord... | 21131573 | 46 days ago | IN | 0 ETH | 0.00330081 | ||||
Cancel Order | 21124526 | 47 days ago | IN | 0 ETH | 0.00041548 | ||||
Cancel Order | 21124520 | 47 days ago | IN | 0 ETH | 0.0005182 | ||||
Cancel Order | 21124515 | 47 days ago | IN | 0 ETH | 0.0004549 | ||||
Cancel Order | 21124510 | 47 days ago | IN | 0 ETH | 0.00057586 | ||||
Fill Or Kill Ord... | 21109815 | 49 days ago | IN | 0 ETH | 0.00059667 | ||||
Fill Or Kill Ord... | 21105361 | 50 days ago | IN | 0 ETH | 0.0009272 | ||||
Fill Or Kill Ord... | 21102988 | 50 days ago | IN | 0 ETH | 0.000618 | ||||
Fill Or Kill Ord... | 21102410 | 50 days ago | IN | 0 ETH | 0.00113491 | ||||
Fill Or Kill Ord... | 21096782 | 51 days ago | IN | 0 ETH | 0.000657 | ||||
Cancel Order | 21081460 | 53 days ago | IN | 0 ETH | 0.00090907 | ||||
Fill Or Kill Ord... | 21074456 | 54 days ago | IN | 0 ETH | 0.0013128 | ||||
Cancel Order | 21053575 | 57 days ago | IN | 0 ETH | 0.00029629 | ||||
Cancel Order | 21032297 | 60 days ago | IN | 0 ETH | 0.00051868 | ||||
Fill Or Kill Ord... | 21021951 | 61 days ago | IN | 0 ETH | 0.0020388 | ||||
Cancel Order | 21014784 | 62 days ago | IN | 0 ETH | 0.001067 | ||||
Cancel Order | 21012010 | 63 days ago | IN | 0 ETH | 0.00056646 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
20452913 | 141 days ago | 0.00007 ETH | ||||
20452913 | 141 days ago | 0.00007 ETH | ||||
20452844 | 141 days ago | 0.00007 ETH | ||||
20452844 | 141 days ago | 0.00007 ETH | ||||
20452785 | 141 days ago | 0.00007 ETH | ||||
20452785 | 141 days ago | 0.00007 ETH | ||||
20452785 | 141 days ago | 0.00007 ETH | ||||
20452785 | 141 days ago | 0.00007 ETH | ||||
20452687 | 141 days ago | 0.00007 ETH | ||||
20452687 | 141 days ago | 0.00007 ETH | ||||
20451862 | 141 days ago | 0.00007 ETH | ||||
20451862 | 141 days ago | 0.00007 ETH | ||||
20451862 | 141 days ago | 0.00007 ETH | ||||
20451862 | 141 days ago | 0.00007 ETH | ||||
20409109 | 147 days ago | 0.00021 ETH | ||||
20409109 | 147 days ago | 0.00021 ETH | ||||
20409109 | 147 days ago | 0.00259 ETH | ||||
20409109 | 147 days ago | 0.00259 ETH | ||||
20407860 | 147 days ago | 0.00007 ETH | ||||
20407860 | 147 days ago | 0.00007 ETH | ||||
20407860 | 147 days ago | 0.00007 ETH | ||||
20407860 | 147 days ago | 0.00007 ETH | ||||
19296793 | 302 days ago | 0.0028 ETH | ||||
19296793 | 302 days ago | 0.0028 ETH | ||||
17525571 | 551 days ago | 0.0105 ETH |
Loading...
Loading
Contract Name:
Exchange
Compiler Version
v0.5.12+commit.7709ece9
Contract Source Code (Solidity Standard Json-Input format)
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; import "./MixinMatchOrders.sol"; import "./MixinWrapperFunctions.sol"; import "./MixinTransferSimulator.sol"; // solhint-disable no-empty-blocks // MixinAssetProxyDispatcher, MixinExchangeCore, MixinSignatureValidator, // and MixinTransactions are all inherited via the other Mixins that are // used. contract Exchange is LibEIP712ExchangeDomain, MixinMatchOrders, MixinWrapperFunctions, MixinTransferSimulator { /// @dev Mixins are instantiated in the order they are inherited /// @param chainId Chain ID of the network this contract is deployed on. constructor (uint256 chainId) public LibEIP712ExchangeDomain(chainId, address(0)) {} }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; import "@0x/contracts-utils/contracts/src/LibEIP712.sol"; contract LibEIP712ExchangeDomain { // EIP712 Exchange Domain Name value string constant internal _EIP712_EXCHANGE_DOMAIN_NAME = "0x Protocol"; // EIP712 Exchange Domain Version value string constant internal _EIP712_EXCHANGE_DOMAIN_VERSION = "3.0.0"; // Hash of the EIP712 Domain Separator data // solhint-disable-next-line var-name-mixedcase bytes32 public EIP712_EXCHANGE_DOMAIN_HASH; /// @param chainId Chain ID of the network this contract is deployed on. /// @param verifyingContractAddressIfExists Address of the verifying contract (null if the address of this contract) constructor ( uint256 chainId, address verifyingContractAddressIfExists ) public { address verifyingContractAddress = verifyingContractAddressIfExists == address(0) ? address(this) : verifyingContractAddressIfExists; EIP712_EXCHANGE_DOMAIN_HASH = LibEIP712.hashEIP712Domain( _EIP712_EXCHANGE_DOMAIN_NAME, _EIP712_EXCHANGE_DOMAIN_VERSION, chainId, verifyingContractAddress ); } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; library LibEIP712 { // Hash of the EIP712 Domain Separator Schema // keccak256(abi.encodePacked( // "EIP712Domain(", // "string name,", // "string version,", // "uint256 chainId,", // "address verifyingContract", // ")" // )) bytes32 constant internal _EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; /// @dev Calculates a EIP712 domain separator. /// @param name The EIP712 domain name. /// @param version The EIP712 domain version. /// @param verifyingContract The EIP712 verifying contract. /// @return EIP712 domain separator. function hashEIP712Domain( string memory name, string memory version, uint256 chainId, address verifyingContract ) internal pure returns (bytes32 result) { bytes32 schemaHash = _EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH; // Assembly for more efficient computing: // keccak256(abi.encodePacked( // _EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH, // keccak256(bytes(name)), // keccak256(bytes(version)), // chainId, // uint256(verifyingContract) // )) assembly { // Calculate hashes of dynamic data let nameHash := keccak256(add(name, 32), mload(name)) let versionHash := keccak256(add(version, 32), mload(version)) // Load free memory pointer let memPtr := mload(64) // Store params in memory mstore(memPtr, schemaHash) mstore(add(memPtr, 32), nameHash) mstore(add(memPtr, 64), versionHash) mstore(add(memPtr, 96), chainId) mstore(add(memPtr, 128), verifyingContract) // Compute hash result := keccak256(memPtr, 160) } return result; } /// @dev Calculates EIP712 encoding for a hash struct with a given domain hash. /// @param eip712DomainHash Hash of the domain domain separator data, computed /// with getDomainHash(). /// @param hashStruct The EIP712 hash struct. /// @return EIP712 hash applied to the given EIP712 Domain. function hashEIP712Message(bytes32 eip712DomainHash, bytes32 hashStruct) internal pure returns (bytes32 result) { // Assembly for more efficient computing: // keccak256(abi.encodePacked( // EIP191_HEADER, // EIP712_DOMAIN_HASH, // hashStruct // )); assembly { // Load free memory pointer let memPtr := mload(64) mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000) // EIP191 header mstore(add(memPtr, 2), eip712DomainHash) // EIP712 domain hash mstore(add(memPtr, 34), hashStruct) // Hash of struct // Compute hash result := keccak256(memPtr, 66) } return result; } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-utils/contracts/src/LibBytes.sol"; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; import "./interfaces/IMatchOrders.sol"; import "./MixinExchangeCore.sol"; contract MixinMatchOrders is MixinExchangeCore, IMatchOrders { using LibBytes for bytes; using LibSafeMath for uint256; using LibOrder for LibOrder.Order; /// @dev Match complementary orders that have a profitable spread. /// Each order is filled at their respective price point, and /// the matcher receives a profit denominated in the left maker asset. /// @param leftOrders Set of orders with the same maker / taker asset. /// @param rightOrders Set of orders to match against `leftOrders` /// @param leftSignatures Proof that left orders were created by the left makers. /// @param rightSignatures Proof that right orders were created by the right makers. /// @return batchMatchedFillResults Amounts filled and profit generated. function batchMatchOrders( LibOrder.Order[] memory leftOrders, LibOrder.Order[] memory rightOrders, bytes[] memory leftSignatures, bytes[] memory rightSignatures ) public payable refundFinalBalanceNoReentry returns (LibFillResults.BatchMatchedFillResults memory batchMatchedFillResults) { return _batchMatchOrders( leftOrders, rightOrders, leftSignatures, rightSignatures, false ); } /// @dev Match complementary orders that have a profitable spread. /// Each order is maximally filled at their respective price point, and /// the matcher receives a profit denominated in either the left maker asset, /// right maker asset, or a combination of both. /// @param leftOrders Set of orders with the same maker / taker asset. /// @param rightOrders Set of orders to match against `leftOrders` /// @param leftSignatures Proof that left orders were created by the left makers. /// @param rightSignatures Proof that right orders were created by the right makers. /// @return batchMatchedFillResults Amounts filled and profit generated. function batchMatchOrdersWithMaximalFill( LibOrder.Order[] memory leftOrders, LibOrder.Order[] memory rightOrders, bytes[] memory leftSignatures, bytes[] memory rightSignatures ) public payable refundFinalBalanceNoReentry returns (LibFillResults.BatchMatchedFillResults memory batchMatchedFillResults) { return _batchMatchOrders( leftOrders, rightOrders, leftSignatures, rightSignatures, true ); } /// @dev Match two complementary orders that have a profitable spread. /// Each order is filled at their respective price point. However, the calculations are /// carried out as though the orders are both being filled at the right order's price point. /// The profit made by the left order goes to the taker (who matched the two orders). /// @param leftOrder First order to match. /// @param rightOrder Second order to match. /// @param leftSignature Proof that order was created by the left maker. /// @param rightSignature Proof that order was created by the right maker. /// @return matchedFillResults Amounts filled and fees paid by maker and taker of matched orders. function matchOrders( LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder, bytes memory leftSignature, bytes memory rightSignature ) public payable refundFinalBalanceNoReentry returns (LibFillResults.MatchedFillResults memory matchedFillResults) { return _matchOrders( leftOrder, rightOrder, leftSignature, rightSignature, false ); } /// @dev Match two complementary orders that have a profitable spread. /// Each order is maximally filled at their respective price point, and /// the matcher receives a profit denominated in either the left maker asset, /// right maker asset, or a combination of both. /// @param leftOrder First order to match. /// @param rightOrder Second order to match. /// @param leftSignature Proof that order was created by the left maker. /// @param rightSignature Proof that order was created by the right maker. /// @return matchedFillResults Amounts filled by maker and taker of matched orders. function matchOrdersWithMaximalFill( LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder, bytes memory leftSignature, bytes memory rightSignature ) public payable refundFinalBalanceNoReentry returns (LibFillResults.MatchedFillResults memory matchedFillResults) { return _matchOrders( leftOrder, rightOrder, leftSignature, rightSignature, true ); } /// @dev Validates context for matchOrders. Succeeds or throws. /// @param leftOrder First order to match. /// @param rightOrder Second order to match. /// @param leftOrderHash First matched order hash. /// @param rightOrderHash Second matched order hash. function _assertValidMatch( LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder, bytes32 leftOrderHash, bytes32 rightOrderHash ) internal pure { // Make sure there is a profitable spread. // There is a profitable spread iff the cost per unit bought (OrderA.MakerAmount/OrderA.TakerAmount) for each order is greater // than the profit per unit sold of the matched order (OrderB.TakerAmount/OrderB.MakerAmount). // This is satisfied by the equations below: // <leftOrder.makerAssetAmount> / <leftOrder.takerAssetAmount> >= <rightOrder.takerAssetAmount> / <rightOrder.makerAssetAmount> // AND // <rightOrder.makerAssetAmount> / <rightOrder.takerAssetAmount> >= <leftOrder.takerAssetAmount> / <leftOrder.makerAssetAmount> // These equations can be combined to get the following: if (leftOrder.makerAssetAmount.safeMul(rightOrder.makerAssetAmount) < leftOrder.takerAssetAmount.safeMul(rightOrder.takerAssetAmount)) { LibRichErrors.rrevert(LibExchangeRichErrors.NegativeSpreadError( leftOrderHash, rightOrderHash )); } } /// @dev Match complementary orders that have a profitable spread. /// Each order is filled at their respective price point, and /// the matcher receives a profit denominated in the left maker asset. /// This is the reentrant version of `batchMatchOrders` and `batchMatchOrdersWithMaximalFill`. /// @param leftOrders Set of orders with the same maker / taker asset. /// @param rightOrders Set of orders to match against `leftOrders` /// @param leftSignatures Proof that left orders were created by the left makers. /// @param rightSignatures Proof that right orders were created by the right makers. /// @param shouldMaximallyFillOrders A value that indicates whether or not the order matching /// should be done with maximal fill. /// @return batchMatchedFillResults Amounts filled and profit generated. function _batchMatchOrders( LibOrder.Order[] memory leftOrders, LibOrder.Order[] memory rightOrders, bytes[] memory leftSignatures, bytes[] memory rightSignatures, bool shouldMaximallyFillOrders ) internal returns (LibFillResults.BatchMatchedFillResults memory batchMatchedFillResults) { // Ensure that the left and right orders have nonzero lengths. if (leftOrders.length == 0) { LibRichErrors.rrevert(LibExchangeRichErrors.BatchMatchOrdersError( LibExchangeRichErrors.BatchMatchOrdersErrorCodes.ZERO_LEFT_ORDERS )); } if (rightOrders.length == 0) { LibRichErrors.rrevert(LibExchangeRichErrors.BatchMatchOrdersError( LibExchangeRichErrors.BatchMatchOrdersErrorCodes.ZERO_RIGHT_ORDERS )); } // Ensure that the left and right arrays are compatible. if (leftOrders.length != leftSignatures.length) { LibRichErrors.rrevert(LibExchangeRichErrors.BatchMatchOrdersError( LibExchangeRichErrors.BatchMatchOrdersErrorCodes.INVALID_LENGTH_LEFT_SIGNATURES )); } if (rightOrders.length != rightSignatures.length) { LibRichErrors.rrevert(LibExchangeRichErrors.BatchMatchOrdersError( LibExchangeRichErrors.BatchMatchOrdersErrorCodes.INVALID_LENGTH_RIGHT_SIGNATURES )); } batchMatchedFillResults.left = new LibFillResults.FillResults[](leftOrders.length); batchMatchedFillResults.right = new LibFillResults.FillResults[](rightOrders.length); // Set up initial indices. uint256 leftIdx = 0; uint256 rightIdx = 0; // Keep local variables for orders, order filled amounts, and signatures for efficiency. LibOrder.Order memory leftOrder = leftOrders[0]; LibOrder.Order memory rightOrder = rightOrders[0]; (, uint256 leftOrderTakerAssetFilledAmount) = _getOrderHashAndFilledAmount(leftOrder); (, uint256 rightOrderTakerAssetFilledAmount) = _getOrderHashAndFilledAmount(rightOrder); LibFillResults.FillResults memory leftFillResults; LibFillResults.FillResults memory rightFillResults; // Loop infinitely (until broken inside of the loop), but keep a counter of how // many orders have been matched. for (;;) { // Match the two orders that are pointed to by the left and right indices LibFillResults.MatchedFillResults memory matchResults = _matchOrders( leftOrder, rightOrder, leftSignatures[leftIdx], rightSignatures[rightIdx], shouldMaximallyFillOrders ); // Update the order filled amounts with the updated takerAssetFilledAmount leftOrderTakerAssetFilledAmount = leftOrderTakerAssetFilledAmount.safeAdd(matchResults.left.takerAssetFilledAmount); rightOrderTakerAssetFilledAmount = rightOrderTakerAssetFilledAmount.safeAdd(matchResults.right.takerAssetFilledAmount); // Aggregate the new fill results with the previous fill results for the current orders. leftFillResults = LibFillResults.addFillResults( leftFillResults, matchResults.left ); rightFillResults = LibFillResults.addFillResults( rightFillResults, matchResults.right ); // Update the profit in the left and right maker assets using the profits from // the match. batchMatchedFillResults.profitInLeftMakerAsset = batchMatchedFillResults.profitInLeftMakerAsset.safeAdd( matchResults.profitInLeftMakerAsset ); batchMatchedFillResults.profitInRightMakerAsset = batchMatchedFillResults.profitInRightMakerAsset.safeAdd( matchResults.profitInRightMakerAsset ); // If the leftOrder is filled, update the leftIdx, leftOrder, and leftSignature, // or break out of the loop if there are no more leftOrders to match. if (leftOrderTakerAssetFilledAmount >= leftOrder.takerAssetAmount) { // Update the batched fill results once the leftIdx is updated. batchMatchedFillResults.left[leftIdx++] = leftFillResults; // Clear the intermediate fill results value. leftFillResults = LibFillResults.FillResults(0, 0, 0, 0, 0); // If all of the left orders have been filled, break out of the loop. // Otherwise, update the current right order. if (leftIdx == leftOrders.length) { // Update the right batched fill results batchMatchedFillResults.right[rightIdx] = rightFillResults; break; } else { leftOrder = leftOrders[leftIdx]; (, leftOrderTakerAssetFilledAmount) = _getOrderHashAndFilledAmount(leftOrder); } } // If the rightOrder is filled, update the rightIdx, rightOrder, and rightSignature, // or break out of the loop if there are no more rightOrders to match. if (rightOrderTakerAssetFilledAmount >= rightOrder.takerAssetAmount) { // Update the batched fill results once the rightIdx is updated. batchMatchedFillResults.right[rightIdx++] = rightFillResults; // Clear the intermediate fill results value. rightFillResults = LibFillResults.FillResults(0, 0, 0, 0, 0); // If all of the right orders have been filled, break out of the loop. // Otherwise, update the current right order. if (rightIdx == rightOrders.length) { // Update the left batched fill results batchMatchedFillResults.left[leftIdx] = leftFillResults; break; } else { rightOrder = rightOrders[rightIdx]; (, rightOrderTakerAssetFilledAmount) = _getOrderHashAndFilledAmount(rightOrder); } } } // Return the fill results from the batch match return batchMatchedFillResults; } /// @dev Match two complementary orders that have a profitable spread. /// Each order is filled at their respective price point. However, the calculations are /// carried out as though the orders are both being filled at the right order's price point. /// The profit made by the left order goes to the taker (who matched the two orders). This /// function is needed to allow for reentrant order matching (used by `batchMatchOrders` and /// `batchMatchOrdersWithMaximalFill`). /// @param leftOrder First order to match. /// @param rightOrder Second order to match. /// @param leftSignature Proof that order was created by the left maker. /// @param rightSignature Proof that order was created by the right maker. /// @param shouldMaximallyFillOrders Indicates whether or not the maximal fill matching strategy should be used /// @return matchedFillResults Amounts filled and fees paid by maker and taker of matched orders. function _matchOrders( LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder, bytes memory leftSignature, bytes memory rightSignature, bool shouldMaximallyFillOrders ) internal returns (LibFillResults.MatchedFillResults memory matchedFillResults) { // We assume that rightOrder.takerAssetData == leftOrder.makerAssetData and rightOrder.makerAssetData == leftOrder.takerAssetData // by pointing these values to the same location in memory. This is cheaper than checking equality. // If this assumption isn't true, the match will fail at signature validation. rightOrder.makerAssetData = leftOrder.takerAssetData; rightOrder.takerAssetData = leftOrder.makerAssetData; // Get left & right order info LibOrder.OrderInfo memory leftOrderInfo = getOrderInfo(leftOrder); LibOrder.OrderInfo memory rightOrderInfo = getOrderInfo(rightOrder); // Fetch taker address address takerAddress = _getCurrentContextAddress(); // Either our context is valid or we revert _assertFillableOrder( leftOrder, leftOrderInfo, takerAddress, leftSignature ); _assertFillableOrder( rightOrder, rightOrderInfo, takerAddress, rightSignature ); _assertValidMatch( leftOrder, rightOrder, leftOrderInfo.orderHash, rightOrderInfo.orderHash ); // Compute proportional fill amounts matchedFillResults = LibFillResults.calculateMatchedFillResults( leftOrder, rightOrder, leftOrderInfo.orderTakerAssetFilledAmount, rightOrderInfo.orderTakerAssetFilledAmount, protocolFeeMultiplier, tx.gasprice, shouldMaximallyFillOrders ); // Update exchange state _updateFilledState( leftOrder, takerAddress, leftOrderInfo.orderHash, leftOrderInfo.orderTakerAssetFilledAmount, matchedFillResults.left ); _updateFilledState( rightOrder, takerAddress, rightOrderInfo.orderHash, rightOrderInfo.orderTakerAssetFilledAmount, matchedFillResults.right ); // Settle matched orders. Succeeds or throws. _settleMatchedOrders( leftOrderInfo.orderHash, rightOrderInfo.orderHash, leftOrder, rightOrder, takerAddress, matchedFillResults ); return matchedFillResults; } /// @dev Settles matched order by transferring appropriate funds between order makers, taker, and fee recipient. /// @param leftOrderHash First matched order hash. /// @param rightOrderHash Second matched order hash. /// @param leftOrder First matched order. /// @param rightOrder Second matched order. /// @param takerAddress Address that matched the orders. The taker receives the spread between orders as profit. /// @param matchedFillResults Struct holding amounts to transfer between makers, taker, and fee recipients. function _settleMatchedOrders( bytes32 leftOrderHash, bytes32 rightOrderHash, LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder, address takerAddress, LibFillResults.MatchedFillResults memory matchedFillResults ) internal { address leftMakerAddress = leftOrder.makerAddress; address rightMakerAddress = rightOrder.makerAddress; address leftFeeRecipientAddress = leftOrder.feeRecipientAddress; address rightFeeRecipientAddress = rightOrder.feeRecipientAddress; // Right maker asset -> left maker _dispatchTransferFrom( rightOrderHash, rightOrder.makerAssetData, rightMakerAddress, leftMakerAddress, matchedFillResults.left.takerAssetFilledAmount ); // Left maker asset -> right maker _dispatchTransferFrom( leftOrderHash, leftOrder.makerAssetData, leftMakerAddress, rightMakerAddress, matchedFillResults.right.takerAssetFilledAmount ); // Right maker fee -> right fee recipient _dispatchTransferFrom( rightOrderHash, rightOrder.makerFeeAssetData, rightMakerAddress, rightFeeRecipientAddress, matchedFillResults.right.makerFeePaid ); // Left maker fee -> left fee recipient _dispatchTransferFrom( leftOrderHash, leftOrder.makerFeeAssetData, leftMakerAddress, leftFeeRecipientAddress, matchedFillResults.left.makerFeePaid ); // Settle taker profits. _dispatchTransferFrom( leftOrderHash, leftOrder.makerAssetData, leftMakerAddress, takerAddress, matchedFillResults.profitInLeftMakerAsset ); _dispatchTransferFrom( rightOrderHash, rightOrder.makerAssetData, rightMakerAddress, takerAddress, matchedFillResults.profitInRightMakerAsset ); // Pay protocol fees for each maker bool didPayProtocolFees = _payTwoProtocolFees( leftOrderHash, rightOrderHash, matchedFillResults.left.protocolFeePaid, leftMakerAddress, rightMakerAddress, takerAddress ); // Protocol fees are not paid if the protocolFeeCollector contract is not set if (!didPayProtocolFees) { matchedFillResults.left.protocolFeePaid = 0; matchedFillResults.right.protocolFeePaid = 0; } // Settle taker fees. if ( leftFeeRecipientAddress == rightFeeRecipientAddress && leftOrder.takerFeeAssetData.equals(rightOrder.takerFeeAssetData) ) { // Fee recipients and taker fee assets are identical, so we can // transfer them in one go. _dispatchTransferFrom( leftOrderHash, leftOrder.takerFeeAssetData, takerAddress, leftFeeRecipientAddress, matchedFillResults.left.takerFeePaid.safeAdd(matchedFillResults.right.takerFeePaid) ); } else { // Right taker fee -> right fee recipient _dispatchTransferFrom( rightOrderHash, rightOrder.takerFeeAssetData, takerAddress, rightFeeRecipientAddress, matchedFillResults.right.takerFeePaid ); // Left taker fee -> left fee recipient _dispatchTransferFrom( leftOrderHash, leftOrder.takerFeeAssetData, takerAddress, leftFeeRecipientAddress, matchedFillResults.left.takerFeePaid ); } } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; import "./LibBytesRichErrors.sol"; import "./LibRichErrors.sol"; library LibBytes { using LibBytes for bytes; /// @dev Gets the memory address for a byte array. /// @param input Byte array to lookup. /// @return memoryAddress Memory address of byte array. This /// points to the header of the byte array which contains /// the length. function rawAddress(bytes memory input) internal pure returns (uint256 memoryAddress) { assembly { memoryAddress := input } return memoryAddress; } /// @dev Gets the memory address for the contents of a byte array. /// @param input Byte array to lookup. /// @return memoryAddress Memory address of the contents of the byte array. function contentAddress(bytes memory input) internal pure returns (uint256 memoryAddress) { assembly { memoryAddress := add(input, 32) } return memoryAddress; } /// @dev Copies `length` bytes from memory location `source` to `dest`. /// @param dest memory address to copy bytes to. /// @param source memory address to copy bytes from. /// @param length number of bytes to copy. function memCopy( uint256 dest, uint256 source, uint256 length ) internal pure { if (length < 32) { // Handle a partial word by reading destination and masking // off the bits we are interested in. // This correctly handles overlap, zero lengths and source == dest assembly { let mask := sub(exp(256, sub(32, length)), 1) let s := and(mload(source), not(mask)) let d := and(mload(dest), mask) mstore(dest, or(s, d)) } } else { // Skip the O(length) loop when source == dest. if (source == dest) { return; } // For large copies we copy whole words at a time. The final // word is aligned to the end of the range (instead of after the // previous) to handle partial words. So a copy will look like this: // // #### // #### // #### // #### // // We handle overlap in the source and destination range by // changing the copying direction. This prevents us from // overwriting parts of source that we still need to copy. // // This correctly handles source == dest // if (source > dest) { assembly { // We subtract 32 from `sEnd` and `dEnd` because it // is easier to compare with in the loop, and these // are also the addresses we need for copying the // last bytes. length := sub(length, 32) let sEnd := add(source, length) let dEnd := add(dest, length) // Remember the last 32 bytes of source // This needs to be done here and not after the loop // because we may have overwritten the last bytes in // source already due to overlap. let last := mload(sEnd) // Copy whole words front to back // Note: the first check is always true, // this could have been a do-while loop. // solhint-disable-next-line no-empty-blocks for {} lt(source, sEnd) {} { mstore(dest, mload(source)) source := add(source, 32) dest := add(dest, 32) } // Write the last 32 bytes mstore(dEnd, last) } } else { assembly { // We subtract 32 from `sEnd` and `dEnd` because those // are the starting points when copying a word at the end. length := sub(length, 32) let sEnd := add(source, length) let dEnd := add(dest, length) // Remember the first 32 bytes of source // This needs to be done here and not after the loop // because we may have overwritten the first bytes in // source already due to overlap. let first := mload(source) // Copy whole words back to front // We use a signed comparisson here to allow dEnd to become // negative (happens when source and dest < 32). Valid // addresses in local memory will never be larger than // 2**255, so they can be safely re-interpreted as signed. // Note: the first check is always true, // this could have been a do-while loop. // solhint-disable-next-line no-empty-blocks for {} slt(dest, dEnd) {} { mstore(dEnd, mload(sEnd)) sEnd := sub(sEnd, 32) dEnd := sub(dEnd, 32) } // Write the first 32 bytes mstore(dest, first) } } } } /// @dev Returns a slices from a byte array. /// @param b The byte array to take a slice from. /// @param from The starting index for the slice (inclusive). /// @param to The final index for the slice (exclusive). /// @return result The slice containing bytes at indices [from, to) function slice( bytes memory b, uint256 from, uint256 to ) internal pure returns (bytes memory result) { // Ensure that the from and to positions are valid positions for a slice within // the byte array that is being used. if (from > to) { LibRichErrors.rrevert(LibBytesRichErrors.InvalidByteOperationError( LibBytesRichErrors.InvalidByteOperationErrorCodes.FromLessThanOrEqualsToRequired, from, to )); } if (to > b.length) { LibRichErrors.rrevert(LibBytesRichErrors.InvalidByteOperationError( LibBytesRichErrors.InvalidByteOperationErrorCodes.ToLessThanOrEqualsLengthRequired, to, b.length )); } // Create a new bytes structure and copy contents result = new bytes(to - from); memCopy( result.contentAddress(), b.contentAddress() + from, result.length ); return result; } /// @dev Returns a slice from a byte array without preserving the input. /// @param b The byte array to take a slice from. Will be destroyed in the process. /// @param from The starting index for the slice (inclusive). /// @param to The final index for the slice (exclusive). /// @return result The slice containing bytes at indices [from, to) /// @dev When `from == 0`, the original array will match the slice. In other cases its state will be corrupted. function sliceDestructive( bytes memory b, uint256 from, uint256 to ) internal pure returns (bytes memory result) { // Ensure that the from and to positions are valid positions for a slice within // the byte array that is being used. if (from > to) { LibRichErrors.rrevert(LibBytesRichErrors.InvalidByteOperationError( LibBytesRichErrors.InvalidByteOperationErrorCodes.FromLessThanOrEqualsToRequired, from, to )); } if (to > b.length) { LibRichErrors.rrevert(LibBytesRichErrors.InvalidByteOperationError( LibBytesRichErrors.InvalidByteOperationErrorCodes.ToLessThanOrEqualsLengthRequired, to, b.length )); } // Create a new bytes structure around [from, to) in-place. assembly { result := add(b, from) mstore(result, sub(to, from)) } return result; } /// @dev Pops the last byte off of a byte array by modifying its length. /// @param b Byte array that will be modified. /// @return The byte that was popped off. function popLastByte(bytes memory b) internal pure returns (bytes1 result) { if (b.length == 0) { LibRichErrors.rrevert(LibBytesRichErrors.InvalidByteOperationError( LibBytesRichErrors.InvalidByteOperationErrorCodes.LengthGreaterThanZeroRequired, b.length, 0 )); } // Store last byte. result = b[b.length - 1]; assembly { // Decrement length of byte array. let newLen := sub(mload(b), 1) mstore(b, newLen) } return result; } /// @dev Tests equality of two byte arrays. /// @param lhs First byte array to compare. /// @param rhs Second byte array to compare. /// @return True if arrays are the same. False otherwise. function equals( bytes memory lhs, bytes memory rhs ) internal pure returns (bool equal) { // Keccak gas cost is 30 + numWords * 6. This is a cheap way to compare. // We early exit on unequal lengths, but keccak would also correctly // handle this. return lhs.length == rhs.length && keccak256(lhs) == keccak256(rhs); } /// @dev Reads an address from a position in a byte array. /// @param b Byte array containing an address. /// @param index Index in byte array of address. /// @return address from byte array. function readAddress( bytes memory b, uint256 index ) internal pure returns (address result) { if (b.length < index + 20) { LibRichErrors.rrevert(LibBytesRichErrors.InvalidByteOperationError( LibBytesRichErrors.InvalidByteOperationErrorCodes.LengthGreaterThanOrEqualsTwentyRequired, b.length, index + 20 // 20 is length of address )); } // Add offset to index: // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index) // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index) index += 20; // Read address from array memory assembly { // 1. Add index to address of bytes array // 2. Load 32-byte word from memory // 3. Apply 20-byte mask to obtain address result := and(mload(add(b, index)), 0xffffffffffffffffffffffffffffffffffffffff) } return result; } /// @dev Writes an address into a specific position in a byte array. /// @param b Byte array to insert address into. /// @param index Index in byte array of address. /// @param input Address to put into byte array. function writeAddress( bytes memory b, uint256 index, address input ) internal pure { if (b.length < index + 20) { LibRichErrors.rrevert(LibBytesRichErrors.InvalidByteOperationError( LibBytesRichErrors.InvalidByteOperationErrorCodes.LengthGreaterThanOrEqualsTwentyRequired, b.length, index + 20 // 20 is length of address )); } // Add offset to index: // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index) // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index) index += 20; // Store address into array memory assembly { // The address occupies 20 bytes and mstore stores 32 bytes. // First fetch the 32-byte word where we'll be storing the address, then // apply a mask so we have only the bytes in the word that the address will not occupy. // Then combine these bytes with the address and store the 32 bytes back to memory with mstore. // 1. Add index to address of bytes array // 2. Load 32-byte word from memory // 3. Apply 12-byte mask to obtain extra bytes occupying word of memory where we'll store the address let neighbors := and( mload(add(b, index)), 0xffffffffffffffffffffffff0000000000000000000000000000000000000000 ) // Make sure input address is clean. // (Solidity does not guarantee this) input := and(input, 0xffffffffffffffffffffffffffffffffffffffff) // Store the neighbors and address into memory mstore(add(b, index), xor(input, neighbors)) } } /// @dev Reads a bytes32 value from a position in a byte array. /// @param b Byte array containing a bytes32 value. /// @param index Index in byte array of bytes32 value. /// @return bytes32 value from byte array. function readBytes32( bytes memory b, uint256 index ) internal pure returns (bytes32 result) { if (b.length < index + 32) { LibRichErrors.rrevert(LibBytesRichErrors.InvalidByteOperationError( LibBytesRichErrors.InvalidByteOperationErrorCodes.LengthGreaterThanOrEqualsThirtyTwoRequired, b.length, index + 32 )); } // Arrays are prefixed by a 256 bit length parameter index += 32; // Read the bytes32 from array memory assembly { result := mload(add(b, index)) } return result; } /// @dev Writes a bytes32 into a specific position in a byte array. /// @param b Byte array to insert <input> into. /// @param index Index in byte array of <input>. /// @param input bytes32 to put into byte array. function writeBytes32( bytes memory b, uint256 index, bytes32 input ) internal pure { if (b.length < index + 32) { LibRichErrors.rrevert(LibBytesRichErrors.InvalidByteOperationError( LibBytesRichErrors.InvalidByteOperationErrorCodes.LengthGreaterThanOrEqualsThirtyTwoRequired, b.length, index + 32 )); } // Arrays are prefixed by a 256 bit length parameter index += 32; // Read the bytes32 from array memory assembly { mstore(add(b, index), input) } } /// @dev Reads a uint256 value from a position in a byte array. /// @param b Byte array containing a uint256 value. /// @param index Index in byte array of uint256 value. /// @return uint256 value from byte array. function readUint256( bytes memory b, uint256 index ) internal pure returns (uint256 result) { result = uint256(readBytes32(b, index)); return result; } /// @dev Writes a uint256 into a specific position in a byte array. /// @param b Byte array to insert <input> into. /// @param index Index in byte array of <input>. /// @param input uint256 to put into byte array. function writeUint256( bytes memory b, uint256 index, uint256 input ) internal pure { writeBytes32(b, index, bytes32(input)); } /// @dev Reads an unpadded bytes4 value from a position in a byte array. /// @param b Byte array containing a bytes4 value. /// @param index Index in byte array of bytes4 value. /// @return bytes4 value from byte array. function readBytes4( bytes memory b, uint256 index ) internal pure returns (bytes4 result) { if (b.length < index + 4) { LibRichErrors.rrevert(LibBytesRichErrors.InvalidByteOperationError( LibBytesRichErrors.InvalidByteOperationErrorCodes.LengthGreaterThanOrEqualsFourRequired, b.length, index + 4 )); } // Arrays are prefixed by a 32 byte length field index += 32; // Read the bytes4 from array memory assembly { result := mload(add(b, index)) // Solidity does not require us to clean the trailing bytes. // We do it anyway result := and(result, 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000) } return result; } /// @dev Writes a new length to a byte array. /// Decreasing length will lead to removing the corresponding lower order bytes from the byte array. /// Increasing length may lead to appending adjacent in-memory bytes to the end of the byte array. /// @param b Bytes array to write new length to. /// @param length New length of byte array. function writeLength(bytes memory b, uint256 length) internal pure { assembly { mstore(b, length) } } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; library LibBytesRichErrors { enum InvalidByteOperationErrorCodes { FromLessThanOrEqualsToRequired, ToLessThanOrEqualsLengthRequired, LengthGreaterThanZeroRequired, LengthGreaterThanOrEqualsFourRequired, LengthGreaterThanOrEqualsTwentyRequired, LengthGreaterThanOrEqualsThirtyTwoRequired, LengthGreaterThanOrEqualsNestedBytesLengthRequired, DestinationLengthGreaterThanOrEqualSourceLengthRequired } // bytes4(keccak256("InvalidByteOperationError(uint8,uint256,uint256)")) bytes4 internal constant INVALID_BYTE_OPERATION_ERROR_SELECTOR = 0x28006595; // solhint-disable func-name-mixedcase function InvalidByteOperationError( InvalidByteOperationErrorCodes errorCode, uint256 offset, uint256 required ) internal pure returns (bytes memory) { return abi.encodeWithSelector( INVALID_BYTE_OPERATION_ERROR_SELECTOR, errorCode, offset, required ); } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; library LibRichErrors { // bytes4(keccak256("Error(string)")) bytes4 internal constant STANDARD_ERROR_SELECTOR = 0x08c379a0; // solhint-disable func-name-mixedcase /// @dev ABI encode a standard, string revert error payload. /// This is the same payload that would be included by a `revert(string)` /// solidity statement. It has the function signature `Error(string)`. /// @param message The error string. /// @return The ABI encoded error. function StandardError( string memory message ) internal pure returns (bytes memory) { return abi.encodeWithSelector( STANDARD_ERROR_SELECTOR, bytes(message) ); } // solhint-enable func-name-mixedcase /// @dev Reverts an encoded rich revert reason `errorData`. /// @param errorData ABI encoded error data. function rrevert(bytes memory errorData) internal pure { assembly { revert(add(errorData, 0x20), mload(errorData)) } } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; import "@0x/contracts-utils/contracts/src/LibEIP712.sol"; library LibOrder { using LibOrder for Order; // Hash for the EIP712 Order Schema: // keccak256(abi.encodePacked( // "Order(", // "address makerAddress,", // "address takerAddress,", // "address feeRecipientAddress,", // "address senderAddress,", // "uint256 makerAssetAmount,", // "uint256 takerAssetAmount,", // "uint256 makerFee,", // "uint256 takerFee,", // "uint256 expirationTimeSeconds,", // "uint256 salt,", // "bytes makerAssetData,", // "bytes takerAssetData,", // "bytes makerFeeAssetData,", // "bytes takerFeeAssetData", // ")" // )) bytes32 constant internal _EIP712_ORDER_SCHEMA_HASH = 0xf80322eb8376aafb64eadf8f0d7623f22130fd9491a221e902b713cb984a7534; // A valid order remains fillable until it is expired, fully filled, or cancelled. // An order's status is unaffected by external factors, like account balances. enum OrderStatus { INVALID, // Default value INVALID_MAKER_ASSET_AMOUNT, // Order does not have a valid maker asset amount INVALID_TAKER_ASSET_AMOUNT, // Order does not have a valid taker asset amount FILLABLE, // Order is fillable EXPIRED, // Order has already expired FULLY_FILLED, // Order is fully filled CANCELLED // Order has been cancelled } // solhint-disable max-line-length struct Order { address makerAddress; // Address that created the order. address takerAddress; // Address that is allowed to fill the order. If set to 0, any address is allowed to fill the order. address feeRecipientAddress; // Address that will recieve fees when order is filled. address senderAddress; // Address that is allowed to call Exchange contract methods that affect this order. If set to 0, any address is allowed to call these methods. uint256 makerAssetAmount; // Amount of makerAsset being offered by maker. Must be greater than 0. uint256 takerAssetAmount; // Amount of takerAsset being bid on by maker. Must be greater than 0. uint256 makerFee; // Fee paid to feeRecipient by maker when order is filled. uint256 takerFee; // Fee paid to feeRecipient by taker when order is filled. uint256 expirationTimeSeconds; // Timestamp in seconds at which order expires. uint256 salt; // Arbitrary number to facilitate uniqueness of the order's hash. bytes makerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring makerAsset. The leading bytes4 references the id of the asset proxy. bytes takerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring takerAsset. The leading bytes4 references the id of the asset proxy. bytes makerFeeAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring makerFeeAsset. The leading bytes4 references the id of the asset proxy. bytes takerFeeAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring takerFeeAsset. The leading bytes4 references the id of the asset proxy. } // solhint-enable max-line-length struct OrderInfo { uint8 orderStatus; // Status that describes order's validity and fillability. bytes32 orderHash; // EIP712 typed data hash of the order (see LibOrder.getTypedDataHash). uint256 orderTakerAssetFilledAmount; // Amount of order that has already been filled. } /// @dev Calculates the EIP712 typed data hash of an order with a given domain separator. /// @param order The order structure. /// @return EIP712 typed data hash of the order. function getTypedDataHash(Order memory order, bytes32 eip712ExchangeDomainHash) internal pure returns (bytes32 orderHash) { orderHash = LibEIP712.hashEIP712Message( eip712ExchangeDomainHash, order.getStructHash() ); return orderHash; } /// @dev Calculates EIP712 hash of the order struct. /// @param order The order structure. /// @return EIP712 hash of the order struct. function getStructHash(Order memory order) internal pure returns (bytes32 result) { bytes32 schemaHash = _EIP712_ORDER_SCHEMA_HASH; bytes memory makerAssetData = order.makerAssetData; bytes memory takerAssetData = order.takerAssetData; bytes memory makerFeeAssetData = order.makerFeeAssetData; bytes memory takerFeeAssetData = order.takerFeeAssetData; // Assembly for more efficiently computing: // keccak256(abi.encodePacked( // EIP712_ORDER_SCHEMA_HASH, // uint256(order.makerAddress), // uint256(order.takerAddress), // uint256(order.feeRecipientAddress), // uint256(order.senderAddress), // order.makerAssetAmount, // order.takerAssetAmount, // order.makerFee, // order.takerFee, // order.expirationTimeSeconds, // order.salt, // keccak256(order.makerAssetData), // keccak256(order.takerAssetData), // keccak256(order.makerFeeAssetData), // keccak256(order.takerFeeAssetData) // )); assembly { // Assert order offset (this is an internal error that should never be triggered) if lt(order, 32) { invalid() } // Calculate memory addresses that will be swapped out before hashing let pos1 := sub(order, 32) let pos2 := add(order, 320) let pos3 := add(order, 352) let pos4 := add(order, 384) let pos5 := add(order, 416) // Backup let temp1 := mload(pos1) let temp2 := mload(pos2) let temp3 := mload(pos3) let temp4 := mload(pos4) let temp5 := mload(pos5) // Hash in place mstore(pos1, schemaHash) mstore(pos2, keccak256(add(makerAssetData, 32), mload(makerAssetData))) // store hash of makerAssetData mstore(pos3, keccak256(add(takerAssetData, 32), mload(takerAssetData))) // store hash of takerAssetData mstore(pos4, keccak256(add(makerFeeAssetData, 32), mload(makerFeeAssetData))) // store hash of makerFeeAssetData mstore(pos5, keccak256(add(takerFeeAssetData, 32), mload(takerFeeAssetData))) // store hash of takerFeeAssetData result := keccak256(pos1, 480) // Restore mstore(pos1, temp1) mstore(pos2, temp2) mstore(pos3, temp3) mstore(pos4, temp4) mstore(pos5, temp5) } return result; } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; import "./LibMath.sol"; import "./LibOrder.sol"; library LibFillResults { using LibSafeMath for uint256; struct BatchMatchedFillResults { FillResults[] left; // Fill results for left orders FillResults[] right; // Fill results for right orders uint256 profitInLeftMakerAsset; // Profit taken from left makers uint256 profitInRightMakerAsset; // Profit taken from right makers } struct FillResults { uint256 makerAssetFilledAmount; // Total amount of makerAsset(s) filled. uint256 takerAssetFilledAmount; // Total amount of takerAsset(s) filled. uint256 makerFeePaid; // Total amount of fees paid by maker(s) to feeRecipient(s). uint256 takerFeePaid; // Total amount of fees paid by taker to feeRecipients(s). uint256 protocolFeePaid; // Total amount of fees paid by taker to the staking contract. } struct MatchedFillResults { FillResults left; // Amounts filled and fees paid of left order. FillResults right; // Amounts filled and fees paid of right order. uint256 profitInLeftMakerAsset; // Profit taken from the left maker uint256 profitInRightMakerAsset; // Profit taken from the right maker } /// @dev Calculates amounts filled and fees paid by maker and taker. /// @param order to be filled. /// @param takerAssetFilledAmount Amount of takerAsset that will be filled. /// @param protocolFeeMultiplier The current protocol fee of the exchange contract. /// @param gasPrice The gasprice of the transaction. This is provided so that the function call can continue /// to be pure rather than view. /// @return fillResults Amounts filled and fees paid by maker and taker. function calculateFillResults( LibOrder.Order memory order, uint256 takerAssetFilledAmount, uint256 protocolFeeMultiplier, uint256 gasPrice ) internal pure returns (FillResults memory fillResults) { // Compute proportional transfer amounts fillResults.takerAssetFilledAmount = takerAssetFilledAmount; fillResults.makerAssetFilledAmount = LibMath.safeGetPartialAmountFloor( takerAssetFilledAmount, order.takerAssetAmount, order.makerAssetAmount ); fillResults.makerFeePaid = LibMath.safeGetPartialAmountFloor( takerAssetFilledAmount, order.takerAssetAmount, order.makerFee ); fillResults.takerFeePaid = LibMath.safeGetPartialAmountFloor( takerAssetFilledAmount, order.takerAssetAmount, order.takerFee ); // Compute the protocol fee that should be paid for a single fill. fillResults.protocolFeePaid = gasPrice.safeMul(protocolFeeMultiplier); return fillResults; } /// @dev Calculates fill amounts for the matched orders. /// Each order is filled at their respective price point. However, the calculations are /// carried out as though the orders are both being filled at the right order's price point. /// The profit made by the leftOrder order goes to the taker (who matched the two orders). /// @param leftOrder First order to match. /// @param rightOrder Second order to match. /// @param leftOrderTakerAssetFilledAmount Amount of left order already filled. /// @param rightOrderTakerAssetFilledAmount Amount of right order already filled. /// @param protocolFeeMultiplier The current protocol fee of the exchange contract. /// @param gasPrice The gasprice of the transaction. This is provided so that the function call can continue /// to be pure rather than view. /// @param shouldMaximallyFillOrders A value that indicates whether or not this calculation should use /// the maximal fill order matching strategy. /// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders. function calculateMatchedFillResults( LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder, uint256 leftOrderTakerAssetFilledAmount, uint256 rightOrderTakerAssetFilledAmount, uint256 protocolFeeMultiplier, uint256 gasPrice, bool shouldMaximallyFillOrders ) internal pure returns (MatchedFillResults memory matchedFillResults) { // Derive maker asset amounts for left & right orders, given store taker assert amounts uint256 leftTakerAssetAmountRemaining = leftOrder.takerAssetAmount.safeSub(leftOrderTakerAssetFilledAmount); uint256 leftMakerAssetAmountRemaining = LibMath.safeGetPartialAmountFloor( leftOrder.makerAssetAmount, leftOrder.takerAssetAmount, leftTakerAssetAmountRemaining ); uint256 rightTakerAssetAmountRemaining = rightOrder.takerAssetAmount.safeSub(rightOrderTakerAssetFilledAmount); uint256 rightMakerAssetAmountRemaining = LibMath.safeGetPartialAmountFloor( rightOrder.makerAssetAmount, rightOrder.takerAssetAmount, rightTakerAssetAmountRemaining ); // Maximally fill the orders and pay out profits to the matcher in one or both of the maker assets. if (shouldMaximallyFillOrders) { matchedFillResults = _calculateMatchedFillResultsWithMaximalFill( leftOrder, rightOrder, leftMakerAssetAmountRemaining, leftTakerAssetAmountRemaining, rightMakerAssetAmountRemaining, rightTakerAssetAmountRemaining ); } else { matchedFillResults = _calculateMatchedFillResults( leftOrder, rightOrder, leftMakerAssetAmountRemaining, leftTakerAssetAmountRemaining, rightMakerAssetAmountRemaining, rightTakerAssetAmountRemaining ); } // Compute fees for left order matchedFillResults.left.makerFeePaid = LibMath.safeGetPartialAmountFloor( matchedFillResults.left.makerAssetFilledAmount, leftOrder.makerAssetAmount, leftOrder.makerFee ); matchedFillResults.left.takerFeePaid = LibMath.safeGetPartialAmountFloor( matchedFillResults.left.takerAssetFilledAmount, leftOrder.takerAssetAmount, leftOrder.takerFee ); // Compute fees for right order matchedFillResults.right.makerFeePaid = LibMath.safeGetPartialAmountFloor( matchedFillResults.right.makerAssetFilledAmount, rightOrder.makerAssetAmount, rightOrder.makerFee ); matchedFillResults.right.takerFeePaid = LibMath.safeGetPartialAmountFloor( matchedFillResults.right.takerAssetFilledAmount, rightOrder.takerAssetAmount, rightOrder.takerFee ); // Compute the protocol fee that should be paid for a single fill. In this // case this should be made the protocol fee for both the left and right orders. uint256 protocolFee = gasPrice.safeMul(protocolFeeMultiplier); matchedFillResults.left.protocolFeePaid = protocolFee; matchedFillResults.right.protocolFeePaid = protocolFee; // Return fill results return matchedFillResults; } /// @dev Adds properties of both FillResults instances. /// @param fillResults1 The first FillResults. /// @param fillResults2 The second FillResults. /// @return The sum of both fill results. function addFillResults( FillResults memory fillResults1, FillResults memory fillResults2 ) internal pure returns (FillResults memory totalFillResults) { totalFillResults.makerAssetFilledAmount = fillResults1.makerAssetFilledAmount.safeAdd(fillResults2.makerAssetFilledAmount); totalFillResults.takerAssetFilledAmount = fillResults1.takerAssetFilledAmount.safeAdd(fillResults2.takerAssetFilledAmount); totalFillResults.makerFeePaid = fillResults1.makerFeePaid.safeAdd(fillResults2.makerFeePaid); totalFillResults.takerFeePaid = fillResults1.takerFeePaid.safeAdd(fillResults2.takerFeePaid); totalFillResults.protocolFeePaid = fillResults1.protocolFeePaid.safeAdd(fillResults2.protocolFeePaid); return totalFillResults; } /// @dev Calculates part of the matched fill results for a given situation using the fill strategy that only /// awards profit denominated in the left maker asset. /// @param leftOrder The left order in the order matching situation. /// @param rightOrder The right order in the order matching situation. /// @param leftMakerAssetAmountRemaining The amount of the left order maker asset that can still be filled. /// @param leftTakerAssetAmountRemaining The amount of the left order taker asset that can still be filled. /// @param rightMakerAssetAmountRemaining The amount of the right order maker asset that can still be filled. /// @param rightTakerAssetAmountRemaining The amount of the right order taker asset that can still be filled. /// @return MatchFillResults struct that does not include fees paid. function _calculateMatchedFillResults( LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder, uint256 leftMakerAssetAmountRemaining, uint256 leftTakerAssetAmountRemaining, uint256 rightMakerAssetAmountRemaining, uint256 rightTakerAssetAmountRemaining ) private pure returns (MatchedFillResults memory matchedFillResults) { // Calculate fill results for maker and taker assets: at least one order will be fully filled. // The maximum amount the left maker can buy is `leftTakerAssetAmountRemaining` // The maximum amount the right maker can sell is `rightMakerAssetAmountRemaining` // We have two distinct cases for calculating the fill results: // Case 1. // If the left maker can buy more than the right maker can sell, then only the right order is fully filled. // If the left maker can buy exactly what the right maker can sell, then both orders are fully filled. // Case 2. // If the left maker cannot buy more than the right maker can sell, then only the left order is fully filled. // Case 3. // If the left maker can buy exactly as much as the right maker can sell, then both orders are fully filled. if (leftTakerAssetAmountRemaining > rightMakerAssetAmountRemaining) { // Case 1: Right order is fully filled matchedFillResults = _calculateCompleteRightFill( leftOrder, rightMakerAssetAmountRemaining, rightTakerAssetAmountRemaining ); } else if (leftTakerAssetAmountRemaining < rightMakerAssetAmountRemaining) { // Case 2: Left order is fully filled matchedFillResults.left.makerAssetFilledAmount = leftMakerAssetAmountRemaining; matchedFillResults.left.takerAssetFilledAmount = leftTakerAssetAmountRemaining; matchedFillResults.right.makerAssetFilledAmount = leftTakerAssetAmountRemaining; // Round up to ensure the maker's exchange rate does not exceed the price specified by the order. // We favor the maker when the exchange rate must be rounded. matchedFillResults.right.takerAssetFilledAmount = LibMath.safeGetPartialAmountCeil( rightOrder.takerAssetAmount, rightOrder.makerAssetAmount, leftTakerAssetAmountRemaining // matchedFillResults.right.makerAssetFilledAmount ); } else { // leftTakerAssetAmountRemaining == rightMakerAssetAmountRemaining // Case 3: Both orders are fully filled. Technically, this could be captured by the above cases, but // this calculation will be more precise since it does not include rounding. matchedFillResults = _calculateCompleteFillBoth( leftMakerAssetAmountRemaining, leftTakerAssetAmountRemaining, rightMakerAssetAmountRemaining, rightTakerAssetAmountRemaining ); } // Calculate amount given to taker matchedFillResults.profitInLeftMakerAsset = matchedFillResults.left.makerAssetFilledAmount.safeSub( matchedFillResults.right.takerAssetFilledAmount ); return matchedFillResults; } /// @dev Calculates part of the matched fill results for a given situation using the maximal fill order matching /// strategy. /// @param leftOrder The left order in the order matching situation. /// @param rightOrder The right order in the order matching situation. /// @param leftMakerAssetAmountRemaining The amount of the left order maker asset that can still be filled. /// @param leftTakerAssetAmountRemaining The amount of the left order taker asset that can still be filled. /// @param rightMakerAssetAmountRemaining The amount of the right order maker asset that can still be filled. /// @param rightTakerAssetAmountRemaining The amount of the right order taker asset that can still be filled. /// @return MatchFillResults struct that does not include fees paid. function _calculateMatchedFillResultsWithMaximalFill( LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder, uint256 leftMakerAssetAmountRemaining, uint256 leftTakerAssetAmountRemaining, uint256 rightMakerAssetAmountRemaining, uint256 rightTakerAssetAmountRemaining ) private pure returns (MatchedFillResults memory matchedFillResults) { // If a maker asset is greater than the opposite taker asset, than there will be a spread denominated in that maker asset. bool doesLeftMakerAssetProfitExist = leftMakerAssetAmountRemaining > rightTakerAssetAmountRemaining; bool doesRightMakerAssetProfitExist = rightMakerAssetAmountRemaining > leftTakerAssetAmountRemaining; // Calculate the maximum fill results for the maker and taker assets. At least one of the orders will be fully filled. // // The maximum that the left maker can possibly buy is the amount that the right order can sell. // The maximum that the right maker can possibly buy is the amount that the left order can sell. // // If the left order is fully filled, profit will be paid out in the left maker asset. If the right order is fully filled, // the profit will be out in the right maker asset. // // There are three cases to consider: // Case 1. // If the left maker can buy more than the right maker can sell, then only the right order is fully filled. // Case 2. // If the right maker can buy more than the left maker can sell, then only the right order is fully filled. // Case 3. // If the right maker can sell the max of what the left maker can buy and the left maker can sell the max of // what the right maker can buy, then both orders are fully filled. if (leftTakerAssetAmountRemaining > rightMakerAssetAmountRemaining) { // Case 1: Right order is fully filled with the profit paid in the left makerAsset matchedFillResults = _calculateCompleteRightFill( leftOrder, rightMakerAssetAmountRemaining, rightTakerAssetAmountRemaining ); } else if (rightTakerAssetAmountRemaining > leftMakerAssetAmountRemaining) { // Case 2: Left order is fully filled with the profit paid in the right makerAsset. matchedFillResults.left.makerAssetFilledAmount = leftMakerAssetAmountRemaining; matchedFillResults.left.takerAssetFilledAmount = leftTakerAssetAmountRemaining; // Round down to ensure the right maker's exchange rate does not exceed the price specified by the order. // We favor the right maker when the exchange rate must be rounded and the profit is being paid in the // right maker asset. matchedFillResults.right.makerAssetFilledAmount = LibMath.safeGetPartialAmountFloor( rightOrder.makerAssetAmount, rightOrder.takerAssetAmount, leftMakerAssetAmountRemaining ); matchedFillResults.right.takerAssetFilledAmount = leftMakerAssetAmountRemaining; } else { // Case 3: The right and left orders are fully filled matchedFillResults = _calculateCompleteFillBoth( leftMakerAssetAmountRemaining, leftTakerAssetAmountRemaining, rightMakerAssetAmountRemaining, rightTakerAssetAmountRemaining ); } // Calculate amount given to taker in the left order's maker asset if the left spread will be part of the profit. if (doesLeftMakerAssetProfitExist) { matchedFillResults.profitInLeftMakerAsset = matchedFillResults.left.makerAssetFilledAmount.safeSub( matchedFillResults.right.takerAssetFilledAmount ); } // Calculate amount given to taker in the right order's maker asset if the right spread will be part of the profit. if (doesRightMakerAssetProfitExist) { matchedFillResults.profitInRightMakerAsset = matchedFillResults.right.makerAssetFilledAmount.safeSub( matchedFillResults.left.takerAssetFilledAmount ); } return matchedFillResults; } /// @dev Calculates the fill results for the maker and taker in the order matching and writes the results /// to the fillResults that are being collected on the order. Both orders will be fully filled in this /// case. /// @param leftMakerAssetAmountRemaining The amount of the left maker asset that is remaining to be filled. /// @param leftTakerAssetAmountRemaining The amount of the left taker asset that is remaining to be filled. /// @param rightMakerAssetAmountRemaining The amount of the right maker asset that is remaining to be filled. /// @param rightTakerAssetAmountRemaining The amount of the right taker asset that is remaining to be filled. /// @return MatchFillResults struct that does not include fees paid or spreads taken. function _calculateCompleteFillBoth( uint256 leftMakerAssetAmountRemaining, uint256 leftTakerAssetAmountRemaining, uint256 rightMakerAssetAmountRemaining, uint256 rightTakerAssetAmountRemaining ) private pure returns (MatchedFillResults memory matchedFillResults) { // Calculate the fully filled results for both orders. matchedFillResults.left.makerAssetFilledAmount = leftMakerAssetAmountRemaining; matchedFillResults.left.takerAssetFilledAmount = leftTakerAssetAmountRemaining; matchedFillResults.right.makerAssetFilledAmount = rightMakerAssetAmountRemaining; matchedFillResults.right.takerAssetFilledAmount = rightTakerAssetAmountRemaining; return matchedFillResults; } /// @dev Calculates the fill results for the maker and taker in the order matching and writes the results /// to the fillResults that are being collected on the order. /// @param leftOrder The left order that is being maximally filled. All of the information about fill amounts /// can be derived from this order and the right asset remaining fields. /// @param rightMakerAssetAmountRemaining The amount of the right maker asset that is remaining to be filled. /// @param rightTakerAssetAmountRemaining The amount of the right taker asset that is remaining to be filled. /// @return MatchFillResults struct that does not include fees paid or spreads taken. function _calculateCompleteRightFill( LibOrder.Order memory leftOrder, uint256 rightMakerAssetAmountRemaining, uint256 rightTakerAssetAmountRemaining ) private pure returns (MatchedFillResults memory matchedFillResults) { matchedFillResults.right.makerAssetFilledAmount = rightMakerAssetAmountRemaining; matchedFillResults.right.takerAssetFilledAmount = rightTakerAssetAmountRemaining; matchedFillResults.left.takerAssetFilledAmount = rightMakerAssetAmountRemaining; // Round down to ensure the left maker's exchange rate does not exceed the price specified by the order. // We favor the left maker when the exchange rate must be rounded and the profit is being paid in the // left maker asset. matchedFillResults.left.makerAssetFilledAmount = LibMath.safeGetPartialAmountFloor( leftOrder.makerAssetAmount, leftOrder.takerAssetAmount, rightMakerAssetAmountRemaining ); return matchedFillResults; } }
pragma solidity ^0.5.9; import "./LibRichErrors.sol"; import "./LibSafeMathRichErrors.sol"; library LibSafeMath { function safeMul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; if (c / a != b) { LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError( LibSafeMathRichErrors.BinOpErrorCodes.MULTIPLICATION_OVERFLOW, a, b )); } return c; } function safeDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError( LibSafeMathRichErrors.BinOpErrorCodes.DIVISION_BY_ZERO, a, b )); } uint256 c = a / b; return c; } function safeSub(uint256 a, uint256 b) internal pure returns (uint256) { if (b > a) { LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError( LibSafeMathRichErrors.BinOpErrorCodes.SUBTRACTION_UNDERFLOW, a, b )); } return a - b; } function safeAdd(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; if (c < a) { LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError( LibSafeMathRichErrors.BinOpErrorCodes.ADDITION_OVERFLOW, a, b )); } return c; } function max256(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } function min256(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } }
pragma solidity ^0.5.9; library LibSafeMathRichErrors { // bytes4(keccak256("Uint256BinOpError(uint8,uint256,uint256)")) bytes4 internal constant UINT256_BINOP_ERROR_SELECTOR = 0xe946c1bb; // bytes4(keccak256("Uint256DowncastError(uint8,uint256)")) bytes4 internal constant UINT256_DOWNCAST_ERROR_SELECTOR = 0xc996af7b; enum BinOpErrorCodes { ADDITION_OVERFLOW, MULTIPLICATION_OVERFLOW, SUBTRACTION_UNDERFLOW, DIVISION_BY_ZERO } enum DowncastErrorCodes { VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT32, VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT64, VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT96 } // solhint-disable func-name-mixedcase function Uint256BinOpError( BinOpErrorCodes errorCode, uint256 a, uint256 b ) internal pure returns (bytes memory) { return abi.encodeWithSelector( UINT256_BINOP_ERROR_SELECTOR, errorCode, a, b ); } function Uint256DowncastError( DowncastErrorCodes errorCode, uint256 a ) internal pure returns (bytes memory) { return abi.encodeWithSelector( UINT256_DOWNCAST_ERROR_SELECTOR, errorCode, a ); } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "./LibMathRichErrors.sol"; library LibMath { using LibSafeMath for uint256; /// @dev Calculates partial value given a numerator and denominator rounded down. /// Reverts if rounding error is >= 0.1% /// @param numerator Numerator. /// @param denominator Denominator. /// @param target Value to calculate partial of. /// @return Partial value of target rounded down. function safeGetPartialAmountFloor( uint256 numerator, uint256 denominator, uint256 target ) internal pure returns (uint256 partialAmount) { if (isRoundingErrorFloor( numerator, denominator, target )) { LibRichErrors.rrevert(LibMathRichErrors.RoundingError( numerator, denominator, target )); } partialAmount = numerator.safeMul(target).safeDiv(denominator); return partialAmount; } /// @dev Calculates partial value given a numerator and denominator rounded down. /// Reverts if rounding error is >= 0.1% /// @param numerator Numerator. /// @param denominator Denominator. /// @param target Value to calculate partial of. /// @return Partial value of target rounded up. function safeGetPartialAmountCeil( uint256 numerator, uint256 denominator, uint256 target ) internal pure returns (uint256 partialAmount) { if (isRoundingErrorCeil( numerator, denominator, target )) { LibRichErrors.rrevert(LibMathRichErrors.RoundingError( numerator, denominator, target )); } // safeDiv computes `floor(a / b)`. We use the identity (a, b integer): // ceil(a / b) = floor((a + b - 1) / b) // To implement `ceil(a / b)` using safeDiv. partialAmount = numerator.safeMul(target) .safeAdd(denominator.safeSub(1)) .safeDiv(denominator); return partialAmount; } /// @dev Calculates partial value given a numerator and denominator rounded down. /// @param numerator Numerator. /// @param denominator Denominator. /// @param target Value to calculate partial of. /// @return Partial value of target rounded down. function getPartialAmountFloor( uint256 numerator, uint256 denominator, uint256 target ) internal pure returns (uint256 partialAmount) { partialAmount = numerator.safeMul(target).safeDiv(denominator); return partialAmount; } /// @dev Calculates partial value given a numerator and denominator rounded down. /// @param numerator Numerator. /// @param denominator Denominator. /// @param target Value to calculate partial of. /// @return Partial value of target rounded up. function getPartialAmountCeil( uint256 numerator, uint256 denominator, uint256 target ) internal pure returns (uint256 partialAmount) { // safeDiv computes `floor(a / b)`. We use the identity (a, b integer): // ceil(a / b) = floor((a + b - 1) / b) // To implement `ceil(a / b)` using safeDiv. partialAmount = numerator.safeMul(target) .safeAdd(denominator.safeSub(1)) .safeDiv(denominator); return partialAmount; } /// @dev Checks if rounding error >= 0.1% when rounding down. /// @param numerator Numerator. /// @param denominator Denominator. /// @param target Value to multiply with numerator/denominator. /// @return Rounding error is present. function isRoundingErrorFloor( uint256 numerator, uint256 denominator, uint256 target ) internal pure returns (bool isError) { if (denominator == 0) { LibRichErrors.rrevert(LibMathRichErrors.DivisionByZeroError()); } // The absolute rounding error is the difference between the rounded // value and the ideal value. The relative rounding error is the // absolute rounding error divided by the absolute value of the // ideal value. This is undefined when the ideal value is zero. // // The ideal value is `numerator * target / denominator`. // Let's call `numerator * target % denominator` the remainder. // The absolute error is `remainder / denominator`. // // When the ideal value is zero, we require the absolute error to // be zero. Fortunately, this is always the case. The ideal value is // zero iff `numerator == 0` and/or `target == 0`. In this case the // remainder and absolute error are also zero. if (target == 0 || numerator == 0) { return false; } // Otherwise, we want the relative rounding error to be strictly // less than 0.1%. // The relative error is `remainder / (numerator * target)`. // We want the relative error less than 1 / 1000: // remainder / (numerator * denominator) < 1 / 1000 // or equivalently: // 1000 * remainder < numerator * target // so we have a rounding error iff: // 1000 * remainder >= numerator * target uint256 remainder = mulmod( target, numerator, denominator ); isError = remainder.safeMul(1000) >= numerator.safeMul(target); return isError; } /// @dev Checks if rounding error >= 0.1% when rounding up. /// @param numerator Numerator. /// @param denominator Denominator. /// @param target Value to multiply with numerator/denominator. /// @return Rounding error is present. function isRoundingErrorCeil( uint256 numerator, uint256 denominator, uint256 target ) internal pure returns (bool isError) { if (denominator == 0) { LibRichErrors.rrevert(LibMathRichErrors.DivisionByZeroError()); } // See the comments in `isRoundingError`. if (target == 0 || numerator == 0) { // When either is zero, the ideal value and rounded value are zero // and there is no rounding error. (Although the relative error // is undefined.) return false; } // Compute remainder as before uint256 remainder = mulmod( target, numerator, denominator ); remainder = denominator.safeSub(remainder) % denominator; isError = remainder.safeMul(1000) >= numerator.safeMul(target); return isError; } }
pragma solidity ^0.5.9; library LibMathRichErrors { // bytes4(keccak256("DivisionByZeroError()")) bytes internal constant DIVISION_BY_ZERO_ERROR = hex"a791837c"; // bytes4(keccak256("RoundingError(uint256,uint256,uint256)")) bytes4 internal constant ROUNDING_ERROR_SELECTOR = 0x339f3de2; // solhint-disable func-name-mixedcase function DivisionByZeroError() internal pure returns (bytes memory) { return DIVISION_BY_ZERO_ERROR; } function RoundingError( uint256 numerator, uint256 denominator, uint256 target ) internal pure returns (bytes memory) { return abi.encodeWithSelector( ROUNDING_ERROR_SELECTOR, numerator, denominator, target ); } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "./LibOrder.sol"; library LibExchangeRichErrors { enum AssetProxyDispatchErrorCodes { INVALID_ASSET_DATA_LENGTH, UNKNOWN_ASSET_PROXY } enum BatchMatchOrdersErrorCodes { ZERO_LEFT_ORDERS, ZERO_RIGHT_ORDERS, INVALID_LENGTH_LEFT_SIGNATURES, INVALID_LENGTH_RIGHT_SIGNATURES } enum ExchangeContextErrorCodes { INVALID_MAKER, INVALID_TAKER, INVALID_SENDER } enum FillErrorCodes { INVALID_TAKER_AMOUNT, TAKER_OVERPAY, OVERFILL, INVALID_FILL_PRICE } enum SignatureErrorCodes { BAD_ORDER_SIGNATURE, BAD_TRANSACTION_SIGNATURE, INVALID_LENGTH, UNSUPPORTED, ILLEGAL, INAPPROPRIATE_SIGNATURE_TYPE, INVALID_SIGNER } enum TransactionErrorCodes { ALREADY_EXECUTED, EXPIRED } enum IncompleteFillErrorCode { INCOMPLETE_MARKET_BUY_ORDERS, INCOMPLETE_MARKET_SELL_ORDERS, INCOMPLETE_FILL_ORDER } // bytes4(keccak256("SignatureError(uint8,bytes32,address,bytes)")) bytes4 internal constant SIGNATURE_ERROR_SELECTOR = 0x7e5a2318; // bytes4(keccak256("SignatureValidatorNotApprovedError(address,address)")) bytes4 internal constant SIGNATURE_VALIDATOR_NOT_APPROVED_ERROR_SELECTOR = 0xa15c0d06; // bytes4(keccak256("EIP1271SignatureError(address,bytes,bytes,bytes)")) bytes4 internal constant EIP1271_SIGNATURE_ERROR_SELECTOR = 0x5bd0428d; // bytes4(keccak256("SignatureWalletError(bytes32,address,bytes,bytes)")) bytes4 internal constant SIGNATURE_WALLET_ERROR_SELECTOR = 0x1b8388f7; // bytes4(keccak256("OrderStatusError(bytes32,uint8)")) bytes4 internal constant ORDER_STATUS_ERROR_SELECTOR = 0xfdb6ca8d; // bytes4(keccak256("ExchangeInvalidContextError(uint8,bytes32,address)")) bytes4 internal constant EXCHANGE_INVALID_CONTEXT_ERROR_SELECTOR = 0xe53c76c8; // bytes4(keccak256("FillError(uint8,bytes32)")) bytes4 internal constant FILL_ERROR_SELECTOR = 0xe94a7ed0; // bytes4(keccak256("OrderEpochError(address,address,uint256)")) bytes4 internal constant ORDER_EPOCH_ERROR_SELECTOR = 0x4ad31275; // bytes4(keccak256("AssetProxyExistsError(bytes4,address)")) bytes4 internal constant ASSET_PROXY_EXISTS_ERROR_SELECTOR = 0x11c7b720; // bytes4(keccak256("AssetProxyDispatchError(uint8,bytes32,bytes)")) bytes4 internal constant ASSET_PROXY_DISPATCH_ERROR_SELECTOR = 0x488219a6; // bytes4(keccak256("AssetProxyTransferError(bytes32,bytes,bytes)")) bytes4 internal constant ASSET_PROXY_TRANSFER_ERROR_SELECTOR = 0x4678472b; // bytes4(keccak256("NegativeSpreadError(bytes32,bytes32)")) bytes4 internal constant NEGATIVE_SPREAD_ERROR_SELECTOR = 0xb6555d6f; // bytes4(keccak256("TransactionError(uint8,bytes32)")) bytes4 internal constant TRANSACTION_ERROR_SELECTOR = 0xf5985184; // bytes4(keccak256("TransactionExecutionError(bytes32,bytes)")) bytes4 internal constant TRANSACTION_EXECUTION_ERROR_SELECTOR = 0x20d11f61; // bytes4(keccak256("TransactionGasPriceError(bytes32,uint256,uint256)")) bytes4 internal constant TRANSACTION_GAS_PRICE_ERROR_SELECTOR = 0xa26dac09; // bytes4(keccak256("TransactionInvalidContextError(bytes32,address)")) bytes4 internal constant TRANSACTION_INVALID_CONTEXT_ERROR_SELECTOR = 0xdec4aedf; // bytes4(keccak256("IncompleteFillError(uint8,uint256,uint256)")) bytes4 internal constant INCOMPLETE_FILL_ERROR_SELECTOR = 0x18e4b141; // bytes4(keccak256("BatchMatchOrdersError(uint8)")) bytes4 internal constant BATCH_MATCH_ORDERS_ERROR_SELECTOR = 0xd4092f4f; // bytes4(keccak256("PayProtocolFeeError(bytes32,uint256,address,address,bytes)")) bytes4 internal constant PAY_PROTOCOL_FEE_ERROR_SELECTOR = 0x87cb1e75; // solhint-disable func-name-mixedcase function SignatureErrorSelector() internal pure returns (bytes4) { return SIGNATURE_ERROR_SELECTOR; } function SignatureValidatorNotApprovedErrorSelector() internal pure returns (bytes4) { return SIGNATURE_VALIDATOR_NOT_APPROVED_ERROR_SELECTOR; } function EIP1271SignatureErrorSelector() internal pure returns (bytes4) { return EIP1271_SIGNATURE_ERROR_SELECTOR; } function SignatureWalletErrorSelector() internal pure returns (bytes4) { return SIGNATURE_WALLET_ERROR_SELECTOR; } function OrderStatusErrorSelector() internal pure returns (bytes4) { return ORDER_STATUS_ERROR_SELECTOR; } function ExchangeInvalidContextErrorSelector() internal pure returns (bytes4) { return EXCHANGE_INVALID_CONTEXT_ERROR_SELECTOR; } function FillErrorSelector() internal pure returns (bytes4) { return FILL_ERROR_SELECTOR; } function OrderEpochErrorSelector() internal pure returns (bytes4) { return ORDER_EPOCH_ERROR_SELECTOR; } function AssetProxyExistsErrorSelector() internal pure returns (bytes4) { return ASSET_PROXY_EXISTS_ERROR_SELECTOR; } function AssetProxyDispatchErrorSelector() internal pure returns (bytes4) { return ASSET_PROXY_DISPATCH_ERROR_SELECTOR; } function AssetProxyTransferErrorSelector() internal pure returns (bytes4) { return ASSET_PROXY_TRANSFER_ERROR_SELECTOR; } function NegativeSpreadErrorSelector() internal pure returns (bytes4) { return NEGATIVE_SPREAD_ERROR_SELECTOR; } function TransactionErrorSelector() internal pure returns (bytes4) { return TRANSACTION_ERROR_SELECTOR; } function TransactionExecutionErrorSelector() internal pure returns (bytes4) { return TRANSACTION_EXECUTION_ERROR_SELECTOR; } function IncompleteFillErrorSelector() internal pure returns (bytes4) { return INCOMPLETE_FILL_ERROR_SELECTOR; } function BatchMatchOrdersErrorSelector() internal pure returns (bytes4) { return BATCH_MATCH_ORDERS_ERROR_SELECTOR; } function TransactionGasPriceErrorSelector() internal pure returns (bytes4) { return TRANSACTION_GAS_PRICE_ERROR_SELECTOR; } function TransactionInvalidContextErrorSelector() internal pure returns (bytes4) { return TRANSACTION_INVALID_CONTEXT_ERROR_SELECTOR; } function PayProtocolFeeErrorSelector() internal pure returns (bytes4) { return PAY_PROTOCOL_FEE_ERROR_SELECTOR; } function BatchMatchOrdersError( BatchMatchOrdersErrorCodes errorCode ) internal pure returns (bytes memory) { return abi.encodeWithSelector( BATCH_MATCH_ORDERS_ERROR_SELECTOR, errorCode ); } function SignatureError( SignatureErrorCodes errorCode, bytes32 hash, address signerAddress, bytes memory signature ) internal pure returns (bytes memory) { return abi.encodeWithSelector( SIGNATURE_ERROR_SELECTOR, errorCode, hash, signerAddress, signature ); } function SignatureValidatorNotApprovedError( address signerAddress, address validatorAddress ) internal pure returns (bytes memory) { return abi.encodeWithSelector( SIGNATURE_VALIDATOR_NOT_APPROVED_ERROR_SELECTOR, signerAddress, validatorAddress ); } function EIP1271SignatureError( address verifyingContractAddress, bytes memory data, bytes memory signature, bytes memory errorData ) internal pure returns (bytes memory) { return abi.encodeWithSelector( EIP1271_SIGNATURE_ERROR_SELECTOR, verifyingContractAddress, data, signature, errorData ); } function SignatureWalletError( bytes32 hash, address walletAddress, bytes memory signature, bytes memory errorData ) internal pure returns (bytes memory) { return abi.encodeWithSelector( SIGNATURE_WALLET_ERROR_SELECTOR, hash, walletAddress, signature, errorData ); } function OrderStatusError( bytes32 orderHash, LibOrder.OrderStatus orderStatus ) internal pure returns (bytes memory) { return abi.encodeWithSelector( ORDER_STATUS_ERROR_SELECTOR, orderHash, orderStatus ); } function ExchangeInvalidContextError( ExchangeContextErrorCodes errorCode, bytes32 orderHash, address contextAddress ) internal pure returns (bytes memory) { return abi.encodeWithSelector( EXCHANGE_INVALID_CONTEXT_ERROR_SELECTOR, errorCode, orderHash, contextAddress ); } function FillError( FillErrorCodes errorCode, bytes32 orderHash ) internal pure returns (bytes memory) { return abi.encodeWithSelector( FILL_ERROR_SELECTOR, errorCode, orderHash ); } function OrderEpochError( address makerAddress, address orderSenderAddress, uint256 currentEpoch ) internal pure returns (bytes memory) { return abi.encodeWithSelector( ORDER_EPOCH_ERROR_SELECTOR, makerAddress, orderSenderAddress, currentEpoch ); } function AssetProxyExistsError( bytes4 assetProxyId, address assetProxyAddress ) internal pure returns (bytes memory) { return abi.encodeWithSelector( ASSET_PROXY_EXISTS_ERROR_SELECTOR, assetProxyId, assetProxyAddress ); } function AssetProxyDispatchError( AssetProxyDispatchErrorCodes errorCode, bytes32 orderHash, bytes memory assetData ) internal pure returns (bytes memory) { return abi.encodeWithSelector( ASSET_PROXY_DISPATCH_ERROR_SELECTOR, errorCode, orderHash, assetData ); } function AssetProxyTransferError( bytes32 orderHash, bytes memory assetData, bytes memory errorData ) internal pure returns (bytes memory) { return abi.encodeWithSelector( ASSET_PROXY_TRANSFER_ERROR_SELECTOR, orderHash, assetData, errorData ); } function NegativeSpreadError( bytes32 leftOrderHash, bytes32 rightOrderHash ) internal pure returns (bytes memory) { return abi.encodeWithSelector( NEGATIVE_SPREAD_ERROR_SELECTOR, leftOrderHash, rightOrderHash ); } function TransactionError( TransactionErrorCodes errorCode, bytes32 transactionHash ) internal pure returns (bytes memory) { return abi.encodeWithSelector( TRANSACTION_ERROR_SELECTOR, errorCode, transactionHash ); } function TransactionExecutionError( bytes32 transactionHash, bytes memory errorData ) internal pure returns (bytes memory) { return abi.encodeWithSelector( TRANSACTION_EXECUTION_ERROR_SELECTOR, transactionHash, errorData ); } function TransactionGasPriceError( bytes32 transactionHash, uint256 actualGasPrice, uint256 requiredGasPrice ) internal pure returns (bytes memory) { return abi.encodeWithSelector( TRANSACTION_GAS_PRICE_ERROR_SELECTOR, transactionHash, actualGasPrice, requiredGasPrice ); } function TransactionInvalidContextError( bytes32 transactionHash, address currentContextAddress ) internal pure returns (bytes memory) { return abi.encodeWithSelector( TRANSACTION_INVALID_CONTEXT_ERROR_SELECTOR, transactionHash, currentContextAddress ); } function IncompleteFillError( IncompleteFillErrorCode errorCode, uint256 expectedAssetFillAmount, uint256 actualAssetFillAmount ) internal pure returns (bytes memory) { return abi.encodeWithSelector( INCOMPLETE_FILL_ERROR_SELECTOR, errorCode, expectedAssetFillAmount, actualAssetFillAmount ); } function PayProtocolFeeError( bytes32 orderHash, uint256 protocolFee, address makerAddress, address takerAddress, bytes memory errorData ) internal pure returns (bytes memory) { return abi.encodeWithSelector( PAY_PROTOCOL_FEE_ERROR_SELECTOR, orderHash, protocolFee, makerAddress, takerAddress, errorData ); } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; contract IMatchOrders { /// @dev Match complementary orders that have a profitable spread. /// Each order is filled at their respective price point, and /// the matcher receives a profit denominated in the left maker asset. /// @param leftOrders Set of orders with the same maker / taker asset. /// @param rightOrders Set of orders to match against `leftOrders` /// @param leftSignatures Proof that left orders were created by the left makers. /// @param rightSignatures Proof that right orders were created by the right makers. /// @return batchMatchedFillResults Amounts filled and profit generated. function batchMatchOrders( LibOrder.Order[] memory leftOrders, LibOrder.Order[] memory rightOrders, bytes[] memory leftSignatures, bytes[] memory rightSignatures ) public payable returns (LibFillResults.BatchMatchedFillResults memory batchMatchedFillResults); /// @dev Match complementary orders that have a profitable spread. /// Each order is maximally filled at their respective price point, and /// the matcher receives a profit denominated in either the left maker asset, /// right maker asset, or a combination of both. /// @param leftOrders Set of orders with the same maker / taker asset. /// @param rightOrders Set of orders to match against `leftOrders` /// @param leftSignatures Proof that left orders were created by the left makers. /// @param rightSignatures Proof that right orders were created by the right makers. /// @return batchMatchedFillResults Amounts filled and profit generated. function batchMatchOrdersWithMaximalFill( LibOrder.Order[] memory leftOrders, LibOrder.Order[] memory rightOrders, bytes[] memory leftSignatures, bytes[] memory rightSignatures ) public payable returns (LibFillResults.BatchMatchedFillResults memory batchMatchedFillResults); /// @dev Match two complementary orders that have a profitable spread. /// Each order is filled at their respective price point. However, the calculations are /// carried out as though the orders are both being filled at the right order's price point. /// The profit made by the left order goes to the taker (who matched the two orders). /// @param leftOrder First order to match. /// @param rightOrder Second order to match. /// @param leftSignature Proof that order was created by the left maker. /// @param rightSignature Proof that order was created by the right maker. /// @return matchedFillResults Amounts filled and fees paid by maker and taker of matched orders. function matchOrders( LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder, bytes memory leftSignature, bytes memory rightSignature ) public payable returns (LibFillResults.MatchedFillResults memory matchedFillResults); /// @dev Match two complementary orders that have a profitable spread. /// Each order is maximally filled at their respective price point, and /// the matcher receives a profit denominated in either the left maker asset, /// right maker asset, or a combination of both. /// @param leftOrder First order to match. /// @param rightOrder Second order to match. /// @param leftSignature Proof that order was created by the left maker. /// @param rightSignature Proof that order was created by the right maker. /// @return matchedFillResults Amounts filled by maker and taker of matched orders. function matchOrdersWithMaximalFill( LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder, bytes memory leftSignature, bytes memory rightSignature ) public payable returns (LibFillResults.MatchedFillResults memory matchedFillResults); }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-utils/contracts/src/LibBytes.sol"; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; import "@0x/contracts-utils/contracts/src/Refundable.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; import "./interfaces/IExchangeCore.sol"; import "./MixinAssetProxyDispatcher.sol"; import "./MixinProtocolFees.sol"; import "./MixinSignatureValidator.sol"; contract MixinExchangeCore is IExchangeCore, Refundable, LibEIP712ExchangeDomain, MixinAssetProxyDispatcher, MixinProtocolFees, MixinSignatureValidator { using LibOrder for LibOrder.Order; using LibSafeMath for uint256; using LibBytes for bytes; // Mapping of orderHash => amount of takerAsset already bought by maker mapping (bytes32 => uint256) public filled; // Mapping of orderHash => cancelled mapping (bytes32 => bool) public cancelled; // Mapping of makerAddress => senderAddress => lowest salt an order can have in order to be fillable // Orders with specified senderAddress and with a salt less than their epoch are considered cancelled mapping (address => mapping (address => uint256)) public orderEpoch; /// @dev Cancels all orders created by makerAddress with a salt less than or equal to the targetOrderEpoch /// and senderAddress equal to msg.sender (or null address if msg.sender == makerAddress). /// @param targetOrderEpoch Orders created with a salt less or equal to this value will be cancelled. function cancelOrdersUpTo(uint256 targetOrderEpoch) external payable refundFinalBalanceNoReentry { address makerAddress = _getCurrentContextAddress(); // If this function is called via `executeTransaction`, we only update the orderEpoch for the makerAddress/msg.sender combination. // This allows external filter contracts to add rules to how orders are cancelled via this function. address orderSenderAddress = makerAddress == msg.sender ? address(0) : msg.sender; // orderEpoch is initialized to 0, so to cancelUpTo we need salt + 1 uint256 newOrderEpoch = targetOrderEpoch + 1; uint256 oldOrderEpoch = orderEpoch[makerAddress][orderSenderAddress]; // Ensure orderEpoch is monotonically increasing if (newOrderEpoch <= oldOrderEpoch) { LibRichErrors.rrevert(LibExchangeRichErrors.OrderEpochError( makerAddress, orderSenderAddress, oldOrderEpoch )); } // Update orderEpoch orderEpoch[makerAddress][orderSenderAddress] = newOrderEpoch; emit CancelUpTo( makerAddress, orderSenderAddress, newOrderEpoch ); } /// @dev Fills the input order. /// @param order Order struct containing order specifications. /// @param takerAssetFillAmount Desired amount of takerAsset to sell. /// @param signature Proof that order has been created by maker. /// @return Amounts filled and fees paid by maker and taker. function fillOrder( LibOrder.Order memory order, uint256 takerAssetFillAmount, bytes memory signature ) public payable refundFinalBalanceNoReentry returns (LibFillResults.FillResults memory fillResults) { fillResults = _fillOrder( order, takerAssetFillAmount, signature ); return fillResults; } /// @dev After calling, the order can not be filled anymore. /// @param order Order struct containing order specifications. function cancelOrder(LibOrder.Order memory order) public payable refundFinalBalanceNoReentry { _cancelOrder(order); } /// @dev Gets information about an order: status, hash, and amount filled. /// @param order Order to gather information on. /// @return OrderInfo Information about the order and its state. /// See LibOrder.OrderInfo for a complete description. function getOrderInfo(LibOrder.Order memory order) public view returns (LibOrder.OrderInfo memory orderInfo) { // Compute the order hash and fetch the amount of takerAsset that has already been filled (orderInfo.orderHash, orderInfo.orderTakerAssetFilledAmount) = _getOrderHashAndFilledAmount(order); // If order.makerAssetAmount is zero, we also reject the order. // While the Exchange contract handles them correctly, they create // edge cases in the supporting infrastructure because they have // an 'infinite' price when computed by a simple division. if (order.makerAssetAmount == 0) { orderInfo.orderStatus = uint8(LibOrder.OrderStatus.INVALID_MAKER_ASSET_AMOUNT); return orderInfo; } // If order.takerAssetAmount is zero, then the order will always // be considered filled because 0 == takerAssetAmount == orderTakerAssetFilledAmount // Instead of distinguishing between unfilled and filled zero taker // amount orders, we choose not to support them. if (order.takerAssetAmount == 0) { orderInfo.orderStatus = uint8(LibOrder.OrderStatus.INVALID_TAKER_ASSET_AMOUNT); return orderInfo; } // Validate order availability if (orderInfo.orderTakerAssetFilledAmount >= order.takerAssetAmount) { orderInfo.orderStatus = uint8(LibOrder.OrderStatus.FULLY_FILLED); return orderInfo; } // Validate order expiration // solhint-disable-next-line not-rely-on-time if (block.timestamp >= order.expirationTimeSeconds) { orderInfo.orderStatus = uint8(LibOrder.OrderStatus.EXPIRED); return orderInfo; } // Check if order has been cancelled if (cancelled[orderInfo.orderHash]) { orderInfo.orderStatus = uint8(LibOrder.OrderStatus.CANCELLED); return orderInfo; } if (orderEpoch[order.makerAddress][order.senderAddress] > order.salt) { orderInfo.orderStatus = uint8(LibOrder.OrderStatus.CANCELLED); return orderInfo; } // All other statuses are ruled out: order is Fillable orderInfo.orderStatus = uint8(LibOrder.OrderStatus.FILLABLE); return orderInfo; } /// @dev Fills the input order. /// @param order Order struct containing order specifications. /// @param takerAssetFillAmount Desired amount of takerAsset to sell. /// @param signature Proof that order has been created by maker. /// @return Amounts filled and fees paid by maker and taker. function _fillOrder( LibOrder.Order memory order, uint256 takerAssetFillAmount, bytes memory signature ) internal returns (LibFillResults.FillResults memory fillResults) { // Fetch order info LibOrder.OrderInfo memory orderInfo = getOrderInfo(order); // Fetch taker address address takerAddress = _getCurrentContextAddress(); // Assert that the order is fillable by taker _assertFillableOrder( order, orderInfo, takerAddress, signature ); // Get amount of takerAsset to fill uint256 remainingTakerAssetAmount = order.takerAssetAmount.safeSub(orderInfo.orderTakerAssetFilledAmount); uint256 takerAssetFilledAmount = LibSafeMath.min256(takerAssetFillAmount, remainingTakerAssetAmount); // Compute proportional fill amounts fillResults = LibFillResults.calculateFillResults( order, takerAssetFilledAmount, protocolFeeMultiplier, tx.gasprice ); bytes32 orderHash = orderInfo.orderHash; // Update exchange internal state _updateFilledState( order, takerAddress, orderHash, orderInfo.orderTakerAssetFilledAmount, fillResults ); // Settle order _settleOrder( orderHash, order, takerAddress, fillResults ); return fillResults; } /// @dev After calling, the order can not be filled anymore. /// Throws if order is invalid or sender does not have permission to cancel. /// @param order Order to cancel. Order must be OrderStatus.FILLABLE. function _cancelOrder(LibOrder.Order memory order) internal { // Fetch current order status LibOrder.OrderInfo memory orderInfo = getOrderInfo(order); // Validate context _assertValidCancel(order, orderInfo); // Noop if order is already unfillable if (orderInfo.orderStatus != uint8(LibOrder.OrderStatus.FILLABLE)) { return; } // Perform cancel _updateCancelledState(order, orderInfo.orderHash); } /// @dev Updates state with results of a fill order. /// @param order that was filled. /// @param takerAddress Address of taker who filled the order. /// @param orderTakerAssetFilledAmount Amount of order already filled. function _updateFilledState( LibOrder.Order memory order, address takerAddress, bytes32 orderHash, uint256 orderTakerAssetFilledAmount, LibFillResults.FillResults memory fillResults ) internal { // Update state filled[orderHash] = orderTakerAssetFilledAmount.safeAdd(fillResults.takerAssetFilledAmount); emit Fill( order.makerAddress, order.feeRecipientAddress, order.makerAssetData, order.takerAssetData, order.makerFeeAssetData, order.takerFeeAssetData, orderHash, takerAddress, msg.sender, fillResults.makerAssetFilledAmount, fillResults.takerAssetFilledAmount, fillResults.makerFeePaid, fillResults.takerFeePaid, fillResults.protocolFeePaid ); } /// @dev Updates state with results of cancelling an order. /// State is only updated if the order is currently fillable. /// Otherwise, updating state would have no effect. /// @param order that was cancelled. /// @param orderHash Hash of order that was cancelled. function _updateCancelledState( LibOrder.Order memory order, bytes32 orderHash ) internal { // Perform cancel cancelled[orderHash] = true; // Log cancel emit Cancel( order.makerAddress, order.feeRecipientAddress, order.makerAssetData, order.takerAssetData, msg.sender, orderHash ); } /// @dev Validates context for fillOrder. Succeeds or throws. /// @param order to be filled. /// @param orderInfo OrderStatus, orderHash, and amount already filled of order. /// @param takerAddress Address of order taker. /// @param signature Proof that the orders was created by its maker. function _assertFillableOrder( LibOrder.Order memory order, LibOrder.OrderInfo memory orderInfo, address takerAddress, bytes memory signature ) internal view { // An order can only be filled if its status is FILLABLE. if (orderInfo.orderStatus != uint8(LibOrder.OrderStatus.FILLABLE)) { LibRichErrors.rrevert(LibExchangeRichErrors.OrderStatusError( orderInfo.orderHash, LibOrder.OrderStatus(orderInfo.orderStatus) )); } // Validate sender is allowed to fill this order if (order.senderAddress != address(0)) { if (order.senderAddress != msg.sender) { LibRichErrors.rrevert(LibExchangeRichErrors.ExchangeInvalidContextError( LibExchangeRichErrors.ExchangeContextErrorCodes.INVALID_SENDER, orderInfo.orderHash, msg.sender )); } } // Validate taker is allowed to fill this order if (order.takerAddress != address(0)) { if (order.takerAddress != takerAddress) { LibRichErrors.rrevert(LibExchangeRichErrors.ExchangeInvalidContextError( LibExchangeRichErrors.ExchangeContextErrorCodes.INVALID_TAKER, orderInfo.orderHash, takerAddress )); } } // Validate signature if (!_isValidOrderWithHashSignature( order, orderInfo.orderHash, signature ) ) { LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( LibExchangeRichErrors.SignatureErrorCodes.BAD_ORDER_SIGNATURE, orderInfo.orderHash, order.makerAddress, signature )); } } /// @dev Validates context for cancelOrder. Succeeds or throws. /// @param order to be cancelled. /// @param orderInfo OrderStatus, orderHash, and amount already filled of order. function _assertValidCancel( LibOrder.Order memory order, LibOrder.OrderInfo memory orderInfo ) internal view { // Validate sender is allowed to cancel this order if (order.senderAddress != address(0)) { if (order.senderAddress != msg.sender) { LibRichErrors.rrevert(LibExchangeRichErrors.ExchangeInvalidContextError( LibExchangeRichErrors.ExchangeContextErrorCodes.INVALID_SENDER, orderInfo.orderHash, msg.sender )); } } // Validate transaction signed by maker address makerAddress = _getCurrentContextAddress(); if (order.makerAddress != makerAddress) { LibRichErrors.rrevert(LibExchangeRichErrors.ExchangeInvalidContextError( LibExchangeRichErrors.ExchangeContextErrorCodes.INVALID_MAKER, orderInfo.orderHash, makerAddress )); } } /// @dev Settles an order by transferring assets between counterparties. /// @param orderHash The order hash. /// @param order Order struct containing order specifications. /// @param takerAddress Address selling takerAsset and buying makerAsset. /// @param fillResults Amounts to be filled and fees paid by maker and taker. function _settleOrder( bytes32 orderHash, LibOrder.Order memory order, address takerAddress, LibFillResults.FillResults memory fillResults ) internal { // Transfer taker -> maker _dispatchTransferFrom( orderHash, order.takerAssetData, takerAddress, order.makerAddress, fillResults.takerAssetFilledAmount ); // Transfer maker -> taker _dispatchTransferFrom( orderHash, order.makerAssetData, order.makerAddress, takerAddress, fillResults.makerAssetFilledAmount ); // Transfer taker fee -> feeRecipient _dispatchTransferFrom( orderHash, order.takerFeeAssetData, takerAddress, order.feeRecipientAddress, fillResults.takerFeePaid ); // Transfer maker fee -> feeRecipient _dispatchTransferFrom( orderHash, order.makerFeeAssetData, order.makerAddress, order.feeRecipientAddress, fillResults.makerFeePaid ); // Pay protocol fee bool didPayProtocolFee = _paySingleProtocolFee( orderHash, fillResults.protocolFeePaid, order.makerAddress, takerAddress ); // Protocol fees are not paid if the protocolFeeCollector contract is not set if (!didPayProtocolFee) { fillResults.protocolFeePaid = 0; } } /// @dev Gets the order's hash and amount of takerAsset that has already been filled. /// @param order Order struct containing order specifications. /// @return The typed data hash and amount filled of the order. function _getOrderHashAndFilledAmount(LibOrder.Order memory order) internal view returns (bytes32 orderHash, uint256 orderTakerAssetFilledAmount) { orderHash = order.getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH); orderTakerAssetFilledAmount = filled[orderHash]; return (orderHash, orderTakerAssetFilledAmount); } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; import "./ReentrancyGuard.sol"; contract Refundable is ReentrancyGuard { // This bool is used by the refund modifier to allow for lazily evaluated refunds. bool internal _shouldNotRefund; modifier refundFinalBalance { _; _refundNonZeroBalanceIfEnabled(); } modifier refundFinalBalanceNoReentry { _lockMutexOrThrowIfAlreadyLocked(); _; _refundNonZeroBalanceIfEnabled(); _unlockMutex(); } modifier disableRefundUntilEnd { if (_areRefundsDisabled()) { _; } else { _disableRefund(); _; _enableAndRefundNonZeroBalance(); } } function _refundNonZeroBalanceIfEnabled() internal { if (!_areRefundsDisabled()) { _refundNonZeroBalance(); } } function _refundNonZeroBalance() internal { uint256 balance = address(this).balance; if (balance > 0) { msg.sender.transfer(balance); } } function _disableRefund() internal { _shouldNotRefund = true; } function _enableAndRefundNonZeroBalance() internal { _shouldNotRefund = false; _refundNonZeroBalance(); } function _areRefundsDisabled() internal view returns (bool) { return _shouldNotRefund; } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; import "./LibReentrancyGuardRichErrors.sol"; import "./LibRichErrors.sol"; contract ReentrancyGuard { // Locked state of mutex. bool private _locked = false; /// @dev Functions with this modifer cannot be reentered. The mutex will be locked /// before function execution and unlocked after. modifier nonReentrant() { _lockMutexOrThrowIfAlreadyLocked(); _; _unlockMutex(); } function _lockMutexOrThrowIfAlreadyLocked() internal { // Ensure mutex is unlocked. if (_locked) { LibRichErrors.rrevert( LibReentrancyGuardRichErrors.IllegalReentrancyError() ); } // Lock mutex. _locked = true; } function _unlockMutex() internal { // Unlock mutex. _locked = false; } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; library LibReentrancyGuardRichErrors { // bytes4(keccak256("IllegalReentrancyError()")) bytes internal constant ILLEGAL_REENTRANCY_ERROR_SELECTOR_BYTES = hex"0c3b823f"; // solhint-disable func-name-mixedcase function IllegalReentrancyError() internal pure returns (bytes memory) { return ILLEGAL_REENTRANCY_ERROR_SELECTOR_BYTES; } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; contract IExchangeCore { // Fill event is emitted whenever an order is filled. event Fill( address indexed makerAddress, // Address that created the order. address indexed feeRecipientAddress, // Address that received fees. bytes makerAssetData, // Encoded data specific to makerAsset. bytes takerAssetData, // Encoded data specific to takerAsset. bytes makerFeeAssetData, // Encoded data specific to makerFeeAsset. bytes takerFeeAssetData, // Encoded data specific to takerFeeAsset. bytes32 indexed orderHash, // EIP712 hash of order (see LibOrder.getTypedDataHash). address takerAddress, // Address that filled the order. address senderAddress, // Address that called the Exchange contract (msg.sender). uint256 makerAssetFilledAmount, // Amount of makerAsset sold by maker and bought by taker. uint256 takerAssetFilledAmount, // Amount of takerAsset sold by taker and bought by maker. uint256 makerFeePaid, // Amount of makerFeeAssetData paid to feeRecipient by maker. uint256 takerFeePaid, // Amount of takerFeeAssetData paid to feeRecipient by taker. uint256 protocolFeePaid // Amount of eth or weth paid to the staking contract. ); // Cancel event is emitted whenever an individual order is cancelled. event Cancel( address indexed makerAddress, // Address that created the order. address indexed feeRecipientAddress, // Address that would have recieved fees if order was filled. bytes makerAssetData, // Encoded data specific to makerAsset. bytes takerAssetData, // Encoded data specific to takerAsset. address senderAddress, // Address that called the Exchange contract (msg.sender). bytes32 indexed orderHash // EIP712 hash of order (see LibOrder.getTypedDataHash). ); // CancelUpTo event is emitted whenever `cancelOrdersUpTo` is executed succesfully. event CancelUpTo( address indexed makerAddress, // Orders cancelled must have been created by this address. address indexed orderSenderAddress, // Orders cancelled must have a `senderAddress` equal to this address. uint256 orderEpoch // Orders with specified makerAddress and senderAddress with a salt less than this value are considered cancelled. ); /// @dev Cancels all orders created by makerAddress with a salt less than or equal to the targetOrderEpoch /// and senderAddress equal to msg.sender (or null address if msg.sender == makerAddress). /// @param targetOrderEpoch Orders created with a salt less or equal to this value will be cancelled. function cancelOrdersUpTo(uint256 targetOrderEpoch) external payable; /// @dev Fills the input order. /// @param order Order struct containing order specifications. /// @param takerAssetFillAmount Desired amount of takerAsset to sell. /// @param signature Proof that order has been created by maker. /// @return Amounts filled and fees paid by maker and taker. function fillOrder( LibOrder.Order memory order, uint256 takerAssetFillAmount, bytes memory signature ) public payable returns (LibFillResults.FillResults memory fillResults); /// @dev After calling, the order can not be filled anymore. /// @param order Order struct containing order specifications. function cancelOrder(LibOrder.Order memory order) public payable; /// @dev Gets information about an order: status, hash, and amount filled. /// @param order Order to gather information on. /// @return OrderInfo Information about the order and its state. /// See LibOrder.OrderInfo for a complete description. function getOrderInfo(LibOrder.Order memory order) public view returns (LibOrder.OrderInfo memory orderInfo); }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; import "@0x/contracts-utils/contracts/src/Ownable.sol"; import "@0x/contracts-utils/contracts/src/LibBytes.sol"; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; import "./interfaces/IAssetProxy.sol"; import "./interfaces/IAssetProxyDispatcher.sol"; contract MixinAssetProxyDispatcher is Ownable, IAssetProxyDispatcher { using LibBytes for bytes; // Mapping from Asset Proxy Id's to their respective Asset Proxy mapping (bytes4 => address) internal _assetProxies; /// @dev Registers an asset proxy to its asset proxy id. /// Once an asset proxy is registered, it cannot be unregistered. /// @param assetProxy Address of new asset proxy to register. function registerAssetProxy(address assetProxy) external onlyOwner { // Ensure that no asset proxy exists with current id. bytes4 assetProxyId = IAssetProxy(assetProxy).getProxyId(); address currentAssetProxy = _assetProxies[assetProxyId]; if (currentAssetProxy != address(0)) { LibRichErrors.rrevert(LibExchangeRichErrors.AssetProxyExistsError( assetProxyId, currentAssetProxy )); } // Add asset proxy and log registration. _assetProxies[assetProxyId] = assetProxy; emit AssetProxyRegistered( assetProxyId, assetProxy ); } /// @dev Gets an asset proxy. /// @param assetProxyId Id of the asset proxy. /// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered. function getAssetProxy(bytes4 assetProxyId) external view returns (address) { return _assetProxies[assetProxyId]; } /// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws. /// @param orderHash Hash of the order associated with this transfer. /// @param assetData Byte array encoded for the asset. /// @param from Address to transfer token from. /// @param to Address to transfer token to. /// @param amount Amount of token to transfer. function _dispatchTransferFrom( bytes32 orderHash, bytes memory assetData, address from, address to, uint256 amount ) internal { // Do nothing if no amount should be transferred. if (amount > 0) { // Ensure assetData is padded to 32 bytes (excluding the id) and is at least 4 bytes long if (assetData.length % 32 != 4) { LibRichErrors.rrevert(LibExchangeRichErrors.AssetProxyDispatchError( LibExchangeRichErrors.AssetProxyDispatchErrorCodes.INVALID_ASSET_DATA_LENGTH, orderHash, assetData )); } // Lookup assetProxy. bytes4 assetProxyId = assetData.readBytes4(0); address assetProxy = _assetProxies[assetProxyId]; // Ensure that assetProxy exists if (assetProxy == address(0)) { LibRichErrors.rrevert(LibExchangeRichErrors.AssetProxyDispatchError( LibExchangeRichErrors.AssetProxyDispatchErrorCodes.UNKNOWN_ASSET_PROXY, orderHash, assetData )); } // Construct the calldata for the transferFrom call. bytes memory proxyCalldata = abi.encodeWithSelector( IAssetProxy(address(0)).transferFrom.selector, assetData, from, to, amount ); // Call the asset proxy's transferFrom function with the constructed calldata. (bool didSucceed, bytes memory returnData) = assetProxy.call(proxyCalldata); // If the transaction did not succeed, revert with the returned data. if (!didSucceed) { LibRichErrors.rrevert(LibExchangeRichErrors.AssetProxyTransferError( orderHash, assetData, returnData )); } } } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; import "./interfaces/IOwnable.sol"; import "./LibOwnableRichErrors.sol"; import "./LibRichErrors.sol"; contract Ownable is IOwnable { address public owner; constructor () public { owner = msg.sender; } modifier onlyOwner() { _assertSenderIsOwner(); _; } function transferOwnership(address newOwner) public onlyOwner { if (newOwner == address(0)) { LibRichErrors.rrevert(LibOwnableRichErrors.TransferOwnerToZeroError()); } else { owner = newOwner; emit OwnershipTransferred(msg.sender, newOwner); } } function _assertSenderIsOwner() internal view { if (msg.sender != owner) { LibRichErrors.rrevert(LibOwnableRichErrors.OnlyOwnerError( msg.sender, owner )); } } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; contract IOwnable { /// @dev Emitted by Ownable when ownership is transferred. /// @param previousOwner The previous owner of the contract. /// @param newOwner The new owner of the contract. event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /// @dev Transfers ownership of the contract to a new address. /// @param newOwner The address that will become the owner. function transferOwnership(address newOwner) public; }
pragma solidity ^0.5.9; library LibOwnableRichErrors { // bytes4(keccak256("OnlyOwnerError(address,address)")) bytes4 internal constant ONLY_OWNER_ERROR_SELECTOR = 0x1de45ad1; // bytes4(keccak256("TransferOwnerToZeroError()")) bytes internal constant TRANSFER_OWNER_TO_ZERO_ERROR_BYTES = hex"e69edc3e"; // solhint-disable func-name-mixedcase function OnlyOwnerError( address sender, address owner ) internal pure returns (bytes memory) { return abi.encodeWithSelector( ONLY_OWNER_ERROR_SELECTOR, sender, owner ); } function TransferOwnerToZeroError() internal pure returns (bytes memory) { return TRANSFER_OWNER_TO_ZERO_ERROR_BYTES; } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; contract IAssetProxy { /// @dev Transfers assets. Either succeeds or throws. /// @param assetData Byte array encoded for the respective asset proxy. /// @param from Address to transfer asset from. /// @param to Address to transfer asset to. /// @param amount Amount of asset to transfer. function transferFrom( bytes calldata assetData, address from, address to, uint256 amount ) external; /// @dev Gets the proxy id associated with the proxy address. /// @return Proxy id. function getProxyId() external pure returns (bytes4); }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; contract IAssetProxyDispatcher { // Logs registration of new asset proxy event AssetProxyRegistered( bytes4 id, // Id of new registered AssetProxy. address assetProxy // Address of new registered AssetProxy. ); /// @dev Registers an asset proxy to its asset proxy id. /// Once an asset proxy is registered, it cannot be unregistered. /// @param assetProxy Address of new asset proxy to register. function registerAssetProxy(address assetProxy) external; /// @dev Gets an asset proxy. /// @param assetProxyId Id of the asset proxy. /// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered. function getAssetProxy(bytes4 assetProxyId) external view returns (address); }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; import "@0x/contracts-utils/contracts/src/Ownable.sol"; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; import "@0x/contracts-staking/contracts/src/interfaces/IStaking.sol"; import "./interfaces/IProtocolFees.sol"; contract MixinProtocolFees is IProtocolFees, Ownable { // The protocol fee multiplier -- the owner can update this field. uint256 public protocolFeeMultiplier; // The address of the registered protocolFeeCollector contract -- the owner can update this field. address public protocolFeeCollector; /// @dev Allows the owner to update the protocol fee multiplier. /// @param updatedProtocolFeeMultiplier The updated protocol fee multiplier. function setProtocolFeeMultiplier(uint256 updatedProtocolFeeMultiplier) external onlyOwner { emit ProtocolFeeMultiplier(protocolFeeMultiplier, updatedProtocolFeeMultiplier); protocolFeeMultiplier = updatedProtocolFeeMultiplier; } /// @dev Allows the owner to update the protocolFeeCollector address. /// @param updatedProtocolFeeCollector The updated protocolFeeCollector contract address. function setProtocolFeeCollectorAddress(address updatedProtocolFeeCollector) external onlyOwner { _setProtocolFeeCollectorAddress(updatedProtocolFeeCollector); } /// @dev Sets the protocolFeeCollector contract address to 0. /// Only callable by owner. function detachProtocolFeeCollector() external onlyOwner { _setProtocolFeeCollectorAddress(address(0)); } /// @dev Sets the protocolFeeCollector address and emits an event. /// @param updatedProtocolFeeCollector The updated protocolFeeCollector contract address. function _setProtocolFeeCollectorAddress(address updatedProtocolFeeCollector) internal { emit ProtocolFeeCollectorAddress(protocolFeeCollector, updatedProtocolFeeCollector); protocolFeeCollector = updatedProtocolFeeCollector; } /// @dev Pays a protocol fee for a single fill. /// @param orderHash Hash of the order being filled. /// @param protocolFee Value of the fee being paid (equal to protocolFeeMultiplier * tx.gasPrice). /// @param makerAddress Address of maker of order being filled. /// @param takerAddress Address filling order. function _paySingleProtocolFee( bytes32 orderHash, uint256 protocolFee, address makerAddress, address takerAddress ) internal returns (bool) { address feeCollector = protocolFeeCollector; if (feeCollector != address(0)) { _payProtocolFeeToFeeCollector( orderHash, feeCollector, address(this).balance, protocolFee, makerAddress, takerAddress ); return true; } else { return false; } } /// @dev Pays a protocol fee for two orders (used when settling functions in MixinMatchOrders) /// @param orderHash1 Hash of the first order being filled. /// @param orderHash2 Hash of the second order being filled. /// @param protocolFee Value of the fee being paid (equal to protocolFeeMultiplier * tx.gasPrice). /// @param makerAddress1 Address of maker of first order being filled. /// @param makerAddress2 Address of maker of second order being filled. /// @param takerAddress Address filling orders. function _payTwoProtocolFees( bytes32 orderHash1, bytes32 orderHash2, uint256 protocolFee, address makerAddress1, address makerAddress2, address takerAddress ) internal returns (bool) { address feeCollector = protocolFeeCollector; if (feeCollector != address(0)) { // Since the `BALANCE` opcode costs 400 gas, we choose to calculate this value by hand rather than calling it twice. uint256 exchangeBalance = address(this).balance; // Pay protocol fee and attribute to first maker uint256 valuePaid = _payProtocolFeeToFeeCollector( orderHash1, feeCollector, exchangeBalance, protocolFee, makerAddress1, takerAddress ); // Pay protocol fee and attribute to second maker _payProtocolFeeToFeeCollector( orderHash2, feeCollector, exchangeBalance - valuePaid, protocolFee, makerAddress2, takerAddress ); return true; } else { return false; } } /// @dev Pays a single protocol fee. /// @param orderHash Hash of the order being filled. /// @param feeCollector Address of protocolFeeCollector contract. /// @param exchangeBalance Assumed ETH balance of Exchange contract (in wei). /// @param protocolFee Value of the fee being paid (equal to protocolFeeMultiplier * tx.gasPrice). /// @param makerAddress Address of maker of order being filled. /// @param takerAddress Address filling order. function _payProtocolFeeToFeeCollector( bytes32 orderHash, address feeCollector, uint256 exchangeBalance, uint256 protocolFee, address makerAddress, address takerAddress ) internal returns (uint256 valuePaid) { // Do not send a value with the call if the exchange has an insufficient balance // The protocolFeeCollector contract will fallback to charging WETH if (exchangeBalance >= protocolFee) { valuePaid = protocolFee; } bytes memory payProtocolFeeData = abi.encodeWithSelector( IStaking(address(0)).payProtocolFee.selector, makerAddress, takerAddress, protocolFee ); // solhint-disable-next-line avoid-call-value (bool didSucceed, bytes memory returnData) = feeCollector.call.value(valuePaid)(payProtocolFeeData); if (!didSucceed) { LibRichErrors.rrevert(LibExchangeRichErrors.PayProtocolFeeError( orderHash, protocolFee, makerAddress, takerAddress, returnData )); } return valuePaid; } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; import "./IStructs.sol"; import "./IZrxVault.sol"; interface IStaking { /// @dev Adds a new exchange address /// @param addr Address of exchange contract to add function addExchangeAddress(address addr) external; /// @dev Create a new staking pool. The sender will be the operator of this pool. /// Note that an operator must be payable. /// @param operatorShare Portion of rewards owned by the operator, in ppm. /// @param addOperatorAsMaker Adds operator to the created pool as a maker for convenience iff true. /// @return poolId The unique pool id generated for this pool. function createStakingPool(uint32 operatorShare, bool addOperatorAsMaker) external returns (bytes32 poolId); /// @dev Decreases the operator share for the given pool (i.e. increases pool rewards for members). /// @param poolId Unique Id of pool. /// @param newOperatorShare The newly decreased percentage of any rewards owned by the operator. function decreaseStakingPoolOperatorShare(bytes32 poolId, uint32 newOperatorShare) external; /// @dev Begins a new epoch, preparing the prior one for finalization. /// Throws if not enough time has passed between epochs or if the /// previous epoch was not fully finalized. /// @return numPoolsToFinalize The number of unfinalized pools. function endEpoch() external returns (uint256); /// @dev Instantly finalizes a single pool that earned rewards in the previous /// epoch, crediting it rewards for members and withdrawing operator's /// rewards as WETH. This can be called by internal functions that need /// to finalize a pool immediately. Does nothing if the pool is already /// finalized or did not earn rewards in the previous epoch. /// @param poolId The pool ID to finalize. function finalizePool(bytes32 poolId) external; /// @dev Initialize storage owned by this contract. /// This function should not be called directly. /// The StakingProxy contract will call it in `attachStakingContract()`. function init() external; /// @dev Allows caller to join a staking pool as a maker. /// @param poolId Unique id of pool. function joinStakingPoolAsMaker(bytes32 poolId) external; /// @dev Moves stake between statuses: 'undelegated' or 'delegated'. /// Delegated stake can also be moved between pools. /// This change comes into effect next epoch. /// @param from status to move stake out of. /// @param to status to move stake into. /// @param amount of stake to move. function moveStake( IStructs.StakeInfo calldata from, IStructs.StakeInfo calldata to, uint256 amount ) external; /// @dev Pays a protocol fee in ETH. /// @param makerAddress The address of the order's maker. /// @param payerAddress The address that is responsible for paying the protocol fee. /// @param protocolFee The amount of protocol fees that should be paid. function payProtocolFee( address makerAddress, address payerAddress, uint256 protocolFee ) external payable; /// @dev Removes an existing exchange address /// @param addr Address of exchange contract to remove function removeExchangeAddress(address addr) external; /// @dev Set all configurable parameters at once. /// @param _epochDurationInSeconds Minimum seconds between epochs. /// @param _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm. /// @param _minimumPoolStake Minimum amount of stake required in a pool to collect rewards. /// @param _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor. /// @param _cobbDouglasAlphaDenominator Denominator for cobb douglas alpha factor. function setParams( uint256 _epochDurationInSeconds, uint32 _rewardDelegatedStakeWeight, uint256 _minimumPoolStake, uint32 _cobbDouglasAlphaNumerator, uint32 _cobbDouglasAlphaDenominator ) external; /// @dev Stake ZRX tokens. Tokens are deposited into the ZRX Vault. /// Unstake to retrieve the ZRX. Stake is in the 'Active' status. /// @param amount of ZRX to stake. function stake(uint256 amount) external; /// @dev Unstake. Tokens are withdrawn from the ZRX Vault and returned to /// the staker. Stake must be in the 'undelegated' status in both the /// current and next epoch in order to be unstaked. /// @param amount of ZRX to unstake. function unstake(uint256 amount) external; /// @dev Withdraws the caller's WETH rewards that have accumulated /// until the last epoch. /// @param poolId Unique id of pool. function withdrawDelegatorRewards(bytes32 poolId) external; /// @dev Computes the reward balance in ETH of a specific member of a pool. /// @param poolId Unique id of pool. /// @param member The member of the pool. /// @return totalReward Balance in ETH. function computeRewardBalanceOfDelegator(bytes32 poolId, address member) external view returns (uint256 reward); /// @dev Computes the reward balance in ETH of the operator of a pool. /// @param poolId Unique id of pool. /// @return totalReward Balance in ETH. function computeRewardBalanceOfOperator(bytes32 poolId) external view returns (uint256 reward); /// @dev Returns the earliest end time in seconds of this epoch. /// The next epoch can begin once this time is reached. /// Epoch period = [startTimeInSeconds..endTimeInSeconds) /// @return Time in seconds. function getCurrentEpochEarliestEndTimeInSeconds() external view returns (uint256); /// @dev Gets global stake for a given status. /// @param stakeStatus UNDELEGATED or DELEGATED /// @return Global stake for given status. function getGlobalStakeByStatus(IStructs.StakeStatus stakeStatus) external view returns (IStructs.StoredBalance memory balance); /// @dev Gets an owner's stake balances by status. /// @param staker Owner of stake. /// @param stakeStatus UNDELEGATED or DELEGATED /// @return Owner's stake balances for given status. function getOwnerStakeByStatus( address staker, IStructs.StakeStatus stakeStatus ) external view returns (IStructs.StoredBalance memory balance); /// @dev Retrieves all configurable parameter values. /// @return _epochDurationInSeconds Minimum seconds between epochs. /// @return _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm. /// @return _minimumPoolStake Minimum amount of stake required in a pool to collect rewards. /// @return _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor. /// @return _cobbDouglasAlphaDenominator Denominator for cobb douglas alpha factor. function getParams() external view returns ( uint256 _epochDurationInSeconds, uint32 _rewardDelegatedStakeWeight, uint256 _minimumPoolStake, uint32 _cobbDouglasAlphaNumerator, uint32 _cobbDouglasAlphaDenominator ); /// @param staker of stake. /// @param poolId Unique Id of pool. /// @return Stake delegated to pool by staker. function getStakeDelegatedToPoolByOwner(address staker, bytes32 poolId) external view returns (IStructs.StoredBalance memory balance); /// @dev Returns a staking pool /// @param poolId Unique id of pool. function getStakingPool(bytes32 poolId) external view returns (IStructs.Pool memory); /// @dev Get stats on a staking pool in this epoch. /// @param poolId Pool Id to query. /// @return PoolStats struct for pool id. function getStakingPoolStatsThisEpoch(bytes32 poolId) external view returns (IStructs.PoolStats memory); /// @dev Returns the total stake delegated to a specific staking pool, /// across all members. /// @param poolId Unique Id of pool. /// @return Total stake delegated to pool. function getTotalStakeDelegatedToPool(bytes32 poolId) external view returns (IStructs.StoredBalance memory balance); /// @dev An overridable way to access the deployed WETH contract. /// Must be view to allow overrides to access state. /// @return wethContract The WETH contract instance. function getWethContract() external view returns (IEtherToken wethContract); /// @dev An overridable way to access the deployed zrxVault. /// Must be view to allow overrides to access state. /// @return zrxVault The zrxVault contract. function getZrxVault() external view returns (IZrxVault zrxVault); }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; import "./IERC20Token.sol"; contract IEtherToken is IERC20Token { function deposit() public payable; function withdraw(uint256 amount) public; }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; contract IERC20Token { // solhint-disable no-simple-event-func-name event Transfer( address indexed _from, address indexed _to, uint256 _value ); event Approval( address indexed _owner, address indexed _spender, uint256 _value ); /// @dev send `value` token to `to` from `msg.sender` /// @param _to The address of the recipient /// @param _value The amount of token to be transferred /// @return True if transfer was successful function transfer(address _to, uint256 _value) external returns (bool); /// @dev send `value` token to `to` from `from` on the condition it is approved by `from` /// @param _from The address of the sender /// @param _to The address of the recipient /// @param _value The amount of token to be transferred /// @return True if transfer was successful function transferFrom( address _from, address _to, uint256 _value ) external returns (bool); /// @dev `msg.sender` approves `_spender` to spend `_value` tokens /// @param _spender The address of the account able to transfer the tokens /// @param _value The amount of wei to be approved for transfer /// @return Always true if the call has enough gas to complete execution function approve(address _spender, uint256 _value) external returns (bool); /// @dev Query total supply of token /// @return Total supply of token function totalSupply() external view returns (uint256); /// @param _owner The address from which the balance will be retrieved /// @return Balance of owner function balanceOf(address _owner) external view returns (uint256); /// @param _owner The address of the account owning tokens /// @param _spender The address of the account able to transfer the tokens /// @return Amount of remaining tokens allowed to spent function allowance(address _owner, address _spender) external view returns (uint256); }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; interface IStructs { /// @dev Stats for a pool that earned rewards. /// @param feesCollected Fees collected in ETH by this pool. /// @param weightedStake Amount of weighted stake in the pool. /// @param membersStake Amount of non-operator stake in the pool. struct PoolStats { uint256 feesCollected; uint256 weightedStake; uint256 membersStake; } /// @dev Holds stats aggregated across a set of pools. /// @param rewardsAvailable Rewards (ETH) available to the epoch /// being finalized (the previous epoch). This is simply the balance /// of the contract at the end of the epoch. /// @param numPoolsToFinalize The number of pools that have yet to be finalized through `finalizePools()`. /// @param totalFeesCollected The total fees collected for the epoch being finalized. /// @param totalWeightedStake The total fees collected for the epoch being finalized. /// @param totalRewardsFinalized Amount of rewards that have been paid during finalization. struct AggregatedStats { uint256 rewardsAvailable; uint256 numPoolsToFinalize; uint256 totalFeesCollected; uint256 totalWeightedStake; uint256 totalRewardsFinalized; } /// @dev Encapsulates a balance for the current and next epochs. /// Note that these balances may be stale if the current epoch /// is greater than `currentEpoch`. /// @param currentEpoch the current epoch /// @param currentEpochBalance balance in the current epoch. /// @param nextEpochBalance balance in `currentEpoch+1`. struct StoredBalance { uint64 currentEpoch; uint96 currentEpochBalance; uint96 nextEpochBalance; } /// @dev Statuses that stake can exist in. /// Any stake can be (re)delegated effective at the next epoch /// Undelegated stake can be withdrawn if it is available in both the current and next epoch enum StakeStatus { UNDELEGATED, DELEGATED } /// @dev Info used to describe a status. /// @param status of the stake. /// @param poolId Unique Id of pool. This is set when status=DELEGATED. struct StakeInfo { StakeStatus status; bytes32 poolId; } /// @dev Struct to represent a fraction. /// @param numerator of fraction. /// @param denominator of fraction. struct Fraction { uint256 numerator; uint256 denominator; } /// @dev Holds the metadata for a staking pool. /// @param operator of the pool. /// @param operatorShare Fraction of the total balance owned by the operator, in ppm. struct Pool { address operator; uint32 operatorShare; } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; interface IZrxVault { /// @dev Emmitted whenever a StakingProxy is set in a vault. event StakingProxySet(address stakingProxyAddress); /// @dev Emitted when the Staking contract is put into Catastrophic Failure Mode /// @param sender Address of sender (`msg.sender`) event InCatastrophicFailureMode(address sender); /// @dev Emitted when Zrx Tokens are deposited into the vault. /// @param staker of Zrx Tokens. /// @param amount of Zrx Tokens deposited. event Deposit( address indexed staker, uint256 amount ); /// @dev Emitted when Zrx Tokens are withdrawn from the vault. /// @param staker of Zrx Tokens. /// @param amount of Zrx Tokens withdrawn. event Withdraw( address indexed staker, uint256 amount ); /// @dev Emitted whenever the ZRX AssetProxy is set. event ZrxProxySet(address zrxProxyAddress); /// @dev Sets the address of the StakingProxy contract. /// Note that only the contract staker can call this function. /// @param _stakingProxyAddress Address of Staking proxy contract. function setStakingProxy(address _stakingProxyAddress) external; /// @dev Vault enters into Catastrophic Failure Mode. /// *** WARNING - ONCE IN CATOSTROPHIC FAILURE MODE, YOU CAN NEVER GO BACK! *** /// Note that only the contract staker can call this function. function enterCatastrophicFailure() external; /// @dev Sets the Zrx proxy. /// Note that only the contract staker can call this. /// Note that this can only be called when *not* in Catastrophic Failure mode. /// @param zrxProxyAddress Address of the 0x Zrx Proxy. function setZrxProxy(address zrxProxyAddress) external; /// @dev Deposit an `amount` of Zrx Tokens from `staker` into the vault. /// Note that only the Staking contract can call this. /// Note that this can only be called when *not* in Catastrophic Failure mode. /// @param staker of Zrx Tokens. /// @param amount of Zrx Tokens to deposit. function depositFrom(address staker, uint256 amount) external; /// @dev Withdraw an `amount` of Zrx Tokens to `staker` from the vault. /// Note that only the Staking contract can call this. /// Note that this can only be called when *not* in Catastrophic Failure mode. /// @param staker of Zrx Tokens. /// @param amount of Zrx Tokens to withdraw. function withdrawFrom(address staker, uint256 amount) external; /// @dev Withdraw ALL Zrx Tokens to `staker` from the vault. /// Note that this can only be called when *in* Catastrophic Failure mode. /// @param staker of Zrx Tokens. function withdrawAllFrom(address staker) external returns (uint256); /// @dev Returns the balance in Zrx Tokens of the `staker` /// @return Balance in Zrx. function balanceOf(address staker) external view returns (uint256); /// @dev Returns the entire balance of Zrx tokens in the vault. function balanceOfZrxVault() external view returns (uint256); }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; contract IProtocolFees { // Logs updates to the protocol fee multiplier. event ProtocolFeeMultiplier(uint256 oldProtocolFeeMultiplier, uint256 updatedProtocolFeeMultiplier); // Logs updates to the protocolFeeCollector address. event ProtocolFeeCollectorAddress(address oldProtocolFeeCollector, address updatedProtocolFeeCollector); /// @dev Allows the owner to update the protocol fee multiplier. /// @param updatedProtocolFeeMultiplier The updated protocol fee multiplier. function setProtocolFeeMultiplier(uint256 updatedProtocolFeeMultiplier) external; /// @dev Allows the owner to update the protocolFeeCollector address. /// @param updatedProtocolFeeCollector The updated protocolFeeCollector contract address. function setProtocolFeeCollectorAddress(address updatedProtocolFeeCollector) external; /// @dev Returns the protocolFeeMultiplier function protocolFeeMultiplier() external view returns (uint256); /// @dev Returns the protocolFeeCollector address function protocolFeeCollector() external view returns (address); }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-utils/contracts/src/LibBytes.sol"; import "@0x/contracts-utils/contracts/src/LibEIP1271.sol"; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; import "./interfaces/IWallet.sol"; import "./interfaces/IEIP1271Wallet.sol"; import "./interfaces/ISignatureValidator.sol"; import "./interfaces/IEIP1271Data.sol"; import "./MixinTransactions.sol"; contract MixinSignatureValidator is LibEIP712ExchangeDomain, LibEIP1271, ISignatureValidator, MixinTransactions { using LibBytes for bytes; using LibOrder for LibOrder.Order; using LibZeroExTransaction for LibZeroExTransaction.ZeroExTransaction; // Magic bytes to be returned by `Wallet` signature type validators. // bytes4(keccak256("isValidWalletSignature(bytes32,address,bytes)")) bytes4 private constant LEGACY_WALLET_MAGIC_VALUE = 0xb0671381; // Mapping of hash => signer => signed mapping (bytes32 => mapping (address => bool)) public preSigned; // Mapping of signer => validator => approved mapping (address => mapping (address => bool)) public allowedValidators; /// @dev Approves a hash on-chain. /// After presigning a hash, the preSign signature type will become valid for that hash and signer. /// @param hash Any 32-byte hash. function preSign(bytes32 hash) external payable refundFinalBalanceNoReentry { address signerAddress = _getCurrentContextAddress(); preSigned[hash][signerAddress] = true; } /// @dev Approves/unnapproves a Validator contract to verify signatures on signer's behalf /// using the `Validator` signature type. /// @param validatorAddress Address of Validator contract. /// @param approval Approval or disapproval of Validator contract. function setSignatureValidatorApproval( address validatorAddress, bool approval ) external payable refundFinalBalanceNoReentry { address signerAddress = _getCurrentContextAddress(); allowedValidators[signerAddress][validatorAddress] = approval; emit SignatureValidatorApproval( signerAddress, validatorAddress, approval ); } /// @dev Verifies that a hash has been signed by the given signer. /// @param hash Any 32-byte hash. /// @param signerAddress Address that should have signed the given hash. /// @param signature Proof that the hash has been signed by signer. /// @return isValid `true` if the signature is valid for the given hash and signer. function isValidHashSignature( bytes32 hash, address signerAddress, bytes memory signature ) public view returns (bool isValid) { SignatureType signatureType = _readValidSignatureType( hash, signerAddress, signature ); // Only hash-compatible signature types can be handled by this // function. if ( signatureType == SignatureType.Validator || signatureType == SignatureType.EIP1271Wallet ) { LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( LibExchangeRichErrors.SignatureErrorCodes.INAPPROPRIATE_SIGNATURE_TYPE, hash, signerAddress, signature )); } isValid = _validateHashSignatureTypes( signatureType, hash, signerAddress, signature ); return isValid; } /// @dev Verifies that a signature for an order is valid. /// @param order The order. /// @param signature Proof that the order has been signed by signer. /// @return isValid `true` if the signature is valid for the given order and signer. function isValidOrderSignature( LibOrder.Order memory order, bytes memory signature ) public view returns (bool isValid) { bytes32 orderHash = order.getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH); isValid = _isValidOrderWithHashSignature( order, orderHash, signature ); return isValid; } /// @dev Verifies that a signature for a transaction is valid. /// @param transaction The transaction. /// @param signature Proof that the order has been signed by signer. /// @return isValid `true` if the signature is valid for the given transaction and signer. function isValidTransactionSignature( LibZeroExTransaction.ZeroExTransaction memory transaction, bytes memory signature ) public view returns (bool isValid) { bytes32 transactionHash = transaction.getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH); isValid = _isValidTransactionWithHashSignature( transaction, transactionHash, signature ); return isValid; } /// @dev Verifies that an order, with provided order hash, has been signed /// by the given signer. /// @param order The order. /// @param orderHash The hash of the order. /// @param signature Proof that the hash has been signed by signer. /// @return isValid True if the signature is valid for the given order and signer. function _isValidOrderWithHashSignature( LibOrder.Order memory order, bytes32 orderHash, bytes memory signature ) internal view returns (bool isValid) { address signerAddress = order.makerAddress; SignatureType signatureType = _readValidSignatureType( orderHash, signerAddress, signature ); if (signatureType == SignatureType.Validator) { // The entire order is verified by a validator contract. isValid = _validateBytesWithValidator( _encodeEIP1271OrderWithHash(order, orderHash), orderHash, signerAddress, signature ); } else if (signatureType == SignatureType.EIP1271Wallet) { // The entire order is verified by a wallet contract. isValid = _validateBytesWithWallet( _encodeEIP1271OrderWithHash(order, orderHash), signerAddress, signature ); } else { // Otherwise, it's one of the hash-only signature types. isValid = _validateHashSignatureTypes( signatureType, orderHash, signerAddress, signature ); } return isValid; } /// @dev Verifies that a transaction, with provided order hash, has been signed /// by the given signer. /// @param transaction The transaction. /// @param transactionHash The hash of the transaction. /// @param signature Proof that the hash has been signed by signer. /// @return isValid True if the signature is valid for the given transaction and signer. function _isValidTransactionWithHashSignature( LibZeroExTransaction.ZeroExTransaction memory transaction, bytes32 transactionHash, bytes memory signature ) internal view returns (bool isValid) { address signerAddress = transaction.signerAddress; SignatureType signatureType = _readValidSignatureType( transactionHash, signerAddress, signature ); if (signatureType == SignatureType.Validator) { // The entire transaction is verified by a validator contract. isValid = _validateBytesWithValidator( _encodeEIP1271TransactionWithHash(transaction, transactionHash), transactionHash, signerAddress, signature ); } else if (signatureType == SignatureType.EIP1271Wallet) { // The entire transaction is verified by a wallet contract. isValid = _validateBytesWithWallet( _encodeEIP1271TransactionWithHash(transaction, transactionHash), signerAddress, signature ); } else { // Otherwise, it's one of the hash-only signature types. isValid = _validateHashSignatureTypes( signatureType, transactionHash, signerAddress, signature ); } return isValid; } /// Validates a hash-only signature type /// (anything but `Validator` and `EIP1271Wallet`). function _validateHashSignatureTypes( SignatureType signatureType, bytes32 hash, address signerAddress, bytes memory signature ) private view returns (bool isValid) { // Always invalid signature. // Like Illegal, this is always implicitly available and therefore // offered explicitly. It can be implicitly created by providing // a correctly formatted but incorrect signature. if (signatureType == SignatureType.Invalid) { if (signature.length != 1) { LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( LibExchangeRichErrors.SignatureErrorCodes.INVALID_LENGTH, hash, signerAddress, signature )); } isValid = false; // Signature using EIP712 } else if (signatureType == SignatureType.EIP712) { if (signature.length != 66) { LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( LibExchangeRichErrors.SignatureErrorCodes.INVALID_LENGTH, hash, signerAddress, signature )); } uint8 v = uint8(signature[0]); bytes32 r = signature.readBytes32(1); bytes32 s = signature.readBytes32(33); address recovered = ecrecover( hash, v, r, s ); isValid = signerAddress == recovered; // Signed using web3.eth_sign } else if (signatureType == SignatureType.EthSign) { if (signature.length != 66) { LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( LibExchangeRichErrors.SignatureErrorCodes.INVALID_LENGTH, hash, signerAddress, signature )); } uint8 v = uint8(signature[0]); bytes32 r = signature.readBytes32(1); bytes32 s = signature.readBytes32(33); address recovered = ecrecover( keccak256(abi.encodePacked( "\x19Ethereum Signed Message:\n32", hash )), v, r, s ); isValid = signerAddress == recovered; // Signature verified by wallet contract. } else if (signatureType == SignatureType.Wallet) { isValid = _validateHashWithWallet( hash, signerAddress, signature ); // Otherwise, signatureType == SignatureType.PreSigned } else { assert(signatureType == SignatureType.PreSigned); // Signer signed hash previously using the preSign function. isValid = preSigned[hash][signerAddress]; } return isValid; } /// @dev Reads the `SignatureType` from a signature with minimal validation. function _readSignatureType( bytes32 hash, address signerAddress, bytes memory signature ) private pure returns (SignatureType) { if (signature.length == 0) { LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( LibExchangeRichErrors.SignatureErrorCodes.INVALID_LENGTH, hash, signerAddress, signature )); } return SignatureType(uint8(signature[signature.length - 1])); } /// @dev Reads the `SignatureType` from the end of a signature and validates it. function _readValidSignatureType( bytes32 hash, address signerAddress, bytes memory signature ) private pure returns (SignatureType signatureType) { // Read the signatureType from the signature signatureType = _readSignatureType( hash, signerAddress, signature ); // Disallow address zero because ecrecover() returns zero on failure. if (signerAddress == address(0)) { LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( LibExchangeRichErrors.SignatureErrorCodes.INVALID_SIGNER, hash, signerAddress, signature )); } // Ensure signature is supported if (uint8(signatureType) >= uint8(SignatureType.NSignatureTypes)) { LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( LibExchangeRichErrors.SignatureErrorCodes.UNSUPPORTED, hash, signerAddress, signature )); } // Always illegal signature. // This is always an implicit option since a signer can create a // signature array with invalid type or length. We may as well make // it an explicit option. This aids testing and analysis. It is // also the initialization value for the enum type. if (signatureType == SignatureType.Illegal) { LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( LibExchangeRichErrors.SignatureErrorCodes.ILLEGAL, hash, signerAddress, signature )); } return signatureType; } /// @dev ABI encodes an order and hash with a selector to be passed into /// an EIP1271 compliant `isValidSignature` function. function _encodeEIP1271OrderWithHash( LibOrder.Order memory order, bytes32 orderHash ) private pure returns (bytes memory encoded) { return abi.encodeWithSelector( IEIP1271Data(address(0)).OrderWithHash.selector, order, orderHash ); } /// @dev ABI encodes a transaction and hash with a selector to be passed into /// an EIP1271 compliant `isValidSignature` function. function _encodeEIP1271TransactionWithHash( LibZeroExTransaction.ZeroExTransaction memory transaction, bytes32 transactionHash ) private pure returns (bytes memory encoded) { return abi.encodeWithSelector( IEIP1271Data(address(0)).ZeroExTransactionWithHash.selector, transaction, transactionHash ); } /// @dev Verifies a hash and signature using logic defined by Wallet contract. /// @param hash Any 32 byte hash. /// @param walletAddress Address that should have signed the given hash /// and defines its own signature verification method. /// @param signature Proof that the hash has been signed by signer. /// @return True if the signature is validated by the Wallet. function _validateHashWithWallet( bytes32 hash, address walletAddress, bytes memory signature ) private view returns (bool) { // Backup length of signature uint256 signatureLength = signature.length; // Temporarily remove signatureType byte from end of signature signature.writeLength(signatureLength - 1); // Encode the call data. bytes memory callData = abi.encodeWithSelector( IWallet(address(0)).isValidSignature.selector, hash, signature ); // Restore the original signature length signature.writeLength(signatureLength); // Static call the verification function. (bool didSucceed, bytes memory returnData) = walletAddress.staticcall(callData); // Return the validity of the signature if the call was successful if (didSucceed && returnData.length == 32) { return returnData.readBytes4(0) == LEGACY_WALLET_MAGIC_VALUE; } // Revert if the call was unsuccessful LibRichErrors.rrevert(LibExchangeRichErrors.SignatureWalletError( hash, walletAddress, signature, returnData )); } /// @dev Verifies arbitrary data and a signature via an EIP1271 Wallet /// contract, where the wallet address is also the signer address. /// @param data Arbitrary signed data. /// @param walletAddress Contract that will verify the data and signature. /// @param signature Proof that the data has been signed by signer. /// @return isValid True if the signature is validated by the Wallet. function _validateBytesWithWallet( bytes memory data, address walletAddress, bytes memory signature ) private view returns (bool isValid) { isValid = _staticCallEIP1271WalletWithReducedSignatureLength( walletAddress, data, signature, 1 // The last byte of the signature (signatureType) is removed before making the staticcall ); return isValid; } /// @dev Verifies arbitrary data and a signature via an EIP1271 contract /// whose address is encoded in the signature. /// @param data Arbitrary signed data. /// @param hash The hash associated with the data. /// @param signerAddress Address that should have signed the given hash. /// @param signature Proof that the data has been signed by signer. /// @return isValid True if the signature is validated by the validator contract. function _validateBytesWithValidator( bytes memory data, bytes32 hash, address signerAddress, bytes memory signature ) private view returns (bool isValid) { uint256 signatureLength = signature.length; if (signatureLength < 21) { LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( LibExchangeRichErrors.SignatureErrorCodes.INVALID_LENGTH, hash, signerAddress, signature )); } // The validator address is appended to the signature before the signatureType. // Read the validator address from the signature. address validatorAddress = signature.readAddress(signatureLength - 21); // Ensure signer has approved validator. if (!allowedValidators[signerAddress][validatorAddress]) { LibRichErrors.rrevert(LibExchangeRichErrors.SignatureValidatorNotApprovedError( signerAddress, validatorAddress )); } isValid = _staticCallEIP1271WalletWithReducedSignatureLength( validatorAddress, data, signature, 21 // The last 21 bytes of the signature (validatorAddress + signatureType) are removed before making the staticcall ); return isValid; } /// @dev Performs a staticcall to an EIP1271 compiant `isValidSignature` function and validates the output. /// @param verifyingContractAddress Address of EIP1271Wallet or Validator contract. /// @param data Arbitrary signed data. /// @param signature Proof that the hash has been signed by signer. Bytes will be temporarily be popped /// off of the signature before calling `isValidSignature`. /// @param ignoredSignatureBytesLen The amount of bytes that will be temporarily popped off the the signature. /// @return The validity of the signature. function _staticCallEIP1271WalletWithReducedSignatureLength( address verifyingContractAddress, bytes memory data, bytes memory signature, uint256 ignoredSignatureBytesLen ) private view returns (bool) { // Backup length of the signature uint256 signatureLength = signature.length; // Temporarily remove bytes from signature end signature.writeLength(signatureLength - ignoredSignatureBytesLen); bytes memory callData = abi.encodeWithSelector( IEIP1271Wallet(address(0)).isValidSignature.selector, data, signature ); // Restore original signature length signature.writeLength(signatureLength); // Static call the verification function (bool didSucceed, bytes memory returnData) = verifyingContractAddress.staticcall(callData); // Return the validity of the signature if the call was successful if (didSucceed && returnData.length == 32) { return returnData.readBytes4(0) == EIP1271_MAGIC_VALUE; } // Revert if the call was unsuccessful LibRichErrors.rrevert(LibExchangeRichErrors.EIP1271SignatureError( verifyingContractAddress, data, signature, returnData )); } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; contract LibEIP1271 { // Magic bytes returned by EIP1271 wallets on success. bytes4 constant public EIP1271_MAGIC_VALUE = 0x20c13b0b; }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-utils/contracts/src/LibEIP712.sol"; library LibZeroExTransaction { using LibZeroExTransaction for ZeroExTransaction; // Hash for the EIP712 0x transaction schema // keccak256(abi.encodePacked( // "ZeroExTransaction(", // "uint256 salt,", // "uint256 expirationTimeSeconds,", // "uint256 gasPrice,", // "address signerAddress,", // "bytes data", // ")" // )); bytes32 constant internal _EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH = 0xec69816980a3a3ca4554410e60253953e9ff375ba4536a98adfa15cc71541508; struct ZeroExTransaction { uint256 salt; // Arbitrary number to ensure uniqueness of transaction hash. uint256 expirationTimeSeconds; // Timestamp in seconds at which transaction expires. uint256 gasPrice; // gasPrice that transaction is required to be executed with. address signerAddress; // Address of transaction signer. bytes data; // AbiV2 encoded calldata. } /// @dev Calculates the EIP712 typed data hash of a transaction with a given domain separator. /// @param transaction 0x transaction structure. /// @return EIP712 typed data hash of the transaction. function getTypedDataHash(ZeroExTransaction memory transaction, bytes32 eip712ExchangeDomainHash) internal pure returns (bytes32 transactionHash) { // Hash the transaction with the domain separator of the Exchange contract. transactionHash = LibEIP712.hashEIP712Message( eip712ExchangeDomainHash, transaction.getStructHash() ); return transactionHash; } /// @dev Calculates EIP712 hash of the 0x transaction struct. /// @param transaction 0x transaction structure. /// @return EIP712 hash of the transaction struct. function getStructHash(ZeroExTransaction memory transaction) internal pure returns (bytes32 result) { bytes32 schemaHash = _EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH; bytes memory data = transaction.data; uint256 salt = transaction.salt; uint256 expirationTimeSeconds = transaction.expirationTimeSeconds; uint256 gasPrice = transaction.gasPrice; address signerAddress = transaction.signerAddress; // Assembly for more efficiently computing: // result = keccak256(abi.encodePacked( // schemaHash, // salt, // expirationTimeSeconds, // gasPrice, // uint256(signerAddress), // keccak256(data) // )); assembly { // Compute hash of data let dataHash := keccak256(add(data, 32), mload(data)) // Load free memory pointer let memPtr := mload(64) mstore(memPtr, schemaHash) // hash of schema mstore(add(memPtr, 32), salt) // salt mstore(add(memPtr, 64), expirationTimeSeconds) // expirationTimeSeconds mstore(add(memPtr, 96), gasPrice) // gasPrice mstore(add(memPtr, 128), and(signerAddress, 0xffffffffffffffffffffffffffffffffffffffff)) // signerAddress mstore(add(memPtr, 160), dataHash) // hash of data // Compute hash result := keccak256(memPtr, 192) } return result; } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; contract IWallet { /// @dev Validates a hash with the `Wallet` signature type. /// @param hash Message hash that is signed. /// @param signature Proof of signing. /// @return magicValue `bytes4(0xb0671381)` if the signature check succeeds. function isValidSignature( bytes32 hash, bytes calldata signature ) external view returns (bytes4 magicValue); }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; import "@0x/contracts-utils/contracts/src/LibEIP1271.sol"; contract IEIP1271Wallet is LibEIP1271 { /// @dev Verifies that a signature is valid. /// @param data Arbitrary signed data. /// @param signature Proof that data has been signed. /// @return magicValue bytes4(0x20c13b0b) if the signature check succeeds. function isValidSignature( bytes calldata data, bytes calldata signature ) external view returns (bytes4 magicValue); }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; contract ISignatureValidator { // Allowed signature types. enum SignatureType { Illegal, // 0x00, default value Invalid, // 0x01 EIP712, // 0x02 EthSign, // 0x03 Wallet, // 0x04 Validator, // 0x05 PreSigned, // 0x06 EIP1271Wallet, // 0x07 NSignatureTypes // 0x08, number of signature types. Always leave at end. } event SignatureValidatorApproval( address indexed signerAddress, // Address that approves or disapproves a contract to verify signatures. address indexed validatorAddress, // Address of signature validator contract. bool isApproved // Approval or disapproval of validator contract. ); /// @dev Approves a hash on-chain. /// After presigning a hash, the preSign signature type will become valid for that hash and signer. /// @param hash Any 32-byte hash. function preSign(bytes32 hash) external payable; /// @dev Approves/unnapproves a Validator contract to verify signatures on signer's behalf. /// @param validatorAddress Address of Validator contract. /// @param approval Approval or disapproval of Validator contract. function setSignatureValidatorApproval( address validatorAddress, bool approval ) external payable; /// @dev Verifies that a hash has been signed by the given signer. /// @param hash Any 32-byte hash. /// @param signature Proof that the hash has been signed by signer. /// @return isValid `true` if the signature is valid for the given hash and signer. function isValidHashSignature( bytes32 hash, address signerAddress, bytes memory signature ) public view returns (bool isValid); /// @dev Verifies that a signature for an order is valid. /// @param order The order. /// @param signature Proof that the order has been signed by signer. /// @return isValid true if the signature is valid for the given order and signer. function isValidOrderSignature( LibOrder.Order memory order, bytes memory signature ) public view returns (bool isValid); /// @dev Verifies that a signature for a transaction is valid. /// @param transaction The transaction. /// @param signature Proof that the order has been signed by signer. /// @return isValid true if the signature is valid for the given transaction and signer. function isValidTransactionSignature( LibZeroExTransaction.ZeroExTransaction memory transaction, bytes memory signature ) public view returns (bool isValid); /// @dev Verifies that an order, with provided order hash, has been signed /// by the given signer. /// @param order The order. /// @param orderHash The hash of the order. /// @param signature Proof that the hash has been signed by signer. /// @return isValid True if the signature is valid for the given order and signer. function _isValidOrderWithHashSignature( LibOrder.Order memory order, bytes32 orderHash, bytes memory signature ) internal view returns (bool isValid); /// @dev Verifies that a transaction, with provided order hash, has been signed /// by the given signer. /// @param transaction The transaction. /// @param transactionHash The hash of the transaction. /// @param signature Proof that the hash has been signed by signer. /// @return isValid True if the signature is valid for the given transaction and signer. function _isValidTransactionWithHashSignature( LibZeroExTransaction.ZeroExTransaction memory transaction, bytes32 transactionHash, bytes memory signature ) internal view returns (bool isValid); }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; // solhint-disable contract IEIP1271Data { /// @dev This function's selector is used when ABI encoding the order /// and hash into a byte array before calling `isValidSignature`. /// This function serves no other purpose. function OrderWithHash( LibOrder.Order calldata order, bytes32 orderHash ) external pure; /// @dev This function's selector is used when ABI encoding the transaction /// and hash into a byte array before calling `isValidSignature`. /// This function serves no other purpose. function ZeroExTransactionWithHash( LibZeroExTransaction.ZeroExTransaction calldata transaction, bytes32 transactionHash ) external pure; }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "@0x/contracts-utils/contracts/src/Refundable.sol"; import "./interfaces/ITransactions.sol"; import "./interfaces/ISignatureValidator.sol"; contract MixinTransactions is Refundable, LibEIP712ExchangeDomain, ISignatureValidator, ITransactions { using LibZeroExTransaction for LibZeroExTransaction.ZeroExTransaction; // Mapping of transaction hash => executed // This prevents transactions from being executed more than once. mapping (bytes32 => bool) public transactionsExecuted; // Address of current transaction signer address public currentContextAddress; /// @dev Executes an Exchange method call in the context of signer. /// @param transaction 0x transaction structure. /// @param signature Proof that transaction has been signed by signer. /// @return ABI encoded return data of the underlying Exchange function call. function executeTransaction( LibZeroExTransaction.ZeroExTransaction memory transaction, bytes memory signature ) public payable disableRefundUntilEnd returns (bytes memory) { return _executeTransaction(transaction, signature); } /// @dev Executes a batch of Exchange method calls in the context of signer(s). /// @param transactions Array of 0x transaction structures. /// @param signatures Array of proofs that transactions have been signed by signer(s). /// @return Array containing ABI encoded return data for each of the underlying Exchange function calls. function batchExecuteTransactions( LibZeroExTransaction.ZeroExTransaction[] memory transactions, bytes[] memory signatures ) public payable disableRefundUntilEnd returns (bytes[] memory) { uint256 length = transactions.length; bytes[] memory returnData = new bytes[](length); for (uint256 i = 0; i != length; i++) { returnData[i] = _executeTransaction(transactions[i], signatures[i]); } return returnData; } /// @dev Executes an Exchange method call in the context of signer. /// @param transaction 0x transaction structure. /// @param signature Proof that transaction has been signed by signer. /// @return ABI encoded return data of the underlying Exchange function call. function _executeTransaction( LibZeroExTransaction.ZeroExTransaction memory transaction, bytes memory signature ) internal returns (bytes memory) { bytes32 transactionHash = transaction.getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH); _assertExecutableTransaction( transaction, signature, transactionHash ); // Set the current transaction signer address signerAddress = transaction.signerAddress; _setCurrentContextAddressIfRequired(signerAddress, signerAddress); // Execute transaction transactionsExecuted[transactionHash] = true; (bool didSucceed, bytes memory returnData) = address(this).delegatecall(transaction.data); if (!didSucceed) { LibRichErrors.rrevert(LibExchangeRichErrors.TransactionExecutionError( transactionHash, returnData )); } // Reset current transaction signer if it was previously updated _setCurrentContextAddressIfRequired(signerAddress, address(0)); emit TransactionExecution(transactionHash); return returnData; } /// @dev Validates context for executeTransaction. Succeeds or throws. /// @param transaction 0x transaction structure. /// @param signature Proof that transaction has been signed by signer. /// @param transactionHash EIP712 typed data hash of 0x transaction. function _assertExecutableTransaction( LibZeroExTransaction.ZeroExTransaction memory transaction, bytes memory signature, bytes32 transactionHash ) internal view { // Check transaction is not expired // solhint-disable-next-line not-rely-on-time if (block.timestamp >= transaction.expirationTimeSeconds) { LibRichErrors.rrevert(LibExchangeRichErrors.TransactionError( LibExchangeRichErrors.TransactionErrorCodes.EXPIRED, transactionHash )); } // Validate that transaction is executed with the correct gasPrice uint256 requiredGasPrice = transaction.gasPrice; if (tx.gasprice != requiredGasPrice) { LibRichErrors.rrevert(LibExchangeRichErrors.TransactionGasPriceError( transactionHash, tx.gasprice, requiredGasPrice )); } // Prevent `executeTransaction` from being called when context is already set address currentContextAddress_ = currentContextAddress; if (currentContextAddress_ != address(0)) { LibRichErrors.rrevert(LibExchangeRichErrors.TransactionInvalidContextError( transactionHash, currentContextAddress_ )); } // Validate transaction has not been executed if (transactionsExecuted[transactionHash]) { LibRichErrors.rrevert(LibExchangeRichErrors.TransactionError( LibExchangeRichErrors.TransactionErrorCodes.ALREADY_EXECUTED, transactionHash )); } // Validate signature // Transaction always valid if signer is sender of transaction address signerAddress = transaction.signerAddress; if (signerAddress != msg.sender && !_isValidTransactionWithHashSignature( transaction, transactionHash, signature ) ) { LibRichErrors.rrevert(LibExchangeRichErrors.SignatureError( LibExchangeRichErrors.SignatureErrorCodes.BAD_TRANSACTION_SIGNATURE, transactionHash, signerAddress, signature )); } } /// @dev Sets the currentContextAddress if the current context is not msg.sender. /// @param signerAddress Address of the transaction signer. /// @param contextAddress The current context address. function _setCurrentContextAddressIfRequired( address signerAddress, address contextAddress ) internal { if (signerAddress != msg.sender) { currentContextAddress = contextAddress; } } /// @dev The current function will be called in the context of this address (either 0x transaction signer or `msg.sender`). /// If calling a fill function, this address will represent the taker. /// If calling a cancel function, this address will represent the maker. /// @return Signer of 0x transaction if entry point is `executeTransaction`. /// `msg.sender` if entry point is any other function. function _getCurrentContextAddress() internal view returns (address) { address currentContextAddress_ = currentContextAddress; address contextAddress = currentContextAddress_ == address(0) ? msg.sender : currentContextAddress_; return contextAddress; } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; contract ITransactions { // TransactionExecution event is emitted when a ZeroExTransaction is executed. event TransactionExecution(bytes32 indexed transactionHash); /// @dev Executes an Exchange method call in the context of signer. /// @param transaction 0x transaction containing salt, signerAddress, and data. /// @param signature Proof that transaction has been signed by signer. /// @return ABI encoded return data of the underlying Exchange function call. function executeTransaction( LibZeroExTransaction.ZeroExTransaction memory transaction, bytes memory signature ) public payable returns (bytes memory); /// @dev Executes a batch of Exchange method calls in the context of signer(s). /// @param transactions Array of 0x transactions containing salt, signerAddress, and data. /// @param signatures Array of proofs that transactions have been signed by signer(s). /// @return Array containing ABI encoded return data for each of the underlying Exchange function calls. function batchExecuteTransactions( LibZeroExTransaction.ZeroExTransaction[] memory transactions, bytes[] memory signatures ) public payable returns (bytes[] memory); /// @dev The current function will be called in the context of this address (either 0x transaction signer or `msg.sender`). /// If calling a fill function, this address will represent the taker. /// If calling a cancel function, this address will represent the maker. /// @return Signer of 0x transaction if entry point is `executeTransaction`. /// `msg.sender` if entry point is any other function. function _getCurrentContextAddress() internal view returns (address); }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; import "./interfaces/IExchangeCore.sol"; import "./interfaces/IWrapperFunctions.sol"; import "./MixinExchangeCore.sol"; contract MixinWrapperFunctions is IWrapperFunctions, MixinExchangeCore { using LibSafeMath for uint256; /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled. /// @param order Order struct containing order specifications. /// @param takerAssetFillAmount Desired amount of takerAsset to sell. /// @param signature Proof that order has been created by maker. function fillOrKillOrder( LibOrder.Order memory order, uint256 takerAssetFillAmount, bytes memory signature ) public payable refundFinalBalanceNoReentry returns (LibFillResults.FillResults memory fillResults) { fillResults = _fillOrKillOrder( order, takerAssetFillAmount, signature ); return fillResults; } /// @dev Executes multiple calls of fillOrder. /// @param orders Array of order specifications. /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders. /// @param signatures Proofs that orders have been created by makers. /// @return Array of amounts filled and fees paid by makers and taker. function batchFillOrders( LibOrder.Order[] memory orders, uint256[] memory takerAssetFillAmounts, bytes[] memory signatures ) public payable refundFinalBalanceNoReentry returns (LibFillResults.FillResults[] memory fillResults) { uint256 ordersLength = orders.length; fillResults = new LibFillResults.FillResults[](ordersLength); for (uint256 i = 0; i != ordersLength; i++) { fillResults[i] = _fillOrder( orders[i], takerAssetFillAmounts[i], signatures[i] ); } return fillResults; } /// @dev Executes multiple calls of fillOrKillOrder. /// @param orders Array of order specifications. /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders. /// @param signatures Proofs that orders have been created by makers. /// @return Array of amounts filled and fees paid by makers and taker. function batchFillOrKillOrders( LibOrder.Order[] memory orders, uint256[] memory takerAssetFillAmounts, bytes[] memory signatures ) public payable refundFinalBalanceNoReentry returns (LibFillResults.FillResults[] memory fillResults) { uint256 ordersLength = orders.length; fillResults = new LibFillResults.FillResults[](ordersLength); for (uint256 i = 0; i != ordersLength; i++) { fillResults[i] = _fillOrKillOrder( orders[i], takerAssetFillAmounts[i], signatures[i] ); } return fillResults; } /// @dev Executes multiple calls of fillOrder. If any fill reverts, the error is caught and ignored. /// @param orders Array of order specifications. /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders. /// @param signatures Proofs that orders have been created by makers. /// @return Array of amounts filled and fees paid by makers and taker. function batchFillOrdersNoThrow( LibOrder.Order[] memory orders, uint256[] memory takerAssetFillAmounts, bytes[] memory signatures ) public payable disableRefundUntilEnd returns (LibFillResults.FillResults[] memory fillResults) { uint256 ordersLength = orders.length; fillResults = new LibFillResults.FillResults[](ordersLength); for (uint256 i = 0; i != ordersLength; i++) { fillResults[i] = _fillOrderNoThrow( orders[i], takerAssetFillAmounts[i], signatures[i] ); } return fillResults; } /// @dev Executes multiple calls of fillOrder until total amount of takerAsset is sold by taker. /// If any fill reverts, the error is caught and ignored. /// NOTE: This function does not enforce that the takerAsset is the same for each order. /// @param orders Array of order specifications. /// @param takerAssetFillAmount Desired amount of takerAsset to sell. /// @param signatures Proofs that orders have been signed by makers. /// @return Amounts filled and fees paid by makers and taker. function marketSellOrdersNoThrow( LibOrder.Order[] memory orders, uint256 takerAssetFillAmount, bytes[] memory signatures ) public payable disableRefundUntilEnd returns (LibFillResults.FillResults memory fillResults) { uint256 ordersLength = orders.length; for (uint256 i = 0; i != ordersLength; i++) { // Calculate the remaining amount of takerAsset to sell uint256 remainingTakerAssetFillAmount = takerAssetFillAmount.safeSub(fillResults.takerAssetFilledAmount); // Attempt to sell the remaining amount of takerAsset LibFillResults.FillResults memory singleFillResults = _fillOrderNoThrow( orders[i], remainingTakerAssetFillAmount, signatures[i] ); // Update amounts filled and fees paid by maker and taker fillResults = LibFillResults.addFillResults(fillResults, singleFillResults); // Stop execution if the entire amount of takerAsset has been sold if (fillResults.takerAssetFilledAmount >= takerAssetFillAmount) { break; } } return fillResults; } /// @dev Executes multiple calls of fillOrder until total amount of makerAsset is bought by taker. /// If any fill reverts, the error is caught and ignored. /// NOTE: This function does not enforce that the makerAsset is the same for each order. /// @param orders Array of order specifications. /// @param makerAssetFillAmount Desired amount of makerAsset to buy. /// @param signatures Proofs that orders have been signed by makers. /// @return Amounts filled and fees paid by makers and taker. function marketBuyOrdersNoThrow( LibOrder.Order[] memory orders, uint256 makerAssetFillAmount, bytes[] memory signatures ) public payable disableRefundUntilEnd returns (LibFillResults.FillResults memory fillResults) { uint256 ordersLength = orders.length; for (uint256 i = 0; i != ordersLength; i++) { // Calculate the remaining amount of makerAsset to buy uint256 remainingMakerAssetFillAmount = makerAssetFillAmount.safeSub(fillResults.makerAssetFilledAmount); // Convert the remaining amount of makerAsset to buy into remaining amount // of takerAsset to sell, assuming entire amount can be sold in the current order uint256 remainingTakerAssetFillAmount = LibMath.getPartialAmountCeil( orders[i].takerAssetAmount, orders[i].makerAssetAmount, remainingMakerAssetFillAmount ); // Attempt to sell the remaining amount of takerAsset LibFillResults.FillResults memory singleFillResults = _fillOrderNoThrow( orders[i], remainingTakerAssetFillAmount, signatures[i] ); // Update amounts filled and fees paid by maker and taker fillResults = LibFillResults.addFillResults(fillResults, singleFillResults); // Stop execution if the entire amount of makerAsset has been bought if (fillResults.makerAssetFilledAmount >= makerAssetFillAmount) { break; } } return fillResults; } /// @dev Calls marketSellOrdersNoThrow then reverts if < takerAssetFillAmount has been sold. /// NOTE: This function does not enforce that the takerAsset is the same for each order. /// @param orders Array of order specifications. /// @param takerAssetFillAmount Minimum amount of takerAsset to sell. /// @param signatures Proofs that orders have been signed by makers. /// @return Amounts filled and fees paid by makers and taker. function marketSellOrdersFillOrKill( LibOrder.Order[] memory orders, uint256 takerAssetFillAmount, bytes[] memory signatures ) public payable returns (LibFillResults.FillResults memory fillResults) { fillResults = marketSellOrdersNoThrow(orders, takerAssetFillAmount, signatures); if (fillResults.takerAssetFilledAmount < takerAssetFillAmount) { LibRichErrors.rrevert(LibExchangeRichErrors.IncompleteFillError( LibExchangeRichErrors.IncompleteFillErrorCode.INCOMPLETE_MARKET_SELL_ORDERS, takerAssetFillAmount, fillResults.takerAssetFilledAmount )); } } /// @dev Calls marketBuyOrdersNoThrow then reverts if < makerAssetFillAmount has been bought. /// NOTE: This function does not enforce that the makerAsset is the same for each order. /// @param orders Array of order specifications. /// @param makerAssetFillAmount Minimum amount of makerAsset to buy. /// @param signatures Proofs that orders have been signed by makers. /// @return Amounts filled and fees paid by makers and taker. function marketBuyOrdersFillOrKill( LibOrder.Order[] memory orders, uint256 makerAssetFillAmount, bytes[] memory signatures ) public payable returns (LibFillResults.FillResults memory fillResults) { fillResults = marketBuyOrdersNoThrow(orders, makerAssetFillAmount, signatures); if (fillResults.makerAssetFilledAmount < makerAssetFillAmount) { LibRichErrors.rrevert(LibExchangeRichErrors.IncompleteFillError( LibExchangeRichErrors.IncompleteFillErrorCode.INCOMPLETE_MARKET_BUY_ORDERS, makerAssetFillAmount, fillResults.makerAssetFilledAmount )); } } /// @dev Executes multiple calls of cancelOrder. /// @param orders Array of order specifications. function batchCancelOrders(LibOrder.Order[] memory orders) public payable refundFinalBalanceNoReentry { uint256 ordersLength = orders.length; for (uint256 i = 0; i != ordersLength; i++) { _cancelOrder(orders[i]); } } /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled. /// @param order Order struct containing order specifications. /// @param takerAssetFillAmount Desired amount of takerAsset to sell. /// @param signature Proof that order has been created by maker. function _fillOrKillOrder( LibOrder.Order memory order, uint256 takerAssetFillAmount, bytes memory signature ) internal returns (LibFillResults.FillResults memory fillResults) { fillResults = _fillOrder( order, takerAssetFillAmount, signature ); if (fillResults.takerAssetFilledAmount != takerAssetFillAmount) { LibRichErrors.rrevert(LibExchangeRichErrors.IncompleteFillError( LibExchangeRichErrors.IncompleteFillErrorCode.INCOMPLETE_FILL_ORDER, takerAssetFillAmount, fillResults.takerAssetFilledAmount )); } return fillResults; } /// @dev Fills the input order. /// Returns a null FillResults instance if the transaction would otherwise revert. /// @param order Order struct containing order specifications. /// @param takerAssetFillAmount Desired amount of takerAsset to sell. /// @param signature Proof that order has been created by maker. /// @return Amounts filled and fees paid by maker and taker. function _fillOrderNoThrow( LibOrder.Order memory order, uint256 takerAssetFillAmount, bytes memory signature ) internal returns (LibFillResults.FillResults memory fillResults) { // ABI encode calldata for `fillOrder` bytes memory fillOrderCalldata = abi.encodeWithSelector( IExchangeCore(address(0)).fillOrder.selector, order, takerAssetFillAmount, signature ); (bool didSucceed, bytes memory returnData) = address(this).delegatecall(fillOrderCalldata); if (didSucceed) { assert(returnData.length == 160); fillResults = abi.decode(returnData, (LibFillResults.FillResults)); } // fillResults values will be 0 by default if call was unsuccessful return fillResults; } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; contract IWrapperFunctions { /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled. /// @param order Order struct containing order specifications. /// @param takerAssetFillAmount Desired amount of takerAsset to sell. /// @param signature Proof that order has been created by maker. function fillOrKillOrder( LibOrder.Order memory order, uint256 takerAssetFillAmount, bytes memory signature ) public payable returns (LibFillResults.FillResults memory fillResults); /// @dev Executes multiple calls of fillOrder. /// @param orders Array of order specifications. /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders. /// @param signatures Proofs that orders have been created by makers. /// @return Array of amounts filled and fees paid by makers and taker. function batchFillOrders( LibOrder.Order[] memory orders, uint256[] memory takerAssetFillAmounts, bytes[] memory signatures ) public payable returns (LibFillResults.FillResults[] memory fillResults); /// @dev Executes multiple calls of fillOrKillOrder. /// @param orders Array of order specifications. /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders. /// @param signatures Proofs that orders have been created by makers. /// @return Array of amounts filled and fees paid by makers and taker. function batchFillOrKillOrders( LibOrder.Order[] memory orders, uint256[] memory takerAssetFillAmounts, bytes[] memory signatures ) public payable returns (LibFillResults.FillResults[] memory fillResults); /// @dev Executes multiple calls of fillOrder. If any fill reverts, the error is caught and ignored. /// @param orders Array of order specifications. /// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders. /// @param signatures Proofs that orders have been created by makers. /// @return Array of amounts filled and fees paid by makers and taker. function batchFillOrdersNoThrow( LibOrder.Order[] memory orders, uint256[] memory takerAssetFillAmounts, bytes[] memory signatures ) public payable returns (LibFillResults.FillResults[] memory fillResults); /// @dev Executes multiple calls of fillOrder until total amount of takerAsset is sold by taker. /// If any fill reverts, the error is caught and ignored. /// NOTE: This function does not enforce that the takerAsset is the same for each order. /// @param orders Array of order specifications. /// @param takerAssetFillAmount Desired amount of takerAsset to sell. /// @param signatures Proofs that orders have been signed by makers. /// @return Amounts filled and fees paid by makers and taker. function marketSellOrdersNoThrow( LibOrder.Order[] memory orders, uint256 takerAssetFillAmount, bytes[] memory signatures ) public payable returns (LibFillResults.FillResults memory fillResults); /// @dev Executes multiple calls of fillOrder until total amount of makerAsset is bought by taker. /// If any fill reverts, the error is caught and ignored. /// NOTE: This function does not enforce that the makerAsset is the same for each order. /// @param orders Array of order specifications. /// @param makerAssetFillAmount Desired amount of makerAsset to buy. /// @param signatures Proofs that orders have been signed by makers. /// @return Amounts filled and fees paid by makers and taker. function marketBuyOrdersNoThrow( LibOrder.Order[] memory orders, uint256 makerAssetFillAmount, bytes[] memory signatures ) public payable returns (LibFillResults.FillResults memory fillResults); /// @dev Calls marketSellOrdersNoThrow then reverts if < takerAssetFillAmount has been sold. /// NOTE: This function does not enforce that the takerAsset is the same for each order. /// @param orders Array of order specifications. /// @param takerAssetFillAmount Minimum amount of takerAsset to sell. /// @param signatures Proofs that orders have been signed by makers. /// @return Amounts filled and fees paid by makers and taker. function marketSellOrdersFillOrKill( LibOrder.Order[] memory orders, uint256 takerAssetFillAmount, bytes[] memory signatures ) public payable returns (LibFillResults.FillResults memory fillResults); /// @dev Calls marketBuyOrdersNoThrow then reverts if < makerAssetFillAmount has been bought. /// NOTE: This function does not enforce that the makerAsset is the same for each order. /// @param orders Array of order specifications. /// @param makerAssetFillAmount Minimum amount of makerAsset to buy. /// @param signatures Proofs that orders have been signed by makers. /// @return Amounts filled and fees paid by makers and taker. function marketBuyOrdersFillOrKill( LibOrder.Order[] memory orders, uint256 makerAssetFillAmount, bytes[] memory signatures ) public payable returns (LibFillResults.FillResults memory fillResults); /// @dev Executes multiple calls of cancelOrder. /// @param orders Array of order specifications. function batchCancelOrders(LibOrder.Order[] memory orders) public payable; }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "./MixinAssetProxyDispatcher.sol"; contract MixinTransferSimulator is MixinAssetProxyDispatcher { /// @dev This function may be used to simulate any amount of transfers /// As they would occur through the Exchange contract. Note that this function /// will always revert, even if all transfers are successful. However, it may /// be used with eth_call or with a try/catch pattern in order to simulate /// the results of the transfers. /// @param assetData Array of asset details, each encoded per the AssetProxy contract specification. /// @param fromAddresses Array containing the `from` addresses that correspond with each transfer. /// @param toAddresses Array containing the `to` addresses that correspond with each transfer. /// @param amounts Array containing the amounts that correspond to each transfer. /// @return This function does not return a value. However, it will always revert with /// `Error("TRANSFERS_SUCCESSFUL")` if all of the transfers were successful. function simulateDispatchTransferFromCalls( bytes[] memory assetData, address[] memory fromAddresses, address[] memory toAddresses, uint256[] memory amounts ) public { uint256 length = assetData.length; for (uint256 i = 0; i != length; i++) { _dispatchTransferFrom( // The index is passed in as `orderHash` so that a failed transfer can be quickly identified when catching the error bytes32(i), assetData[i], fromAddresses[i], toAddresses[i], amounts[i] ); } revert("TRANSFERS_SUCCESSFUL"); } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "./IExchangeCore.sol"; import "./IProtocolFees.sol"; import "./IMatchOrders.sol"; import "./ISignatureValidator.sol"; import "./ITransactions.sol"; import "./IAssetProxyDispatcher.sol"; import "./IWrapperFunctions.sol"; import "./ITransferSimulator.sol"; // solhint-disable no-empty-blocks contract IExchange is IProtocolFees, IExchangeCore, IMatchOrders, ISignatureValidator, ITransactions, IAssetProxyDispatcher, ITransferSimulator, IWrapperFunctions {}
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; contract ITransferSimulator { /// @dev This function may be used to simulate any amount of transfers /// As they would occur through the Exchange contract. Note that this function /// will always revert, even if all transfers are successful. However, it may /// be used with eth_call or with a try/catch pattern in order to simulate /// the results of the transfers. /// @param assetData Array of asset details, each encoded per the AssetProxy contract specification. /// @param fromAddresses Array containing the `from` addresses that correspond with each transfer. /// @param toAddresses Array containing the `to` addresses that correspond with each transfer. /// @param amounts Array containing the amounts that correspond to each transfer. /// @return This function does not return a value. However, it will always revert with /// `Error("TRANSFERS_SUCCESSFUL")` if all of the transfers were successful. function simulateDispatchTransferFromCalls( bytes[] memory assetData, address[] memory fromAddresses, address[] memory toAddresses, uint256[] memory amounts ) public; }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol"; import "@0x/contracts-utils/contracts/src/LibBytes.sol"; contract LibExchangeRichErrorDecoder { using LibBytes for bytes; /// @dev Decompose an ABI-encoded SignatureError. /// @param encoded ABI-encoded revert error. /// @return errorCode The error code. /// @return signerAddress The expected signer of the hash. /// @return signature The full signature. function decodeSignatureError(bytes memory encoded) public pure returns ( LibExchangeRichErrors.SignatureErrorCodes errorCode, bytes32 hash, address signerAddress, bytes memory signature ) { _assertSelectorBytes(encoded, LibExchangeRichErrors.SignatureErrorSelector()); uint8 _errorCode; (_errorCode, hash, signerAddress, signature) = abi.decode( encoded.sliceDestructive(4, encoded.length), (uint8, bytes32, address, bytes) ); errorCode = LibExchangeRichErrors.SignatureErrorCodes(_errorCode); } /// @dev Decompose an ABI-encoded SignatureValidatorError. /// @param encoded ABI-encoded revert error. /// @return signerAddress The expected signer of the hash. /// @return signature The full signature bytes. /// @return errorData The revert data thrown by the validator contract. function decodeEIP1271SignatureError(bytes memory encoded) public pure returns ( address verifyingContractAddress, bytes memory data, bytes memory signature, bytes memory errorData ) { _assertSelectorBytes(encoded, LibExchangeRichErrors.EIP1271SignatureErrorSelector()); (verifyingContractAddress, data, signature, errorData) = abi.decode( encoded.sliceDestructive(4, encoded.length), (address, bytes, bytes, bytes) ); } /// @dev Decompose an ABI-encoded SignatureValidatorNotApprovedError. /// @param encoded ABI-encoded revert error. /// @return signerAddress The expected signer of the hash. /// @return validatorAddress The expected validator. function decodeSignatureValidatorNotApprovedError(bytes memory encoded) public pure returns ( address signerAddress, address validatorAddress ) { _assertSelectorBytes(encoded, LibExchangeRichErrors.SignatureValidatorNotApprovedErrorSelector()); (signerAddress, validatorAddress) = abi.decode( encoded.sliceDestructive(4, encoded.length), (address, address) ); } /// @dev Decompose an ABI-encoded SignatureWalletError. /// @param encoded ABI-encoded revert error. /// @return errorCode The error code. /// @return signerAddress The expected signer of the hash. /// @return signature The full signature bytes. /// @return errorData The revert data thrown by the validator contract. function decodeSignatureWalletError(bytes memory encoded) public pure returns ( bytes32 hash, address signerAddress, bytes memory signature, bytes memory errorData ) { _assertSelectorBytes(encoded, LibExchangeRichErrors.SignatureWalletErrorSelector()); (hash, signerAddress, signature, errorData) = abi.decode( encoded.sliceDestructive(4, encoded.length), (bytes32, address, bytes, bytes) ); } /// @dev Decompose an ABI-encoded OrderStatusError. /// @param encoded ABI-encoded revert error. /// @return orderHash The order hash. /// @return orderStatus The order status. function decodeOrderStatusError(bytes memory encoded) public pure returns ( bytes32 orderHash, LibOrder.OrderStatus orderStatus ) { _assertSelectorBytes(encoded, LibExchangeRichErrors.OrderStatusErrorSelector()); uint8 _orderStatus; (orderHash, _orderStatus) = abi.decode( encoded.sliceDestructive(4, encoded.length), (bytes32, uint8) ); orderStatus = LibOrder.OrderStatus(_orderStatus); } /// @dev Decompose an ABI-encoded OrderStatusError. /// @param encoded ABI-encoded revert error. /// @return errorCode Error code that corresponds to invalid maker, taker, or sender. /// @return orderHash The order hash. /// @return contextAddress The maker, taker, or sender address function decodeExchangeInvalidContextError(bytes memory encoded) public pure returns ( LibExchangeRichErrors.ExchangeContextErrorCodes errorCode, bytes32 orderHash, address contextAddress ) { _assertSelectorBytes(encoded, LibExchangeRichErrors.ExchangeInvalidContextErrorSelector()); uint8 _errorCode; (_errorCode, orderHash, contextAddress) = abi.decode( encoded.sliceDestructive(4, encoded.length), (uint8, bytes32, address) ); errorCode = LibExchangeRichErrors.ExchangeContextErrorCodes(_errorCode); } /// @dev Decompose an ABI-encoded FillError. /// @param encoded ABI-encoded revert error. /// @return errorCode The error code. /// @return orderHash The order hash. function decodeFillError(bytes memory encoded) public pure returns ( LibExchangeRichErrors.FillErrorCodes errorCode, bytes32 orderHash ) { _assertSelectorBytes(encoded, LibExchangeRichErrors.FillErrorSelector()); uint8 _errorCode; (_errorCode, orderHash) = abi.decode( encoded.sliceDestructive(4, encoded.length), (uint8, bytes32) ); errorCode = LibExchangeRichErrors.FillErrorCodes(_errorCode); } /// @dev Decompose an ABI-encoded OrderEpochError. /// @param encoded ABI-encoded revert error. /// @return makerAddress The order maker. /// @return orderSenderAddress The order sender. /// @return currentEpoch The current epoch for the maker. function decodeOrderEpochError(bytes memory encoded) public pure returns ( address makerAddress, address orderSenderAddress, uint256 currentEpoch ) { _assertSelectorBytes(encoded, LibExchangeRichErrors.OrderEpochErrorSelector()); (makerAddress, orderSenderAddress, currentEpoch) = abi.decode( encoded.sliceDestructive(4, encoded.length), (address, address, uint256) ); } /// @dev Decompose an ABI-encoded AssetProxyExistsError. /// @param encoded ABI-encoded revert error. /// @return assetProxyId Id of asset proxy. /// @return assetProxyAddress The address of the asset proxy. function decodeAssetProxyExistsError(bytes memory encoded) public pure returns ( bytes4 assetProxyId, address assetProxyAddress) { _assertSelectorBytes(encoded, LibExchangeRichErrors.AssetProxyExistsErrorSelector()); (assetProxyId, assetProxyAddress) = abi.decode( encoded.sliceDestructive(4, encoded.length), (bytes4, address) ); } /// @dev Decompose an ABI-encoded AssetProxyDispatchError. /// @param encoded ABI-encoded revert error. /// @return errorCode The error code. /// @return orderHash Hash of the order being dispatched. /// @return assetData Asset data of the order being dispatched. function decodeAssetProxyDispatchError(bytes memory encoded) public pure returns ( LibExchangeRichErrors.AssetProxyDispatchErrorCodes errorCode, bytes32 orderHash, bytes memory assetData ) { _assertSelectorBytes(encoded, LibExchangeRichErrors.AssetProxyDispatchErrorSelector()); uint8 _errorCode; (_errorCode, orderHash, assetData) = abi.decode( encoded.sliceDestructive(4, encoded.length), (uint8, bytes32, bytes) ); errorCode = LibExchangeRichErrors.AssetProxyDispatchErrorCodes(_errorCode); } /// @dev Decompose an ABI-encoded AssetProxyTransferError. /// @param encoded ABI-encoded revert error. /// @return orderHash Hash of the order being dispatched. /// @return assetData Asset data of the order being dispatched. /// @return errorData ABI-encoded revert data from the asset proxy. function decodeAssetProxyTransferError(bytes memory encoded) public pure returns ( bytes32 orderHash, bytes memory assetData, bytes memory errorData ) { _assertSelectorBytes(encoded, LibExchangeRichErrors.AssetProxyTransferErrorSelector()); (orderHash, assetData, errorData) = abi.decode( encoded.sliceDestructive(4, encoded.length), (bytes32, bytes, bytes) ); } /// @dev Decompose an ABI-encoded NegativeSpreadError. /// @param encoded ABI-encoded revert error. /// @return leftOrderHash Hash of the left order being matched. /// @return rightOrderHash Hash of the right order being matched. function decodeNegativeSpreadError(bytes memory encoded) public pure returns ( bytes32 leftOrderHash, bytes32 rightOrderHash ) { _assertSelectorBytes(encoded, LibExchangeRichErrors.NegativeSpreadErrorSelector()); (leftOrderHash, rightOrderHash) = abi.decode( encoded.sliceDestructive(4, encoded.length), (bytes32, bytes32) ); } /// @dev Decompose an ABI-encoded TransactionError. /// @param encoded ABI-encoded revert error. /// @return errorCode The error code. /// @return transactionHash Hash of the transaction. function decodeTransactionError(bytes memory encoded) public pure returns ( LibExchangeRichErrors.TransactionErrorCodes errorCode, bytes32 transactionHash ) { _assertSelectorBytes(encoded, LibExchangeRichErrors.TransactionErrorSelector()); uint8 _errorCode; (_errorCode, transactionHash) = abi.decode( encoded.sliceDestructive(4, encoded.length), (uint8, bytes32) ); errorCode = LibExchangeRichErrors.TransactionErrorCodes(_errorCode); } /// @dev Decompose an ABI-encoded TransactionExecutionError. /// @param encoded ABI-encoded revert error. /// @return transactionHash Hash of the transaction. /// @return errorData Error thrown by exeucteTransaction(). function decodeTransactionExecutionError(bytes memory encoded) public pure returns ( bytes32 transactionHash, bytes memory errorData ) { _assertSelectorBytes(encoded, LibExchangeRichErrors.TransactionExecutionErrorSelector()); (transactionHash, errorData) = abi.decode( encoded.sliceDestructive(4, encoded.length), (bytes32, bytes) ); } /// @dev Decompose an ABI-encoded IncompleteFillError. /// @param encoded ABI-encoded revert error. /// @return orderHash Hash of the order being filled. function decodeIncompleteFillError(bytes memory encoded) public pure returns ( LibExchangeRichErrors.IncompleteFillErrorCode errorCode, uint256 expectedAssetFillAmount, uint256 actualAssetFillAmount ) { _assertSelectorBytes(encoded, LibExchangeRichErrors.IncompleteFillErrorSelector()); uint8 _errorCode; (_errorCode, expectedAssetFillAmount, actualAssetFillAmount) = abi.decode( encoded.sliceDestructive(4, encoded.length), (uint8, uint256, uint256) ); errorCode = LibExchangeRichErrors.IncompleteFillErrorCode(_errorCode); } /// @dev Revert if the leading 4 bytes of `encoded` is not `selector`. function _assertSelectorBytes(bytes memory encoded, bytes4 selector) private pure { bytes4 actualSelector = LibBytes.readBytes4(encoded, 0); require( actualSelector == selector, "BAD_SELECTOR" ); } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.5; pragma experimental ABIEncoderV2; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "../src/Exchange.sol"; /// @dev A version of the Exchange contract with simplified signature validation /// and a `_dispatchTransferFrom()` that only logs arguments. /// See the `IsolatedExchangeWrapper` and `isolated_fill_order` tests /// for example usage. contract IsolatedExchange is Exchange { // solhint-disable no-unused-vars event DispatchTransferFromCalled( bytes32 orderHash, bytes assetData, address from, address to, uint256 amount ); // solhint-disable no-empty-blocks constructor () public Exchange(1337) {} /// @dev Overridden to only log arguments and revert on certain assetDatas. function _dispatchTransferFrom( bytes32 orderHash, bytes memory assetData, address from, address to, uint256 amount ) internal { emit DispatchTransferFromCalled( orderHash, assetData, from, to, amount ); // Fail if the first byte is 0. if (assetData.length > 0 && assetData[0] == 0x00) { revert("TRANSFER_FAILED"); } } /// @dev Overridden to simplify signature validation. /// Unfortunately, this is `view`, so it can't log arguments. function _isValidOrderWithHashSignature( LibOrder.Order memory, bytes32, bytes memory signature ) internal view returns (bool isValid) { // '0x01' in the first byte is valid. return signature.length == 2 && signature[0] == 0x01; } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.5; pragma experimental ABIEncoderV2; import "@0x/contracts-utils/contracts/src/LibReentrancyGuardRichErrors.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; import "../src/Exchange.sol"; /// @dev A version of the Exchange that exposes a `testReentrancyGuard()` /// function which is used to test whether a function is protected by the /// `nonReentrant` modifier. Several internal functions have also been /// overridden to simplify constructing valid calls to external functions. contract ReentrancyTester is Exchange { using LibBytes for bytes; // solhint-disable no-empty-blocks // solhint-disable no-unused-vars constructor () public // Initialize the exchange with a fixed chainId ("test" in hex). Exchange(0x74657374) {} /// @dev Calls a public function to check if it is reentrant. /// Because this function uses the `nonReentrant` modifier, if /// the function being called is also guarded by the `nonReentrant` modifier, /// it will revert when it returns. function isReentrant(bytes calldata fnCallData) external nonReentrant returns (bool allowsReentrancy) { (bool didSucceed, bytes memory resultData) = address(this).delegatecall(fnCallData); if (didSucceed) { allowsReentrancy = true; } else { if (resultData.equals(LibReentrancyGuardRichErrors.IllegalReentrancyError())) { allowsReentrancy = false; } else { allowsReentrancy = true; } } } /// @dev Overridden to revert on unsuccessful fillOrder call. function _fillOrderNoThrow( LibOrder.Order memory order, uint256 takerAssetFillAmount, bytes memory signature ) internal returns (LibFillResults.FillResults memory fillResults) { // ABI encode calldata for `fillOrder` bytes memory fillOrderCalldata = abi.encodeWithSelector( IExchangeCore(address(0)).fillOrder.selector, order, takerAssetFillAmount, signature ); (bool didSucceed, bytes memory returnData) = address(this).delegatecall(fillOrderCalldata); if (didSucceed) { assert(returnData.length == 128); fillResults = abi.decode(returnData, (LibFillResults.FillResults)); return fillResults; } // Revert and rethrow error if unsuccessful assembly { revert(add(returnData, 32), mload(returnData)) } } /// @dev Overridden to always succeed. function _fillOrder( LibOrder.Order memory order, uint256, bytes memory ) internal returns (LibFillResults.FillResults memory fillResults) { fillResults.makerAssetFilledAmount = order.makerAssetAmount; fillResults.takerAssetFilledAmount = order.takerAssetAmount; fillResults.makerFeePaid = order.makerFee; fillResults.takerFeePaid = order.takerFee; } /// @dev Overridden to always succeed. function _fillOrKillOrder( LibOrder.Order memory order, uint256, bytes memory ) internal returns (LibFillResults.FillResults memory fillResults) { fillResults.makerAssetFilledAmount = order.makerAssetAmount; fillResults.takerAssetFilledAmount = order.takerAssetAmount; fillResults.makerFeePaid = order.makerFee; fillResults.takerFeePaid = order.takerFee; } /// @dev Overridden to always succeed. function _executeTransaction( LibZeroExTransaction.ZeroExTransaction memory, bytes memory ) internal returns (bytes memory resultData) { // Should already point to an empty array. return resultData; } /// @dev Overridden to always succeed. function _batchMatchOrders( LibOrder.Order[] memory leftOrders, LibOrder.Order[] memory rightOrders, bytes[] memory, bytes[] memory, bool ) internal returns (LibFillResults.BatchMatchedFillResults memory batchMatchedFillResults) { uint256 numOrders = leftOrders.length; batchMatchedFillResults.left = new LibFillResults.FillResults[](numOrders); batchMatchedFillResults.right = new LibFillResults.FillResults[](numOrders); for (uint256 i = 0; i < numOrders; ++i) { batchMatchedFillResults.left[i] = LibFillResults.FillResults({ makerAssetFilledAmount: leftOrders[i].makerAssetAmount, takerAssetFilledAmount: leftOrders[i].takerAssetAmount, makerFeePaid: leftOrders[i].makerFee, takerFeePaid: leftOrders[i].takerFee, protocolFeePaid: 0 }); batchMatchedFillResults.right[i] = LibFillResults.FillResults({ makerAssetFilledAmount: rightOrders[i].makerAssetAmount, takerAssetFilledAmount: rightOrders[i].takerAssetAmount, makerFeePaid: rightOrders[i].makerFee, takerFeePaid: rightOrders[i].takerFee, protocolFeePaid: 0 }); } } /// @dev Overridden to always succeed. function _matchOrders( LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder, bytes memory, bytes memory, bool ) internal returns (LibFillResults.MatchedFillResults memory matchedFillResults) { matchedFillResults.left = LibFillResults.FillResults({ makerAssetFilledAmount: leftOrder.makerAssetAmount, takerAssetFilledAmount: leftOrder.takerAssetAmount, makerFeePaid: leftOrder.makerFee, takerFeePaid: leftOrder.takerFee, protocolFeePaid: 0 }); matchedFillResults.right = LibFillResults.FillResults({ makerAssetFilledAmount: rightOrder.makerAssetAmount, takerAssetFilledAmount: rightOrder.takerAssetAmount, makerFeePaid: rightOrder.makerFee, takerFeePaid: rightOrder.takerFee, protocolFeePaid: 0 }); } /// @dev Overridden to do nothing. function _cancelOrder(LibOrder.Order memory order) internal {} }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.5; pragma experimental ABIEncoderV2; import "../src/MixinAssetProxyDispatcher.sol"; import "../src/MixinTransferSimulator.sol"; contract TestAssetProxyDispatcher is MixinAssetProxyDispatcher, MixinTransferSimulator { function dispatchTransferFrom( bytes32 orderHash, bytes memory assetData, address from, address to, uint256 amount ) public { _dispatchTransferFrom(orderHash, assetData, from, to, amount); } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.5; pragma experimental ABIEncoderV2; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; import "../src/Exchange.sol"; // solhint-disable no-empty-blocks contract TestExchangeInternals is Exchange { event DispatchTransferFromCalled( bytes32 orderHash, bytes assetData, address from, address to, uint256 amount ); constructor (uint256 chainId) public Exchange(chainId) {} function assertValidMatch( LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder ) public view { _assertValidMatch( leftOrder, rightOrder, leftOrder.getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH), rightOrder.getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH) ); } /// @dev Call `_updateFilledState()` but first set `filled[order]` to /// `orderTakerAssetFilledAmount`. function testUpdateFilledState( LibOrder.Order memory order, address takerAddress, bytes32 orderHash, uint256 orderTakerAssetFilledAmount, LibFillResults.FillResults memory fillResults ) public payable { filled[LibOrder.getTypedDataHash(order, EIP712_EXCHANGE_DOMAIN_HASH)] = orderTakerAssetFilledAmount; _updateFilledState( order, takerAddress, orderHash, orderTakerAssetFilledAmount, fillResults ); } function settleOrder( bytes32 orderHash, LibOrder.Order memory order, address takerAddress, LibFillResults.FillResults memory fillResults ) public { _settleOrder(orderHash, order, takerAddress, fillResults); } function settleMatchOrders( bytes32 leftOrderHash, bytes32 rightOrderHash, LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder, address takerAddress, LibFillResults.MatchedFillResults memory matchedFillResults ) public { _settleMatchedOrders( leftOrderHash, rightOrderHash, leftOrder, rightOrder, takerAddress, matchedFillResults ); } /// @dev Overidden to only log arguments so we can test `_settleOrder()`. function _dispatchTransferFrom( bytes32 orderHash, bytes memory assetData, address from, address to, uint256 amount ) internal { emit DispatchTransferFromCalled( orderHash, assetData, from, to, amount ); } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.5; pragma experimental ABIEncoderV2; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; import "../src/Exchange.sol"; // Exchange contract with settlement disabled so we can just check `_fillOrder()`` // calculations. contract TestFillRounding is Exchange { // solhint-disable no-empty-blocks constructor () public // Initialize the exchange with a fixed chainId ("test" in hex). Exchange(0x74657374) {} function _settleOrder( bytes32 orderHash, LibOrder.Order memory order, address takerAddress, LibFillResults.FillResults memory fillResults ) internal { // No-op. } function _assertFillableOrder( LibOrder.Order memory order, LibOrder.OrderInfo memory orderInfo, address takerAddress, bytes memory signature ) internal view { // No-op. } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.5; import "../src/libs/LibExchangeRichErrorDecoder.sol"; // solhint-disable no-empty-blocks contract TestLibExchangeRichErrorDecoder is LibExchangeRichErrorDecoder {}
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; // solhint-disable no-unused-vars, no-empty-blocks contract TestProtocolFeeCollector { address private _wethAddress; constructor ( address wethAddress ) public { _wethAddress = wethAddress; } function () external payable {} /// @dev Pays a protocol fee in WETH (Forwarder orders will always pay protocol fees in WETH). /// @param makerAddress The address of the order's maker. /// @param payerAddress The address of the protocol fee payer. /// @param protocolFeePaid The protocol fee that should be paid. function payProtocolFee( address makerAddress, address payerAddress, uint256 protocolFeePaid ) external payable { if (msg.value != protocolFeePaid) { require( msg.value == 0, "No value should be forwarded to collector when paying fee in WETH" ); // Transfer the protocol fee to this address in WETH. IEtherToken(_wethAddress).transferFrom( payerAddress, address(this), protocolFeePaid ); } } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "../src/Exchange.sol"; contract TestProtocolFees is Exchange { // solhint-disable no-empty-blocks constructor () public Exchange(1337) {} // @dev Expose a setter to the `protocolFeeCollector` state variable. // @param newProtocolFeeCollector The address that should be made the `protocolFeeCollector`. function setProtocolFeeCollector(address newProtocolFeeCollector) external { protocolFeeCollector = newProtocolFeeCollector; } // @dev Expose a setter to the `protocolFeeMultiplier` state variable. // @param newProtocolFeeMultiplier The number that should be made the `protocolFeeMultiplier`. function setProtocolFeeMultiplier(uint256 newProtocolFeeMultiplier) external { protocolFeeMultiplier = newProtocolFeeMultiplier; } // @dev Stub out the `_assertFillableOrder` function because we don't actually // care about order validation in these tests. function _assertFillableOrder( LibOrder.Order memory, LibOrder.OrderInfo memory, address, bytes memory ) internal view {} // solhint-disable-line no-empty-blocks // @dev Stub out the `_assertFillableOrder` function because we don't actually // care about transfering through proxies in these tests. function _dispatchTransferFrom( bytes32 orderHash, bytes memory assetData, address from, address to, uint256 amount ) internal {} // solhint-disable-line no-empty-blocks }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "./TestProtocolFees.sol"; // Disable solhint to allow for more informative comments. // solhint-disable contract TestProtocolFeesReceiver { // Attach LibSafeMath to uint256 using LibSafeMath for uint256; /* Testing Constants */ // A constant to represent a maker address. address internal constant makerAddress1 = address(1); // A constant to represent a maker address that is distinct from the // other maker address. address internal constant makerAddress2 = address(2); /* Testing State */ // A struct that provides a schema for test data that should be logged. struct TestLog { address loggedMaker; address loggedPayer; uint256 loggedProtocolFeePaid; uint256 loggedValue; } // The array of testLogs that will be added to by `payProtocolFee` and processed by the tests. TestLog[] testLogs; /* Testing Functions */ /// @dev Tests the `batchFillOrders` function's payment of protocol fees. /// @param testProtocolFees The TestProtocolFees that should be tested against. /// @param protocolFeeMultiplier The protocol fee multiplier that should be registered /// in the test suite before executing `batchFillOrders`. /// @param numberOfOrders The number of orders that should be created and executed for this test. /// @param shouldSetProtocolFeeCollector A boolean value indicating whether or not this contract /// should be registered as the `protocolFeeCollector`. function testBatchFillOrdersProtocolFees( TestProtocolFees testProtocolFees, uint256 protocolFeeMultiplier, uint256 numberOfOrders, bool shouldSetProtocolFeeCollector ) external payable handleState(testProtocolFees, protocolFeeMultiplier, shouldSetProtocolFeeCollector) { // Create empty arrays for taker asset filled amounts and signatures, which will suffice for this test. uint256[] memory takerAssetFilledAmounts = new uint256[](numberOfOrders); bytes[] memory signatures = new bytes[](numberOfOrders); // Construct an array of orders in which every even-indexed order has a makerAddress of makerAddress1 and // every odd-indexed order has a makerAddress of makerAddress2. This is done to make sure that the correct // makers are being logged. LibOrder.Order[] memory orders = new LibOrder.Order[](numberOfOrders); for (uint256 i = 0; i < numberOfOrders; i++) { orders[i] = createOrder(i % 2 == 0 ? makerAddress1 : makerAddress2); } // Forward all of the value sent to the contract to `batchFillOrders()`. testProtocolFees.batchFillOrders.value(msg.value)(orders, takerAssetFilledAmounts, signatures); // If the `protocolFeeCollector` was set, ensure that the protocol fees were paid correctly. // Otherwise, the protocol fees should not have been paid. if (shouldSetProtocolFeeCollector) { // Ensure that the correct number of test logs were recorded. require(testLogs.length == numberOfOrders, "Incorrect number of test logs in batchFillOrders test"); // Calculate the expected protocol fee. uint256 expectedProtocolFeePaid = tx.gasprice.safeMul(protocolFeeMultiplier); // Set the expected available balance for the first log. uint256 expectedAvailableBalance = msg.value; // Verify all of the test logs. for (uint256 i = 0; i < testLogs.length; i++) { // Verify the logged data. verifyTestLog( testLogs[i], expectedAvailableBalance, // expectedAvailableBalance i % 2 == 0 ? makerAddress1 : makerAddress2, // expectedMakerAddress address(this), // expectedPayerAddress expectedProtocolFeePaid // expectedProtocolFeePaid ); // Set the expected available balance for the next log. expectedAvailableBalance = expectedAvailableBalance >= expectedProtocolFeePaid ? expectedAvailableBalance - expectedProtocolFeePaid : expectedAvailableBalance; } } else { // Ensure that zero test logs were created. require(testLogs.length == 0, "Incorrect number of test logs in batchFillOrders test"); } } /// @dev Tests the `fillOrder` function's payment of protocol fees. /// @param testProtocolFees The TestProtocolFees that should be tested against. /// @param protocolFeeMultiplier The protocol fee multiplier that should be registered /// in the test suite before executing `fillOrder`. /// @param shouldSetProtocolFeeCollector A boolean value indicating whether or not this contract /// should be registered as the `protocolFeeCollector`. function testFillOrderProtocolFees( TestProtocolFees testProtocolFees, uint256 protocolFeeMultiplier, bool shouldSetProtocolFeeCollector ) external payable handleState(testProtocolFees, protocolFeeMultiplier, shouldSetProtocolFeeCollector) { // Create empty values for the takerAssetFilledAmount and the signature since these values don't // matter for this test. uint256 takerAssetFilledAmount = 0; bytes memory signature = new bytes(0); // Construct an of order with distinguishing information. LibOrder.Order memory order = createOrder(makerAddress1); // Forward all of the value sent to the contract to `fillOrder()`. testProtocolFees.fillOrder.value(msg.value)(order, takerAssetFilledAmount, signature); // If the `protocolFeeCollector` was set, ensure that the protocol fee was paid correctly. // Otherwise, the protocol fee should not have been paid. if (shouldSetProtocolFeeCollector) { // Ensure that only one test log was created by the call to `fillOrder()`. require(testLogs.length == 1, "Incorrect number of test logs in fillOrder test"); // Calculate the expected protocol fee. uint256 expectedProtocolFeePaid = tx.gasprice.safeMul(protocolFeeMultiplier); // Verify that the test log that was created is correct. verifyTestLog( testLogs[0], msg.value, // expectedAvailableBalance makerAddress1, // expectedMakerAddress address(this), // expectedPayerAddress expectedProtocolFeePaid // expectedProtocolFeePaid ); } else { // Ensure that zero test logs were created. require(testLogs.length == 0, "Incorrect number of test logs in fillOrder test"); } } /// @dev Tests the `matchOrders` function's payment of protocol fees. /// @param testProtocolFees The TestProtocolFees that should be tested against. /// @param protocolFeeMultiplier The protocol fee multiplier that should be registered /// in the test suite before executing `matchOrders`. /// @param shouldSetProtocolFeeCollector A boolean value indicating whether or not this contract /// should be registered as the `protocolFeeCollector`. function testMatchOrdersProtocolFees( TestProtocolFees testProtocolFees, uint256 protocolFeeMultiplier, bool shouldSetProtocolFeeCollector ) external payable handleState(testProtocolFees, protocolFeeMultiplier, shouldSetProtocolFeeCollector) { // Create two empty signatures since signatures are not used in this test. bytes memory leftSignature = new bytes(0); bytes memory rightSignature = new bytes(0); // Construct a distinguished left order. LibOrder.Order memory leftOrder = createOrder(makerAddress1); // Construct a distinguished right order. LibOrder.Order memory rightOrder = createOrder(makerAddress2); // Forward all of the value sent to the contract to `matchOrders()`. testProtocolFees.matchOrders.value(msg.value)(leftOrder, rightOrder, leftSignature, rightSignature); // If the `protocolFeeCollector` was set, ensure that the protocol fee was paid correctly. // Otherwise, the protocol fee should not have been paid. if (shouldSetProtocolFeeCollector) { // Ensure that only one test log was created by the call to `fillOrder()`. require(testLogs.length == 2, "Incorrect number of test logs in matchOrders test"); // Calculate the expected protocol fee. uint256 expectedProtocolFeePaid = tx.gasprice.safeMul(protocolFeeMultiplier); // Set the expected available balance for the first log. uint256 expectedAvailableBalance = msg.value; // Verify that the first test log that was created is correct. verifyTestLog( testLogs[0], expectedAvailableBalance, // expectedAvailableBalance makerAddress1, // expectedMakerAddress address(this), // expectedPayerAddress expectedProtocolFeePaid // expectedProtocolFeePaid ); // Set the expected available balance for the second log. expectedAvailableBalance = expectedAvailableBalance >= expectedProtocolFeePaid ? expectedAvailableBalance - expectedProtocolFeePaid : expectedAvailableBalance; // Verify that the second test log that was created is correct. verifyTestLog( testLogs[1], expectedAvailableBalance, // expectedAvailableBalance makerAddress2, // expectedMakerAddress address(this), // expectedPayerAddress expectedProtocolFeePaid // expectedProtocolFeePaid ); } else { // Ensure that zero test logs were created. require(testLogs.length == 0, "Incorrect number of test logs in matchOrders test"); } } /* Verification Functions */ /// @dev Verifies a test log against expected values. /// @param expectedAvailableBalance The balance that should be available when this call is made. /// This is important especially for tests on wrapper functions. /// @param expectedMakerAddress The expected maker address to be recorded in `payProtocolFee`. /// @param expectedPayerAddress The expected payer address to be recorded in `payProtocolFee`. /// @param expectedProtocolFeePaid The expected protocol fee paidto be recorded in `payProtocolFee`. function verifyTestLog( TestLog memory log, uint256 expectedAvailableBalance, address expectedMakerAddress, address expectedPayerAddress, uint256 expectedProtocolFeePaid ) internal pure { // If the expected available balance was sufficient to pay the protocol fee, the protocol fee // should have been paid in ether. Otherwise, no ether should be sent to pay the protocol fee. if (expectedAvailableBalance >= expectedProtocolFeePaid) { // Ensure that the protocol fee was paid in ether. require( log.loggedValue == expectedProtocolFeePaid, "Incorrect eth was received during fillOrder test when adequate ETH was sent" ); } else { // Ensure that the protocol fee was not paid in ether. require( log.loggedValue == 0, "Incorrect eth was received during fillOrder test when inadequate ETH was sent" ); } // Ensure that the correct data was logged. require(log.loggedMaker == expectedMakerAddress, "Incorrect maker address was logged"); require(log.loggedPayer == expectedPayerAddress, "Incorrect taker address was logged"); require(log.loggedProtocolFeePaid == expectedProtocolFeePaid, "Incorrect protocol fee was logged"); } /* Testing Convenience Functions */ /// @dev Sets up state that is necessary for tests and then cleans up the state that was written /// to so that test cases can be thought of as atomic. /// @param testProtocolFees The TestProtocolFees contract that is being used during testing. /// @param protocolFeeMultiplier The protocolFeeMultiplier of this test case. /// @param shouldSetProtocolFeeCollector A boolean value that indicates whether or not this address /// should be made the protocol fee collector. modifier handleState( TestProtocolFees testProtocolFees, uint256 protocolFeeMultiplier, bool shouldSetProtocolFeeCollector ) { // If necessary, set the protocol fee collector field in the exchange. if (shouldSetProtocolFeeCollector) { testProtocolFees.setProtocolFeeCollector(address(this)); } // Set the protocol fee multiplier in the exchange. testProtocolFees.setProtocolFeeMultiplier(protocolFeeMultiplier); // Execute the test. _; } /// @dev Constructs an order with a specified maker address. /// @param makerAddress The maker address of the order. function createOrder(address makerAddress) internal pure returns (LibOrder.Order memory order) { order.makerAddress = makerAddress; order.makerAssetAmount = 1; // This is 1 so that it doesn't trigger a `DivionByZero()` error. order.takerAssetAmount = 1; // This is 1 so that it doesn't trigger a `DivionByZero()` error. } /* Protocol Fee Receiver and Fallback */ /// @dev Receives payments of protocol fees from a TestProtocolFees contract /// and records the data provided and the message value sent. /// @param makerAddress The maker address that should be recorded. /// @param payerAddress The payer address that should be recorded. /// @param protocolFeePaid The protocol fee that should be recorded. function payProtocolFee( address makerAddress, address payerAddress, uint256 protocolFeePaid ) external payable { // Push the collected data into `testLogs`. testLogs.push(TestLog({ loggedMaker: makerAddress, loggedPayer: payerAddress, loggedProtocolFeePaid: protocolFeePaid, loggedValue: msg.value })); } /// @dev A payable fallback function that makes this contract "payable". This is necessary to allow /// this contract to gracefully handle refunds from TestProtocolFees contracts. function () external payable {} }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.9; pragma experimental ABIEncoderV2; import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; import "../src/Exchange.sol"; contract TestTransactions is Exchange { event ExecutableCalled( bytes data, bytes returnData, address contextAddress ); constructor () public Exchange(1337) {} // solhint-disable-line no-empty-blocks function setCurrentContextAddress(address context) external { currentContextAddress = context; } function setTransactionExecuted(bytes32 hash) external { transactionsExecuted[hash] = true; } function setCurrentContextAddressIfRequired(address signerAddress, address context) external { _setCurrentContextAddressIfRequired(signerAddress, context); } function getCurrentContextAddress() external view returns (address) { return _getCurrentContextAddress(); } function assertExecutableTransaction( LibZeroExTransaction.ZeroExTransaction memory transaction, bytes memory signature ) public view { return _assertExecutableTransaction( transaction, signature, transaction.getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH) ); } // This function will execute arbitrary calldata via a delegatecall. This is highly unsafe to use in production, and this // is only meant to be used during testing. function executable( bool shouldSucceed, bytes memory data, bytes memory returnData ) public returns (bytes memory) { emit ExecutableCalled( data, returnData, currentContextAddress ); require(shouldSucceed, "EXECUTABLE_FAILED"); if (data.length != 0) { (bool didSucceed, bytes memory callResultData) = address(this).delegatecall(data); // This is a delegatecall to preserve the `msg.sender` field if (!didSucceed) { assembly { revert(add(callResultData, 0x20), mload(callResultData)) } } } return returnData; } function _isValidTransactionWithHashSignature( LibZeroExTransaction.ZeroExTransaction memory, bytes32, bytes memory signature ) internal view returns (bool) { if ( signature.length == 2 && signature[0] == 0x0 && signature[1] == 0x0 ) { return false; } return true; } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.5; pragma experimental ABIEncoderV2; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol"; import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; import "@0x/contracts-utils/contracts/src/LibBytes.sol"; import "@0x/contracts-utils/contracts/src/LibEIP1271.sol"; import "../src/interfaces/IEIP1271Data.sol"; // solhint-disable no-unused-vars contract TestValidatorWallet is LibEIP1271 { using LibBytes for bytes; // Magic bytes to be returned by `Wallet` signature type validators. // bytes4(keccak256("isValidWalletSignature(bytes32,address,bytes)")) bytes4 private constant LEGACY_WALLET_MAGIC_VALUE = 0xb0671381; /// @dev Revert reason for `Revert` `ValidatorAction`. string constant public REVERT_REASON = "you shall not pass"; enum ValidatorAction { // Return failure (default) Reject, // Return success Accept, // Revert Revert, // Update state UpdateState, // Ensure the signature hash matches what was prepared MatchSignatureHash, // Return boolean `true`, ReturnTrue, // Return no data. ReturnNothing, NTypes } /// @dev The Exchange domain hash.. LibEIP712ExchangeDomain internal _exchange; /// @dev Internal state to modify. uint256 internal _state = 1; /// @dev What action to execute when a hash is validated . mapping (bytes32 => ValidatorAction) internal _hashActions; /// @dev keccak256 of the expected signature data for a hash. mapping (bytes32 => bytes32) internal _hashSignatureHashes; constructor(address exchange) public { _exchange = LibEIP712ExchangeDomain(exchange); } /// @dev Approves an ERC20 token to spend tokens from this address. /// @param token Address of ERC20 token. /// @param spender Address that will spend tokens. /// @param value Amount of tokens spender is approved to spend. function approveERC20( address token, address spender, uint256 value ) external { IERC20Token(token).approve(spender, value); } /// @dev Prepares this contract to validate a signature. /// @param hash The hash. /// @param action Action to take. /// @param signatureHash keccak256 of the expected signature data. function prepare( bytes32 hash, ValidatorAction action, bytes32 signatureHash ) external { if (uint8(action) >= uint8(ValidatorAction.NTypes)) { revert("UNSUPPORTED_VALIDATOR_ACTION"); } _hashActions[hash] = action; _hashSignatureHashes[hash] = signatureHash; } /// @dev Validates data signed by either `EIP1271Wallet` or `Validator` signature types. /// @param data Abi-encoded data (Order or ZeroExTransaction) and a hash. /// @param signature Signature for `data`. /// @return magicValue `EIP1271_MAGIC_VALUE` if the signature check succeeds. function isValidSignature( bytes memory data, bytes memory signature ) public returns (bytes4 magicValue) { bytes32 hash = _decodeAndValidateHashFromEncodedData(data); ValidatorAction action = _hashActions[hash]; if (action == ValidatorAction.Reject) { magicValue = 0x0; } else if (action == ValidatorAction.Accept) { magicValue = EIP1271_MAGIC_VALUE; } else if (action == ValidatorAction.Revert) { revert(REVERT_REASON); } else if (action == ValidatorAction.UpdateState) { _updateState(); } else if (action == ValidatorAction.ReturnNothing) { assembly { return(0x0, 0) } } else if (action == ValidatorAction.ReturnTrue) { assembly { mstore(0x0, 1) return(0x0, 32) } } else { assert(action == ValidatorAction.MatchSignatureHash); bytes32 expectedSignatureHash = _hashSignatureHashes[hash]; if (keccak256(signature) == expectedSignatureHash) { magicValue = EIP1271_MAGIC_VALUE; } } } /// @dev Validates a hash with the `Wallet` signature type. /// @param hash Message hash that is signed. /// @param signature Proof of signing. /// @return `LEGACY_WALLET_MAGIC_VALUE` if the signature check succeeds. function isValidSignature( bytes32 hash, bytes memory signature ) public returns (bytes4 magicValue) { ValidatorAction action = _hashActions[hash]; if (action == ValidatorAction.Reject) { magicValue = bytes4(0); } else if (action == ValidatorAction.Accept) { magicValue = LEGACY_WALLET_MAGIC_VALUE; } else if (action == ValidatorAction.Revert) { revert(REVERT_REASON); } else if (action == ValidatorAction.UpdateState) { _updateState(); } else if (action == ValidatorAction.ReturnNothing) { assembly { return(0x0, 0) } } else if (action == ValidatorAction.ReturnTrue) { assembly { mstore(0x0, 1) return(0x0, 32) } } else { assert(action == ValidatorAction.MatchSignatureHash); bytes32 expectedSignatureHash = _hashSignatureHashes[hash]; if (keccak256(signature) == expectedSignatureHash) { magicValue = LEGACY_WALLET_MAGIC_VALUE; } } } /// @dev Increments state variable to trigger a state change. function _updateState() private { _state++; } function _decodeAndValidateHashFromEncodedData(bytes memory data) private view returns (bytes32 hash) { bytes4 dataId = data.readBytes4(0); if (dataId == IEIP1271Data(address(0)).OrderWithHash.selector) { // Decode the order and hash LibOrder.Order memory order; (order, hash) = abi.decode( data.slice(4, data.length), (LibOrder.Order, bytes32) ); // Use the Exchange to calculate the hash of the order and assert // that it matches the one we extracted previously. require( LibOrder.getTypedDataHash(order, _exchange.EIP712_EXCHANGE_DOMAIN_HASH()) == hash, "UNEXPECTED_ORDER_HASH" ); } else if (dataId == IEIP1271Data(address(0)).ZeroExTransactionWithHash.selector) { // Decode the transaction and hash LibZeroExTransaction.ZeroExTransaction memory transaction; (transaction, hash) = abi.decode( data.slice(4, data.length), (LibZeroExTransaction.ZeroExTransaction, bytes32) ); // Use the Exchange to calculate the hash of the transaction and assert // that it matches the one we extracted previously. require( LibZeroExTransaction.getTypedDataHash(transaction, _exchange.EIP712_EXCHANGE_DOMAIN_HASH()) == hash, "UNEXPECTED_TRANSACTION_HASH" ); } else { revert("EXPECTED_NO_DATA_TYPE"); } return hash; } }
/* Copyright 2019 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.5.5; pragma experimental ABIEncoderV2; import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol"; import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol"; import "../src/Exchange.sol"; /// @dev A version of the Exchange contract with`_fillOrder()`, /// `_cancelOrder()`, and `getOrderInfo()` overridden to test /// `MixinWrapperFunctions`. contract TestWrapperFunctions is Exchange { uint8 internal constant MAX_ORDER_STATUS = uint8(LibOrder.OrderStatus.CANCELLED); uint256 internal constant ALWAYS_FAILING_SALT = uint256(-1); string internal constant ALWAYS_FAILING_SALT_REVERT_REASON = "ALWAYS_FAILING_SALT"; // solhint-disable no-unused-vars event FillOrderCalled( LibOrder.Order order, uint256 takerAssetFillAmount, bytes signature ); event CancelOrderCalled( LibOrder.Order order ); // solhint-disable no-empty-blocks constructor () public // Initialize the exchange with a fixed chainId ("test" in hex). Exchange(0x74657374) {} /// @dev Overridden to be deterministic and simplified. function getOrderInfo(LibOrder.Order memory order) public view returns (LibOrder.OrderInfo memory orderInfo) { // Lower uint128 of `order.salt` is the `orderTakerAssetFilledAmount`. orderInfo.orderTakerAssetFilledAmount = uint128(order.salt); // High byte of `order.salt` is the `orderStatus`. orderInfo.orderStatus = uint8(order.salt >> 248) % (MAX_ORDER_STATUS + 1); orderInfo.orderHash = order.getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH); } function fillOrderNoThrow( LibOrder.Order memory order, uint256 takerAssetFillAmount, bytes memory signature ) public returns (LibFillResults.FillResults memory fillResults) { return _fillOrderNoThrow( order, takerAssetFillAmount, signature ); } /// @dev Overridden to log arguments, be deterministic, and revert with certain inputs. function _fillOrder( LibOrder.Order memory order, uint256 takerAssetFillAmount, bytes memory signature ) internal returns (LibFillResults.FillResults memory fillResults) { emit FillOrderCalled( order, takerAssetFillAmount, signature ); // Fail if the salt is ALWAYS_FAILING_SALT. if (order.salt == ALWAYS_FAILING_SALT) { revert(ALWAYS_FAILING_SALT_REVERT_REASON); } // We aren't interested in correctness here because we are testing the // behavior of the caller, not `_fillOrder()` itself. We just need some // values that the caller can aggregate together. fillResults.makerAssetFilledAmount = order.makerAssetAmount; fillResults.takerAssetFilledAmount = order.takerAssetAmount; fillResults.makerFeePaid = order.makerFee; fillResults.takerFeePaid = order.takerFee; fillResults.protocolFeePaid = protocolFeeMultiplier; } /// @dev Overridden to only log arguments and revert with certain inputs. function _cancelOrder( LibOrder.Order memory order ) internal { emit CancelOrderCalled( order ); // Fail if the salt is ALWAYS_FAILING_SALT. if (order.salt == ALWAYS_FAILING_SALT) { revert(ALWAYS_FAILING_SALT_REVERT_REASON); } } }
{ "optimizer": { "enabled": true, "runs": 1000000, "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "evmVersion": "constantinople", "remappings": [ "@0x/contracts-exchange-libs=/Users/amir/github/0xproject/0x-monorepo/contracts/exchange/node_modules/@0x/contracts-exchange-libs", "@0x/contracts-utils=/Users/amir/github/0xproject/0x-monorepo/contracts/exchange/node_modules/@0x/contracts-utils", "@0x/contracts-staking=/Users/amir/github/0xproject/0x-monorepo/contracts/exchange/node_modules/@0x/contracts-staking", "@0x/contracts-erc20=/Users/amir/github/0xproject/0x-monorepo/contracts/exchange/node_modules/@0x/contracts-erc20" ] }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes4","name":"id","type":"bytes4"},{"indexed":false,"internalType":"address","name":"assetProxy","type":"address"}],"name":"AssetProxyRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"makerAddress","type":"address"},{"indexed":true,"internalType":"address","name":"feeRecipientAddress","type":"address"},{"indexed":false,"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"indexed":false,"internalType":"address","name":"senderAddress","type":"address"},{"indexed":true,"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"Cancel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"makerAddress","type":"address"},{"indexed":true,"internalType":"address","name":"orderSenderAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"orderEpoch","type":"uint256"}],"name":"CancelUpTo","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"makerAddress","type":"address"},{"indexed":true,"internalType":"address","name":"feeRecipientAddress","type":"address"},{"indexed":false,"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"},{"indexed":true,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"takerAddress","type":"address"},{"indexed":false,"internalType":"address","name":"senderAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"name":"Fill","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":"address","name":"oldProtocolFeeCollector","type":"address"},{"indexed":false,"internalType":"address","name":"updatedProtocolFeeCollector","type":"address"}],"name":"ProtocolFeeCollectorAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldProtocolFeeMultiplier","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"updatedProtocolFeeMultiplier","type":"uint256"}],"name":"ProtocolFeeMultiplier","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"signerAddress","type":"address"},{"indexed":true,"internalType":"address","name":"validatorAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"SignatureValidatorApproval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"TransactionExecution","type":"event"},{"constant":true,"inputs":[],"name":"EIP1271_MAGIC_VALUE","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"EIP712_EXCHANGE_DOMAIN_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowedValidators","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order[]","name":"orders","type":"tuple[]"}],"name":"batchCancelOrders","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"address","name":"signerAddress","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct LibZeroExTransaction.ZeroExTransaction[]","name":"transactions","type":"tuple[]"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"}],"name":"batchExecuteTransactions","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order[]","name":"orders","type":"tuple[]"},{"internalType":"uint256[]","name":"takerAssetFillAmounts","type":"uint256[]"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"}],"name":"batchFillOrKillOrders","outputs":[{"components":[{"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"internalType":"struct LibFillResults.FillResults[]","name":"fillResults","type":"tuple[]"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order[]","name":"orders","type":"tuple[]"},{"internalType":"uint256[]","name":"takerAssetFillAmounts","type":"uint256[]"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"}],"name":"batchFillOrders","outputs":[{"components":[{"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"internalType":"struct LibFillResults.FillResults[]","name":"fillResults","type":"tuple[]"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order[]","name":"orders","type":"tuple[]"},{"internalType":"uint256[]","name":"takerAssetFillAmounts","type":"uint256[]"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"}],"name":"batchFillOrdersNoThrow","outputs":[{"components":[{"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"internalType":"struct LibFillResults.FillResults[]","name":"fillResults","type":"tuple[]"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order[]","name":"leftOrders","type":"tuple[]"},{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order[]","name":"rightOrders","type":"tuple[]"},{"internalType":"bytes[]","name":"leftSignatures","type":"bytes[]"},{"internalType":"bytes[]","name":"rightSignatures","type":"bytes[]"}],"name":"batchMatchOrders","outputs":[{"components":[{"components":[{"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"internalType":"struct LibFillResults.FillResults[]","name":"left","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"internalType":"struct LibFillResults.FillResults[]","name":"right","type":"tuple[]"},{"internalType":"uint256","name":"profitInLeftMakerAsset","type":"uint256"},{"internalType":"uint256","name":"profitInRightMakerAsset","type":"uint256"}],"internalType":"struct LibFillResults.BatchMatchedFillResults","name":"batchMatchedFillResults","type":"tuple"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order[]","name":"leftOrders","type":"tuple[]"},{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order[]","name":"rightOrders","type":"tuple[]"},{"internalType":"bytes[]","name":"leftSignatures","type":"bytes[]"},{"internalType":"bytes[]","name":"rightSignatures","type":"bytes[]"}],"name":"batchMatchOrdersWithMaximalFill","outputs":[{"components":[{"components":[{"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"internalType":"struct LibFillResults.FillResults[]","name":"left","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"internalType":"struct LibFillResults.FillResults[]","name":"right","type":"tuple[]"},{"internalType":"uint256","name":"profitInLeftMakerAsset","type":"uint256"},{"internalType":"uint256","name":"profitInRightMakerAsset","type":"uint256"}],"internalType":"struct LibFillResults.BatchMatchedFillResults","name":"batchMatchedFillResults","type":"tuple"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order","name":"order","type":"tuple"}],"name":"cancelOrder","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"targetOrderEpoch","type":"uint256"}],"name":"cancelOrdersUpTo","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"cancelled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentContextAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"detachProtocolFeeCollector","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"address","name":"signerAddress","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct LibZeroExTransaction.ZeroExTransaction","name":"transaction","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"executeTransaction","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order","name":"order","type":"tuple"},{"internalType":"uint256","name":"takerAssetFillAmount","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"fillOrKillOrder","outputs":[{"components":[{"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"internalType":"struct LibFillResults.FillResults","name":"fillResults","type":"tuple"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order","name":"order","type":"tuple"},{"internalType":"uint256","name":"takerAssetFillAmount","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"fillOrder","outputs":[{"components":[{"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"internalType":"struct LibFillResults.FillResults","name":"fillResults","type":"tuple"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"filled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes4","name":"assetProxyId","type":"bytes4"}],"name":"getAssetProxy","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order","name":"order","type":"tuple"}],"name":"getOrderInfo","outputs":[{"components":[{"internalType":"uint8","name":"orderStatus","type":"uint8"},{"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"internalType":"uint256","name":"orderTakerAssetFilledAmount","type":"uint256"}],"internalType":"struct LibOrder.OrderInfo","name":"orderInfo","type":"tuple"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"address","name":"signerAddress","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"isValidHashSignature","outputs":[{"internalType":"bool","name":"isValid","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order","name":"order","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"isValidOrderSignature","outputs":[{"internalType":"bool","name":"isValid","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"components":[{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"address","name":"signerAddress","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct LibZeroExTransaction.ZeroExTransaction","name":"transaction","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"isValidTransactionSignature","outputs":[{"internalType":"bool","name":"isValid","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order[]","name":"orders","type":"tuple[]"},{"internalType":"uint256","name":"makerAssetFillAmount","type":"uint256"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"}],"name":"marketBuyOrdersFillOrKill","outputs":[{"components":[{"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"internalType":"struct LibFillResults.FillResults","name":"fillResults","type":"tuple"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order[]","name":"orders","type":"tuple[]"},{"internalType":"uint256","name":"makerAssetFillAmount","type":"uint256"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"}],"name":"marketBuyOrdersNoThrow","outputs":[{"components":[{"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"internalType":"struct LibFillResults.FillResults","name":"fillResults","type":"tuple"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order[]","name":"orders","type":"tuple[]"},{"internalType":"uint256","name":"takerAssetFillAmount","type":"uint256"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"}],"name":"marketSellOrdersFillOrKill","outputs":[{"components":[{"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"internalType":"struct LibFillResults.FillResults","name":"fillResults","type":"tuple"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order[]","name":"orders","type":"tuple[]"},{"internalType":"uint256","name":"takerAssetFillAmount","type":"uint256"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"}],"name":"marketSellOrdersNoThrow","outputs":[{"components":[{"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"internalType":"struct LibFillResults.FillResults","name":"fillResults","type":"tuple"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order","name":"leftOrder","type":"tuple"},{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order","name":"rightOrder","type":"tuple"},{"internalType":"bytes","name":"leftSignature","type":"bytes"},{"internalType":"bytes","name":"rightSignature","type":"bytes"}],"name":"matchOrders","outputs":[{"components":[{"components":[{"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"internalType":"struct LibFillResults.FillResults","name":"left","type":"tuple"},{"components":[{"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"internalType":"struct LibFillResults.FillResults","name":"right","type":"tuple"},{"internalType":"uint256","name":"profitInLeftMakerAsset","type":"uint256"},{"internalType":"uint256","name":"profitInRightMakerAsset","type":"uint256"}],"internalType":"struct LibFillResults.MatchedFillResults","name":"matchedFillResults","type":"tuple"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order","name":"leftOrder","type":"tuple"},{"components":[{"internalType":"address","name":"makerAddress","type":"address"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"address","name":"feeRecipientAddress","type":"address"},{"internalType":"address","name":"senderAddress","type":"address"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerFee","type":"uint256"},{"internalType":"uint256","name":"takerFee","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes","name":"makerAssetData","type":"bytes"},{"internalType":"bytes","name":"takerAssetData","type":"bytes"},{"internalType":"bytes","name":"makerFeeAssetData","type":"bytes"},{"internalType":"bytes","name":"takerFeeAssetData","type":"bytes"}],"internalType":"struct LibOrder.Order","name":"rightOrder","type":"tuple"},{"internalType":"bytes","name":"leftSignature","type":"bytes"},{"internalType":"bytes","name":"rightSignature","type":"bytes"}],"name":"matchOrdersWithMaximalFill","outputs":[{"components":[{"components":[{"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"internalType":"struct LibFillResults.FillResults","name":"left","type":"tuple"},{"components":[{"internalType":"uint256","name":"makerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"takerAssetFilledAmount","type":"uint256"},{"internalType":"uint256","name":"makerFeePaid","type":"uint256"},{"internalType":"uint256","name":"takerFeePaid","type":"uint256"},{"internalType":"uint256","name":"protocolFeePaid","type":"uint256"}],"internalType":"struct LibFillResults.FillResults","name":"right","type":"tuple"},{"internalType":"uint256","name":"profitInLeftMakerAsset","type":"uint256"},{"internalType":"uint256","name":"profitInRightMakerAsset","type":"uint256"}],"internalType":"struct LibFillResults.MatchedFillResults","name":"matchedFillResults","type":"tuple"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"orderEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"preSign","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"preSigned","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"protocolFeeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"protocolFeeMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"assetProxy","type":"address"}],"name":"registerAssetProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"updatedProtocolFeeCollector","type":"address"}],"name":"setProtocolFeeCollectorAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"updatedProtocolFeeMultiplier","type":"uint256"}],"name":"setProtocolFeeMultiplier","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"validatorAddress","type":"address"},{"internalType":"bool","name":"approval","type":"bool"}],"name":"setSignatureValidatorApproval","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes[]","name":"assetData","type":"bytes[]"},{"internalType":"address[]","name":"fromAddresses","type":"address[]"},{"internalType":"address[]","name":"toAddresses","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"simulateDispatchTransferFromCalls","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"transactionsExecuted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040526000805460ff60a01b191690553480156200001e57600080fd5b5060405162005ddf38038062005ddf833981016040819052620000419162000141565b600080546001600160a01b03191633178155819080309050620000dc6040518060400160405280600b81526020017f30782050726f746f636f6c0000000000000000000000000000000000000000008152506040518060400160405280600581526020017f332e302e300000000000000000000000000000000000000000000000000000008152508584620000ea60201b62005bdb1760201c565b600155506200015a92505050565b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a0902090565b60006020828403121562000153578081fd5b5051919050565b615c75806200016a6000396000f3fe6080604052600436106102dc5760003560e01c80638d45cd2311610184578063beee2e14116100d6578063dd885e2d1161008a578063eea086ba11610064578063eea086ba14610735578063f2fde38b1461074a578063fc74896d1461076a576102dc565b8063dd885e2d146106ed578063dedfc1f11461070f578063e14b58c414610722576102dc565b8063c26cfecd116100bb578063c26cfecd14610698578063c585bb93146106ad578063d9bfa73e146106cd576102dc565b8063beee2e1414610665578063c0fa16cc14610678576102dc565b80639b44d55611610138578063a6c3bf3311610112578063a6c3bf331461061f578063b04fbddd14610632578063b718e29214610652576102dc565b80639b44d556146105bf5780639d3fa4b9146105d2578063a12dcc6f146105ff576102dc565b80638ea8dfe4116101695780638ea8dfe41461056c5780639331c7421461058c5780639694a402146105ac576102dc565b80638d45cd23146105375780638da5cb5b14610557576102dc565b8063607041081161023d5780637b8e3514116101f1578063850a1501116101cb578063850a1501146104ef57806388ec79fb146105045780638bc8efb314610524576102dc565b80637b8e35141461048f5780638171c407146104af57806382c174d0146104cf576102dc565b80636fcf3e9e116102225780636fcf3e9e1461045657806377fcce681461046957806378d29ac11461047c576102dc565b806360704108146104095780636a1a80fd14610436576102dc565b80632ac1262211610294578063369da09911610279578063369da099146103c357806346c02d7a146103e35780634f9559b1146103f6576102dc565b80632ac12622146103905780632da62987146103b0576102dc565b80631ce4c78b116102c55780631ce4c78b1461032e5780632280c91014610350578063288cdc9114610370576102dc565b80630228e168146102e15780630efca18514610317575b600080fd5b3480156102ed57600080fd5b506103016102fc366004614e67565b61078a565b60405161030e91906154c7565b60405180910390f35b34801561032357600080fd5b5061032c61079f565b005b34801561033a57600080fd5b506103436107b3565b60405161030e91906154d2565b61036361035e36600461510b565b6107b9565b60405161030e91906156a3565b34801561037c57600080fd5b5061034361038b366004614e67565b6107fb565b34801561039c57600080fd5b506103016103ab366004614e67565b61080d565b61032c6103be366004614f85565b610822565b6103d66103d1366004614d63565b610846565b60405161030e91906159c5565b61032c6103f1366004614e67565b61096d565b61032c610404366004614e67565b6109e0565b34801561041557600080fd5b50610429610424366004614ef0565b610aed565b60405161030e919061535e565b610449610444366004614c43565b610b3b565b60405161030e919061594e565b610449610464366004614c43565b610b73565b61032c610477366004614b2d565b610b91565b6103d661048a366004614d63565b610c54565b34801561049b57600080fd5b506103016104aa366004614af9565b610da4565b3480156104bb57600080fd5b506103016104ca366004614ea3565b610dc4565b3480156104db57600080fd5b506103016104ea366004614e7f565b610e23565b3480156104fb57600080fd5b50610429610e43565b61051761051236600461500f565b610e5f565b60405161030e91906159d3565b6103d6610532366004614d63565b610e7d565b34801561054357600080fd5b5061030161055236600461510b565b610eb1565b34801561056357600080fd5b50610429610ed6565b61057f61057a366004614cdf565b610ef2565b60405161030e91906154b4565b34801561059857600080fd5b5061032c6105a7366004614e67565b61101d565b61057f6105ba366004614cdf565b611065565b6103d66105cd3660046150ab565b61112c565b3480156105de57600080fd5b506105f26105ed366004614f85565b611151565b60405161030e9190615a15565b34801561060b57600080fd5b5061030161061a366004614fb8565b611235565b6103d661062d366004614d63565b61125a565b34801561063e57600080fd5b5061032c61064d366004614b68565b61128e565b61051761066036600461500f565b61133a565b61057f610673366004614cdf565b611358565b34801561068457600080fd5b5061032c610693366004614ade565b61140d565b3480156106a457600080fd5b5061034361141e565b3480156106b957600080fd5b5061032c6106c8366004614ade565b611424565b3480156106d957600080fd5b506103436106e8366004614af9565b6115b8565b3480156106f957600080fd5b506107026115d5565b60405161030e919061562e565b61032c61071d366004614c10565b6115f9565b6103d66107303660046150ab565b61163b565b34801561074157600080fd5b50610429611656565b34801561075657600080fd5b5061032c610765366004614ade565b611672565b61077d610778366004614db6565b611715565b60405161030e9190615436565b60056020526000908152604090205460ff1681565b6107a7611848565b6107b1600061188f565b565b60035481565b60606107c361192a565b156107d9576107d2838361194c565b90506107f5565b6107e1611a66565b6107eb838361194c565b90506107f5611aa8565b92915050565b60096020526000908152604090205481565b600a6020526000908152604090205460ff1681565b61082a611ad8565b61083381611b47565b61083b611b84565b610843611b98565b50565b61084e614564565b61085661192a565b156108ec57835160005b8181146108e5576000610880846020015187611bc290919063ffffffff16565b905061088a614564565b6108bb88848151811061089957fe5b6020026020010151838886815181106108ae57fe5b6020026020010151611be1565b90506108c78582611d22565b9450868560200151106108db5750506108e5565b5050600101610860565b5050610966565b6108f4611a66565b835160005b81811461095c576000610919846020015187611bc290919063ffffffff16565b9050610923614564565b61093288848151811061089957fe5b905061093e8582611d22565b94508685602001511061095257505061095c565b50506001016108f9565b5050610966611aa8565b9392505050565b610975611ad8565b600061097f611dbd565b600083815260076020908152604080832073ffffffffffffffffffffffffffffffffffffffff90941683529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555061083b611b84565b6109e8611ad8565b60006109f2611dbd565b9050600073ffffffffffffffffffffffffffffffffffffffff82163314610a195733610a1c565b60005b73ffffffffffffffffffffffffffffffffffffffff8084166000908152600b60209081526040808320938516835292905220549091506001840190808211610a7157610a71610a6c858584611def565b611e94565b73ffffffffffffffffffffffffffffffffffffffff8085166000818152600b602090815260408083209488168084529490915290819020859055517f82af639571738f4ebd4268fb0363d8957ebe1bbb9e78dba5ebd69eed39b154f090610ad99086906154d2565b60405180910390a35050505061083b611b84565b7fffffffff00000000000000000000000000000000000000000000000000000000811660009081526002602052604090205473ffffffffffffffffffffffffffffffffffffffff165b919050565b610b43614593565b610b4b611ad8565b610b59858585856001611e9c565b9050610b63611b84565b610b6b611b98565b949350505050565b610b7b614593565b610b83611ad8565b610b59858585856000611e9c565b610b99611ad8565b6000610ba3611dbd565b73ffffffffffffffffffffffffffffffffffffffff8181166000818152600860209081526040808320948916808452949091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168715151790555192935090917fa8656e308026eeabce8f0bc18048433252318ab80ac79da0b3d3d8697dfba89190610c379086906154c7565b60405180910390a350610c48611b84565b610c50611b98565b5050565b610c5c614564565b610c6461192a565b15610d2257835160005b8181146108e5578251600090610c8b90879063ffffffff611bc216565b90506000610cc8888481518110610c9e57fe5b602002602001015160a00151898581518110610cb657fe5b60200260200101516080015184612209565b9050610cd2614564565b610cf6898581518110610ce157fe5b6020026020010151838987815181106108ae57fe5b9050610d028682611d22565b955087866000015110610d17575050506108e5565b505050600101610c6e565b610d2a611a66565b835160005b81811461095c578251600090610d4c90879063ffffffff611bc216565b90506000610d5f888481518110610c9e57fe5b9050610d69614564565b610d78898581518110610ce157fe5b9050610d848682611d22565b955087866000015110610d995750505061095c565b505050600101610d2f565b600860209081526000928352604080842090915290825290205460ff1681565b600080610dd285858561224b565b90506005816008811115610de257fe5b1480610df957506007816008811115610df757fe5b145b15610e0e57610e0e610a6c60058787876122ca565b610e1a81868686612372565b95945050505050565b600760209081526000928352604080842090915290825290205460ff1681565b60045473ffffffffffffffffffffffffffffffffffffffff1681565b610e676145bb565b610e6f611ad8565b610b598585858560006125e2565b610e85614564565b610e90848484610c54565b9050828160000151101561096657610966610a6c60008584600001516126cf565b600080610ec9600154856126ee90919063ffffffff16565b9050610b6b848285612702565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b6060610efc61192a565b15610f9f578351604080518281526020808402820101909152818015610f3c57816020015b610f29614564565b815260200190600190039081610f215790505b50915060005b8181146108e557610f80868281518110610f5857fe5b6020026020010151868381518110610f6c57fe5b60200260200101518684815181106108ae57fe5b838281518110610f8c57fe5b6020908102919091010152600101610f42565b610fa7611a66565b8351604080518281526020808402820101909152818015610fe257816020015b610fcf614564565b815260200190600190039081610fc75790505b50915060005b81811461095c57610ffe868281518110610f5857fe5b83828151811061100a57fe5b6020908102919091010152600101610fe8565b611025611848565b7f3a3e76d7a75e198aef1f53137e4f2a8a2ec74e2e9526db8404d08ccc9f1e621d60035482604051611058929190615546565b60405180910390a1600355565b606061106f611ad8565b83516040805182815260208084028201019091528180156110aa57816020015b611097614564565b81526020019060019003908161108f5790505b50915060005b81811461111a576110fb8682815181106110c657fe5b60200260200101518683815181106110da57fe5b60200260200101518684815181106110ee57fe5b6020026020010151612788565b83828151811061110757fe5b60209081029190910101526001016110b0565b5050611124611b84565b610966611b98565b611134614564565b61113c611ad8565b611147848484612788565b9050611124611b84565b6111596145ef565b6111628261282a565b6040830152602082015260808201516111825760015b60ff168152610b36565b60a0820151611192576002611178565b8160a001518160400151106111a8576005611178565b81610100015142106111bb576004611178565b6020808201516000908152600a909152604090205460ff16156111df576006611178565b610120820151825173ffffffffffffffffffffffffffffffffffffffff9081166000908152600b60209081526040808320606088015190941683529290522054111561122c576006611178565b60038152919050565b60008061124d6001548561285b90919063ffffffff16565b9050610b6b84828561286a565b611262614564565b61126d848484610846565b9050828160200151101561096657610966610a6c60018584602001516126cf565b835160005b8181146112fe576112f68160001b8783815181106112ad57fe5b60200260200101518784815181106112c157fe5b60200260200101518785815181106112d557fe5b60200260200101518786815181106112e957fe5b60200260200101516128bf565b600101611293565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161133190615917565b60405180910390fd5b6113426145bb565b61134a611ad8565b610b598585858560016125e2565b6060611362611ad8565b835160408051828152602080840282010190915281801561139d57816020015b61138a614564565b8152602001906001900390816113825790505b50915060005b81811461111a576113ee8682815181106113b957fe5b60200260200101518683815181106113cd57fe5b60200260200101518684815181106113e157fe5b6020026020010151612a83565b8382815181106113fa57fe5b60209081029190910101526001016113a3565b611415611848565b6108438161188f565b60015481565b61142c611848565b60008173ffffffffffffffffffffffffffffffffffffffff1663ae25532e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561147457600080fd5b505afa158015611488573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114ac9190810190614f0c565b7fffffffff00000000000000000000000000000000000000000000000000000000811660009081526002602052604090205490915073ffffffffffffffffffffffffffffffffffffffff16801561150a5761150a610a6c8383612ab6565b7fffffffff0000000000000000000000000000000000000000000000000000000082166000908152600260205260409081902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8616179055517fd2c6b762299c609bdb96520b58a49bfb80186934d4f71a86a367571a15c03194906115ab908490869061565b565b60405180910390a1505050565b600b60209081526000928352604080842090915290825290205481565b7f20c13b0b0000000000000000000000000000000000000000000000000000000081565b611601611ad8565b805160005b8181146116315761162983828151811061161c57fe5b6020026020010151611b47565b600101611606565b505061083b611b84565b611643614564565b61164b611ad8565b611147848484612a83565b60065473ffffffffffffffffffffffffffffffffffffffff1681565b61167a611848565b73ffffffffffffffffffffffffffffffffffffffff81166116a5576116a0610a6c612b58565b610843565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b606061171f61192a565b156117c157825160408051828152602080840282010190915260609082801561175c57816020015b60608152602001906001900390816117475790505b50905060005b8281146117b85761179986828151811061177857fe5b602002602001015186838151811061178c57fe5b602002602001015161194c565b8282815181106117a557fe5b6020908102919091010152600101611762565b509150506107f5565b6117c9611a66565b825160408051828152602080840282010190915260609082801561180157816020015b60608152602001906001900390816117ec5790505b50905060005b82811461183c5761181d86828151811061177857fe5b82828151811061182957fe5b6020908102919091010152600101611807565b509150506107f5611aa8565b60005473ffffffffffffffffffffffffffffffffffffffff1633146107b1576000546107b190610a6c90339073ffffffffffffffffffffffffffffffffffffffff16612b8f565b6004546040517fe1a5430ebec577336427f40f15822f1f36c5e3509ff209d6db9e6c9e6941cb0b916118db9173ffffffffffffffffffffffffffffffffffffffff90911690849061537f565b60405180910390a1600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000547501000000000000000000000000000000000000000000900460ff1690565b60606000611965600154856126ee90919063ffffffff16565b9050611972848483612bac565b60608401516119818180612c80565b60008281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556080870151905160609130916119cf9190615311565b600060405180830381855af49150503d8060008114611a0a576040519150601f19603f3d011682016040523d82523d6000602084013e611a0f565b606091505b509150915081611a2657611a26610a6c8583612ce3565b611a31836000612c80565b60405184907fa4a7329f1dd821363067e07d359e347b4af9b1efe4b6cccf13240228af3c800d90600090a29695505050505050565b600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff167501000000000000000000000000000000000000000000179055565b600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690556107b1612d00565b60005474010000000000000000000000000000000000000000900460ff1615611b0657611b06610a6c612d35565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611b4f6145ef565b611b5882611151565b9050611b648282612d6c565b805160ff16600314611b765750610843565b610c50828260200151612e1b565b611b8c61192a565b6107b1576107b1612d00565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600082821115611bdb57611bdb610a6c60028585612ec4565b50900390565b611be9614564565b6040516060907f9b44d5560000000000000000000000000000000000000000000000000000000090611c2390879087908790602401615a5b565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600060603073ffffffffffffffffffffffffffffffffffffffff1683604051611cab9190615311565b600060405180830381855af49150503d8060008114611ce6576040519150601f19603f3d011682016040523d82523d6000602084013e611ceb565b606091505b50915091508115611d1857805160a014611d0157fe5b80806020019051611d159190810190614f28565b93505b5050509392505050565b611d2a614564565b81518351611d3d9163ffffffff612ee316565b815260208083015190840151611d589163ffffffff612ee316565b602082015260408083015190840151611d769163ffffffff612ee316565b604082015260608083015190840151611d949163ffffffff612ee316565b606082015260808083015190840151611db29163ffffffff612ee316565b608082015292915050565b60065460009073ffffffffffffffffffffffffffffffffffffffff16818115611de65781611de8565b335b9250505090565b6060634ad3127560e01b848484604051602401611e0e939291906153a6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290509392505050565b805160208201fd5b611ea4614593565b8551611eb757611eb7610a6c6000612eff565b8451611eca57611eca610a6c6001612eff565b8351865114611ee057611ee0610a6c6002612eff565b8251855114611ef657611ef6610a6c6003612eff565b8551604051908082528060200260200182016040528015611f3157816020015b611f1e614564565b815260200190600190039081611f165790505b5081528451604080518281526020808402820101909152908015611f6f57816020015b611f5c614564565b815260200190600190039081611f545790505b506020820152600080611f8061460f565b88600081518110611f8d57fe5b60200260200101519050611f9f61460f565b88600081518110611fac57fe5b602002602001015190506000611fc18361282a565b9150506000611fcf8361282a565b915050611fda614564565b611fe2614564565b611fea6145bb565b61201d87878f8c81518110611ffb57fe5b60200260200101518f8c8151811061200f57fe5b60200260200101518f6125e2565b80516020015190915061203790869063ffffffff612ee316565b945061205481602001516020015185612ee390919063ffffffff16565b9350612064838260000151611d22565b9250612074828260200151611d22565b915061209181604001518b60400151612ee390919063ffffffff16565b60408b0152606080820151908b01516120af9163ffffffff612ee316565b60608b015260a0870151851061215a578951805160018b019a85929181106120d357fe5b60200260200101819052506040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525092508e5189141561213757818a60200151898151811061212657fe5b6020026020010181905250506121f8565b8e898151811061214357fe5b602002602001015196506121568761282a565b9550505b8560a0015184106121f257818a6020015189806001019a508151811061217c57fe5b60200260200101819052506040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525091508d518814156121cf57828a600001518a8151811061212657fe5b8d88815181106121db57fe5b602002602001015195506121ee8661282a565b9450505b50611fe2565b505050505050505095945050505050565b6000610b6b8361223f61222382600163ffffffff611bc216565b612233888763ffffffff612f9e16565b9063ffffffff612ee316565b9063ffffffff612fcf16565b6000612258848484612ff9565b905073ffffffffffffffffffffffffffffffffffffffff831661228557612285610a6c60068686866122ca565b6008818181111561229257fe5b60ff16106122aa576122aa610a6c60038686866122ca565b60008160088111156122b857fe5b141561096657610966610a6c60048686865b6060637e5a231860e01b858585856040516024016122eb94939291906158bc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050949350505050565b6000600185600881111561238257fe5b14156123a95781516001146123a1576123a1610a6c60028686866122ca565b506000610b6b565b60028560088111156123b757fe5b14156124b05781516042146123d6576123d6610a6c60028686866122ca565b6000826000815181106123e557fe5b016020015160f81c9050600061240284600163ffffffff61303816565b9050600061241785602163ffffffff61303816565b905060006001888585856040516000815260200160405260405161243e9493929190615610565b6020604051602081039080840390855afa158015612460573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015173ffffffffffffffffffffffffffffffffffffffff8981169116149550610b6b945050505050565b60038560088111156124be57fe5b141561256b5781516042146124dd576124dd610a6c60028686866122ca565b6000826000815181106124ec57fe5b016020015160f81c9050600061250984600163ffffffff61303816565b9050600061251e85602163ffffffff61303816565b90506000600188604051602001612535919061532d565b604051602081830303815290604052805190602001208585856040516000815260200160405260405161243e9493929190615610565b600485600881111561257957fe5b14156125915761258a848484613062565b9050610b6b565b600685600881111561259f57fe5b146125a657fe5b50600083815260076020908152604080832073ffffffffffffffffffffffffffffffffffffffff8616845290915290205460ff16949350505050565b6125ea6145bb565b61016080870151610140808801919091528701519086015261260a6145ef565b61261387611151565b905061261d6145ef565b61262687611151565b90506000612632611dbd565b90506126408984838a613258565b61264c88838389613258565b612660898985602001518560200151613376565b6126798989856040015185604001516003543a8b6133bb565b93506126948982856020015186604001518860000151613510565b6126ad8882846020015185604001518860200151613510565b6126c3836020015183602001518b8b85896135ee565b50505095945050505050565b60606318e4b14160e01b848484604051602401611e0e939291906158a1565b6000610966826126fd85613795565b61381d565b60608301516000908161271685838661224b565b9050600581600881111561272657fe5b1415612748576127416127398787613857565b86848761388f565b925061277f565b600781600881111561275657fe5b1415612770576127416127698787613857565b8386613943565b61277c81868487612372565b92505b50509392505050565b612790614564565b6127986145ef565b6127a185611151565b905060006127ad611dbd565b90506127bb86838387613258565b60006127d883604001518860a00151611bc290919063ffffffff16565b905060006127e68783613952565b90506127f688826003543a613968565b945060008460200151905061281289858388604001518a613510565b61281e818a86896139df565b50505050509392505050565b6000806128426001548461285b90919063ffffffff16565b6000818152600960205260409020549092509050915091565b6000610966826126fd85613a76565b82516000908161287b85838661224b565b9050600581600881111561288b57fe5b141561289e576127416127398787613b4d565b60078160088111156128ac57fe5b1415612770576127416127698787613b4d565b8015612a7c5760208451816128d057fe5b066004146128e7576128e7610a6c60008787613b85565b60006128f9858263ffffffff613ba416565b7fffffffff00000000000000000000000000000000000000000000000000000000811660009081526002602052604090205490915073ffffffffffffffffffffffffffffffffffffffff168061295857612958610a6c60018989613b85565b6040516060907fa85e59e400000000000000000000000000000000000000000000000000000000906129949089908990899089906024016156b6565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600060608373ffffffffffffffffffffffffffffffffffffffff1683604051612a1c9190615311565b6000604051808303816000865af19150503d8060008114612a59576040519150601f19603f3d011682016040523d82523d6000602084013e612a5e565b606091505b509150915081612a7657612a76610a6c8b8b84613bf0565b50505050505b5050505050565b612a8b614564565b612a96848484612788565b90508281602001511461096657610966610a6c60028584602001516126cf565b60606311c7b72060e01b8383604051602401612ad392919061565b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152905092915050565b60408051808201909152600481527fe69edc3e00000000000000000000000000000000000000000000000000000000602082015290565b6060631de45ad160e01b8383604051602401612ad392919061537f565b82602001514210612bc557612bc5610a6c600183613c0f565b60408301513a8114612bdf57612bdf610a6c833a84613c2c565b60065473ffffffffffffffffffffffffffffffffffffffff168015612c0b57612c0b610a6c8483613c4b565b60008381526005602052604090205460ff1615612c3057612c30610a6c600085613c0f565b606085015173ffffffffffffffffffffffffffffffffffffffff81163314801590612c635750612c61868587612702565b155b15612c7857612c78610a6c60018684896122ca565b505050505050565b73ffffffffffffffffffffffffffffffffffffffff82163314610c50576006805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff00000000000000000000000000000000000000009091161790555050565b60606320d11f6160e01b8383604051602401612ad3929190615554565b3031801561084357604051339082156108fc029083906000818181858888f19350505050158015610c50573d6000803e3d6000fd5b60408051808201909152600481527f0c3b823f00000000000000000000000000000000000000000000000000000000602082015290565b606082015173ffffffffffffffffffffffffffffffffffffffff1615612dc057606082015173ffffffffffffffffffffffffffffffffffffffff163314612dc057612dc0610a6c6002836020015133613c68565b6000612dca611dbd565b90508073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff1614612e1657612e16610a6c6000846020015184613c68565b505050565b6000818152600a60205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558281015183516101408501516101608601519351859473ffffffffffffffffffffffffffffffffffffffff9485169493909316927f02c310a9a43963ff31a754a4099cc435ed498049687539d72d7818d9b093415c92612eb892909190339061571e565b60405180910390a45050565b606063e946c1bb60e01b848484604051602401611e0e93929190615849565b60008282018381101561096657610966610a6c60008686612ec4565b606063d4092f4f60e01b82604051602401612f1a9190615836565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050919050565b600082612fad575060006107f5565b82820282848281612fba57fe5b041461096657610966610a6c60018686612ec4565b600081612fe557612fe5610a6c60038585612ec4565b6000828481612ff057fe5b04949350505050565b600081516000141561301557613015610a6c60028686866122ca565b8160018351038151811061302557fe5b016020015160f81c6008811115610b6b57fe5b6000816020018351101561305957613059610a6c6005855185602001613c87565b50016020015190565b8051600090613099837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff830163ffffffff613ca616565b6040516060907f1626ba7e00000000000000000000000000000000000000000000000000000000906130d19088908790602401615554565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050613160848363ffffffff613ca616565b600060608673ffffffffffffffffffffffffffffffffffffffff16836040516131899190615311565b600060405180830381855afa9150503d80600081146131c4576040519150601f19603f3d011682016040523d82523d6000602084013e6131c9565b606091505b50915091508180156131dc575080516020145b1561323e577fb06713810000000000000000000000000000000000000000000000000000000061321382600063ffffffff613ba416565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614945050505050610966565b61324d610a6c89898985613caa565b505050509392505050565b825160ff1660031461328757613287610a6c8460200151856000015160ff16600681111561328257fe5b613ccb565b606084015173ffffffffffffffffffffffffffffffffffffffff16156132db57606084015173ffffffffffffffffffffffffffffffffffffffff1633146132db576132db610a6c6002856020015133613c68565b602084015173ffffffffffffffffffffffffffffffffffffffff1615613345578173ffffffffffffffffffffffffffffffffffffffff16846020015173ffffffffffffffffffffffffffffffffffffffff161461334557613345610a6c6001856020015185613c68565b6133548484602001518361286a565b61337057613370610a6c600085602001518760000151856122ca565b50505050565b60a0808401519085015161338f9163ffffffff612f9e16565b608080850151908601516133a89163ffffffff612f9e16565b101561337057613370610a6c8383613ce8565b6133c36145bb565b60a08801516000906133db908863ffffffff611bc216565b905060006133f28a608001518b60a0015184613d05565b9050600061340d888b60a00151611bc290919063ffffffff16565b905060006134248b608001518c60a0015184613d05565b905085156134415761343a8c8c85878587613d39565b9450613452565b61344f8c8c85878587613e0b565b94505b84515160808d015160c08e015161346a929190613d05565b85516040015284516020015160a08d015160e08e015161348b929190613d05565b85516060015260208501515160808c015160c08d01516134ac929190613d05565b856020015160400181815250506134d48560200151602001518c60a001518d60e00151613d05565b60208601516060015260006134ef888a63ffffffff612f9e16565b86516080908101829052602088015101525050505050979650505050505050565b602081015161352690839063ffffffff612ee316565b600960008581526020019081526020016000208190555082856040015173ffffffffffffffffffffffffffffffffffffffff16866000015173ffffffffffffffffffffffffffffffffffffffff167f6869791f0a34781b29882982cc39e882768cf2c96995c2a110c577c53bc932d58861014001518961016001518a61018001518b6101a001518b338a600001518b602001518c604001518d606001518e608001516040516135df9b9a9998979695949392919061576a565b60405180910390a45050505050565b8351835160408087015190860151610140870151855160200151613617918b91869088906128bf565b6136318a89610140015186868960200151602001516128bf565b61364b8988610180015185848960200151604001516128bf565b6136658a89610180015186858960000151604001516128bf565b61367b8a896101400151868989604001516128bf565b61369189886101400151858989606001516128bf565b60006136a98b8b88600001516080015188888c613ea4565b9050806136c6578551600060809182018190526020880151909101525b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614801561371657506101a080890151908a01516137169163ffffffff613f0116565b156137545761374f8b8a6101a00151898661374a8b60200151606001518c6000015160600151612ee390919063ffffffff16565b6128bf565b613788565b61376e8a896101a0015189858a60200151606001516128bf565b6137888b8a6101a0015189868a60000151606001516128bf565b5050505050505050505050565b608081810151825160208085015160408087015160609788015186519685019690962082517fec69816980a3a3ca4554410e60253953e9ff375ba4536a98adfa15cc71541508815294850195909552908301919091529481019490945273ffffffffffffffffffffffffffffffffffffffff9091169183019190915260a082015260c0902090565b6040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b6040516060907fde047db40000000000000000000000000000000000000000000000000000000090612ad39085908590602401615a86565b805160009060158110156138ad576138ad610a6c60028787876122ca565b60006138e1847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb840163ffffffff613f2616565b73ffffffffffffffffffffffffffffffffffffffff80871660009081526008602090815260408083209385168352929052205490915060ff1661392b5761392b610a6c8683613f66565b6139388188866015613f83565b979650505050505050565b6000610b6b8385846001613f83565b60008183106139615781610966565b5090919050565b613970614564565b6020810184905260a0850151608086015161398c918691613d05565b815260a085015160c08601516139a3918691613d05565b604082015260a085015160e08601516139bd918691613d05565b60608201526139d2828463ffffffff612f9e16565b6080820152949350505050565b6139f98484610160015184866000015185602001516128bf565b613a138484610140015185600001518585600001516128bf565b613a2d84846101a0015184866040015185606001516128bf565b613a4b848461018001518560000151866040015185604001516128bf565b6000613a6185836080015186600001518661415a565b905080612a7c57600060808301525050505050565b6101408101516101608201516101808301516101a08401516000937ff80322eb8376aafb64eadf8f0d7623f22130fd9491a221e902b713cb984a753493909290916020871015613ac257fe5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe087018051610140890180516101608b0180516101808d0180516101a08f0180519d89528c5160209d8e012087528b519b8d019b909b2084528951998c01999099208152875197909a019690962088526101e085209390945290529190529252919091529050919050565b6040516060907f3efe50c80000000000000000000000000000000000000000000000000000000090612ad39085908590602401615a39565b606063488219a660e01b848484604051602401611e0e9392919061580e565b60008160040183511015613bc557613bc5610a6c6003855185600401613c87565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b6060634678472b60e01b848484604051602401611e0e9392919061556d565b606063f598518460e01b8383604051602401612ad3929190615900565b606063a26dac0960e01b848484604051602401611e0e939291906155fa565b606063dec4aedf60e01b8383604051602401612ad39291906154db565b606063e53c76c860e01b848484604051602401611e0e9392919061586a565b6060632800659560e01b848484604051602401611e0e939291906158ae565b9052565b6060631b8388f760e01b858585856040516024016122eb94939291906154ff565b606063fdb6ca8d60e01b8383604051602401612ad3929190615598565b606063b6555d6f60e01b8383604051602401612ad3929190615546565b6000613d128484846141a0565b15613d2557613d25610a6c858585614206565b610b6b8361223f868563ffffffff612f9e16565b613d416145bb565b81851184841184861115613d6157613d5a898686614225565b9250613db0565b86841115613da15782518790528251602001869052608088015160a0890151613d8b919089613d05565b6020808501805192909252905101879052613db0565b613dad87878787614262565b92505b8115613dd6576020808401510151835151613dd09163ffffffff611bc216565b60408401525b8015613dfe5782516020908101519084015151613df89163ffffffff611bc216565b60608401525b50505b9695505050505050565b613e136145bb565b82841115613e2d57613e26878484614225565b9050613e7b565b82841015613e6c5780518590528051602090810185905281015184905260a08601516080870151613e5f91908661428d565b6020808301510152613e7b565b613e7885858585614262565b90505b6020808201510151815151613e959163ffffffff611bc216565b60408201529695505050505050565b60045460009073ffffffffffffffffffffffffffffffffffffffff168015613ef75730316000613ed88a84848b8b8a6142c5565b9050613eea89848385038b8a8a6142c5565b5060019350505050613e01565b6000915050613e01565b6000815183511480156109665750508051602091820120825192909101919091201490565b60008160140183511015613f4757613f47610a6c6004855185601401613c87565b50016014015173ffffffffffffffffffffffffffffffffffffffff1690565b606063a15c0d0660e01b8383604051602401612ad392919061537f565b8151600090613f9a8484830363ffffffff613ca616565b6040516060907f20c13b0b0000000000000000000000000000000000000000000000000000000090613fd290889088906024016156f9565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050614061858363ffffffff613ca616565b600060608873ffffffffffffffffffffffffffffffffffffffff168360405161408a9190615311565b600060405180830381855afa9150503d80600081146140c5576040519150601f19603f3d011682016040523d82523d6000602084013e6140ca565b606091505b50915091508180156140dd575080516020145b1561413f577f20c13b0b0000000000000000000000000000000000000000000000000000000061411482600063ffffffff613ba416565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614945050505050610b6b565b61414e610a6c8a8a8a856143fd565b50505050949350505050565b60045460009073ffffffffffffffffffffffffffffffffffffffff1680156141965761418b868230318888886142c5565b506001915050610b6b565b6000915050610b6b565b6000826141b2576141b2610a6c61441e565b8115806141bd575083155b156141ca57506000610966565b600083806141d457fe5b85840990506141e9858463ffffffff612f9e16565b6141fb826103e863ffffffff612f9e16565b101595945050505050565b606063339f3de260e01b848484604051602401611e0e939291906155fa565b61422d6145bb565b60208082018051859052518101839052815101839052608084015160a0850151614258919085613d05565b8151529392505050565b61426a6145bb565b805194909452835160209081019390935282840180519290925290519091015290565b600061429a848484614455565b156142ad576142ad610a6c858585614206565b610b6b8361223f61222382600163ffffffff611bc216565b60008385106142d15750825b6040516060907fa3b4a327000000000000000000000000000000000000000000000000000000009061430b908690869089906024016153a6565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600060608873ffffffffffffffffffffffffffffffffffffffff1684846040516143949190615311565b60006040518083038185875af1925050503d80600081146143d1576040519150601f19603f3d011682016040523d82523d6000602084013e6143d6565b606091505b5091509150816143f0576143f0610a6c8b898989866144b9565b5050509695505050505050565b6060635bd0428d60e01b858585856040516024016122eb94939291906153d7565b60408051808201909152600481527fa791837c00000000000000000000000000000000000000000000000000000000602082015290565b60008261446757614467610a6c61441e565b811580614472575083155b1561447f57506000610966565b6000838061448957fe5b85840990508361449f818363ffffffff611bc216565b816144a657fe5b0690506141e9858463ffffffff612f9e16565b60606387cb1e7560e01b86868686866040516024016144dc9594939291906155b5565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152905095945050505050565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b6040518060800160405280606081526020016060815260200160008152602001600081525090565b60405180608001604052806145ce614564565b81526020016145db614564565b815260200160008152602001600081525090565b604080516060810182526000808252602082018190529181019190915290565b604051806101c00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001606081526020016060815260200160608152602001606081525090565b803573ffffffffffffffffffffffffffffffffffffffff811681146107f557600080fd5b600082601f83011261470a578081fd5b813561471d61471882615b17565b615af0565b81815291506020808301908481018184028601820187101561473e57600080fd5b60005b848110156147655761475388836146d6565b84529282019290820190600101614741565b505050505092915050565b600082601f830112614780578081fd5b813561478e61471882615b17565b8181529150602080830190840160005b838110156147cb576147b6876020843589010161488e565b8352602092830192919091019060010161479e565b5050505092915050565b600082601f8301126147e5578081fd5b81356147f361471882615b17565b8181529150602080830190840160005b838110156147cb5761481b8760208435890101614915565b83526020928301929190910190600101614803565b600082601f830112614840578081fd5b813561484e61471882615b17565b81815291506020808301908481018184028601820187101561486f57600080fd5b60005b8481101561476557813584529282019290820190600101614872565b600082601f83011261489e578081fd5b813567ffffffffffffffff8111156148b4578182fd5b6148e560207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601615af0565b91508082528360208285010111156148fc57600080fd5b8060208401602084013760009082016020015292915050565b60006101c0808385031215614928578182fd5b61493181615af0565b91505061493e83836146d6565b815261494d83602084016146d6565b602082015261495f83604084016146d6565b604082015261497183606084016146d6565b60608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e08201526101008083013581830152506101208083013581830152506101408083013567ffffffffffffffff808211156149d357600080fd5b6149df8683870161488e565b838501526101609250828501359150808211156149fb57600080fd5b614a078683870161488e565b83850152610180925082850135915080821115614a2357600080fd5b614a2f8683870161488e565b838501526101a0925082850135915080821115614a4b57600080fd5b50614a588582860161488e565b82840152505092915050565b600060a08284031215614a75578081fd5b614a7f60a0615af0565b90508135815260208201356020820152604082013560408201526060820135614aa781615b8b565b6060820152608082013567ffffffffffffffff811115614ac657600080fd5b614ad28482850161488e565b60808301525092915050565b600060208284031215614aef578081fd5b61096683836146d6565b60008060408385031215614b0b578081fd5b614b1584846146d6565b9150614b2484602085016146d6565b90509250929050565b60008060408385031215614b3f578182fd5b614b4984846146d6565b915060208301358015158114614b5d578182fd5b809150509250929050565b60008060008060808587031215614b7d578182fd5b843567ffffffffffffffff80821115614b94578384fd5b614ba088838901614770565b95506020870135915080821115614bb5578384fd5b614bc1888389016146fa565b94506040870135915080821115614bd6578384fd5b614be2888389016146fa565b93506060870135915080821115614bf7578283fd5b50614c0487828801614830565b91505092959194509250565b600060208284031215614c21578081fd5b813567ffffffffffffffff811115614c37578182fd5b610b6b848285016147d5565b60008060008060808587031215614c58578182fd5b843567ffffffffffffffff80821115614c6f578384fd5b614c7b888389016147d5565b95506020870135915080821115614c90578384fd5b614c9c888389016147d5565b94506040870135915080821115614cb1578384fd5b614cbd88838901614770565b93506060870135915080821115614cd2578283fd5b50614c0487828801614770565b600080600060608486031215614cf3578081fd5b833567ffffffffffffffff80821115614d0a578283fd5b614d16878388016147d5565b94506020860135915080821115614d2b578283fd5b614d3787838801614830565b93506040860135915080821115614d4c578283fd5b50614d5986828701614770565b9150509250925092565b600080600060608486031215614d77578081fd5b833567ffffffffffffffff80821115614d8e578283fd5b614d9a878388016147d5565b9450602086013593506040860135915080821115614d4c578283fd5b60008060408385031215614dc8578182fd5b823567ffffffffffffffff80821115614ddf578384fd5b81850186601f820112614df0578485fd5b80359250614e0061471884615b17565b83815260208082019190838101885b87811015614e3857614e268c848435890101614a64565b85529382019390820190600101614e0f565b50919750880135945050505080821115614e50578283fd5b50614e5d85828601614770565b9150509250929050565b600060208284031215614e78578081fd5b5035919050565b60008060408385031215614e91578182fd5b823591506020830135614b5d81615b8b565b600080600060608486031215614eb7578081fd5b833592506020840135614ec981615b8b565b9150604084013567ffffffffffffffff811115614ee4578182fd5b614d598682870161488e565b600060208284031215614f01578081fd5b813561096681615bad565b600060208284031215614f1d578081fd5b815161096681615bad565b600060a0828403128015614f3a578182fd5b8015614f44578182fd5b50614f4f60a0615af0565b82518152602083015160208201526040830151604082015260608301516060820152608083015160808201528091505092915050565b600060208284031215614f96578081fd5b813567ffffffffffffffff811115614fac578182fd5b610b6b84828501614915565b60008060408385031215614fca578182fd5b823567ffffffffffffffff80821115614fe1578384fd5b614fed86838701614915565b93506020850135915080821115615002578283fd5b50614e5d8582860161488e565b60008060008060808587031215615024578182fd5b843567ffffffffffffffff8082111561503b578384fd5b61504788838901614915565b9550602087013591508082111561505c578384fd5b61506888838901614915565b9450604087013591508082111561507d578384fd5b6150898883890161488e565b9350606087013591508082111561509e578283fd5b50614c048782880161488e565b6000806000606084860312156150bf578081fd5b833567ffffffffffffffff808211156150d6578283fd5b6150e287838801614915565b94506020860135935060408601359150808211156150fe578283fd5b50614d598682870161488e565b6000806040838503121561511d578182fd5b823567ffffffffffffffff80821115615134578384fd5b614fed86838701614a64565b73ffffffffffffffffffffffffffffffffffffffff169052565b6000815180845260208401935060208301825b82811015615196576151808683516151ea565b60a095909501946020919091019060010161516d565b5093949350505050565b600081518084526151b8816020860160208601615b37565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b80518252602081015160208301526040810151604083015260608101516060830152608081015160808301525050565b60006101c061522a848451615140565b602083015161523c6020860182615140565b50604083015161524f6040860182615140565b5060608301516152626060860182615140565b506080830151608085015260a083015160a085015260c083015160c085015260e083015160e08501526101008084015181860152506101208084015181860152506101408084015182828701526152bb838701826151a0565b915050610160915081840151858203838701526152d882826151a0565b9250505061018080840151858303828701526152f483826151a0565b9150506101a091508184015185820383870152613e0182826151a0565b60008251615323818460208701615b37565b9190910192915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b73ffffffffffffffffffffffffffffffffffffffff9384168152919092166020820152604081019190915260600190565b600073ffffffffffffffffffffffffffffffffffffffff861682526080602083015261540660808301866151a0565b828103604084015261541881866151a0565b838103606085015261542a81866151a0565b98975050505050505050565b6000602080830181845280855180835260408601915060408482028701019250838701855b828110156154a7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526154958583516151a0565b9450928501929085019060010161545b565b5092979650505050505050565b600060208252610966602083018461515a565b901515815260200190565b90815260200190565b91825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600085825273ffffffffffffffffffffffffffffffffffffffff851660208301526080604083015261553460808301856151a0565b828103606084015261393881856151a0565b918252602082015260400190565b600083825260406020830152610b6b60408301846151a0565b60008482526060602083015261558660608301856151a0565b8281036040840152613e0181856151a0565b828152604081016155a883615b81565b8260208301529392505050565b600086825285602083015273ffffffffffffffffffffffffffffffffffffffff808616604084015280851660608401525060a0608083015261393860a08301846151a0565b9283526020830191909152604082015260600190565b93845260ff9290921660208401526040830152606082015260800190565b7fffffffff0000000000000000000000000000000000000000000000000000000091909116815260200190565b7fffffffff0000000000000000000000000000000000000000000000000000000092909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60006020825261096660208301846151a0565b6000608082526156c960808301876151a0565b73ffffffffffffffffffffffffffffffffffffffff95861660208401529390941660408201526060015292915050565b60006040825261570c60408301856151a0565b8281036020840152610e1a81856151a0565b60006060825261573160608301866151a0565b828103602084015261574381866151a0565b91505073ffffffffffffffffffffffffffffffffffffffff83166040830152949350505050565b600061016080835261577e8184018f6151a0565b8381036020850152615790818f6151a0565b91505082810360408401526157a5818d6151a0565b83810360608501526157b7818d6151a0565b73ffffffffffffffffffffffffffffffffffffffff9b8c16608086015299909a1660a0840152505060c081019590955260e08501939093526101008401919091526101208301526101409091015295945050505050565b600061581985615b63565b84825283602083015260606040830152610e1a60608301846151a0565b6020810161584383615b6d565b91905290565b6060810161585685615b6d565b938152602081019290925260409091015290565b6060810161587785615b77565b938152602081019290925273ffffffffffffffffffffffffffffffffffffffff1660409091015290565b6060810161585685615b77565b606081016008851061585657fe5b60006158c786615b81565b85825284602083015273ffffffffffffffffffffffffffffffffffffffff8416604083015260806060830152613e0160808301846151a0565b6040810161590d84615b63565b9281526020015290565b60208082526014908201527f5452414e53464552535f5355434345535346554c000000000000000000000000604082015260600190565b60006020825282516080602084015261596a60a084018261515a565b602085015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08482030160408501526159a5818361515a565b604086015160608601526060860151608086015280935050505092915050565b60a081016107f582846151ea565b6000610180820190506159e78284516151ea565b60208301516159f960a08401826151ea565b5060408301516101408301526060909201516101609091015290565b815160ff168152602080830151908201526040918201519181019190915260600190565b600060408252615a4c604083018561521a565b90508260208301529392505050565b600060608252615a6e606083018661521a565b8460208401528281036040840152613e0181856151a0565b60006040825283516040830152602084015160608301526040840151608083015273ffffffffffffffffffffffffffffffffffffffff60608501511660a0830152608084015160a060c0840152615ae060e08401826151a0565b9150508260208301529392505050565b60405181810167ffffffffffffffff81118282101715615b0f57600080fd5b604052919050565b600067ffffffffffffffff821115615b2d578081fd5b5060209081020190565b60005b83811015615b52578181015183820152602001615b3a565b838111156133705750506000910152565b6002811061084357fe5b6004811061084357fe5b6003811061084357fe5b6007811061084357fe5b73ffffffffffffffffffffffffffffffffffffffff8116811461084357600080fd5b7fffffffff000000000000000000000000000000000000000000000000000000008116811461084357600080fd5b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a090209056fea365627a7a72315820b04b72453866bc2a2b65ed60afe19776964cb10cdc5fa9307d4967867c2b64816c6578706572696d656e74616cf564736f6c634300050c00400000000000000000000000000000000000000000000000000000000000000001
Deployed Bytecode
0x6080604052600436106102dc5760003560e01c80638d45cd2311610184578063beee2e14116100d6578063dd885e2d1161008a578063eea086ba11610064578063eea086ba14610735578063f2fde38b1461074a578063fc74896d1461076a576102dc565b8063dd885e2d146106ed578063dedfc1f11461070f578063e14b58c414610722576102dc565b8063c26cfecd116100bb578063c26cfecd14610698578063c585bb93146106ad578063d9bfa73e146106cd576102dc565b8063beee2e1414610665578063c0fa16cc14610678576102dc565b80639b44d55611610138578063a6c3bf3311610112578063a6c3bf331461061f578063b04fbddd14610632578063b718e29214610652576102dc565b80639b44d556146105bf5780639d3fa4b9146105d2578063a12dcc6f146105ff576102dc565b80638ea8dfe4116101695780638ea8dfe41461056c5780639331c7421461058c5780639694a402146105ac576102dc565b80638d45cd23146105375780638da5cb5b14610557576102dc565b8063607041081161023d5780637b8e3514116101f1578063850a1501116101cb578063850a1501146104ef57806388ec79fb146105045780638bc8efb314610524576102dc565b80637b8e35141461048f5780638171c407146104af57806382c174d0146104cf576102dc565b80636fcf3e9e116102225780636fcf3e9e1461045657806377fcce681461046957806378d29ac11461047c576102dc565b806360704108146104095780636a1a80fd14610436576102dc565b80632ac1262211610294578063369da09911610279578063369da099146103c357806346c02d7a146103e35780634f9559b1146103f6576102dc565b80632ac12622146103905780632da62987146103b0576102dc565b80631ce4c78b116102c55780631ce4c78b1461032e5780632280c91014610350578063288cdc9114610370576102dc565b80630228e168146102e15780630efca18514610317575b600080fd5b3480156102ed57600080fd5b506103016102fc366004614e67565b61078a565b60405161030e91906154c7565b60405180910390f35b34801561032357600080fd5b5061032c61079f565b005b34801561033a57600080fd5b506103436107b3565b60405161030e91906154d2565b61036361035e36600461510b565b6107b9565b60405161030e91906156a3565b34801561037c57600080fd5b5061034361038b366004614e67565b6107fb565b34801561039c57600080fd5b506103016103ab366004614e67565b61080d565b61032c6103be366004614f85565b610822565b6103d66103d1366004614d63565b610846565b60405161030e91906159c5565b61032c6103f1366004614e67565b61096d565b61032c610404366004614e67565b6109e0565b34801561041557600080fd5b50610429610424366004614ef0565b610aed565b60405161030e919061535e565b610449610444366004614c43565b610b3b565b60405161030e919061594e565b610449610464366004614c43565b610b73565b61032c610477366004614b2d565b610b91565b6103d661048a366004614d63565b610c54565b34801561049b57600080fd5b506103016104aa366004614af9565b610da4565b3480156104bb57600080fd5b506103016104ca366004614ea3565b610dc4565b3480156104db57600080fd5b506103016104ea366004614e7f565b610e23565b3480156104fb57600080fd5b50610429610e43565b61051761051236600461500f565b610e5f565b60405161030e91906159d3565b6103d6610532366004614d63565b610e7d565b34801561054357600080fd5b5061030161055236600461510b565b610eb1565b34801561056357600080fd5b50610429610ed6565b61057f61057a366004614cdf565b610ef2565b60405161030e91906154b4565b34801561059857600080fd5b5061032c6105a7366004614e67565b61101d565b61057f6105ba366004614cdf565b611065565b6103d66105cd3660046150ab565b61112c565b3480156105de57600080fd5b506105f26105ed366004614f85565b611151565b60405161030e9190615a15565b34801561060b57600080fd5b5061030161061a366004614fb8565b611235565b6103d661062d366004614d63565b61125a565b34801561063e57600080fd5b5061032c61064d366004614b68565b61128e565b61051761066036600461500f565b61133a565b61057f610673366004614cdf565b611358565b34801561068457600080fd5b5061032c610693366004614ade565b61140d565b3480156106a457600080fd5b5061034361141e565b3480156106b957600080fd5b5061032c6106c8366004614ade565b611424565b3480156106d957600080fd5b506103436106e8366004614af9565b6115b8565b3480156106f957600080fd5b506107026115d5565b60405161030e919061562e565b61032c61071d366004614c10565b6115f9565b6103d66107303660046150ab565b61163b565b34801561074157600080fd5b50610429611656565b34801561075657600080fd5b5061032c610765366004614ade565b611672565b61077d610778366004614db6565b611715565b60405161030e9190615436565b60056020526000908152604090205460ff1681565b6107a7611848565b6107b1600061188f565b565b60035481565b60606107c361192a565b156107d9576107d2838361194c565b90506107f5565b6107e1611a66565b6107eb838361194c565b90506107f5611aa8565b92915050565b60096020526000908152604090205481565b600a6020526000908152604090205460ff1681565b61082a611ad8565b61083381611b47565b61083b611b84565b610843611b98565b50565b61084e614564565b61085661192a565b156108ec57835160005b8181146108e5576000610880846020015187611bc290919063ffffffff16565b905061088a614564565b6108bb88848151811061089957fe5b6020026020010151838886815181106108ae57fe5b6020026020010151611be1565b90506108c78582611d22565b9450868560200151106108db5750506108e5565b5050600101610860565b5050610966565b6108f4611a66565b835160005b81811461095c576000610919846020015187611bc290919063ffffffff16565b9050610923614564565b61093288848151811061089957fe5b905061093e8582611d22565b94508685602001511061095257505061095c565b50506001016108f9565b5050610966611aa8565b9392505050565b610975611ad8565b600061097f611dbd565b600083815260076020908152604080832073ffffffffffffffffffffffffffffffffffffffff90941683529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555061083b611b84565b6109e8611ad8565b60006109f2611dbd565b9050600073ffffffffffffffffffffffffffffffffffffffff82163314610a195733610a1c565b60005b73ffffffffffffffffffffffffffffffffffffffff8084166000908152600b60209081526040808320938516835292905220549091506001840190808211610a7157610a71610a6c858584611def565b611e94565b73ffffffffffffffffffffffffffffffffffffffff8085166000818152600b602090815260408083209488168084529490915290819020859055517f82af639571738f4ebd4268fb0363d8957ebe1bbb9e78dba5ebd69eed39b154f090610ad99086906154d2565b60405180910390a35050505061083b611b84565b7fffffffff00000000000000000000000000000000000000000000000000000000811660009081526002602052604090205473ffffffffffffffffffffffffffffffffffffffff165b919050565b610b43614593565b610b4b611ad8565b610b59858585856001611e9c565b9050610b63611b84565b610b6b611b98565b949350505050565b610b7b614593565b610b83611ad8565b610b59858585856000611e9c565b610b99611ad8565b6000610ba3611dbd565b73ffffffffffffffffffffffffffffffffffffffff8181166000818152600860209081526040808320948916808452949091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168715151790555192935090917fa8656e308026eeabce8f0bc18048433252318ab80ac79da0b3d3d8697dfba89190610c379086906154c7565b60405180910390a350610c48611b84565b610c50611b98565b5050565b610c5c614564565b610c6461192a565b15610d2257835160005b8181146108e5578251600090610c8b90879063ffffffff611bc216565b90506000610cc8888481518110610c9e57fe5b602002602001015160a00151898581518110610cb657fe5b60200260200101516080015184612209565b9050610cd2614564565b610cf6898581518110610ce157fe5b6020026020010151838987815181106108ae57fe5b9050610d028682611d22565b955087866000015110610d17575050506108e5565b505050600101610c6e565b610d2a611a66565b835160005b81811461095c578251600090610d4c90879063ffffffff611bc216565b90506000610d5f888481518110610c9e57fe5b9050610d69614564565b610d78898581518110610ce157fe5b9050610d848682611d22565b955087866000015110610d995750505061095c565b505050600101610d2f565b600860209081526000928352604080842090915290825290205460ff1681565b600080610dd285858561224b565b90506005816008811115610de257fe5b1480610df957506007816008811115610df757fe5b145b15610e0e57610e0e610a6c60058787876122ca565b610e1a81868686612372565b95945050505050565b600760209081526000928352604080842090915290825290205460ff1681565b60045473ffffffffffffffffffffffffffffffffffffffff1681565b610e676145bb565b610e6f611ad8565b610b598585858560006125e2565b610e85614564565b610e90848484610c54565b9050828160000151101561096657610966610a6c60008584600001516126cf565b600080610ec9600154856126ee90919063ffffffff16565b9050610b6b848285612702565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b6060610efc61192a565b15610f9f578351604080518281526020808402820101909152818015610f3c57816020015b610f29614564565b815260200190600190039081610f215790505b50915060005b8181146108e557610f80868281518110610f5857fe5b6020026020010151868381518110610f6c57fe5b60200260200101518684815181106108ae57fe5b838281518110610f8c57fe5b6020908102919091010152600101610f42565b610fa7611a66565b8351604080518281526020808402820101909152818015610fe257816020015b610fcf614564565b815260200190600190039081610fc75790505b50915060005b81811461095c57610ffe868281518110610f5857fe5b83828151811061100a57fe5b6020908102919091010152600101610fe8565b611025611848565b7f3a3e76d7a75e198aef1f53137e4f2a8a2ec74e2e9526db8404d08ccc9f1e621d60035482604051611058929190615546565b60405180910390a1600355565b606061106f611ad8565b83516040805182815260208084028201019091528180156110aa57816020015b611097614564565b81526020019060019003908161108f5790505b50915060005b81811461111a576110fb8682815181106110c657fe5b60200260200101518683815181106110da57fe5b60200260200101518684815181106110ee57fe5b6020026020010151612788565b83828151811061110757fe5b60209081029190910101526001016110b0565b5050611124611b84565b610966611b98565b611134614564565b61113c611ad8565b611147848484612788565b9050611124611b84565b6111596145ef565b6111628261282a565b6040830152602082015260808201516111825760015b60ff168152610b36565b60a0820151611192576002611178565b8160a001518160400151106111a8576005611178565b81610100015142106111bb576004611178565b6020808201516000908152600a909152604090205460ff16156111df576006611178565b610120820151825173ffffffffffffffffffffffffffffffffffffffff9081166000908152600b60209081526040808320606088015190941683529290522054111561122c576006611178565b60038152919050565b60008061124d6001548561285b90919063ffffffff16565b9050610b6b84828561286a565b611262614564565b61126d848484610846565b9050828160200151101561096657610966610a6c60018584602001516126cf565b835160005b8181146112fe576112f68160001b8783815181106112ad57fe5b60200260200101518784815181106112c157fe5b60200260200101518785815181106112d557fe5b60200260200101518786815181106112e957fe5b60200260200101516128bf565b600101611293565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161133190615917565b60405180910390fd5b6113426145bb565b61134a611ad8565b610b598585858560016125e2565b6060611362611ad8565b835160408051828152602080840282010190915281801561139d57816020015b61138a614564565b8152602001906001900390816113825790505b50915060005b81811461111a576113ee8682815181106113b957fe5b60200260200101518683815181106113cd57fe5b60200260200101518684815181106113e157fe5b6020026020010151612a83565b8382815181106113fa57fe5b60209081029190910101526001016113a3565b611415611848565b6108438161188f565b60015481565b61142c611848565b60008173ffffffffffffffffffffffffffffffffffffffff1663ae25532e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561147457600080fd5b505afa158015611488573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114ac9190810190614f0c565b7fffffffff00000000000000000000000000000000000000000000000000000000811660009081526002602052604090205490915073ffffffffffffffffffffffffffffffffffffffff16801561150a5761150a610a6c8383612ab6565b7fffffffff0000000000000000000000000000000000000000000000000000000082166000908152600260205260409081902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8616179055517fd2c6b762299c609bdb96520b58a49bfb80186934d4f71a86a367571a15c03194906115ab908490869061565b565b60405180910390a1505050565b600b60209081526000928352604080842090915290825290205481565b7f20c13b0b0000000000000000000000000000000000000000000000000000000081565b611601611ad8565b805160005b8181146116315761162983828151811061161c57fe5b6020026020010151611b47565b600101611606565b505061083b611b84565b611643614564565b61164b611ad8565b611147848484612a83565b60065473ffffffffffffffffffffffffffffffffffffffff1681565b61167a611848565b73ffffffffffffffffffffffffffffffffffffffff81166116a5576116a0610a6c612b58565b610843565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b606061171f61192a565b156117c157825160408051828152602080840282010190915260609082801561175c57816020015b60608152602001906001900390816117475790505b50905060005b8281146117b85761179986828151811061177857fe5b602002602001015186838151811061178c57fe5b602002602001015161194c565b8282815181106117a557fe5b6020908102919091010152600101611762565b509150506107f5565b6117c9611a66565b825160408051828152602080840282010190915260609082801561180157816020015b60608152602001906001900390816117ec5790505b50905060005b82811461183c5761181d86828151811061177857fe5b82828151811061182957fe5b6020908102919091010152600101611807565b509150506107f5611aa8565b60005473ffffffffffffffffffffffffffffffffffffffff1633146107b1576000546107b190610a6c90339073ffffffffffffffffffffffffffffffffffffffff16612b8f565b6004546040517fe1a5430ebec577336427f40f15822f1f36c5e3509ff209d6db9e6c9e6941cb0b916118db9173ffffffffffffffffffffffffffffffffffffffff90911690849061537f565b60405180910390a1600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000547501000000000000000000000000000000000000000000900460ff1690565b60606000611965600154856126ee90919063ffffffff16565b9050611972848483612bac565b60608401516119818180612c80565b60008281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556080870151905160609130916119cf9190615311565b600060405180830381855af49150503d8060008114611a0a576040519150601f19603f3d011682016040523d82523d6000602084013e611a0f565b606091505b509150915081611a2657611a26610a6c8583612ce3565b611a31836000612c80565b60405184907fa4a7329f1dd821363067e07d359e347b4af9b1efe4b6cccf13240228af3c800d90600090a29695505050505050565b600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff167501000000000000000000000000000000000000000000179055565b600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690556107b1612d00565b60005474010000000000000000000000000000000000000000900460ff1615611b0657611b06610a6c612d35565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611b4f6145ef565b611b5882611151565b9050611b648282612d6c565b805160ff16600314611b765750610843565b610c50828260200151612e1b565b611b8c61192a565b6107b1576107b1612d00565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600082821115611bdb57611bdb610a6c60028585612ec4565b50900390565b611be9614564565b6040516060907f9b44d5560000000000000000000000000000000000000000000000000000000090611c2390879087908790602401615a5b565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600060603073ffffffffffffffffffffffffffffffffffffffff1683604051611cab9190615311565b600060405180830381855af49150503d8060008114611ce6576040519150601f19603f3d011682016040523d82523d6000602084013e611ceb565b606091505b50915091508115611d1857805160a014611d0157fe5b80806020019051611d159190810190614f28565b93505b5050509392505050565b611d2a614564565b81518351611d3d9163ffffffff612ee316565b815260208083015190840151611d589163ffffffff612ee316565b602082015260408083015190840151611d769163ffffffff612ee316565b604082015260608083015190840151611d949163ffffffff612ee316565b606082015260808083015190840151611db29163ffffffff612ee316565b608082015292915050565b60065460009073ffffffffffffffffffffffffffffffffffffffff16818115611de65781611de8565b335b9250505090565b6060634ad3127560e01b848484604051602401611e0e939291906153a6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290509392505050565b805160208201fd5b611ea4614593565b8551611eb757611eb7610a6c6000612eff565b8451611eca57611eca610a6c6001612eff565b8351865114611ee057611ee0610a6c6002612eff565b8251855114611ef657611ef6610a6c6003612eff565b8551604051908082528060200260200182016040528015611f3157816020015b611f1e614564565b815260200190600190039081611f165790505b5081528451604080518281526020808402820101909152908015611f6f57816020015b611f5c614564565b815260200190600190039081611f545790505b506020820152600080611f8061460f565b88600081518110611f8d57fe5b60200260200101519050611f9f61460f565b88600081518110611fac57fe5b602002602001015190506000611fc18361282a565b9150506000611fcf8361282a565b915050611fda614564565b611fe2614564565b611fea6145bb565b61201d87878f8c81518110611ffb57fe5b60200260200101518f8c8151811061200f57fe5b60200260200101518f6125e2565b80516020015190915061203790869063ffffffff612ee316565b945061205481602001516020015185612ee390919063ffffffff16565b9350612064838260000151611d22565b9250612074828260200151611d22565b915061209181604001518b60400151612ee390919063ffffffff16565b60408b0152606080820151908b01516120af9163ffffffff612ee316565b60608b015260a0870151851061215a578951805160018b019a85929181106120d357fe5b60200260200101819052506040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525092508e5189141561213757818a60200151898151811061212657fe5b6020026020010181905250506121f8565b8e898151811061214357fe5b602002602001015196506121568761282a565b9550505b8560a0015184106121f257818a6020015189806001019a508151811061217c57fe5b60200260200101819052506040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525091508d518814156121cf57828a600001518a8151811061212657fe5b8d88815181106121db57fe5b602002602001015195506121ee8661282a565b9450505b50611fe2565b505050505050505095945050505050565b6000610b6b8361223f61222382600163ffffffff611bc216565b612233888763ffffffff612f9e16565b9063ffffffff612ee316565b9063ffffffff612fcf16565b6000612258848484612ff9565b905073ffffffffffffffffffffffffffffffffffffffff831661228557612285610a6c60068686866122ca565b6008818181111561229257fe5b60ff16106122aa576122aa610a6c60038686866122ca565b60008160088111156122b857fe5b141561096657610966610a6c60048686865b6060637e5a231860e01b858585856040516024016122eb94939291906158bc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050949350505050565b6000600185600881111561238257fe5b14156123a95781516001146123a1576123a1610a6c60028686866122ca565b506000610b6b565b60028560088111156123b757fe5b14156124b05781516042146123d6576123d6610a6c60028686866122ca565b6000826000815181106123e557fe5b016020015160f81c9050600061240284600163ffffffff61303816565b9050600061241785602163ffffffff61303816565b905060006001888585856040516000815260200160405260405161243e9493929190615610565b6020604051602081039080840390855afa158015612460573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015173ffffffffffffffffffffffffffffffffffffffff8981169116149550610b6b945050505050565b60038560088111156124be57fe5b141561256b5781516042146124dd576124dd610a6c60028686866122ca565b6000826000815181106124ec57fe5b016020015160f81c9050600061250984600163ffffffff61303816565b9050600061251e85602163ffffffff61303816565b90506000600188604051602001612535919061532d565b604051602081830303815290604052805190602001208585856040516000815260200160405260405161243e9493929190615610565b600485600881111561257957fe5b14156125915761258a848484613062565b9050610b6b565b600685600881111561259f57fe5b146125a657fe5b50600083815260076020908152604080832073ffffffffffffffffffffffffffffffffffffffff8616845290915290205460ff16949350505050565b6125ea6145bb565b61016080870151610140808801919091528701519086015261260a6145ef565b61261387611151565b905061261d6145ef565b61262687611151565b90506000612632611dbd565b90506126408984838a613258565b61264c88838389613258565b612660898985602001518560200151613376565b6126798989856040015185604001516003543a8b6133bb565b93506126948982856020015186604001518860000151613510565b6126ad8882846020015185604001518860200151613510565b6126c3836020015183602001518b8b85896135ee565b50505095945050505050565b60606318e4b14160e01b848484604051602401611e0e939291906158a1565b6000610966826126fd85613795565b61381d565b60608301516000908161271685838661224b565b9050600581600881111561272657fe5b1415612748576127416127398787613857565b86848761388f565b925061277f565b600781600881111561275657fe5b1415612770576127416127698787613857565b8386613943565b61277c81868487612372565b92505b50509392505050565b612790614564565b6127986145ef565b6127a185611151565b905060006127ad611dbd565b90506127bb86838387613258565b60006127d883604001518860a00151611bc290919063ffffffff16565b905060006127e68783613952565b90506127f688826003543a613968565b945060008460200151905061281289858388604001518a613510565b61281e818a86896139df565b50505050509392505050565b6000806128426001548461285b90919063ffffffff16565b6000818152600960205260409020549092509050915091565b6000610966826126fd85613a76565b82516000908161287b85838661224b565b9050600581600881111561288b57fe5b141561289e576127416127398787613b4d565b60078160088111156128ac57fe5b1415612770576127416127698787613b4d565b8015612a7c5760208451816128d057fe5b066004146128e7576128e7610a6c60008787613b85565b60006128f9858263ffffffff613ba416565b7fffffffff00000000000000000000000000000000000000000000000000000000811660009081526002602052604090205490915073ffffffffffffffffffffffffffffffffffffffff168061295857612958610a6c60018989613b85565b6040516060907fa85e59e400000000000000000000000000000000000000000000000000000000906129949089908990899089906024016156b6565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600060608373ffffffffffffffffffffffffffffffffffffffff1683604051612a1c9190615311565b6000604051808303816000865af19150503d8060008114612a59576040519150601f19603f3d011682016040523d82523d6000602084013e612a5e565b606091505b509150915081612a7657612a76610a6c8b8b84613bf0565b50505050505b5050505050565b612a8b614564565b612a96848484612788565b90508281602001511461096657610966610a6c60028584602001516126cf565b60606311c7b72060e01b8383604051602401612ad392919061565b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152905092915050565b60408051808201909152600481527fe69edc3e00000000000000000000000000000000000000000000000000000000602082015290565b6060631de45ad160e01b8383604051602401612ad392919061537f565b82602001514210612bc557612bc5610a6c600183613c0f565b60408301513a8114612bdf57612bdf610a6c833a84613c2c565b60065473ffffffffffffffffffffffffffffffffffffffff168015612c0b57612c0b610a6c8483613c4b565b60008381526005602052604090205460ff1615612c3057612c30610a6c600085613c0f565b606085015173ffffffffffffffffffffffffffffffffffffffff81163314801590612c635750612c61868587612702565b155b15612c7857612c78610a6c60018684896122ca565b505050505050565b73ffffffffffffffffffffffffffffffffffffffff82163314610c50576006805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff00000000000000000000000000000000000000009091161790555050565b60606320d11f6160e01b8383604051602401612ad3929190615554565b3031801561084357604051339082156108fc029083906000818181858888f19350505050158015610c50573d6000803e3d6000fd5b60408051808201909152600481527f0c3b823f00000000000000000000000000000000000000000000000000000000602082015290565b606082015173ffffffffffffffffffffffffffffffffffffffff1615612dc057606082015173ffffffffffffffffffffffffffffffffffffffff163314612dc057612dc0610a6c6002836020015133613c68565b6000612dca611dbd565b90508073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff1614612e1657612e16610a6c6000846020015184613c68565b505050565b6000818152600a60205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558281015183516101408501516101608601519351859473ffffffffffffffffffffffffffffffffffffffff9485169493909316927f02c310a9a43963ff31a754a4099cc435ed498049687539d72d7818d9b093415c92612eb892909190339061571e565b60405180910390a45050565b606063e946c1bb60e01b848484604051602401611e0e93929190615849565b60008282018381101561096657610966610a6c60008686612ec4565b606063d4092f4f60e01b82604051602401612f1a9190615836565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050919050565b600082612fad575060006107f5565b82820282848281612fba57fe5b041461096657610966610a6c60018686612ec4565b600081612fe557612fe5610a6c60038585612ec4565b6000828481612ff057fe5b04949350505050565b600081516000141561301557613015610a6c60028686866122ca565b8160018351038151811061302557fe5b016020015160f81c6008811115610b6b57fe5b6000816020018351101561305957613059610a6c6005855185602001613c87565b50016020015190565b8051600090613099837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff830163ffffffff613ca616565b6040516060907f1626ba7e00000000000000000000000000000000000000000000000000000000906130d19088908790602401615554565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050613160848363ffffffff613ca616565b600060608673ffffffffffffffffffffffffffffffffffffffff16836040516131899190615311565b600060405180830381855afa9150503d80600081146131c4576040519150601f19603f3d011682016040523d82523d6000602084013e6131c9565b606091505b50915091508180156131dc575080516020145b1561323e577fb06713810000000000000000000000000000000000000000000000000000000061321382600063ffffffff613ba416565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614945050505050610966565b61324d610a6c89898985613caa565b505050509392505050565b825160ff1660031461328757613287610a6c8460200151856000015160ff16600681111561328257fe5b613ccb565b606084015173ffffffffffffffffffffffffffffffffffffffff16156132db57606084015173ffffffffffffffffffffffffffffffffffffffff1633146132db576132db610a6c6002856020015133613c68565b602084015173ffffffffffffffffffffffffffffffffffffffff1615613345578173ffffffffffffffffffffffffffffffffffffffff16846020015173ffffffffffffffffffffffffffffffffffffffff161461334557613345610a6c6001856020015185613c68565b6133548484602001518361286a565b61337057613370610a6c600085602001518760000151856122ca565b50505050565b60a0808401519085015161338f9163ffffffff612f9e16565b608080850151908601516133a89163ffffffff612f9e16565b101561337057613370610a6c8383613ce8565b6133c36145bb565b60a08801516000906133db908863ffffffff611bc216565b905060006133f28a608001518b60a0015184613d05565b9050600061340d888b60a00151611bc290919063ffffffff16565b905060006134248b608001518c60a0015184613d05565b905085156134415761343a8c8c85878587613d39565b9450613452565b61344f8c8c85878587613e0b565b94505b84515160808d015160c08e015161346a929190613d05565b85516040015284516020015160a08d015160e08e015161348b929190613d05565b85516060015260208501515160808c015160c08d01516134ac929190613d05565b856020015160400181815250506134d48560200151602001518c60a001518d60e00151613d05565b60208601516060015260006134ef888a63ffffffff612f9e16565b86516080908101829052602088015101525050505050979650505050505050565b602081015161352690839063ffffffff612ee316565b600960008581526020019081526020016000208190555082856040015173ffffffffffffffffffffffffffffffffffffffff16866000015173ffffffffffffffffffffffffffffffffffffffff167f6869791f0a34781b29882982cc39e882768cf2c96995c2a110c577c53bc932d58861014001518961016001518a61018001518b6101a001518b338a600001518b602001518c604001518d606001518e608001516040516135df9b9a9998979695949392919061576a565b60405180910390a45050505050565b8351835160408087015190860151610140870151855160200151613617918b91869088906128bf565b6136318a89610140015186868960200151602001516128bf565b61364b8988610180015185848960200151604001516128bf565b6136658a89610180015186858960000151604001516128bf565b61367b8a896101400151868989604001516128bf565b61369189886101400151858989606001516128bf565b60006136a98b8b88600001516080015188888c613ea4565b9050806136c6578551600060809182018190526020880151909101525b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614801561371657506101a080890151908a01516137169163ffffffff613f0116565b156137545761374f8b8a6101a00151898661374a8b60200151606001518c6000015160600151612ee390919063ffffffff16565b6128bf565b613788565b61376e8a896101a0015189858a60200151606001516128bf565b6137888b8a6101a0015189868a60000151606001516128bf565b5050505050505050505050565b608081810151825160208085015160408087015160609788015186519685019690962082517fec69816980a3a3ca4554410e60253953e9ff375ba4536a98adfa15cc71541508815294850195909552908301919091529481019490945273ffffffffffffffffffffffffffffffffffffffff9091169183019190915260a082015260c0902090565b6040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b6040516060907fde047db40000000000000000000000000000000000000000000000000000000090612ad39085908590602401615a86565b805160009060158110156138ad576138ad610a6c60028787876122ca565b60006138e1847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb840163ffffffff613f2616565b73ffffffffffffffffffffffffffffffffffffffff80871660009081526008602090815260408083209385168352929052205490915060ff1661392b5761392b610a6c8683613f66565b6139388188866015613f83565b979650505050505050565b6000610b6b8385846001613f83565b60008183106139615781610966565b5090919050565b613970614564565b6020810184905260a0850151608086015161398c918691613d05565b815260a085015160c08601516139a3918691613d05565b604082015260a085015160e08601516139bd918691613d05565b60608201526139d2828463ffffffff612f9e16565b6080820152949350505050565b6139f98484610160015184866000015185602001516128bf565b613a138484610140015185600001518585600001516128bf565b613a2d84846101a0015184866040015185606001516128bf565b613a4b848461018001518560000151866040015185604001516128bf565b6000613a6185836080015186600001518661415a565b905080612a7c57600060808301525050505050565b6101408101516101608201516101808301516101a08401516000937ff80322eb8376aafb64eadf8f0d7623f22130fd9491a221e902b713cb984a753493909290916020871015613ac257fe5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe087018051610140890180516101608b0180516101808d0180516101a08f0180519d89528c5160209d8e012087528b519b8d019b909b2084528951998c01999099208152875197909a019690962088526101e085209390945290529190529252919091529050919050565b6040516060907f3efe50c80000000000000000000000000000000000000000000000000000000090612ad39085908590602401615a39565b606063488219a660e01b848484604051602401611e0e9392919061580e565b60008160040183511015613bc557613bc5610a6c6003855185600401613c87565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b6060634678472b60e01b848484604051602401611e0e9392919061556d565b606063f598518460e01b8383604051602401612ad3929190615900565b606063a26dac0960e01b848484604051602401611e0e939291906155fa565b606063dec4aedf60e01b8383604051602401612ad39291906154db565b606063e53c76c860e01b848484604051602401611e0e9392919061586a565b6060632800659560e01b848484604051602401611e0e939291906158ae565b9052565b6060631b8388f760e01b858585856040516024016122eb94939291906154ff565b606063fdb6ca8d60e01b8383604051602401612ad3929190615598565b606063b6555d6f60e01b8383604051602401612ad3929190615546565b6000613d128484846141a0565b15613d2557613d25610a6c858585614206565b610b6b8361223f868563ffffffff612f9e16565b613d416145bb565b81851184841184861115613d6157613d5a898686614225565b9250613db0565b86841115613da15782518790528251602001869052608088015160a0890151613d8b919089613d05565b6020808501805192909252905101879052613db0565b613dad87878787614262565b92505b8115613dd6576020808401510151835151613dd09163ffffffff611bc216565b60408401525b8015613dfe5782516020908101519084015151613df89163ffffffff611bc216565b60608401525b50505b9695505050505050565b613e136145bb565b82841115613e2d57613e26878484614225565b9050613e7b565b82841015613e6c5780518590528051602090810185905281015184905260a08601516080870151613e5f91908661428d565b6020808301510152613e7b565b613e7885858585614262565b90505b6020808201510151815151613e959163ffffffff611bc216565b60408201529695505050505050565b60045460009073ffffffffffffffffffffffffffffffffffffffff168015613ef75730316000613ed88a84848b8b8a6142c5565b9050613eea89848385038b8a8a6142c5565b5060019350505050613e01565b6000915050613e01565b6000815183511480156109665750508051602091820120825192909101919091201490565b60008160140183511015613f4757613f47610a6c6004855185601401613c87565b50016014015173ffffffffffffffffffffffffffffffffffffffff1690565b606063a15c0d0660e01b8383604051602401612ad392919061537f565b8151600090613f9a8484830363ffffffff613ca616565b6040516060907f20c13b0b0000000000000000000000000000000000000000000000000000000090613fd290889088906024016156f9565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050614061858363ffffffff613ca616565b600060608873ffffffffffffffffffffffffffffffffffffffff168360405161408a9190615311565b600060405180830381855afa9150503d80600081146140c5576040519150601f19603f3d011682016040523d82523d6000602084013e6140ca565b606091505b50915091508180156140dd575080516020145b1561413f577f20c13b0b0000000000000000000000000000000000000000000000000000000061411482600063ffffffff613ba416565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614945050505050610b6b565b61414e610a6c8a8a8a856143fd565b50505050949350505050565b60045460009073ffffffffffffffffffffffffffffffffffffffff1680156141965761418b868230318888886142c5565b506001915050610b6b565b6000915050610b6b565b6000826141b2576141b2610a6c61441e565b8115806141bd575083155b156141ca57506000610966565b600083806141d457fe5b85840990506141e9858463ffffffff612f9e16565b6141fb826103e863ffffffff612f9e16565b101595945050505050565b606063339f3de260e01b848484604051602401611e0e939291906155fa565b61422d6145bb565b60208082018051859052518101839052815101839052608084015160a0850151614258919085613d05565b8151529392505050565b61426a6145bb565b805194909452835160209081019390935282840180519290925290519091015290565b600061429a848484614455565b156142ad576142ad610a6c858585614206565b610b6b8361223f61222382600163ffffffff611bc216565b60008385106142d15750825b6040516060907fa3b4a327000000000000000000000000000000000000000000000000000000009061430b908690869089906024016153a6565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600060608873ffffffffffffffffffffffffffffffffffffffff1684846040516143949190615311565b60006040518083038185875af1925050503d80600081146143d1576040519150601f19603f3d011682016040523d82523d6000602084013e6143d6565b606091505b5091509150816143f0576143f0610a6c8b898989866144b9565b5050509695505050505050565b6060635bd0428d60e01b858585856040516024016122eb94939291906153d7565b60408051808201909152600481527fa791837c00000000000000000000000000000000000000000000000000000000602082015290565b60008261446757614467610a6c61441e565b811580614472575083155b1561447f57506000610966565b6000838061448957fe5b85840990508361449f818363ffffffff611bc216565b816144a657fe5b0690506141e9858463ffffffff612f9e16565b60606387cb1e7560e01b86868686866040516024016144dc9594939291906155b5565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152905095945050505050565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b6040518060800160405280606081526020016060815260200160008152602001600081525090565b60405180608001604052806145ce614564565b81526020016145db614564565b815260200160008152602001600081525090565b604080516060810182526000808252602082018190529181019190915290565b604051806101c00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001606081526020016060815260200160608152602001606081525090565b803573ffffffffffffffffffffffffffffffffffffffff811681146107f557600080fd5b600082601f83011261470a578081fd5b813561471d61471882615b17565b615af0565b81815291506020808301908481018184028601820187101561473e57600080fd5b60005b848110156147655761475388836146d6565b84529282019290820190600101614741565b505050505092915050565b600082601f830112614780578081fd5b813561478e61471882615b17565b8181529150602080830190840160005b838110156147cb576147b6876020843589010161488e565b8352602092830192919091019060010161479e565b5050505092915050565b600082601f8301126147e5578081fd5b81356147f361471882615b17565b8181529150602080830190840160005b838110156147cb5761481b8760208435890101614915565b83526020928301929190910190600101614803565b600082601f830112614840578081fd5b813561484e61471882615b17565b81815291506020808301908481018184028601820187101561486f57600080fd5b60005b8481101561476557813584529282019290820190600101614872565b600082601f83011261489e578081fd5b813567ffffffffffffffff8111156148b4578182fd5b6148e560207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601615af0565b91508082528360208285010111156148fc57600080fd5b8060208401602084013760009082016020015292915050565b60006101c0808385031215614928578182fd5b61493181615af0565b91505061493e83836146d6565b815261494d83602084016146d6565b602082015261495f83604084016146d6565b604082015261497183606084016146d6565b60608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e08201526101008083013581830152506101208083013581830152506101408083013567ffffffffffffffff808211156149d357600080fd5b6149df8683870161488e565b838501526101609250828501359150808211156149fb57600080fd5b614a078683870161488e565b83850152610180925082850135915080821115614a2357600080fd5b614a2f8683870161488e565b838501526101a0925082850135915080821115614a4b57600080fd5b50614a588582860161488e565b82840152505092915050565b600060a08284031215614a75578081fd5b614a7f60a0615af0565b90508135815260208201356020820152604082013560408201526060820135614aa781615b8b565b6060820152608082013567ffffffffffffffff811115614ac657600080fd5b614ad28482850161488e565b60808301525092915050565b600060208284031215614aef578081fd5b61096683836146d6565b60008060408385031215614b0b578081fd5b614b1584846146d6565b9150614b2484602085016146d6565b90509250929050565b60008060408385031215614b3f578182fd5b614b4984846146d6565b915060208301358015158114614b5d578182fd5b809150509250929050565b60008060008060808587031215614b7d578182fd5b843567ffffffffffffffff80821115614b94578384fd5b614ba088838901614770565b95506020870135915080821115614bb5578384fd5b614bc1888389016146fa565b94506040870135915080821115614bd6578384fd5b614be2888389016146fa565b93506060870135915080821115614bf7578283fd5b50614c0487828801614830565b91505092959194509250565b600060208284031215614c21578081fd5b813567ffffffffffffffff811115614c37578182fd5b610b6b848285016147d5565b60008060008060808587031215614c58578182fd5b843567ffffffffffffffff80821115614c6f578384fd5b614c7b888389016147d5565b95506020870135915080821115614c90578384fd5b614c9c888389016147d5565b94506040870135915080821115614cb1578384fd5b614cbd88838901614770565b93506060870135915080821115614cd2578283fd5b50614c0487828801614770565b600080600060608486031215614cf3578081fd5b833567ffffffffffffffff80821115614d0a578283fd5b614d16878388016147d5565b94506020860135915080821115614d2b578283fd5b614d3787838801614830565b93506040860135915080821115614d4c578283fd5b50614d5986828701614770565b9150509250925092565b600080600060608486031215614d77578081fd5b833567ffffffffffffffff80821115614d8e578283fd5b614d9a878388016147d5565b9450602086013593506040860135915080821115614d4c578283fd5b60008060408385031215614dc8578182fd5b823567ffffffffffffffff80821115614ddf578384fd5b81850186601f820112614df0578485fd5b80359250614e0061471884615b17565b83815260208082019190838101885b87811015614e3857614e268c848435890101614a64565b85529382019390820190600101614e0f565b50919750880135945050505080821115614e50578283fd5b50614e5d85828601614770565b9150509250929050565b600060208284031215614e78578081fd5b5035919050565b60008060408385031215614e91578182fd5b823591506020830135614b5d81615b8b565b600080600060608486031215614eb7578081fd5b833592506020840135614ec981615b8b565b9150604084013567ffffffffffffffff811115614ee4578182fd5b614d598682870161488e565b600060208284031215614f01578081fd5b813561096681615bad565b600060208284031215614f1d578081fd5b815161096681615bad565b600060a0828403128015614f3a578182fd5b8015614f44578182fd5b50614f4f60a0615af0565b82518152602083015160208201526040830151604082015260608301516060820152608083015160808201528091505092915050565b600060208284031215614f96578081fd5b813567ffffffffffffffff811115614fac578182fd5b610b6b84828501614915565b60008060408385031215614fca578182fd5b823567ffffffffffffffff80821115614fe1578384fd5b614fed86838701614915565b93506020850135915080821115615002578283fd5b50614e5d8582860161488e565b60008060008060808587031215615024578182fd5b843567ffffffffffffffff8082111561503b578384fd5b61504788838901614915565b9550602087013591508082111561505c578384fd5b61506888838901614915565b9450604087013591508082111561507d578384fd5b6150898883890161488e565b9350606087013591508082111561509e578283fd5b50614c048782880161488e565b6000806000606084860312156150bf578081fd5b833567ffffffffffffffff808211156150d6578283fd5b6150e287838801614915565b94506020860135935060408601359150808211156150fe578283fd5b50614d598682870161488e565b6000806040838503121561511d578182fd5b823567ffffffffffffffff80821115615134578384fd5b614fed86838701614a64565b73ffffffffffffffffffffffffffffffffffffffff169052565b6000815180845260208401935060208301825b82811015615196576151808683516151ea565b60a095909501946020919091019060010161516d565b5093949350505050565b600081518084526151b8816020860160208601615b37565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b80518252602081015160208301526040810151604083015260608101516060830152608081015160808301525050565b60006101c061522a848451615140565b602083015161523c6020860182615140565b50604083015161524f6040860182615140565b5060608301516152626060860182615140565b506080830151608085015260a083015160a085015260c083015160c085015260e083015160e08501526101008084015181860152506101208084015181860152506101408084015182828701526152bb838701826151a0565b915050610160915081840151858203838701526152d882826151a0565b9250505061018080840151858303828701526152f483826151a0565b9150506101a091508184015185820383870152613e0182826151a0565b60008251615323818460208701615b37565b9190910192915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b73ffffffffffffffffffffffffffffffffffffffff9384168152919092166020820152604081019190915260600190565b600073ffffffffffffffffffffffffffffffffffffffff861682526080602083015261540660808301866151a0565b828103604084015261541881866151a0565b838103606085015261542a81866151a0565b98975050505050505050565b6000602080830181845280855180835260408601915060408482028701019250838701855b828110156154a7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526154958583516151a0565b9450928501929085019060010161545b565b5092979650505050505050565b600060208252610966602083018461515a565b901515815260200190565b90815260200190565b91825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600085825273ffffffffffffffffffffffffffffffffffffffff851660208301526080604083015261553460808301856151a0565b828103606084015261393881856151a0565b918252602082015260400190565b600083825260406020830152610b6b60408301846151a0565b60008482526060602083015261558660608301856151a0565b8281036040840152613e0181856151a0565b828152604081016155a883615b81565b8260208301529392505050565b600086825285602083015273ffffffffffffffffffffffffffffffffffffffff808616604084015280851660608401525060a0608083015261393860a08301846151a0565b9283526020830191909152604082015260600190565b93845260ff9290921660208401526040830152606082015260800190565b7fffffffff0000000000000000000000000000000000000000000000000000000091909116815260200190565b7fffffffff0000000000000000000000000000000000000000000000000000000092909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60006020825261096660208301846151a0565b6000608082526156c960808301876151a0565b73ffffffffffffffffffffffffffffffffffffffff95861660208401529390941660408201526060015292915050565b60006040825261570c60408301856151a0565b8281036020840152610e1a81856151a0565b60006060825261573160608301866151a0565b828103602084015261574381866151a0565b91505073ffffffffffffffffffffffffffffffffffffffff83166040830152949350505050565b600061016080835261577e8184018f6151a0565b8381036020850152615790818f6151a0565b91505082810360408401526157a5818d6151a0565b83810360608501526157b7818d6151a0565b73ffffffffffffffffffffffffffffffffffffffff9b8c16608086015299909a1660a0840152505060c081019590955260e08501939093526101008401919091526101208301526101409091015295945050505050565b600061581985615b63565b84825283602083015260606040830152610e1a60608301846151a0565b6020810161584383615b6d565b91905290565b6060810161585685615b6d565b938152602081019290925260409091015290565b6060810161587785615b77565b938152602081019290925273ffffffffffffffffffffffffffffffffffffffff1660409091015290565b6060810161585685615b77565b606081016008851061585657fe5b60006158c786615b81565b85825284602083015273ffffffffffffffffffffffffffffffffffffffff8416604083015260806060830152613e0160808301846151a0565b6040810161590d84615b63565b9281526020015290565b60208082526014908201527f5452414e53464552535f5355434345535346554c000000000000000000000000604082015260600190565b60006020825282516080602084015261596a60a084018261515a565b602085015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08482030160408501526159a5818361515a565b604086015160608601526060860151608086015280935050505092915050565b60a081016107f582846151ea565b6000610180820190506159e78284516151ea565b60208301516159f960a08401826151ea565b5060408301516101408301526060909201516101609091015290565b815160ff168152602080830151908201526040918201519181019190915260600190565b600060408252615a4c604083018561521a565b90508260208301529392505050565b600060608252615a6e606083018661521a565b8460208401528281036040840152613e0181856151a0565b60006040825283516040830152602084015160608301526040840151608083015273ffffffffffffffffffffffffffffffffffffffff60608501511660a0830152608084015160a060c0840152615ae060e08401826151a0565b9150508260208301529392505050565b60405181810167ffffffffffffffff81118282101715615b0f57600080fd5b604052919050565b600067ffffffffffffffff821115615b2d578081fd5b5060209081020190565b60005b83811015615b52578181015183820152602001615b3a565b838111156133705750506000910152565b6002811061084357fe5b6004811061084357fe5b6003811061084357fe5b6007811061084357fe5b73ffffffffffffffffffffffffffffffffffffffff8116811461084357600080fd5b7fffffffff000000000000000000000000000000000000000000000000000000008116811461084357600080fd5b8351602094850120835193850193909320604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f815295860194909452928401929092526060830152608082015260a090209056fea365627a7a72315820b04b72453866bc2a2b65ed60afe19776964cb10cdc5fa9307d4967867c2b64816c6578706572696d656e74616cf564736f6c634300050c0040
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000001
-----Decoded View---------------
Arg [0] : chainId (uint256): 1
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000001
Deployed Bytecode Sourcemap
1022:384:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1402:53:6;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1402:53:6;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;2135:137:4;;8:9:-1;5:2;;;30:1;27;20:12;5:2;2135:137:4;;;:::i;:::-;;1052:36;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1052:36:4;;;:::i;:::-;;;;;;;;1832:296:6;;;;;;;;;:::i;:::-;;;;;;;;1756:42:2;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1756:42:2;;;;;;;;:::i;1846:::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1846:42:2;;;;;;;;:::i;4634:157::-;;;;;;;;;:::i;5675:1239:8:-;;;;;;;;;:::i;:::-;;;;;;;;2239:219:5;;;;;;;;;:::i;2497:1260:2:-;;;;;;;;;:::i;2280:155:1:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;2280:155:1;;;;;;;;:::i;:::-;;;;;;;;3083:549:3;;;;;;;;;:::i;:::-;;;;;;;;1847:535;;;;;;;;;:::i;2745:444:5:-;;;;;;;;;:::i;7453:1652:8:-;;;;;;;;;:::i;1975:71:5:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1975:71:5;;;;;;;;:::i;3541:1003::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;3541:1003:5;;;;;;;;:::i;1855:63::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1855:63:5;;;;;;;;:::i;1198:35:4:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1198:35:4;;;:::i;4361:499:3:-;;;;;;;;;:::i;:::-;;;;;;;;10747:705:8;;;;;;;;;:::i;5497:472:5:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;5497:472:5;;;;;;;;:::i;749:20:56:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;749:20:56;;;:::i;4468:669:8:-;;;;;;;;;:::i;:::-;;;;;;;;1390:269:4;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1390:269:4;;;;;;;;:::i;2366:661:8:-;;;;;;;;;:::i;4074:422:2:-;;;;;;;;;:::i;5065:2354::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;5065:2354:2;;;;;;;;:::i;:::-;;;;;;;;4806:406:5;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;4806:406:5;;;;;;;;:::i;9572:708:8:-;;;;;;;;;:::i;1676:696:7:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1676:696:7;;;;;;;;:::i;5507:513:3:-;;;;;;;;;:::i;3387:673:8:-;;;;;;;;;:::i;1833:193:4:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1833:193:4;;;;;;;;:::i;1039:42:37:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1039:42:37;;;:::i;1390:700:1:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;1390:700:1;;;;;;;;:::i;2106:67:2:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;2106:67:2;;;;;;;;:::i;692:55:49:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;692:55:49;;;:::i;:::-;;;;;;;;11564:284:8;;;;;;;;;:::i;1578:434::-;;;;;;;;;:::i;1507:36:6:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1507:36:6;;;:::i;928:329:56:-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;928:329:56;;;;;;;;:::i;2482:519:6:-;;;;;;;;;:::i;:::-;;;;;;;;1402:53;;;;;;;;;;;;;;;:::o;2135:137:4:-;882:22:56;:20;:22::i;:::-;2222:43:4;2262:1;2222:31;:43::i;:::-;2135:137::o;1052:36::-;;;;:::o;1832:296:6:-;2043:12;1123:21:58;:19;:21::i;:::-;1119:161;;;2078:43:6;2098:11;2111:9;2078:19;:43::i;:::-;2071:50;;1119:161:58;;;1192:16;:14;:16::i;:::-;2078:43:6;2098:11;2111:9;2078:19;:43::i;:::-;2071:50;;1237:32:58;:30;:32::i;:::-;1832:296:6;;;;:::o;1756:42:2:-;;;;;;;;;;;;;:::o;1846:::-;;;;;;;;;;;;;;;:::o;4634:157::-;954:34:58;:32;:34::i;:::-;4765:19:2;4778:5;4765:12;:19::i;:::-;1009:32:58;:30;:32::i;:::-;1051:14;:12;:14::i;:::-;4634:157:2;:::o;5675:1239:8:-;5905:45;;:::i;:::-;1123:21:58;:19;:21::i;:::-;1119:161;;;5989:13:8;;5966:20;6012:868;6037:12;6032:1;:17;6012:868;;6139:37;6179:64;6208:11;:34;;;6179:20;:28;;:64;;;;:::i;:::-;6139:104;;6324:51;;:::i;:::-;6378:136;6413:6;6420:1;6413:9;;;;;;;;;;;;;;6440:29;6487:10;6498:1;6487:13;;;;;;;;;;;;;;6378:17;:136::i;:::-;6324:190;;6613:61;6643:11;6656:17;6613:29;:61::i;:::-;6599:75;;6810:20;6772:11;:34;;;:58;6768:102;;6850:5;;;;6768:102;-1:-1:-1;;6051:3:8;;6012:868;;;-1:-1:-1;;1119:161:58;;;1192:16;:14;:16::i;:::-;5989:13:8;;5966:20;6012:868;6037:12;6032:1;:17;6012:868;;6139:37;6179:64;6208:11;:34;;;6179:20;:28;;:64;;;;:::i;:::-;6139:104;;6324:51;;:::i;:::-;6378:136;6413:6;6420:1;6413:9;;;;;;;6378:136;6324:190;;6613:61;6643:11;6656:17;6613:29;:61::i;:::-;6599:75;;6810:20;6772:11;:34;;;:58;6768:102;;6850:5;;;;6768:102;-1:-1:-1;;6051:3:8;;6012:868;;;-1:-1:-1;;1237:32:58;:30;:32::i;:::-;5675:1239:8;;;;;:::o;2239:219:5:-;954:34:58;:32;:34::i;:::-;2353:21:5;2377:27;:25;:27::i;:::-;2414:15;;;;:9;:15;;;;;;;;:30;;;;;;;;;;:37;;;;2447:4;2414:37;;;-1:-1:-1;1009:32:58;:30;:32::i;2497:1260:2:-;954:34:58;:32;:34::i;:::-;2632:20:2;2655:27;:25;:27::i;:::-;2632:50;-1:-1:-1;2940:26:2;2969;;;2985:10;2969:26;:52;;3011:10;2969:52;;;3006:1;2969:52;3187:24;;;;3109:21;3187:24;;;:10;:24;;;;;;;;:44;;;;;;;;;;2940:81;;-1:-1:-1;3152:1:2;3133:20;;;3303:30;;;3299:232;;3349:171;3371:148;3426:12;3456:18;3492:13;3371:37;:148::i;:::-;3349:21;:171::i;:::-;3570:24;;;;;;;;:10;:24;;;;;;;;:44;;;;;;;;;;;;;;:60;;;3645:105;;;;;3617:13;;3645:105;;;;;;;;;;998:1:58;;;;1009:32;:30;:32::i;2280:155:1:-;2401:27;;;2371:7;2401:27;;;:13;:27;;;;;;;;2280:155;;;;:::o;3083:549:3:-;3382:69;;:::i;:::-;954:34:58;:32;:34::i;:::-;3474:151:3;3505:10;3529:11;3554:14;3582:15;3611:4;3474:17;:151::i;:::-;3467:158;;1009:32:58;:30;:32::i;:::-;1051:14;:12;:14::i;:::-;3083:549:3;;;;;;:::o;1847:535::-;2131:69;;:::i;:::-;954:34:58;:32;:34::i;:::-;2223:152:3;2254:10;2278:11;2303:14;2331:15;2360:5;2223:17;:152::i;2745:444:5:-;954:34:58;:32;:34::i;:::-;2930:21:5;2954:27;:25;:27::i;:::-;2991:32;;;;;;;;:17;:32;;;;;;;;:50;;;;;;;;;;;;;;:61;;;;;;;;;;3067:115;2991:32;;-1:-1:-1;2991:50:5;;3067:115;;;;2991:61;;3067:115;;;;;;;;;;998:1:58;1009:32;:30;:32::i;:::-;1051:14;:12;:14::i;:::-;2745:444:5;;:::o;7453:1652:8:-;7682:45;;:::i;:::-;1123:21:58;:19;:21::i;:::-;1119:161;;;7766:13:8;;7743:20;7789:1282;7814:12;7809:1;:17;7789:1282;;7984:34;;7915:37;;7955:64;;:20;;:64;:28;:64;:::i;:::-;7915:104;;8215:37;8255:177;8301:6;8308:1;8301:9;;;;;;;;;;;;;;:26;;;8345:6;8352:1;8345:9;;;;;;;;;;;;;;:26;;;8389:29;8255:28;:177::i;:::-;8215:217;;8513:51;;:::i;:::-;8567:136;8602:6;8609:1;8602:9;;;;;;;;;;;;;;8629:29;8676:10;8687:1;8676:13;;;;;;;8567:136;8513:190;;8802:61;8832:11;8845:17;8802:29;:61::i;:::-;8788:75;;9001:20;8963:11;:34;;;:58;8959:102;;9041:5;;;;;8959:102;-1:-1:-1;;;7828:3:8;;7789:1282;;1119:161:58;1192:16;:14;:16::i;:::-;7766:13:8;;7743:20;7789:1282;7814:12;7809:1;:17;7789:1282;;7984:34;;7915:37;;7955:64;;:20;;:64;:28;:64;:::i;:::-;7915:104;;8215:37;8255:177;8301:6;8308:1;8301:9;;;;;;;8255:177;8215:217;;8513:51;;:::i;:::-;8567:136;8602:6;8609:1;8602:9;;;;;;;8567:136;8513:190;;8802:61;8832:11;8845:17;8802:29;:61::i;:::-;8788:75;;9001:20;8963:11;:34;;;:58;8959:102;;9041:5;;;;;8959:102;-1:-1:-1;;;7828:3:8;;7789:1282;;1975:71:5;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;3541:1003::-;3707:12;3735:27;3765:101;3802:4;3820:13;3847:9;3765:23;:101::i;:::-;3735:131;-1:-1:-1;4002:23:5;3985:13;:40;;;;;;;;;:100;;;-1:-1:-1;4058:27:5;4041:13;:44;;;;;;;;;3985:100;3968:394;;;4110:241;4132:218;4186:70;4274:4;4296:13;4327:9;4132:36;:218::i;4110:241::-;4381:132;4422:13;4449:4;4467:13;4494:9;4381:27;:132::i;:::-;4371:142;3541:1003;-1:-1:-1;;;;;3541:1003:5:o;1855:63::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;1198:35:4:-;;;;;;:::o;4361:499:3:-;4628:59;;:::i;:::-;954:34:58;:32;:34::i;:::-;4710:143:3;4736:9;4759:10;4783:13;4810:14;4838:5;4710:12;:143::i;10747:705:8:-;10949:45;;:::i;:::-;11024:64;11047:6;11055:20;11077:10;11024:22;:64::i;:::-;11010:78;;11139:20;11102:11;:34;;;:57;11098:348;;;11175:260;11197:237;11256:74;11348:20;11386:11;:34;;;11197:41;:237::i;5497:472:5:-;5684:12;5712:23;5738:57;5767:27;;5738:11;:28;;:57;;;;:::i;:::-;5712:83;;5815:123;5865:11;5890:15;5919:9;5815:36;:123::i;749:20:56:-;;;;;;:::o;4468:669:8:-;4707:47;1123:21:58;:19;:21::i;:::-;1119:161;;;4793:13:8;;4830:46;;;;;;;;;;;;;;;;4793:13;4830:46;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;4816:60:8;-1:-1:-1;4891:9:8;4886:217;4911:12;4906:1;:17;4886:217;;4961:131;4996:6;5003:1;4996:9;;;;;;;;;;;;;;5023:21;5045:1;5023:24;;;;;;;;;;;;;;5065:10;5076:1;5065:13;;;;;;;4961:131;4944:11;4956:1;4944:14;;;;;;;;;;;;;;;;;:148;4925:3;;4886:217;;1119:161:58;1192:16;:14;:16::i;:::-;4793:13:8;;4830:46;;;;;;;;;;;;;;;;4793:13;4830:46;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;4816:60:8;-1:-1:-1;4891:9:8;4886:217;4911:12;4906:1;:17;4886:217;;4961:131;4996:6;5003:1;4996:9;;;;;;;4961:131;4944:11;4956:1;4944:14;;;;;;;;;;;;;;;;;:148;4925:3;;4886:217;;1390:269:4;882:22:56;:20;:22::i;:::-;1516:74:4;1538:21;;1561:28;1516:74;;;;;;;;;;;;;;;;1600:21;:52;1390:269::o;2366:661:8:-;2604:47;954:34:58;:32;:34::i;:::-;2690:13:8;;2727:46;;;;;;;;;;;;;;;;2690:13;2727:46;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;2713:60:8;-1:-1:-1;2788:9:8;2783:210;2808:12;2803:1;:17;2783:210;;2858:124;2886:6;2893:1;2886:9;;;;;;;;;;;;;;2913:21;2935:1;2913:24;;;;;;;;;;;;;;2955:10;2966:1;2955:13;;;;;;;;;;;;;;2858:10;:124::i;:::-;2841:11;2853:1;2841:14;;;;;;;;;;;;;;;;;:141;2822:3;;2783:210;;;-1:-1:-1;;1009:32:58;:30;:32::i;:::-;1051:14;:12;:14::i;4074:422:2:-;4290:45;;:::i;:::-;954:34:58;:32;:34::i;:::-;4365:96:2;4389:5;4408:20;4442:9;4365:10;:96::i;:::-;4351:110;-1:-1:-1;1009:32:58;:30;:32::i;5065:2354:2:-;5161:35;;:::i;:::-;5373;5402:5;5373:28;:35::i;:::-;5332:37;;;5310:98;5311:19;;;5310:98;5710:22;;;;5706:166;;5783:47;5777:54;5753:78;;;;5845:16;;5706:166;6185:22;;;;6181:166;;6258:47;6252:54;;6181:166;6441:5;:22;;;6400:9;:37;;;:63;6396:188;;6509:33;6503:40;;6396:188;6708:5;:27;;;6689:15;:46;6685:166;;6781:28;6775:35;;6685:166;6920:19;;;;;6910:30;;;;:9;:30;;;;;;;;;6906:152;;;6986:30;6980:37;;6906:152;7125:10;;;;7082:18;;7071:30;;;;;;;;:10;:30;;;;;;;;7102:19;;;;7071:51;;;;;;;;;;:64;7067:186;;;7181:30;7175:37;;7067:186;7356:29;7326:60;;;5065:2354;-1:-1:-1;5065:2354:2:o;4806:406:5:-;4957:12;4985:17;5005:51;5028:27;;5005:5;:22;;:51;;;;:::i;:::-;4985:71;;5076:105;5120:5;5139:9;5162;5076:30;:105::i;9572:708:8:-;9775:45;;:::i;:::-;9850:65;9874:6;9882:20;9904:10;9850:23;:65::i;:::-;9836:79;;9966:20;9929:11;:34;;;:57;9925:349;;;10002:261;10024:238;10083:75;10176:20;10214:11;:34;;;10024:41;:238::i;1676:696:7:-;1917:16;;1900:14;1943:383;1968:6;1963:1;:11;1943:383;;1995:320;2175:1;2167:10;;2195:9;2205:1;2195:12;;;;;;;;;;;;;;2225:13;2239:1;2225:16;;;;;;;;;;;;;;2259:11;2271:1;2259:14;;;;;;;;;;;;;;2291:7;2299:1;2291:10;;;;;;;;;;;;;;1995:21;:320::i;:::-;1976:3;;1943:383;;;;2335:30;;;;;;;;;;;;;;;;;;;5507:513:3;5789:59;;:::i;:::-;954:34:58;:32;:34::i;:::-;5871:142:3;5897:9;5920:10;5944:13;5971:14;5999:4;5871:12;:142::i;3387:673:8:-;3631:47;954:34:58;:32;:34::i;:::-;3717:13:8;;3754:46;;;;;;;;;;;;;;;;3717:13;3754:46;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;3740:60:8;-1:-1:-1;3815:9:8;3810:216;3835:12;3830:1;:17;3810:216;;3885:130;3919:6;3926:1;3919:9;;;;;;;;;;;;;;3946:21;3968:1;3946:24;;;;;;;;;;;;;;3988:10;3999:1;3988:13;;;;;;;;;;;;;;3885:16;:130::i;:::-;3868:11;3880:1;3868:14;;;;;;;;;;;;;;;;;:147;3849:3;;3810:216;;1833:193:4;882:22:56;:20;:22::i;:::-;1959:60:4;1991:27;1959:31;:60::i;1039:42:37:-;;;;:::o;1390:700:1:-;882:22:56;:20;:22::i;:::-;1549:19:1;1583:10;1571:34;;;:36;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1571:36:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;1571:36:1;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;1571:36:1;;;;;;;;;1645:27;;;1617:25;1645:27;;;:13;:27;;;;;;1549:58;;-1:-1:-1;1645:27:1;;1686:31;;1682:207;;1733:145;1755:122;1816:12;1846:17;1755:43;:122::i;1733:145::-;1948:27;;;;;;;:13;:27;;;;;;;:40;;;;;;;;;;2003:80;;;;;1948:27;;:40;;2003:80;;;;;;;;;;914:1:56;;1390:700:1;:::o;2106:67:2:-;;;;;;;;;;;;;;;;;;;;;;;;:::o;692:55:49:-;;;:::o;11564:284:8:-;954:34:58;:32;:34::i;:::-;11727:13:8;;11704:20;11750:92;11775:12;11770:1;:17;11750:92;;11808:23;11821:6;11828:1;11821:9;;;;;;;;;;;;;;11808:12;:23::i;:::-;11789:3;;11750:92;;;;998:1:58;1009:32;:30;:32::i;1578:434:8:-;1800:45;;:::i;:::-;954:34:58;:32;:34::i;:::-;1875:102:8;1905:5;1924:20;1958:9;1875:16;:102::i;1507:36:6:-;;;;;;:::o;928:329:56:-;882:22;:20;:22::i;:::-;1024;;;1020:231;;1062:70;1084:47;:45;:47::i;1062:70::-;1020:231;;;1163:5;:16;;;;;;;;;;;;1198:42;;1163:16;;1219:10;;1198:42;;1163:5;1198:42;928:329;:::o;2482:519:6:-;2705:14;1123:21:58;:19;:21::i;:::-;1119:161;;;2752:19:6;;2809;;;;;;;;;;;;;;;;2781:25;;2752:19;2809;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2781:47:6;-1:-1:-1;2843:9:6;2838:130;2863:6;2858:1;:11;2838:130;;2906:51;2926:12;2939:1;2926:15;;;;;;;;;;;;;;2943:10;2954:1;2943:13;;;;;;;;;;;;;;2906:19;:51::i;:::-;2890:10;2901:1;2890:13;;;;;;;;;;;;;;;;;:67;2871:3;;2838:130;;;-1:-1:-1;2984:10:6;-1:-1:-1;;1119:161:58;;;1192:16;:14;:16::i;:::-;2752:19:6;;2809;;;;;;;;;;;;;;;;2781:25;;2752:19;2809;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2781:47:6;-1:-1:-1;2843:9:6;2838:130;2863:6;2858:1;:11;2838:130;;2906:51;2926:12;2939:1;2926:15;;;;;;;2906:51;2890:10;2901:1;2890:13;;;;;;;;;;;;;;;;;:67;2871:3;;2838:130;;;-1:-1:-1;2984:10:6;-1:-1:-1;;1237:32:58;:30;:32::i;1263:255:56:-;1357:5;;;;1343:10;:19;1339:173;;1481:5;;1378:123;;1400:100;;1453:10;;1481:5;;1400:35;:100::i;2443:259:4:-;2585:20;;2557:78;;;;;;2585:20;;;;;2607:27;;2557:78;;;;;;;;;;2645:20;:50;;;;;;;;;;;;;;;2443:259::o;1884:128:58:-;1962:4;1989:16;;;;;;;1884:128::o;3289:1209:6:-;3457:12;3485:23;3511:57;3540:27;;3511:11;:28;;:57;;;;:::i;:::-;3485:83;;3579:115;3621:11;3646:9;3669:15;3579:28;:115::i;:::-;3775:25;;;;3810:65;3775:25;;3810:35;:65::i;:::-;3917:37;;;;:20;:37;;;;;;:44;;;;3957:4;3917:44;;;4043:16;;;;4016:44;;3989:23;;4024:4;;4016:44;;4043:16;4016:44;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;3971:89:6;;;;4075:10;4070:187;;4101:145;4123:122;4188:15;4221:10;4123:47;:122::i;4101:145::-;4340:62;4376:13;4399:1;4340:35;:62::i;:::-;4418:37;;4439:15;;4418:37;;;;;4481:10;3289:1209;-1:-1:-1;;;;;;3289:1209:6:o;1648:87:58:-;1705:16;:23;;;;;;;;1648:87::o;1741:137::-;1833:5;1814:24;;;;;;1848:23;:21;:23::i;1041:309:57:-;1157:7;;;;;;;1153:144;;;1180:106;1219:53;:51;:53::i;1180:106::-;1329:7;:14;;;;;;;;1041:309::o;9519:500:2:-;9639:35;;:::i;:::-;9677:19;9690:5;9677:12;:19::i;:::-;9639:57;;9735:36;9754:5;9761:9;9735:18;:36::i;:::-;9833:21;;:61;;9864:29;9833:61;9829:98;;9910:7;;;9829:98;9963:49;9985:5;9992:9;:19;;;9963:21;:49::i;1292:155:58:-;1370:21;:19;:21::i;:::-;1365:76;;1407:23;:21;:23::i;1356:102:57:-;1446:5;1436:15;;;;;;1356:102::o;965:364:54:-;1051:7;1082:1;1078;:5;1074:227;;;1099:191;1121:168;1178:59;1255:1;1274;1121:39;:168::i;1099:191::-;-1:-1:-1;1317:5:54;;;965:364::o;13289:855:8:-;13463:45;;:::i;:::-;13604:166;;13571:30;;13640:44;;13604:166;;13698:5;;13717:20;;13751:9;;13604:166;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;13604:166:8;;;;;;;38:4:-1;29:7;25:18;67:10;61:17;96:58;199:8;192:4;186;182:15;179:29;167:10;160:49;0:215;;;13604:166:8;13571:199;;13782:15;13799:23;13834:4;13826:26;;13853:17;13826:45;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;13781:90:8;;;;13885:10;13881:153;;;13918:10;:17;13939:3;13918:24;13911:32;;;;13982:10;13971:52;;;;;;;;;;;;;;13957:66;;13881:153;-1:-1:-1;;;13289:855:8;;;;;:::o;8481:820:39:-;8640:35;;:::i;:::-;8777;;8733;;:80;;;:43;:80;:::i;:::-;8691:122;;8909:35;;;;;8865;;;;:80;;;:43;:80;:::i;:::-;8823:39;;;:122;9021:25;;;;;8987;;;;:60;;;:33;:60;:::i;:::-;8955:29;;;:92;9123:25;;;;;9089;;;;:60;;;:33;:60;:::i;:::-;9057:29;;;:92;9231:28;;;;;9194;;;;:66;;;:36;:66;:::i;:::-;9159:32;;;:101;8481:820;;;;:::o;7990:308:6:-;8130:21;;8074:7;;8130:21;;8074:7;8186:36;;:74;;8238:22;8186:74;;;8225:10;8186:74;8161:99;-1:-1:-1;;;7990:308:6;:::o;10732:372:38:-;10906:12;2939:10;10977:26;;11017:12;11043:18;11075:12;10941:156;;;;;;;;;;;;;;;22:32:-1;26:21;;;22:32;6:49;;10941:156:38;;;49:4:-1;25:18;;61:17;;10941:156:38;182:15:-1;10941:156:38;;;;179:29:-1;;;;160:49;;;10941:156:38;-1:-1:-1;10732:372:38;;;;;:::o;1511:170:53:-;1654:9;1648:16;1641:4;1630:9;1626:20;1619:46;8431:6398:3;8706:69;;:::i;:::-;8866:17;;8862:216;;8904:163;8926:140;8987:65;8926:43;:140::i;8904:163::-;9091:18;;9087:218;;9130:164;9152:141;9213:66;9152:43;:141::i;9130:164::-;9405:14;:21;9384:10;:17;:42;9380:250;;9442:177;9464:154;9525:79;9464:43;:154::i;9442:177::-;9665:15;:22;9643:11;:18;:44;9639:253;;9703:178;9725:155;9786:80;9725:43;:155::i;9703:178::-;9966:10;:17;9933:51;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;9902:82:3;;10059:18;;10026:52;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;9994:29:3;;;:84;10124:15;;10281:31;;:::i;:::-;10315:10;10326:1;10315:13;;;;;;;;;;;;;;10281:47;;10338:32;;:::i;:::-;10373:11;10385:1;10373:14;;;;;;;;;;;;;;10338:49;;10400:39;10443;10472:9;10443:28;:39::i;:::-;10397:85;;;10495:40;10539;10568:10;10539:28;:40::i;:::-;10492:87;;;10589:49;;:::i;:::-;10648:50;;:::i;:::-;10948:53;;:::i;:::-;11004:208;11034:9;11061:10;11089:14;11104:7;11089:23;;;;;;;;;;;;;;11130:15;11146:8;11130:25;;;;;;;;;;;;;;11173;11004:12;:208::i;:::-;11388:17;;:40;;;10948:264;;-1:-1:-1;11348:81:3;;:31;;:81;:39;:81;:::i;:::-;11314:115;;11478:83;11519:12;:18;;;:41;;;11478:32;:40;;:83;;;;:::i;:::-;11443:118;;11695:111;11742:15;11775:12;:17;;;11695:29;:111::i;:::-;11677:129;;11839:113;11886:16;11920:12;:18;;;11839:29;:113::i;:::-;11820:132;;12133:121;12205:12;:35;;;12133:23;:46;;;:54;;:121;;;;:::i;:::-;12084:46;;;:170;12391:36;;;;;12318:47;;;;:123;;;:55;:123;:::i;:::-;12268:47;;;:173;12670:26;;;;12635:61;;12631:940;;12796:28;;:39;;12825:9;;;;12838:15;;12796:28;:39;;;;;;;;;;;:57;;;;12951:41;;;;;;;;12978:1;12951:41;;;;12981:1;12951:41;;;;12984:1;12951:41;;;;12987:1;12951:41;;;;12990:1;12951:41;;;12933:59;;13174:10;:17;13163:7;:28;13159:398;;;13318:16;13276:23;:29;;;13306:8;13276:39;;;;;;;;;;;;;:58;;;;13356:5;;;13159:398;13420:10;13431:7;13420:19;;;;;;;;;;;;;;13408:31;;13499:39;13528:9;13499:28;:39::i;:::-;13461:77;-1:-1:-1;;13159:398:3;13805:10;:27;;;13769:32;:63;13765:951;;13977:16;13933:23;:29;;;13963:10;;;;;;13933:41;;;;;;;;;;;;;:60;;;;14092:41;;;;;;;;14119:1;14092:41;;;;14122:1;14092:41;;;;14125:1;14092:41;;;;14128:1;14092:41;;;;14131:1;14092:41;;;14073:60;;14317:11;:18;14305:8;:30;14301:401;;;14459:15;14419:23;:28;;;14448:7;14419:37;;;;;;;14301:401;14561:11;14573:8;14561:21;;;;;;;;;;;;;;14548:34;;14643:40;14672:10;14643:28;:40::i;:::-;14604:79;-1:-1:-1;;14301:401:3;10839:3887;;;;-1:-1:-1;;;;;;;;8431:6398:3;;;;;;;:::o;3762:545:40:-;3925:21;4165:104;4257:11;4165:70;4212:22;4257:11;4232:1;4212:22;:19;:22;:::i;:::-;4165:25;:9;4183:6;4165:25;:17;:25;:::i;:::-;:46;:70;:46;:70;:::i;:::-;:91;:104;:91;:104;:::i;13461:1772:5:-;13631:27;13743:96;13775:4;13793:13;13820:9;13743:18;:96::i;:::-;13727:112;-1:-1:-1;13932:27:5;;;13928:285;;13975:227;13997:204;14051:56;14125:4;14147:13;14178:9;13997:36;:204::i;13975:227::-;14298:29;14274:13;14268:20;;;;;;;;:60;;;14264:315;;14344:224;14366:201;14420:53;14491:4;14513:13;14544:9;14366:36;:201::i;14344:224::-;14928:21;14911:13;:38;;;;;;;;;14907:289;;;14965:220;14987:197;15041:49;15108:4;15130:13;15161:9;8091:404:38;8292:12;1851:10;8363:24;;8401:9;8424:4;8442:13;8469:9;8327:161;;;;;;;;;;;;;;;;22:32:-1;26:21;;;22:32;6:49;;8327:161:38;;;49:4:-1;25:18;;61:17;;8327:161:38;182:15:-1;8327:161:38;;;;179:29:-1;;;;160:49;;;8327:161:38;-1:-1:-1;8091:404:38;;;;;;:::o;9676:3058:5:-;9887:12;10179:21;10162:13;:38;;;;;;;;;10158:2546;;;10220:9;:16;10240:1;10220:21;10216:307;;10261:247;10283:224;10341:56;10419:4;10445:13;10480:9;10283:36;:224::i;10261:247::-;-1:-1:-1;10546:5:5;10158:2546;;;10624:20;10607:13;:37;;;;;;;;;10603:2101;;;10664:9;:16;10684:2;10664:22;10660:308;;10706:247;10728:224;10786:56;10864:4;10890:13;10925:9;10728:36;:224::i;10706:247::-;10981:7;10997:9;11007:1;10997:12;;;;;;;;;;;;;;;-1:-1:-1;11024:9:5;11036:24;:9;11058:1;11036:24;:21;:24;:::i;:::-;11024:36;-1:-1:-1;11074:9:5;11086:25;:9;11108:2;11086:25;:21;:25;:::i;:::-;11074:37;;11125:17;11145:102;11172:4;11194:1;11213;11232;11145:102;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;11145:102:5;;;;;11271:26;;;;;;;;-1:-1:-1;10603:2101:5;;-1:-1:-1;;;;;10603:2101:5;;11374:21;11357:13;:38;;;;;;;;;11353:1351;;;11415:9;:16;11435:2;11415:22;11411:308;;11457:247;11479:224;11537:56;11615:4;11641:13;11676:9;11479:36;:224::i;11457:247::-;11732:7;11748:9;11758:1;11748:12;;;;;;;;;;;;;;;-1:-1:-1;11775:9:5;11787:24;:9;11809:1;11787:24;:21;:24;:::i;:::-;11775:36;-1:-1:-1;11825:9:5;11837:25;:9;11859:2;11837:25;:21;:25;:::i;:::-;11825:37;;11876:17;11896:225;12027:4;11933:116;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;11933:116:5;;;11923:127;;;;;;12068:1;12087;12106;11896:225;;;;;;;;;;;;;;;;;;;11353:1351;12260:20;12243:13;:37;;;;;;;;;12239:465;;;12306:117;12347:4;12369:13;12400:9;12306:23;:117::i;:::-;12296:127;;12239:465;;;12542:23;12525:13;:40;;;;;;;;;12518:48;;;;-1:-1:-1;12663:15:5;;;;:9;:15;;;;;;;;:30;;;;;;;;;;;;;9676:3058;;;;;;:::o;15830:2739:3:-;16088:59;;:::i;:::-;16524:24;;;;;16496:25;;;;:52;;;;16586:24;;;16558:25;;;:52;16660:39;;:::i;:::-;16702:23;16715:9;16702:12;:23::i;:::-;16660:65;;16735:40;;:::i;:::-;16778:24;16791:10;16778:12;:24::i;:::-;16735:67;;16844:20;16867:27;:25;:27::i;:::-;16844:50;;16957:133;16991:9;17014:13;17041:12;17067:13;16957:20;:133::i;:::-;17100:136;17134:10;17158:14;17186:12;17212:14;17100:20;:136::i;:::-;17246:149;17277:9;17300:10;17324:13;:23;;;17361:14;:24;;;17246:17;:149::i;:::-;17472:309;17528:9;17551:10;17575:13;:41;;;17630:14;:42;;;17686:21;;17721:11;17746:25;17472:42;:309::i;:::-;17451:330;;17825:206;17857:9;17880:12;17906:13;:23;;;17943:13;:41;;;17998:18;:23;;;17825:18;:206::i;:::-;18041:210;18073:10;18097:12;18123:14;:24;;;18161:14;:42;;;18217:18;:24;;;18041:18;:210::i;:::-;18316;18350:13;:23;;;18387:14;:24;;;18425:9;18448:10;18472:12;18498:18;18316:20;:210::i;:::-;-1:-1:-1;;;15830:2739:3;;;;;;;:::o;13960:418:38:-;14165:12;4354:10;14236:30;;14280:9;14303:23;14340:21;14200:171;;;;;;;;;;;1921:441:43;2066:23;2207:116;2248:24;2286:27;:11;:25;:27::i;:::-;2207;:116::i;8087:1482:5:-;8370:25;;;;8318:12;;;8435:112;8472:15;8370:25;8528:9;8435:23;:112::i;:::-;8405:142;-1:-1:-1;8578:23:5;8561:13;:40;;;;;;;;;8557:982;;;8702:213;8747:63;8781:11;8794:15;8747:33;:63::i;:::-;8828:15;8861:13;8892:9;8702:27;:213::i;:::-;8692:223;;8557:982;;;8953:27;8936:13;:44;;;;;;;;;8932:607;;;9078:177;9120:63;9154:11;9167:15;9120:33;:63::i;:::-;9201:13;9232:9;9078:24;:177::i;8932:607::-;9365:163;9410:13;9441:15;9474:13;9505:9;9365:27;:163::i;:::-;9355:173;;8932:607;-1:-1:-1;;8087:1482:5;;;;;:::o;7736:1552:2:-;7903:45;;:::i;:::-;7992:35;;:::i;:::-;8030:19;8043:5;8030:12;:19::i;:::-;7992:57;;8091:20;8114:27;:25;:27::i;:::-;8091:50;;8206:121;8240:5;8259:9;8282:12;8308:9;8206:20;:121::i;:::-;8382:33;8418:69;8449:9;:37;;;8418:5;:22;;;:30;;:69;;;;:::i;:::-;8382:105;;8497:30;8530:67;8549:20;8571:25;8530:18;:67::i;:::-;8497:100;;8667:160;8716:5;8735:22;8771:21;;8806:11;8667:35;:160::i;:::-;8653:174;;8838:17;8858:9;:19;;;8838:39;;8930:172;8962:5;8981:12;9007:9;9030;:37;;;9081:11;8930:18;:172::i;:::-;9137:115;9163:9;9186:5;9205:12;9231:11;9137:12;:115::i;:::-;-1:-1:-1;;;;;7736:1552:2;;;;;:::o;17532:368::-;17646:17;17665:35;17728:51;17751:27;;17728:5;:22;;:51;;;;:::i;:::-;17819:17;;;;:6;:17;;;;;;17716:63;;-1:-1:-1;17819:17:2;-1:-1:-1;17532:368:2;;;:::o;4703:315:42:-;4830:17;4875:110;4916:24;4954:21;:5;:19;:21::i;6327:1367:5:-;6568:18;;6516:12;;;6626:106;6663:9;6568:18;6713:9;6626:23;:106::i;:::-;6596:136;-1:-1:-1;6763:23:5;6746:13;:40;;;;;;;;;6742:922;;;6881:189;6926:45;6954:5;6961:9;6926:27;:45::i;6742:922::-;7108:27;7091:13;:44;;;;;;;;;7087:577;;;7227:159;7269:45;7297:5;7304:9;7269:27;:45::i;2824:2037:1:-;3079:10;;3075:1780;;3231:2;3212:9;:16;:21;;;;;;3237:1;3212:26;3208:311;;3258:246;3280:223;3347:76;3445:9;3476;3280:45;:223::i;3258:246::-;3567:19;3589:23;:9;3567:19;3589:23;:20;:23;:::i;:::-;3647:27;;;3626:18;3647:27;;;:13;:27;;;;;;3567:45;;-1:-1:-1;3647:27:1;;3738:24;3734:303;;3782:240;3804:217;3871:70;3963:9;3994;3804:45;:217::i;3782:240::-;4145:192;;4116:26;;4185:45;;4145:192;;4248:9;;4275:4;;4297:2;;4317:6;;4145:192;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;4145:192:1;;;;;;;38:4:-1;29:7;25:18;67:10;61:17;96:58;199:8;192:4;186;182:15;179:29;167:10;160:49;0:215;;;4145:192:1;4116:221;;4444:15;4461:23;4488:10;:15;;4504:13;4488:30;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;4443:75:1;;;;4620:10;4615:230;;4650:180;4672:157;4739:9;4770;4801:10;4672:45;:157::i;4650:180::-;3075:1780;;;;;;2824:2037;;;;;:::o;12150:730:8:-;12323:45;;:::i;:::-;12398:96;12422:5;12441:20;12475:9;12398:10;:96::i;:::-;12384:110;;12546:20;12508:11;:34;;;:58;12504:342;;12582:253;12604:230;12663:67;12748:20;12786:11;:34;;;12604:41;:230::i;11110:326:38:-;11258:12;3091:10;11329:33;;11376:12;11402:17;11293:136;;;;;;;;;;;;;;22:32:-1;26:21;;;22:32;6:49;;11293:136:38;;;49:4:-1;25:18;;61:17;;11293:136:38;182:15:-1;11293:136:38;;;;179:29:-1;;;;160:49;;;11293:136:38;-1:-1:-1;11110:326:38;;;;:::o;669:159:51:-;787:34;;;;;;;;;;;;;;;;;669:159;:::o;387:276::-;511:12;183:10;582:25;;621:6;641:5;546:110;;;;;;;;;;4780:2304:6;5121:11;:33;;;5102:15;:52;5098:260;;5170:177;5192:154;5248:51;5317:15;5192:38;:154::i;5170:177::-;5470:20;;;;5504:11;:31;;5500:241;;5551:179;5573:156;5637:15;5670:11;5699:16;5573:46;:156::i;5551:179::-;5870:21;;;;5905:36;;5901:229;;5957:162;5979:139;6049:15;6082:22;5979:52;:139::i;5957:162::-;6198:37;;;;:20;:37;;;;;;;;6194:254;;;6251:186;6273:163;6329:60;6407:15;6273:38;:163::i;6251:186::-;6583:25;;;;6622:27;;;6639:10;6622:27;;;;:171;;;6654:139;6708:11;6737:15;6770:9;6654:36;:139::i;:::-;6653:140;6622:171;6618:460;;;6818:249;6840:226;6894:67;6979:15;7012:13;7043:9;6840:36;:226::i;6818:249::-;4780:2304;;;;;;:::o;7299:247::-;7448:27;;;7465:10;7448:27;7444:96;;7491:21;:38;;;;;;;;;;;;7299:247;;:::o;12857:329:38:-;13010:12;3858:10;13081:36;;13131:15;13160:9;13045:134;;;;;;;;;;1453:189:58;1543:4;1535:21;1570:11;;1566:70;;1597:28;;:10;;:28;;;;;1617:7;;1597:28;;;;1617:7;1597:10;:28;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;840:162:52;956:39;;;;;;;;;;;;;;;;;840:162;:::o;14343:1022:2:-;14566:19;;;;:33;;;14562:382;;14619:19;;;;:33;;14642:10;14619:33;14615:319;;14672:247;14694:224;14765:62;14849:9;:19;;;14890:10;14694:49;:224::i;14672:247::-;15002:20;15025:27;:25;:27::i;:::-;15002:50;;15088:12;15066:34;;:5;:18;;;:34;;;15062:297;;15116:232;15138:209;15205:61;15284:9;:19;;;15321:12;15138:49;:209::i;15116:232::-;14343:1022;;;:::o;11474:432::-;11632:20;;;;:9;:20;;;;;;;:27;;;;11655:4;11632:27;;;11749:25;;;;11717:18;;11788:20;;;;11822;;;;11697:202;;11642:9;;11697:202;;;;;;;;;;;;;;11788:20;;11822;11856:10;;11697:202;;;;;;;;;;11474:432;;:::o;731:322:55:-;884:12;196:10;955:28;;997:9;1020:1;1035;919:127;;;;;;;;;;;1335:383:54;1421:7;1456:5;;;1475;;;1471:223;;;1496:187;1518:164;1575:55;1648:1;1667;1518:39;:164::i;7811:274:38:-;7941:12;4497:10;8012:33;;8059:9;7976:102;;;;;;;;;;;;;22:32:-1;26:21;;;22:32;6:49;;7976:102:38;;;49:4:-1;25:18;;61:17;;7976:102:38;182:15:-1;7976:102:38;;;;179:29:-1;;;;160:49;;;7976:102:38;-1:-1:-1;7811:274:38;;;:::o;122:448:54:-;208:7;235:6;231:45;;-1:-1:-1;264:1:54;257:8;;231:45;297:5;;;301:1;297;:5;:1;316:5;;;;;:10;312:234;;342:193;364:170;421:61;500:1;519;364:39;:170::i;576:383::-;662:7;689:6;685:223;;711:186;733:163;790:54;862:1;881;733:39;:163::i;711:186::-;917:9;933:1;929;:5;;;;;;;576:383;-1:-1:-1;;;;576:383:54:o;12821:549:5:-;12986:13;13019:9;:16;13039:1;13019:21;13015:279;;;13056:227;13078:204;13132:56;13206:4;13228:13;13259:9;13078:36;:204::i;13056:227::-;13330:9;13359:1;13340:9;:16;:20;13330:31;;;;;;;;;;;;;;13310:53;;;;;;;14133:679:47;14254:14;14299:5;14307:2;14299:10;14288:1;:8;:21;14284:297;;;14325:245;14347:222;14409:92;14519:1;:8;14545:5;14553:2;14545:10;14347:44;:222::i;14325:245::-;-1:-1:-1;14759:13:47;14661:2;14759:13;14753:20;;14133:679::o;16693:1271:5:-;16947:16;;16863:4;;17044:42;16947:9;17066:19;;;17044:42;:21;:42;:::i;:::-;17153:132;;17129:21;;17189:45;;17153:132;;17248:4;;17266:9;;17153:132;;;;;;;;22:32:-1;26:21;;;22:32;6:49;;17153:132:5;;;49:4:-1;25:18;;61:17;;17153:132:5;182:15:-1;17153:132:5;;;;179:29:-1;;;;160:49;;;17153:132:5;-1:-1:-1;17344:38:5;:9;17366:15;17344:38;:21;:38;:::i;:::-;17443:15;17460:23;17487:13;:24;;17512:8;17487:34;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;17442:79:5;;;;17610:10;:37;;;;;17624:10;:17;17645:2;17624:23;17610:37;17606:128;;;17698:25;17670:24;:10;17692:1;17670:24;:21;:24;:::i;:::-;:53;;;;17663:60;;;;;;;;17606:128;17790:167;17812:144;17868:4;17886:13;17913:9;17936:10;17812:42;:144::i;17790:167::-;16693:1271;;;;;;;;;:::o;12223:1923:2:-;12517:21;;:61;;12548:29;12517:61;12513:265;;12594:173;12616:150;12672:9;:19;;;12730:9;:21;;;12709:43;;;;;;;;;;12616:38;:150::i;12594:173::-;12849:19;;;;:33;;;12845:382;;12902:19;;;;:33;;12925:10;12902:33;12898:319;;12955:247;12977:224;13048:62;13132:9;:19;;;13173:10;12977:49;:224::i;12955:247::-;13297:18;;;;:32;;;13293:383;;13371:12;13349:34;;:5;:18;;;:34;;;13345:321;;13403:248;13425:225;13496:61;13579:9;:19;;;13620:12;13425:49;:225::i;13403:248::-;13721:131;13769:5;13792:9;:19;;;13829:9;13721:30;:131::i;:::-;13716:424;;13877:252;13899:229;13953:61;14032:9;:19;;;14069:5;:18;;;14105:9;13899:36;:229::i;13877:252::-;12223:1923;;;;:::o;6302:1236:3:-;7336:27;;;;;7301:26;;;;:63;;;:34;:63;:::i;:::-;7258:27;;;;;7223:26;;;;:63;;;:34;:63;:::i;:::-;:141;7219:313;;;7380:141;7402:118;7461:13;7492:14;7402:41;:118::i;4804:3462:39:-;5181:44;;:::i;:::-;5377:26;;;;5337:37;;5377:67;;5412:31;5377:67;:34;:67;:::i;:::-;5337:107;;5454:37;5494:166;5541:9;:26;;;5581:9;:26;;;5621:29;5494:33;:166::i;:::-;5454:206;;5670:38;5711:69;5747:32;5711:10;:27;;;:35;;:69;;;;:::i;:::-;5670:110;;5790:38;5831:169;5878:10;:27;;;5919:10;:27;;;5960:30;5831:33;:169::i;:::-;5790:210;;6123:25;6119:718;;;6185:302;6246:9;6273:10;6301:29;6348;6395:30;6443;6185:43;:302::i;:::-;6164:323;;6119:718;;;6539:287;6585:9;6612:10;6640:29;6687;6734:30;6782;6539:28;:287::i;:::-;6518:308;;6119:718;6972:23;;:46;7032:26;;;;7072:18;;;;6925:175;;6972:46;7032:26;6925:33;:175::i;:::-;6886:23;;:36;;:214;7196:23;;:46;;;7256:26;;;;7296:18;;;;7149:175;;7196:46;7256:26;7149:33;:175::i;:::-;7110:23;;:36;;:214;7462:24;;;;:47;7523:27;;;;7564:19;;;;7415:178;;7462:47;7523:27;7415:33;:178::i;:::-;7375:18;:24;;;:37;;:218;;;;;7643:178;7690:18;:24;;;:47;;;7751:10;:27;;;7792:10;:19;;;7643:33;:178::i;:::-;7603:24;;;;:37;;:218;8004:19;8026:39;:8;8043:21;8026:39;:16;:39;:::i;:::-;8075:23;;:39;;;;:53;;;8138:24;;;;:40;:54;-1:-1:-1;;;;;4804:3462:39;;;;;;;;;:::o;10262:910:2:-;10601:34;;;;10565:71;;:27;;:71;:35;:71;:::i;:::-;10545:6;:17;10552:9;10545:17;;;;;;;;;;;:91;;;;10883:9;10702:5;:25;;;10652:513;;10670:5;:18;;;10652:513;;;10741:5;:20;;;10775:5;:20;;;10809:5;:23;;;10846:5;:23;;;10906:12;10932:10;10956:11;:34;;;11004:11;:34;;;11052:11;:24;;;11090:11;:24;;;11128:11;:27;;;10652:513;;;;;;;;;;;;;;;;;;;;;;;;;10262:910;;;;;:::o;19127:3954:3:-;19466:22;;19526:23;;19593:29;;;;;19667:30;;;;19814:25;;;;19914:23;;:46;;;19751:219;;19786:14;;19526:23;;19466:22;;19751:21;:219::i;:::-;20024:218;20059:13;20086:9;:24;;;20124:16;20154:17;20185:18;:24;;;:47;;;20024:21;:218::i;:::-;20303:221;20338:14;20366:10;:28;;;20408:17;20439:24;20477:18;:24;;;:37;;;20303:21;:221::i;:::-;20583:216;20618:13;20645:9;:27;;;20686:16;20716:23;20753:18;:23;;;:36;;;20583:21;:216::i;:::-;20843:207;20878:13;20905:9;:24;;;20943:16;20973:12;20999:18;:41;;;20843:21;:207::i;:::-;21060:211;21095:14;21123:10;:25;;;21162:17;21193:12;21219:18;:42;;;21060:21;:211::i;:::-;21326:23;21352:224;21385:13;21412:14;21440:18;:23;;;:39;;;21493:16;21523:17;21554:12;21352:19;:224::i;:::-;21326:250;;21678:18;21673:151;;21712:23;;21754:1;21712:39;;;;:43;;;21769:24;;;;:40;;;:44;21673:151;21908:24;21881:51;;:23;:51;;;:131;;;;-1:-1:-1;21983:28:3;;;;;21948:27;;;;:64;;;:34;:64;:::i;:::-;21864:1211;;;22153:283;22192:13;22223:9;:27;;;22268:12;22298:23;22339:83;22384:18;:24;;;:37;;;22339:18;:23;;;:36;;;:44;;:83;;;;:::i;:::-;22153:21;:283::i;:::-;21864:1211;;;22521:240;22560:14;22592:10;:28;;;22638:12;22668:24;22710:18;:24;;;:37;;;22521:21;:240::i;:::-;22828:236;22867:13;22898:9;:27;;;22943:12;22973:23;23014:18;:23;;;:36;;;22828:21;:236::i;:::-;19127:3954;;;;;;;;;;;:::o;2542:1786:43:-;2769:16;;;;;2810;;2868:33;;;;;2930:20;;;;;2749:17;2984:25;;;;3417:11;;3402:13;;;3392:37;;;;3497:9;;1160:66;3520:26;;3647:15;;;3640:29;;;;3757:15;;;3750:46;;;;3884:15;;;3877:33;;;;4035:42;4016:62;;;3998:16;;;3991:88;;;;4129:3;4117:16;;4110:34;4285:3;4267:22;;;2542:1786::o;2889:890:50:-;3318:2;3312:9;3350:66;3335:82;;3467:1;3455:14;;3448:40;;;;3585:2;3573:15;;3566:35;3737:2;3719:21;;;2889:890::o;15868:404:5:-;16106:159;;16063:20;;16142:59;;16106:159;;16215:11;;16240:15;;16106:159;;;;19340:1395;19595:16;;19541:12;;19643:2;19625:20;;19621:278;;;19661:227;19683:204;19737:56;19811:4;19833:13;19864:9;19683:36;:204::i;19661:227::-;20054:24;20081:43;:9;20103:20;;;20081:43;:21;:43;:::i;:::-;20188:32;;;;;;;;:17;:32;;;;;;;;:50;;;;;;;;;;20054:70;;-1:-1:-1;20188:50:5;;20183:240;;20254:158;20276:135;20350:13;20381:16;20276:56;:135::i;20254:158::-;20442:262;20506:16;20536:4;20554:9;20577:2;20442:50;:262::i;:::-;20432:272;19340:1395;-1:-1:-1;;;;;;;19340:1395:5:o;18389:479::-;18565:12;18603:234;18667:13;18694:4;18712:9;18735:1;18603:50;:234::i;1866:135:54:-;1951:7;1985:1;1981;:5;:13;;1993:1;1981:13;;;-1:-1:-1;1989:1:54;;1974:20;-1:-1:-1;1866:135:54:o;2505:1128:39:-;2730:30;;:::i;:::-;2825:34;;;:59;;;3014:22;;;;3050;;;;2931:151;;2862:22;;2931:33;:151::i;:::-;2894:188;;3202:22;;;;3238:14;;;;3119:143;;3166:22;;3119:33;:143::i;:::-;3092:24;;;:170;3382:22;;;;3418:14;;;;3299:143;;3346:22;;3299:33;:143::i;:::-;3272:24;;;:170;3558:39;:8;3575:21;3558:39;:16;:39;:::i;:::-;3528:27;;;:69;2505:1128;;;;;;:::o;15716:1585:2:-;15959:194;15994:9;16017:5;:20;;;16051:12;16077:5;:18;;;16109:11;:34;;;15959:21;:194::i;:::-;16199;16234:9;16257:5;:20;;;16291:5;:18;;;16323:12;16349:11;:34;;;16199:21;:194::i;:::-;16450;16485:9;16508:5;:23;;;16545:12;16571:5;:25;;;16610:11;:24;;;16450:21;:194::i;:::-;16701:200;16736:9;16759:5;:23;;;16796:5;:18;;;16828:5;:25;;;16867:11;:24;;;16701:21;:200::i;:::-;16940:22;16965:153;17000:9;17023:11;:27;;;17064:5;:18;;;17096:12;16965:21;:153::i;:::-;16940:178;;17220:17;17215:80;;17283:1;17253:27;;;:31;15716:1585;;;;;:::o;5172:2665:42:-;5378:20;;;;5438;;;;5501:23;;;;5567;;;;5262:14;;1422:66;;5378:20;;5438;;6471:2;6461:13;;6458:2;;;6493:9;6458:2;6624:14;;;6847:11;;6674:3;6663:15;;6884:11;;6714:3;6703:15;;6921:11;;6754:3;6743:15;;6958:11;;6794:3;6783:15;;6995:11;;7049:24;;;7134:21;;6635:2;7109:23;;;7099:57;7086:71;;7257:21;;7232:23;;;7222:57;;;;7209:71;;7383:24;;7355:26;;;7345:63;;;;7332:77;;7509:24;;7481:26;;;;7471:63;;;;7458:77;;7610:3;7594:20;;7651:19;;;;7683;;7715;;;7747;;7779;;;;7594:20;-1:-1:-1;5172:2665:42;;;:::o;15379:338:5:-;15575:135;;15532:20;;15611:47;;15575:135;;15672:5;;15691:9;;15575:135;;;;11442:385:38;11635:12;3252:10;11706:35;;11755:9;11778;11801;11670:150;;;;;;;;;;;16814:871:47;16934:13;16978:5;16986:1;16978:9;16967:1;:8;:20;16963:290;;;17003:239;17025:216;17087:87;17192:1;:8;17218:5;17226:1;17218:9;17025:44;:216::i;17003:239::-;-1:-1:-1;17426:13:47;17329:2;17426:13;17420:20;17579:66;17567:79;;16814:871::o;11833:369:38:-;12010:12;3413:10;12081:35;;12130:9;12153;12176;12045:150;;;;;;;;;;;12532:319;12685:12;3700:10;12756:26;;12796:9;12819:15;12720:124;;;;;;;;;;13192:397;13378:12;4029:10;13449:36;;13499:15;13528:14;13556:16;13413:169;;;;;;;;;;;13595:359;13760:12;4200:10;13831:42;;13887:15;13916:21;13795:152;;;;;;;;;;10039:395;10233:12;2666:10;10304:39;;10357:9;10380;10403:14;10268:159;;;;;;;;;;;1292:378:48;1480:12;1232:10;1551:37;;1602:9;1625:6;1645:8;1515:148;;;;;;;;;;;18060:153:47;18180:17;;18166:41::o;9306:410:38:-;9506:12;2355:10;9577:31;;9622:4;9640:13;9667:9;9690;9541:168;;;;;;;;;;;;9722:311;9870:12;2495:10;9941:27;;9982:9;10005:11;9905:121;;;;;;;;;;12208:318;12353:12;3561:10;12424:30;;12468:13;12495:14;12388:131;;;;;;;;;;1141:603:40;1309:21;1350:110;1388:9;1415:11;1444:6;1350:20;:110::i;:::-;1346:289;;;1476:148;1498:125;1547:9;1574:11;1603:6;1498:31;:125::i;1476:148::-;1661:46;1695:11;1661:25;:9;1679:6;1661:25;:17;:25;:::i;14339:4364:39:-;14717:44;;:::i;:::-;14945:62;;;15055;;;16229;;;16225:1694;;;16423:164;16468:9;16495:30;16543;16423:27;:164::i;:::-;16402:185;;16225:1694;;;16641:29;16608:30;:62;16604:1315;;;16782:23;;:78;;;16874:23;;:46;;:78;;;17334:27;;;;17379;;;;17283:184;;17334:27;16831:29;17283:33;:184::i;:::-;17233:24;;;;;;:234;;;;17481:24;;:47;:79;;;16604:1315;;;17678:230;17722:29;17769;17816:30;17864;17678:26;:230::i;:::-;17657:251;;16604:1315;18055:29;18051:237;;;18216:24;;;;;:47;;18144:23;;:46;:133;;;:54;:133;:::i;:::-;18100:41;;;:177;18051:237;18426:30;18422:239;;;18590:23;;:46;;;;;18517:24;;;;:47;:133;;;:55;:133;:::i;:::-;18472:42;;;:178;18422:239;-1:-1:-1;;14339:4364:39;;;;;;;;;:::o;10157:3363::-;10520:44;;:::i;:::-;11497:30;11465:29;:62;11461:1794;;;11615:164;11660:9;11687:30;11735;11615:27;:164::i;:::-;11594:185;;11461:1794;;;11832:30;11800:29;:62;11796:1459;;;11928:23;;:78;;;12020:23;;:46;;;;:78;;;12112:24;;;:79;;;12489:27;;;;12534;;;;12439:234;;12489:27;12069:29;12439:32;:234::i;:::-;12389:24;;;;;:47;:284;11796:1459;;;13014:230;13058:29;13105;13152:30;13200;13014:26;:230::i;:::-;12993:251;;11796:1459;13420:24;;;;;:47;;13352:23;;:46;:125;;;:54;:125;:::i;:::-;13308:41;;;:169;10157:3363;;;;;;;;:::o;4198:1259:4:-;4487:20;;4444:4;;4487:20;;4521:26;;4517:934;;4726:4;4718:21;4692:23;4835:224;4882:10;4910:12;4718:21;4973:11;5002:13;5033:12;4835:29;:224::i;:::-;4815:244;;5136:236;5183:10;5211:12;5259:9;5241:15;:27;5286:11;5315:13;5346:12;5136:29;:236::i;:::-;;5393:4;5386:11;;;;;;;4517:934;5435:5;5428:12;;;;;10136:403:47;10257:10;10486:3;:10;10472:3;:10;:24;:60;;;;-1:-1:-1;;10518:14:47;;;;;;;10500;;;;;;;;;;:32;;10136:403::o;10753:1071::-;10874:14;10919:5;10927:2;10919:10;10908:1;:8;:21;10904:321;;;10945:269;10967:246;11029:89;11136:1;:8;11162:5;11170:2;11162:10;10967:44;:246::i;10945:269::-;-1:-1:-1;11726:13:47;11471:2;11726:13;11720:20;11742:42;11716:69;;10753:1071::o;8501:354:38:-;8663:12;2031:10;8734:47;;8795:13;8822:16;8698:150;;;;;;;;;;21335:1353:5;21678:16;;21590:4;;21759:65;21678:9;21781:42;;;21759:65;:21;:65;:::i;:::-;21858:139;;21834:21;;21894:52;;21858:139;;21960:4;;21978:9;;21858:139;;;;;;;;22:32:-1;26:21;;;22:32;6:49;;21858:139:5;;;49:4:-1;25:18;;61:17;;21858:139:5;182:15:-1;21858:139:5;;;;179:29:-1;;;;160:49;;;21858:139:5;-1:-1:-1;22052:38:5;:9;22074:15;22052:38;:21;:38;:::i;:::-;22150:15;22167:23;22194:24;:35;;22230:8;22194:45;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;22149:90:5;;;;22328:10;:37;;;;;22342:10;:17;22363:2;22342:23;22328:37;22324:122;;;22416:19;22388:24;:10;22410:1;22388:24;:21;:24;:::i;:::-;:47;;;;22381:54;;;;;;;;22324:122;22502:179;22524:156;22581:24;22619:4;22637:9;22660:10;22524:43;:156::i;22502:179::-;21335:1353;;;;;;;;;;:::o;3039:619:4:-;3269:20;;3226:4;;3269:20;;3303:26;;3299:353;;3345:228;3392:9;3419:12;3457:4;3449:21;3488:11;3517:12;3547;3345:29;:228::i;:::-;;3594:4;3587:11;;;;;3299:353;3636:5;3629:12;;;;;4566:1880:40;4729:12;4761:16;4757:109;;4793:62;4815:39;:37;:39::i;4793:62::-;5676:11;;;:29;;-1:-1:-1;5691:14:40;;5676:29;5672:72;;;-1:-1:-1;5728:5:40;5721:12;;5672:72;6239:17;6322:11;6259:84;;;;;6299:9;6279:6;6259:84;6239:104;-1:-1:-1;6390:25:40;:9;6408:6;6390:25;:17;:25;:::i;:::-;6363:23;:9;6381:4;6363:23;:17;:23;:::i;:::-;:52;;;4566:1880;-1:-1:-1;;;;;4566:1880:40:o;520:335:41:-;676:12;312:10;747:23;;784:9;807:11;832:6;711:137;;;;;;;;;;;20995:1066:39;21221:44;;:::i;:::-;21281:24;;;;;;:80;;;21371:24;:47;;:80;;;21461:23;;:46;:79;;;21898:26;;;;21938;;;;21851:167;;21898:26;21331:30;21851:33;:167::i;:::-;21802:23;;:216;20995:1066;;;;;:::o;19492:790::-;19770:44;;:::i;:::-;19893:23;;:78;;;;19981:23;;:46;;;;:78;;;;20069:24;;;;;:80;;;;20159:24;;:47;;;:80;19893:23;19492:790::o;2067:847:40:-;2234:21;2275:109;2312:9;2339:11;2368:6;2275:19;:109::i;:::-;2271:288;;;2400:148;2422:125;2471:9;2498:11;2527:6;2422:31;:125::i;2400:148::-;2772:104;2864:11;2772:70;2819:22;2864:11;2839:1;2819:22;:19;:22;:::i;5935:1219:4:-;6193:17;6414:11;6395:15;:30;6391:84;;-1:-1:-1;6453:11:4;6391:84;6518:167;;6484:31;;6554:44;;6518:167;;6612:12;;6638;;6664:11;;6518:167;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;6518:167:4;;;;;;;38:4:-1;29:7;25:18;67:10;61:17;96:58;199:8;192:4;186;182:15;179:29;167:10;160:49;0:215;;;6518:167:4;6484:201;;6750:15;6767:23;6794:12;:17;;6818:9;6829:18;6794:54;;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;6749:99:4;;;;6863:10;6858:264;;6889:222;6911:199;6970:9;6997:11;7026:12;7056;7086:10;6911:41;:199::i;6889:222::-;-1:-1:-1;;;5935:1219:4;;;;;;;;:::o;8861:439:38:-;9078:12;2193:10;9149:32;;9195:24;9233:4;9251:9;9274;9113:180;;;;;;;;;;;;372:142:41;485:22;;;;;;;;;;;;;;;;;372:142;:::o;6703:937:40:-;6865:12;6897:16;6893:109;;6929:62;6951:39;:37;:39::i;6929:62::-;7066:11;;;:29;;-1:-1:-1;7081:14:40;;7066:29;7062:257;;;-1:-1:-1;7303:5:40;7296:12;;7062:257;7367:17;7450:11;7387:84;;;;;7427:9;7407:6;7387:84;7367:104;-1:-1:-1;7526:11:40;7493:30;7526:11;7367:104;7493:30;:19;:30;:::i;:::-;:44;;;;;;;-1:-1:-1;7584:25:40;:9;7602:6;7584:25;:17;:25;:::i;14384:472:38:-;14614:12;4668:10;14685:31;;14730:9;14753:11;14778:12;14804;14830:9;14649:200;;;;;;;;;;;;;;;;;22:32:-1;26:21;;;22:32;6:49;;14649:200:38;;;49:4:-1;25:18;;61:17;;14649:200:38;182:15:-1;14649:200:38;;;;179:29:-1;;;;160:49;;;14649:200:38;-1:-1:-1;14384:472:38;;;;;;;:::o;1022:384:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;-1:-1:-1;1022:384:0;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;5:130:-1:-;72:20;;73571:42;73560:54;;77482:35;;77472:2;;77531:1;;77521:12;160:707;;277:3;270:4;262:6;258:17;254:27;244:2;;-1:-1;;285:12;244:2;332:6;319:20;354:80;369:64;426:6;369:64;;;354:80;;;462:21;;;345:89;-1:-1;506:4;519:14;;;;494:17;;;608;;;599:27;;;;596:36;-1:-1;593:2;;;645:1;;635:12;593:2;670:1;655:206;680:6;677:1;674:13;655:206;;;760:37;793:3;781:10;760:37;;;748:50;;812:14;;;;840;;;;702:1;695:9;655:206;;;659:14;;;;;237:630;;;;;891:693;;1013:3;1006:4;998:6;994:17;990:27;980:2;;-1:-1;;1021:12;980:2;1068:6;1055:20;1090:85;1105:69;1167:6;1105:69;;1090:85;1203:21;;;1081:94;-1:-1;1247:4;1260:14;;;;1235:17;;1355:1;1340:238;1365:6;1362:1;1359:13;1340:238;;;1472:42;1510:3;1247:4;1448:3;1435:17;1239:6;1423:30;;1472:42;;;1460:55;;1247:4;1529:14;;;;1557;;;;;1387:1;1380:9;1340:238;;;1344:14;;;;973:611;;;;;1624:735;;1760:3;1753:4;1745:6;1741:17;1737:27;1727:2;;-1:-1;;1768:12;1727:2;1815:6;1802:20;1837:99;1852:83;1928:6;1852:83;;1837:99;1964:21;;;1828:108;-1:-1;2008:4;2021:14;;;;1996:17;;2116:1;2101:252;2126:6;2123:1;2120:13;2101:252;;;2233:56;2285:3;2008:4;2209:3;2196:17;2000:6;2184:30;;2233:56;;;2221:69;;2008:4;2304:14;;;;2332;;;;;2148:1;2141:9;2101:252;;3220:707;;3337:3;3330:4;3322:6;3318:17;3314:27;3304:2;;-1:-1;;3345:12;3304:2;3392:6;3379:20;3414:80;3429:64;3486:6;3429:64;;3414:80;3522:21;;;3405:89;-1:-1;3566:4;3579:14;;;;3554:17;;;3668;;;3659:27;;;;3656:36;-1:-1;3653:2;;;3705:1;;3695:12;3653:2;3730:1;3715:206;3740:6;3737:1;3734:13;3715:206;;;14167:20;;3808:50;;3872:14;;;;3900;;;;3762:1;3755:9;3715:206;;4478:432;;4575:3;4568:4;4560:6;4556:17;4552:27;4542:2;;-1:-1;;4583:12;4542:2;4630:6;4617:20;67985:18;67977:6;67974:30;67971:2;;;-1:-1;;68007:12;67971:2;4652:60;68148:4;68080:9;4568:4;68065:6;68061:17;68057:33;68138:15;4652:60;;;4643:69;;4732:6;4725:5;4718:21;4836:3;68148:4;4827:6;4760;4818:16;;4815:25;4812:2;;;4853:1;;4843:12;4812:2;75761:6;68148:4;4760:6;4756:17;68148:4;4794:5;4790:16;75738:30;75817:1;75799:16;;;68148:4;75799:16;75792:27;4794:5;4535:375;-1:-1;;4535:375;6470:2705;;6578:5;;6566:9;6561:3;6557:19;6553:31;6550:2;;;-1:-1;;6587:12;6550:2;6615:21;6578:5;6615:21;;;6606:30;;;6725:49;6770:3;6746:22;6725:49;;;6708:15;6701:74;6877:49;6922:3;6844:2;6902:9;6898:22;6877:49;;;6844:2;6863:5;6859:16;6852:75;7036:49;7081:3;7003:2;7061:9;7057:22;7036:49;;;7003:2;7022:5;7018:16;7011:75;7189:49;7234:3;7156:2;7214:9;7210:22;7189:49;;;7156:2;7175:5;7171:16;7164:75;7312:3;7371:9;7367:22;14167:20;7312:3;7332:5;7328:16;7321:75;7469:3;7528:9;7524:22;14167:20;7469:3;7489:5;7485:16;7478:75;7618:3;7677:9;7673:22;14167:20;7618:3;7638:5;7634:16;7627:75;7767:3;7826:9;7822:22;14167:20;7767:3;7787:5;7783:16;7776:75;7929:3;;7989:9;7985:22;14167:20;7929:3;7949:5;7945:17;7938:76;;8075:3;;8135:9;8131:22;14167:20;8075:3;8095:5;8091:17;8084:76;;8259:3;;8248:9;8244:19;8231:33;8284:18;;8276:6;8273:30;8270:2;;;6694:1;;8306:12;8270:2;8352:54;8402:3;8393:6;8382:9;8378:22;8352:54;;;8259:3;8337:5;8333:17;8326:81;8506:3;;;;8495:9;8491:19;8478:33;8464:47;;8284:18;8523:6;8520:30;8517:2;;;6694:1;;8553:12;8517:2;8599:54;8649:3;8640:6;8629:9;8625:22;8599:54;;;8506:3;8584:5;8580:17;8573:81;8756:3;;;;8745:9;8741:19;8728:33;8714:47;;8284:18;8773:6;8770:30;8767:2;;;6694:1;;8803:12;8767:2;8849:54;8899:3;8890:6;8879:9;8875:22;8849:54;;;8756:3;8834:5;8830:17;8823:81;9006:3;;;;8995:9;8991:19;8978:33;8964:47;;8284:18;9023:6;9020:30;9017:2;;;6694:1;;9053:12;9017:2;;9099:54;9149:3;9140:6;9129:9;9125:22;9099:54;;;9006:3;9084:5;9080:17;9073:81;;;6544:2631;;;;;11978:1026;;12098:4;12086:9;12081:3;12077:19;12073:30;12070:2;;;-1:-1;;12106:12;12070:2;12134:20;12098:4;12134:20;;;12125:29;;14180:6;14167:20;12218:15;12211:74;12363:2;12421:9;12417:22;14167:20;12363:2;12382:5;12378:16;12371:75;12511:2;12569:9;12565:22;14167:20;12511:2;12530:5;12526:16;12519:75;12664:2;12722:9;12718:22;72:20;97:33;124:5;97:33;;;12664:2;12679:16;;12672:75;12836:3;12821:19;;12808:33;12861:18;12850:30;;12847:2;;;-1:-1;;12883:12;12847:2;12928:54;12978:3;12969:6;12958:9;12954:22;12928:54;;;12836:3;12914:5;12910:16;12903:80;;12064:940;;;;;14378:241;;14482:2;14470:9;14461:7;14457:23;14453:32;14450:2;;;-1:-1;;14488:12;14450:2;14550:53;14595:7;14571:22;14550:53;;14626:366;;;14747:2;14735:9;14726:7;14722:23;14718:32;14715:2;;;-1:-1;;14753:12;14715:2;14815:53;14860:7;14836:22;14815:53;;;14805:63;;14923:53;14968:7;14905:2;14948:9;14944:22;14923:53;;;14913:63;;14709:283;;;;;;14999:360;;;15117:2;15105:9;15096:7;15092:23;15088:32;15085:2;;;-1:-1;;15123:12;15085:2;15185:53;15230:7;15206:22;15185:53;;;15175:63;;15275:2;15315:9;15311:22;3999:20;77628:5;71735:13;71728:21;77606:5;77603:32;77593:2;;-1:-1;;77639:12;77593:2;15283:60;;;;15079:280;;;;;;15366:1171;;;;;15626:3;15614:9;15605:7;15601:23;15597:33;15594:2;;;-1:-1;;15633:12;15594:2;15691:17;15678:31;15729:18;;15721:6;15718:30;15715:2;;;-1:-1;;15751:12;15715:2;15781:83;15856:7;15847:6;15836:9;15832:22;15781:83;;;15771:93;;15929:2;15918:9;15914:18;15901:32;15887:46;;15729:18;15945:6;15942:30;15939:2;;;-1:-1;;15975:12;15939:2;16005:78;16075:7;16066:6;16055:9;16051:22;16005:78;;;15995:88;;16148:2;16137:9;16133:18;16120:32;16106:46;;15729:18;16164:6;16161:30;16158:2;;;-1:-1;;16194:12;16158:2;16224:78;16294:7;16285:6;16274:9;16270:22;16224:78;;;16214:88;;16367:2;16356:9;16352:18;16339:32;16325:46;;15729:18;16383:6;16380:30;16377:2;;;-1:-1;;16413:12;16377:2;;16443:78;16513:7;16504:6;16493:9;16489:22;16443:78;;;16433:88;;;15588:949;;;;;;;;16544:415;;16692:2;16680:9;16671:7;16667:23;16663:32;16660:2;;;-1:-1;;16698:12;16660:2;16756:17;16743:31;16794:18;16786:6;16783:30;16780:2;;;-1:-1;;16816:12;16780:2;16846:97;16935:7;16926:6;16915:9;16911:22;16846:97;;16966:1257;;;;;17269:3;17257:9;17248:7;17244:23;17240:33;17237:2;;;-1:-1;;17276:12;17237:2;17334:17;17321:31;17372:18;;17364:6;17361:30;17358:2;;;-1:-1;;17394:12;17358:2;17424:97;17513:7;17504:6;17493:9;17489:22;17424:97;;;17414:107;;17586:2;17575:9;17571:18;17558:32;17544:46;;17372:18;17602:6;17599:30;17596:2;;;-1:-1;;17632:12;17596:2;17662:97;17751:7;17742:6;17731:9;17727:22;17662:97;;;17652:107;;17824:2;17813:9;17809:18;17796:32;17782:46;;17372:18;17840:6;17837:30;17834:2;;;-1:-1;;17870:12;17834:2;17900:83;17975:7;17966:6;17955:9;17951:22;17900:83;;;17890:93;;18048:2;18037:9;18033:18;18020:32;18006:46;;17372:18;18064:6;18061:30;18058:2;;;-1:-1;;18094:12;18058:2;;18124:83;18199:7;18190:6;18179:9;18175:22;18124:83;;18230:947;;;;18467:2;18455:9;18446:7;18442:23;18438:32;18435:2;;;-1:-1;;18473:12;18435:2;18531:17;18518:31;18569:18;;18561:6;18558:30;18555:2;;;-1:-1;;18591:12;18555:2;18621:97;18710:7;18701:6;18690:9;18686:22;18621:97;;;18611:107;;18783:2;18772:9;18768:18;18755:32;18741:46;;18569:18;18799:6;18796:30;18793:2;;;-1:-1;;18829:12;18793:2;18859:78;18929:7;18920:6;18909:9;18905:22;18859:78;;;18849:88;;19002:2;18991:9;18987:18;18974:32;18960:46;;18569:18;19018:6;19015:30;19012:2;;;-1:-1;;19048:12;19012:2;;19078:83;19153:7;19144:6;19133:9;19129:22;19078:83;;;19068:93;;;18429:748;;;;;;19184:811;;;;19396:2;19384:9;19375:7;19371:23;19367:32;19364:2;;;-1:-1;;19402:12;19364:2;19460:17;19447:31;19498:18;;19490:6;19487:30;19484:2;;;-1:-1;;19520:12;19484:2;19550:97;19639:7;19630:6;19619:9;19615:22;19550:97;;;19540:107;;19684:2;19727:9;19723:22;14167:20;19692:63;;19820:2;19809:9;19805:18;19792:32;19778:46;;19498:18;19836:6;19833:30;19830:2;;;-1:-1;;19866:12;20002:710;;;20209:2;20197:9;20188:7;20184:23;20180:32;20177:2;;;-1:-1;;20215:12;20177:2;20273:17;20260:31;20311:18;;20303:6;20300:30;20297:2;;;-1:-1;;20333:12;20297:2;20455:6;20444:9;20440:22;2571:3;2564:4;2556:6;2552:17;2548:27;2538:2;;-1:-1;;2579:12;2538:2;2626:6;2613:20;2599:34;;2648:111;2663:95;2751:6;2663:95;;2648:111;2787:21;;;2831:4;2844:14;;;;2765:16;2819:17;;;-1:-1;2924:264;2949:6;2946:1;2943:13;2924:264;;;3056:68;3120:3;2831:4;3032:3;3019:17;2823:6;3007:30;;3056:68;;;3044:81;;3139:14;;;;3167;;;;2971:1;2964:9;2924:264;;;-1:-1;20353:119;;-1:-1;20522:18;;20509:32;;-1:-1;;;;20550:30;;;20547:2;;;-1:-1;;20583:12;20547:2;;20613:83;20688:7;20679:6;20668:9;20664:22;20613:83;;;20603:93;;;20171:541;;;;;;20719:241;;20823:2;20811:9;20802:7;20798:23;20794:32;20791:2;;;-1:-1;;20829:12;20791:2;-1:-1;4133:20;;20785:175;-1:-1;20785:175;20967:366;;;21088:2;21076:9;21067:7;21063:23;21059:32;21056:2;;;-1:-1;;21094:12;21056:2;4146:6;4133:20;21146:63;;21246:2;21289:9;21285:22;72:20;97:33;124:5;97:33;;21340:595;;;;21487:2;21475:9;21466:7;21462:23;21458:32;21455:2;;;-1:-1;;21493:12;21455:2;4146:6;4133:20;21545:63;;21645:2;21688:9;21684:22;72:20;97:33;124:5;97:33;;;21653:63;-1:-1;21781:2;21766:18;;21753:32;21805:18;21794:30;;21791:2;;;-1:-1;;21827:12;21791:2;21857:62;21911:7;21902:6;21891:9;21887:22;21857:62;;21942:239;;22045:2;22033:9;22024:7;22020:23;22016:32;22013:2;;;-1:-1;;22051:12;22013:2;4282:6;4269:20;4294:32;4320:5;4294:32;;22188:261;;22302:2;22290:9;22281:7;22277:23;22273:32;22270:2;;;-1:-1;;22308:12;22270:2;4421:6;4415:13;4433:32;4459:5;4433:32;;22456:314;;22596:3;22584:9;22575:7;22571:23;22567:33;;22564:2;;;-1:-1;;22603:12;22564:2;5507:30;5504:2;;;-1:-1;;5540:12;5504:2;;5568:20;22596:3;5568:20;;;5719:22;14315:13;5670:15;5663:85;5827:2;5896:9;5892:22;14315:13;5827:2;5846:5;5842:16;5835:86;5990:2;6059:9;6055:22;14315:13;5990:2;6009:5;6005:16;5998:86;6153:2;6222:9;6218:22;14315:13;6153:2;6172:5;6168:16;6161:86;6319:3;6389:9;6385:22;14315:13;6319:3;6339:5;6335:16;6328:86;22655:99;;;;22558:212;;;;;22777:373;;22904:2;22892:9;22883:7;22879:23;22875:32;22872:2;;;-1:-1;;22910:12;22872:2;22968:17;22955:31;23006:18;22998:6;22995:30;22992:2;;;-1:-1;;23028:12;22992:2;23058:76;23126:7;23117:6;23106:9;23102:22;23058:76;;23157:602;;;23310:2;23298:9;23289:7;23285:23;23281:32;23278:2;;;-1:-1;;23316:12;23278:2;23374:17;23361:31;23412:18;;23404:6;23401:30;23398:2;;;-1:-1;;23434:12;23398:2;23464:76;23532:7;23523:6;23512:9;23508:22;23464:76;;;23454:86;;23605:2;23594:9;23590:18;23577:32;23563:46;;23412:18;23621:6;23618:30;23615:2;;;-1:-1;;23651:12;23615:2;;23681:62;23735:7;23726:6;23715:9;23711:22;23681:62;;23766:1089;;;;;23985:3;23973:9;23964:7;23960:23;23956:33;23953:2;;;-1:-1;;23992:12;23953:2;24050:17;24037:31;24088:18;;24080:6;24077:30;24074:2;;;-1:-1;;24110:12;24074:2;24140:76;24208:7;24199:6;24188:9;24184:22;24140:76;;;24130:86;;24281:2;24270:9;24266:18;24253:32;24239:46;;24088:18;24297:6;24294:30;24291:2;;;-1:-1;;24327:12;24291:2;24357:76;24425:7;24416:6;24405:9;24401:22;24357:76;;;24347:86;;24498:2;24487:9;24483:18;24470:32;24456:46;;24088:18;24514:6;24511:30;24508:2;;;-1:-1;;24544:12;24508:2;24574:62;24628:7;24619:6;24608:9;24604:22;24574:62;;;24564:72;;24701:2;24690:9;24686:18;24673:32;24659:46;;24088:18;24717:6;24714:30;24711:2;;;-1:-1;;24747:12;24711:2;;24777:62;24831:7;24822:6;24811:9;24807:22;24777:62;;24862:727;;;;25032:2;25020:9;25011:7;25007:23;25003:32;25000:2;;;-1:-1;;25038:12;25000:2;25096:17;25083:31;25134:18;;25126:6;25123:30;25120:2;;;-1:-1;;25156:12;25120:2;25186:76;25254:7;25245:6;25234:9;25230:22;25186:76;;;25176:86;;25299:2;25342:9;25338:22;14167:20;25307:63;;25435:2;25424:9;25420:18;25407:32;25393:46;;25134:18;25451:6;25448:30;25445:2;;;-1:-1;;25481:12;25445:2;;25511:62;25565:7;25556:6;25545:9;25541:22;25511:62;;25596:626;;;25761:2;25749:9;25740:7;25736:23;25732:32;25729:2;;;-1:-1;;25767:12;25729:2;25825:17;25812:31;25863:18;;25855:6;25852:30;25849:2;;;-1:-1;;25885:12;25849:2;25915:88;25995:7;25986:6;25975:9;25971:22;25915:88;;27098:103;73571:42;73560:54;27159:37;;27153:48;28334:890;;28602:5;69131:12;70290:6;70285:3;70278:19;70327:4;70322:3;70318:14;28614:118;;70327:4;28828:5;68618:14;-1:-1;28867:335;28892:6;28889:1;28886:13;28867:335;;;26801:100;26897:3;28959:6;28953:13;26801:100;;;26930:4;26921:14;;;;;70327:4;69852:14;;;;;28914:1;28907:9;28867:335;;;-1:-1;29208:10;;28508:716;-1:-1;;;;28508:716;30794:343;;30936:5;69131:12;70290:6;70285:3;70278:19;31029:52;31074:6;70327:4;70322:3;70318:14;70327:4;31055:5;31051:16;31029:52;;;76279:2;76259:14;76275:7;76255:28;31093:39;;;;70327:4;31093:39;;30884:253;-1:-1;;30884:253;36319:1007;36560:15;36554:22;30356:3;30349:37;36741:4;36734:5;36730:16;36724:23;36741:4;36805:3;36801:14;30349:37;36903:4;36896:5;36892:16;36886:23;36903:4;36967:3;36963:14;30349:37;37065:4;37058:5;37054:16;37048:23;37065:4;37129:3;37125:14;30349:37;37230:4;37223:5;37219:16;37213:23;37230:4;37294:3;37290:14;30349:37;36443:883;;;40245:2765;;40392:5;40495:62;40543:13;40473:15;40467:22;40495:62;;;40644:4;40637:5;40633:16;40627:23;40656:63;40644:4;40708:3;40704:14;40690:12;40656:63;;;;40813:4;40806:5;40802:16;40796:23;40825:63;40813:4;40877:3;40873:14;40859:12;40825:63;;;;40976:4;40969:5;40965:16;40959:23;40988:63;40976:4;41040:3;41036:14;41022:12;40988:63;;;;41142:4;41135:5;41131:16;41125:23;41142:4;41206:3;41202:14;30349:37;41308:4;41301:5;41297:16;41291:23;41308:4;41372:3;41368:14;30349:37;41466:4;41459:5;41455:16;41449:23;41466:4;41530:3;41526:14;30349:37;41624:4;41617:5;41613:16;41607:23;41624:4;41688:3;41684:14;30349:37;41795:5;;41788;41784:17;41778:24;41795:5;41860:3;41856:15;30349:37;;41951:5;;41944;41940:17;41934:24;41951:5;42016:3;42012:15;30349:37;;42117:5;;42110;42106:17;42100:24;40392:5;42117;42148:3;42144:15;42137:39;42191:67;40392:5;40387:3;40383:15;42239:12;42191:67;;;42183:75;;;42353:5;;;;42346;42342:17;42336:24;42407:3;42401:4;42397:14;42353:5;42384:3;42380:15;42373:39;42427:67;42489:4;42475:12;42427:67;;;42419:75;;;;42592:5;;42585;42581:17;42575:24;42646:3;42640:4;42636:14;42592:5;42623:3;42619:15;42612:39;42666:67;42728:4;42714:12;42666:67;;;42658:75;;;42831:5;;;;42824;42820:17;42814:24;42885:3;42879:4;42875:14;42831:5;42862:3;42858:15;42851:39;42905:67;42967:4;42953:12;42905:67;;44648:254;;31304:5;69131:12;31415:52;31460:6;31455:3;31448:4;31441:5;31437:16;31415:52;;;31479:16;;;;;44769:133;-1:-1;;44769:133;45178:511;34474:66;34454:87;;34438:2;34560:12;;30349:37;;;;45652:12;;;45386:303;45696:213;73571:42;73560:54;;;;27159:37;;45814:2;45799:18;;45785:124;45916:324;73571:42;73560:54;;;27159:37;;73560:54;;46226:2;46211:18;;27159:37;46062:2;46047:18;;46033:207;46247:435;73571:42;73560:54;;;27159:37;;73560:54;;;;46585:2;46570:18;;27159:37;46668:2;46653:18;;30349:37;;;;46421:2;46406:18;;46392:290;46689:799;;73571:42;73564:5;73560:54;27166:3;27159:37;46945:3;47064:2;47053:9;47049:18;47042:48;47104:76;46945:3;46934:9;46930:19;47166:6;47104:76;;;47228:9;47222:4;47218:20;47213:2;47202:9;47198:18;47191:48;47253:76;47324:4;47315:6;47253:76;;;47377:9;47371:4;47367:20;47362:2;47351:9;47347:18;47340:48;47402:76;47473:4;47464:6;47402:76;;;47394:84;46916:572;-1:-1;;;;;;;;46916:572;47495:381;;47673:2;;47662:9;47658:18;47673:2;47694:17;47687:47;47748:118;27563:5;69131:12;70290:6;70285:3;70278:19;70318:14;47662:9;70318:14;27575:98;;70318:14;47673:2;27730:6;27726:17;47662:9;27717:27;;27705:39;;47673:2;27820:5;68618:14;-1:-1;27859:345;27884:6;27881:1;27878:13;27859:345;;;27936:20;47662:9;27940:4;27936:20;;27931:3;27924:33;26589:60;26645:3;27991:6;27985:13;26589:60;;;28005:82;-1:-1;28183:14;;;;69852;;;;27906:1;27899:9;27859:345;;;-1:-1;47740:126;;47644:232;-1:-1;;;;;;;47644:232;47883:461;;48101:2;48122:17;48115:47;48176:158;48101:2;48090:9;48086:18;48320:6;48176:158;;48351:201;71735:13;;71728:21;30242:34;;48463:2;48448:18;;48434:118;48559:213;30349:37;;;48677:2;48662:18;;48648:124;48779:324;30349:37;;;73571:42;73560:54;49089:2;49074:18;;27159:37;48925:2;48910:18;;48896:207;49110:715;;30379:5;30356:3;30349:37;73571:42;27189:5;73560:54;49513:2;49502:9;49498:18;27159:37;49348:3;49550:2;49539:9;49535:18;49528:48;49590:76;49348:3;49337:9;49333:19;49652:6;49590:76;;;49714:9;49708:4;49704:20;49699:2;49688:9;49684:18;49677:48;49739:76;49810:4;49801:6;49739:76;;49832:324;30349:37;;;50142:2;50127:18;;30349:37;49978:2;49963:18;;49949:207;50163:408;;30379:5;30356:3;30349:37;50327:2;50445;50434:9;50430:18;50423:48;50485:76;50327:2;50316:9;50312:18;50547:6;50485:76;;50578:603;;30379:5;30356:3;30349:37;50788:2;50906;50895:9;50891:18;50884:48;50946:76;50788:2;50777:9;50773:18;51008:6;50946:76;;;51070:9;51064:4;51060:20;51055:2;51044:9;51040:18;51033:48;51095:76;51166:4;51157:6;51095:76;;51188:352;30349:37;;;51348:2;51333:18;;73111:49;73154:5;73111:49;;;75058:40;51526:2;51515:9;51511:18;33743:64;51319:221;;;;;;51547:743;;30379:5;30356:3;30349:37;30379:5;51960:2;51949:9;51945:18;30349:37;73571:42;;73564:5;73560:54;52043:2;52032:9;52028:18;27159:37;73571:42;73564:5;73560:54;52126:2;52115:9;52111:18;27159:37;;51795:3;52163;52152:9;52148:19;52141:49;52204:76;51795:3;51784:9;51780:19;52266:6;52204:76;;52297:435;30349:37;;;52635:2;52620:18;;30349:37;;;;52718:2;52703:18;;30349:37;52471:2;52456:18;;52442:290;52739:539;30349:37;;;73776:4;73765:16;;;;53098:2;53083:18;;44487:35;53181:2;53166:18;;30349:37;53264:2;53249:18;;30349:37;52937:3;52922:19;;52908:370;53285:209;71912:66;71901:78;;;;30746:36;;53401:2;53386:18;;53372:122;53501:320;71912:66;71901:78;;;;30746:36;;73571:42;73560:54;53807:2;53792:18;;27159:37;53645:2;53630:18;;53616:205;53828:297;;53964:2;53985:17;53978:47;54039:76;53964:2;53953:9;53949:18;54101:6;54039:76;;54132:631;;54352:3;54374:17;54367:47;54428:76;54352:3;54341:9;54337:19;54490:6;54428:76;;;73571:42;73560:54;;;54583:2;54568:18;;27159:37;73560:54;;;;54666:2;54651:18;;27159:37;54749:2;54734:18;30349:37;54420:84;54323:440;-1:-1;;54323:440;54770:492;;54952:2;54973:17;54966:47;55027:76;54952:2;54941:9;54937:18;55089:6;55027:76;;;55151:9;55145:4;55141:20;55136:2;55125:9;55121:18;55114:48;55176:76;55247:4;55238:6;55176:76;;55269:603;;55479:2;55500:17;55493:47;55554:72;55479:2;55468:9;55464:18;55612:6;55554:72;;;55674:9;55668:4;55664:20;55659:2;55648:9;55644:18;55637:48;55699:72;55766:4;55757:6;55699:72;;;55691:80;;;73571:42;73564:5;73560:54;55858:2;55847:9;55843:18;27028:58;55450:422;;;;;;;55879:1653;;56342:3;;56364:17;56357:47;56418:72;56342:3;56331:9;56327:19;56476:6;56418:72;;;56538:9;56532:4;56528:20;56523:2;56512:9;56508:18;56501:48;56563:72;56630:4;56621:6;56563:72;;;56555:80;;;56683:9;56677:4;56673:20;56668:2;56657:9;56653:18;56646:48;56708:72;56775:4;56766:6;56708:72;;;56828:9;56822:4;56818:20;56813:2;56802:9;56798:18;56791:48;56853:72;56920:4;56911:6;56853:72;;;73571:42;73560:54;;;57004:3;56989:19;;27159:37;73560:54;;;;57096:3;57081:19;;27028:58;-1:-1;;57180:3;57165:19;;30349:37;;;;57264:3;57249:19;;30349:37;;;;57348:3;57333:19;;30349:37;;;;57432:3;57417:19;;30349:37;57517:3;57502:19;;;30349:37;56845:80;56313:1219;-1:-1;;;;;56313:1219;57539:581;;72092:66;72152:5;72092:66;;;74039:57;32635:3;32628:81;30379:5;57957:2;57946:9;57942:18;30349:37;57762:2;57994;57983:9;57979:18;57972:48;58034:76;57762:2;57751:9;57747:18;58096:6;58034:76;;58127:271;58274:2;58259:18;;72269:64;72327:5;72269:64;;;32821:79;;;58245:153;;58405:473;58598:2;58583:18;;72269:64;72327:5;72269:64;;;33002:69;;;58781:2;58766:18;;30349:37;;;;58864:2;58849:18;;;30349:37;58569:309;;58885:491;59087:2;59072:18;;72598:63;72655:5;72598:63;;;33182:78;;;59279:2;59264:18;;30349:37;;;;73571:42;73560:54;59362:2;59347:18;;;27159:37;59058:318;;59383:487;59583:2;59568:18;;72598:63;72655:5;72598:63;;59877:503;60085:2;60070:18;;77034:1;77024:12;;77014:2;;77040:9;60387:675;;73111:49;73154:5;73111:49;;;75211:48;33919:3;33912:72;30379:5;60816:2;60805:9;60801:18;30349:37;73571:42;27189:5;73560:54;60899:2;60888:9;60884:18;27159:37;60629:3;60936:2;60925:9;60921:18;60914:48;60976:76;60629:3;60618:9;60614:19;61038:6;60976:76;;61069:372;61239:2;61224:18;;72092:66;72152:5;72092:66;;;34091:74;;;61427:2;61412:18;30349:37;61210:231;;61448:407;61639:2;61653:47;;;34811:2;61624:18;;;70278:19;34847:66;70318:14;;;34827:87;34933:12;;;61610:245;61862:425;;62062:2;62083:17;62076:47;35315:15;35309:22;35243:4;62062:2;62051:9;62047:18;35344:37;35396:149;35234:14;62051:9;35234:14;35526:12;35396:149;;;62062:2;35624:5;35620:16;35614:23;35594:43;;35673:14;62051:9;35677:4;35673:14;;35657;62051:9;35657:14;35650:38;35703:149;35847:4;35833:12;35703:149;;;35657:14;35948:5;35944:16;35938:23;36015:14;62051:9;36015:14;30349:37;36015:14;36121:5;36117:16;36111:23;35243:4;62051:9;36188:14;30349:37;62129:148;;;;;;62033:254;;;;;62294:330;62470:3;62455:19;;62485:129;62459:9;62587:6;62485:129;;62631:358;;62821:3;62810:9;62806:19;62798:27;;38761:116;38863:13;38739:15;38733:22;38761:116;;;38957:4;38950:5;38946:16;38940:23;38969:117;39080:4;39075:3;39071:14;39057:12;38969:117;;;-1:-1;39183:4;39172:16;;39166:23;39252:5;39243:15;;30349:37;39357:4;39346:16;;;39340:23;39426:5;39417:15;;;30349:37;62792:197;;62996:321;39742:22;;73776:4;73765:16;44487:35;;39912:4;39901:16;;;39895:23;39972:14;;;30349:37;40089:4;40078:16;;;40072:23;40149:14;;;30349:37;;;;63168:2;63153:18;;63139:178;63324:464;;63516:2;63537:17;63530:47;63591:104;63516:2;63505:9;63501:18;63681:6;63591:104;;;63583:112;;30379:5;63774:2;63763:9;63759:18;30349:37;63487:301;;;;;;63795:659;;64033:2;64054:17;64047:47;64108:104;64033:2;64022:9;64018:18;64198:6;64108:104;;;30379:5;64291:2;64280:9;64276:18;30349:37;64343:9;64337:4;64333:20;64328:2;64317:9;64313:18;64306:48;64368:76;64439:4;64430:6;64368:76;;64461:512;;64677:2;64698:17;64691:47;43361:15;43355:22;64677:2;64666:9;64662:18;30349:37;43541:4;43534:5;43530:16;43524:23;43601:14;64666:9;43601:14;30349:37;64677:2;43692:5;43688:16;43682:23;43759:14;64666:9;43759:14;30349:37;73571:42;43601:14;43855:5;43851:16;43845:23;73560:54;43289:4;64666:9;43922:14;27159:37;43759:14;44009:5;44005:16;43999:23;43289:4;44042:14;64666:9;44042:14;44035:38;44088:67;43280:14;64666:9;43280:14;44136:12;44088:67;;;64744:136;;;30379:5;43541:4;64948:9;64944:18;30349:37;64648:325;;;;;;65973:256;66035:2;66029:9;66061:17;;;66136:18;66121:34;;66157:22;;;66118:62;66115:2;;;66193:1;;66183:12;66115:2;66035;66202:22;66013:216;;-1:-1;66013:216;66236:304;;66395:18;66387:6;66384:30;66381:2;;;-1:-1;;66417:12;66381:2;-1:-1;66462:4;66450:17;;;66515:15;;66318:222;75834:268;75899:1;75906:101;75920:6;75917:1;75914:13;75906:101;;;75987:11;;;75981:18;75968:11;;;75961:39;75942:2;75935:10;75906:101;;;76022:6;76019:1;76016:13;76013:2;;;-1:-1;;75899:1;76069:16;;76062:27;75883:219;76296:124;76398:1;76391:5;76388:12;76378:2;;76404:9;76427:122;76527:1;76520:5;76517:12;76507:2;;76533:9;76675:121;76774:1;76767:5;76764:12;76754:2;;76780:9;77063:107;77148:1;77141:5;77138:12;77128:2;;77154:9;77423:117;73571:42;77510:5;73560:54;77485:5;77482:35;77472:2;;77531:1;;77521:12;77789:115;71912:66;77874:5;71901:78;77850:5;77847:34;77837:2;;77895:1;;77885:12;77831:73;1997:11:50;;1992:2;1982:13;;;1972:37;2069:14;;2051:16;;;2041:43;;;;2158:2;2152:9;;962:66;2213:26;;2259:15;;;2252:33;;;;2305:15;;;2298:36;;;;2366:2;2354:15;;2347:32;2411:3;2399:16;;2392:43;2505:3;2487:22;;;1285:1263::o
Swarm Source
bzzr://b04b72453866bc2a2b65ed60afe19776964cb10cdc5fa9307d4967867c2b6481
Loading...
Loading
Loading...
Loading
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.