Overview
ETH Balance
ETH Value
$0.00Latest 25 from a total of 20,899 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Fulfill Order | 17362404 | 852 days ago | IN | 0.0002 ETH | 0.0000025 | ||||
| Fulfill Order | 17357431 | 852 days ago | IN | 0.0001 ETH | 0.00000272 | ||||
| Fulfill Order | 17357052 | 852 days ago | IN | 0.0001 ETH | 0.00000264 | ||||
| Fulfill Order | 17356412 | 852 days ago | IN | 0.0001 ETH | 0.00000278 | ||||
| Fulfill Order | 17354893 | 852 days ago | IN | 0.0001 ETH | 0.00000269 | ||||
| Fulfill Order | 17354103 | 852 days ago | IN | 0.0001 ETH | 0.0000027 | ||||
| Fulfill Order | 17329808 | 852 days ago | IN | 0.0001 ETH | 0.00000235 | ||||
| Fulfill Order | 17329787 | 852 days ago | IN | 0.0001 ETH | 0.00000279 | ||||
| Fulfill Order | 17328602 | 852 days ago | IN | 0.0001 ETH | 0.00000262 | ||||
| Fulfill Order | 17327905 | 852 days ago | IN | 0.0001 ETH | 0.00000262 | ||||
| Fulfill Order | 17327796 | 852 days ago | IN | 0.0001 ETH | 0.00000262 | ||||
| Fulfill Order | 17326658 | 852 days ago | IN | 0.0001 ETH | 0.00000258 | ||||
| Fulfill Order | 17325593 | 852 days ago | IN | 0.0001 ETH | 0.00000254 | ||||
| Fulfill Order | 17323411 | 852 days ago | IN | 0.0001 ETH | 0.00000259 | ||||
| Fulfill Order | 17319445 | 852 days ago | IN | 0.0001 ETH | 0.00000195 | ||||
| Fulfill Order | 17318074 | 852 days ago | IN | 0.0001 ETH | 0.00000195 | ||||
| Fulfill Order | 17315517 | 852 days ago | IN | 0.00023 ETH | 0.00000237 | ||||
| Fulfill Order | 17313018 | 852 days ago | IN | 0.001 ETH | 0.00000228 | ||||
| Fulfill Order | 17312830 | 852 days ago | IN | 0.0001 ETH | 0.00000228 | ||||
| Fulfill Order | 17311209 | 852 days ago | IN | 0.0001 ETH | 0.00000229 | ||||
| Fulfill Order | 17308968 | 852 days ago | IN | 0.0001 ETH | 0.00000225 | ||||
| Fulfill Order | 17307641 | 852 days ago | IN | 0.00011 ETH | 0.0000017 | ||||
| Fulfill Order | 17307524 | 852 days ago | IN | 0.0001 ETH | 0.00000191 | ||||
| Fulfill Order | 17304695 | 852 days ago | IN | 0.0001 ETH | 0.00000227 | ||||
| Fulfill Order | 17304160 | 852 days ago | IN | 0.0001 ETH | 0.00000227 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 17362404 | 852 days ago | 0.0000002 ETH | ||||
| 17362404 | 852 days ago | 0.0001948 ETH | ||||
| 17362404 | 852 days ago | 0.000005 ETH | ||||
| 17357431 | 852 days ago | 0.0000009 ETH | ||||
| 17357431 | 852 days ago | 0.0000966 ETH | ||||
| 17357431 | 852 days ago | 0.0000025 ETH | ||||
| 17357052 | 852 days ago | 0.000015 ETH | ||||
| 17357052 | 852 days ago | 0.0000825 ETH | ||||
| 17357052 | 852 days ago | 0.0000025 ETH | ||||
| 17356412 | 852 days ago | 0.000015 ETH | ||||
| 17356412 | 852 days ago | 0.0000825 ETH | ||||
| 17356412 | 852 days ago | 0.0000025 ETH | ||||
| 17354893 | 852 days ago | 0.0000009 ETH | ||||
| 17354893 | 852 days ago | 0.0000966 ETH | ||||
| 17354893 | 852 days ago | 0.0000025 ETH | ||||
| 17354103 | 852 days ago | 0.0000001 ETH | ||||
| 17354103 | 852 days ago | 0.0000974 ETH | ||||
| 17354103 | 852 days ago | 0.0000025 ETH | ||||
| 17329808 | 852 days ago | 0.0000025 ETH | ||||
| 17329808 | 852 days ago | 0.000095 ETH | ||||
| 17329808 | 852 days ago | 0.0000025 ETH | ||||
| 17329787 | 852 days ago | 0.000001 ETH | ||||
| 17329787 | 852 days ago | 0.0000965 ETH | ||||
| 17329787 | 852 days ago | 0.0000025 ETH | ||||
| 17328602 | 852 days ago | 0.000001 ETH |
Cross-Chain Transactions
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { Consideration } from "./Consideration.sol";
/**
* @title Seaport
* @custom:version 1.1
* @author 0age (0age.eth)
* @custom:coauthor d1ll0n (d1ll0n.eth)
* @custom:coauthor transmissions11 (t11s.eth)
* @custom:contributor Kartik (slokh.eth)
* @custom:contributor LeFevre (lefevre.eth)
* @custom:contributor Joseph Schiarizzi (CupOJoseph.eth)
* @custom:contributor Aspyn Palatnick (stuckinaboot.eth)
* @custom:contributor James Wenzel (emo.eth)
* @custom:contributor Stephan Min (stephanm.eth)
* @custom:contributor Ryan Ghods (ralxz.eth)
* @custom:contributor hack3r-0m (hack3r-0m.eth)
* @custom:contributor Diego Estevez (antidiego.eth)
* @custom:contributor Chomtana (chomtana.eth)
* @custom:contributor Saw-mon and Natalie (sawmonandnatalie.eth)
* @custom:contributor 0xBeans (0xBeans.eth)
* @custom:contributor 0x4non (punkdev.eth)
* @custom:contributor Laurence E. Day (norsefire.eth)
* @custom:contributor vectorized.eth (vectorized.eth)
* @custom:contributor karmacoma (karmacoma.eth)
* @custom:contributor horsefacts (horsefacts.eth)
* @custom:contributor UncarvedBlock (uncarvedblock.eth)
* @custom:contributor Zoraiz Mahmood (zorz.eth)
* @custom:contributor William Poulin (wpoulin.eth)
* @custom:contributor Rajiv Patel-O'Connor (rajivpoc.eth)
* @custom:contributor tserg (tserg.eth)
* @custom:contributor cygaar (cygaar.eth)
* @custom:contributor Meta0xNull (meta0xnull.eth)
* @custom:contributor gpersoon (gpersoon.eth)
* @custom:contributor Matt Solomon (msolomon.eth)
* @custom:contributor Weikang Song (weikangs.eth)
* @custom:contributor zer0dot (zer0dot.eth)
* @custom:contributor Mudit Gupta (mudit.eth)
* @custom:contributor leonardoalt (leoalt.eth)
* @custom:contributor cmichel (cmichel.eth)
* @custom:contributor PraneshASP (pranesh.eth)
* @custom:contributor JasperAlexander (jasperalexander.eth)
* @custom:contributor Ellahi (ellahi.eth)
* @custom:contributor zaz (1zaz1.eth)
* @custom:contributor berndartmueller (berndartmueller.eth)
* @custom:contributor dmfxyz (dmfxyz.eth)
* @custom:contributor daltoncoder (dontkillrobots.eth)
* @custom:contributor 0xf4ce (0xf4ce.eth)
* @custom:contributor phaze (phaze.eth)
* @custom:contributor hrkrshnn (hrkrshnn.eth)
* @custom:contributor axic (axic.eth)
* @custom:contributor leastwood (leastwood.eth)
* @custom:contributor 0xsanson (sanson.eth)
* @custom:contributor blockdev (blockd3v.eth)
* @custom:contributor fiveoutofnine (fiveoutofnine.eth)
* @custom:contributor shuklaayush (shuklaayush.eth)
* @custom:contributor 0xPatissier
* @custom:contributor pcaversaccio
* @custom:contributor David Eiber
* @custom:contributor csanuragjain
* @custom:contributor sach1r0
* @custom:contributor twojoy0
* @custom:contributor ori_dabush
* @custom:contributor Daniel Gelfand
* @custom:contributor okkothejawa
* @custom:contributor FlameHorizon
* @custom:contributor vdrg
* @custom:contributor dmitriia
* @custom:contributor bokeh-eth
* @custom:contributor asutorufos
* @custom:contributor rfart(rfa)
* @custom:contributor Riley Holterhus
* @custom:contributor big-tech-sux
* @notice Seaport is a generalized ETH/ERC20/ERC721/ERC1155 marketplace. It
* minimizes external calls to the greatest extent possible and provides
* lightweight methods for common routes as well as more flexible
* methods for composing advanced orders or groups of orders. Each order
* contains an arbitrary number of items that may be spent (the "offer")
* along with an arbitrary number of items that must be received back by
* the indicated recipients (the "consideration").
*/
contract Seaport is Consideration {
/**
* @notice Derive and set hashes, reference chainId, and associated domain
* separator during deployment.
*
* @param conduitController A contract that deploys conduits, or proxies
* that may optionally be used to transfer approved
* ERC20/721/1155 tokens.
*/
constructor(address conduitController) Consideration(conduitController) {}
/**
* @dev Internal pure function to retrieve and return the name of this
* contract.
*
* @return The name of this contract.
*/
function _name() internal pure override returns (string memory) {
// Return the name of the contract.
assembly {
mstore(0x20, 0x20)
mstore(0x47, 0x07536561706f7274)
return(0x20, 0x60)
}
}
/**
* @dev Internal pure function to retrieve the name of this contract as a
* string that will be used to derive the name hash in the constructor.
*
* @return The name of this contract as a string.
*/
function _nameString() internal pure override returns (string memory) {
// Return the name of the contract.
return "Seaport";
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
// prettier-ignore
import {
ConsiderationInterface
} from "./ConsiderationInterface.sol";
// prettier-ignore
import {
OrderComponents,
BasicOrderParameters,
OrderParameters,
Order,
AdvancedOrder,
OrderStatus,
CriteriaResolver,
Fulfillment,
FulfillmentComponent,
Execution
} from "./ConsiderationStructs.sol";
import { OrderCombiner } from "./OrderCombiner.sol";
/**
* @title Consideration
* @author 0age
* @custom:coauthor d1ll0n
* @custom:coauthor transmissions11
* @custom:version 1.1
* @notice Consideration is a generalized ETH/ERC20/ERC721/ERC1155 marketplace.
* It minimizes external calls to the greatest extent possible and
* provides lightweight methods for common routes as well as more
* flexible methods for composing advanced orders or groups of orders.
* Each order contains an arbitrary number of items that may be spent
* (the "offer") along with an arbitrary number of items that must be
* received back by the indicated recipients (the "consideration").
*/
contract Consideration is ConsiderationInterface, OrderCombiner {
/**
* @notice Derive and set hashes, reference chainId, and associated domain
* separator during deployment.
*
* @param conduitController A contract that deploys conduits, or proxies
* that may optionally be used to transfer approved
* ERC20/721/1155 tokens.
*/
constructor(address conduitController) OrderCombiner(conduitController) {}
/**
* @notice Fulfill an order offering an ERC20, ERC721, or ERC1155 item by
* supplying Ether (or other native tokens), ERC20 tokens, an ERC721
* item, or an ERC1155 item as consideration. Six permutations are
* supported: Native token to ERC721, Native token to ERC1155, ERC20
* to ERC721, ERC20 to ERC1155, ERC721 to ERC20, and ERC1155 to
* ERC20 (with native tokens supplied as msg.value). For an order to
* be eligible for fulfillment via this method, it must contain a
* single offer item (though that item may have a greater amount if
* the item is not an ERC721). An arbitrary number of "additional
* recipients" may also be supplied which will each receive native
* tokens or ERC20 items from the fulfiller as consideration. Refer
* to the documentation for a more comprehensive summary of how to
* utilize this method and what orders are compatible with it.
*
* @param parameters Additional information on the fulfilled order. Note
* that the offerer and the fulfiller must first approve
* this contract (or their chosen conduit if indicated)
* before any tokens can be transferred. Also note that
* contract recipients of ERC1155 consideration items must
* implement `onERC1155Received` in order to receive those
* items.
*
* @return fulfilled A boolean indicating whether the order has been
* successfully fulfilled.
*/
function fulfillBasicOrder(BasicOrderParameters calldata parameters)
external
payable
override
returns (bool fulfilled)
{
// Validate and fulfill the basic order.
fulfilled = _validateAndFulfillBasicOrder(parameters);
}
/**
* @notice Fulfill an order with an arbitrary number of items for offer and
* consideration. Note that this function does not support
* criteria-based orders or partial filling of orders (though
* filling the remainder of a partially-filled order is supported).
*
* @param order The order to fulfill. Note that both the
* offerer and the fulfiller must first approve
* this contract (or the corresponding conduit if
* indicated) to transfer any relevant tokens on
* their behalf and that contracts must implement
* `onERC1155Received` to receive ERC1155 tokens
* as consideration.
* @param fulfillerConduitKey A bytes32 value indicating what conduit, if
* any, to source the fulfiller's token approvals
* from. The zero hash signifies that no conduit
* should be used (and direct approvals set on
* Consideration).
*
* @return fulfilled A boolean indicating whether the order has been
* successfully fulfilled.
*/
function fulfillOrder(Order calldata order, bytes32 fulfillerConduitKey)
external
payable
override
returns (bool fulfilled)
{
// Convert order to "advanced" order, then validate and fulfill it.
fulfilled = _validateAndFulfillAdvancedOrder(
_convertOrderToAdvanced(order),
new CriteriaResolver[](0), // No criteria resolvers supplied.
fulfillerConduitKey,
msg.sender
);
}
/**
* @notice Fill an order, fully or partially, with an arbitrary number of
* items for offer and consideration alongside criteria resolvers
* containing specific token identifiers and associated proofs.
*
* @param advancedOrder The order to fulfill along with the fraction
* of the order to attempt to fill. Note that
* both the offerer and the fulfiller must first
* approve this contract (or their conduit if
* indicated by the order) to transfer any
* relevant tokens on their behalf and that
* contracts must implement `onERC1155Received`
* to receive ERC1155 tokens as consideration.
* Also note that all offer and consideration
* components must have no remainder after
* multiplication of the respective amount with
* the supplied fraction for the partial fill to
* be considered valid.
* @param criteriaResolvers An array where each element contains a
* reference to a specific offer or
* consideration, a token identifier, and a proof
* that the supplied token identifier is
* contained in the merkle root held by the item
* in question's criteria element. Note that an
* empty criteria indicates that any
* (transferable) token identifier on the token
* in question is valid and that no associated
* proof needs to be supplied.
* @param fulfillerConduitKey A bytes32 value indicating what conduit, if
* any, to source the fulfiller's token approvals
* from. The zero hash signifies that no conduit
* should be used (and direct approvals set on
* Consideration).
* @param recipient The intended recipient for all received items,
* with `address(0)` indicating that the caller
* should receive the items.
*
* @return fulfilled A boolean indicating whether the order has been
* successfully fulfilled.
*/
function fulfillAdvancedOrder(
AdvancedOrder calldata advancedOrder,
CriteriaResolver[] calldata criteriaResolvers,
bytes32 fulfillerConduitKey,
address recipient
) external payable override returns (bool fulfilled) {
// Validate and fulfill the order.
fulfilled = _validateAndFulfillAdvancedOrder(
advancedOrder,
criteriaResolvers,
fulfillerConduitKey,
recipient == address(0) ? msg.sender : recipient
);
}
/**
* @notice Attempt to fill a group of orders, each with an arbitrary number
* of items for offer and consideration. Any order that is not
* currently active, has already been fully filled, or has been
* cancelled will be omitted. Remaining offer and consideration
* items will then be aggregated where possible as indicated by the
* supplied offer and consideration component arrays and aggregated
* items will be transferred to the fulfiller or to each intended
* recipient, respectively. Note that a failing item transfer or an
* issue with order formatting will cause the entire batch to fail.
* Note that this function does not support criteria-based orders or
* partial filling of orders (though filling the remainder of a
* partially-filled order is supported).
*
* @param orders The orders to fulfill. Note that both
* the offerer and the fulfiller must first
* approve this contract (or the
* corresponding conduit if indicated) to
* transfer any relevant tokens on their
* behalf and that contracts must implement
* `onERC1155Received` to receive ERC1155
* tokens as consideration.
* @param offerFulfillments An array of FulfillmentComponent arrays
* indicating which offer items to attempt
* to aggregate when preparing executions.
* @param considerationFulfillments An array of FulfillmentComponent arrays
* indicating which consideration items to
* attempt to aggregate when preparing
* executions.
* @param fulfillerConduitKey A bytes32 value indicating what conduit,
* if any, to source the fulfiller's token
* approvals from. The zero hash signifies
* that no conduit should be used (and
* direct approvals set on Consideration).
* @param maximumFulfilled The maximum number of orders to fulfill.
*
* @return availableOrders An array of booleans indicating if each order
* with an index corresponding to the index of the
* returned boolean was fulfillable or not.
* @return executions An array of elements indicating the sequence of
* transfers performed as part of matching the given
* orders.
*/
function fulfillAvailableOrders(
Order[] calldata orders,
FulfillmentComponent[][] calldata offerFulfillments,
FulfillmentComponent[][] calldata considerationFulfillments,
bytes32 fulfillerConduitKey,
uint256 maximumFulfilled
)
external
payable
override
returns (bool[] memory availableOrders, Execution[] memory executions)
{
// Convert orders to "advanced" orders and fulfill all available orders.
return
_fulfillAvailableAdvancedOrders(
_convertOrdersToAdvanced(orders), // Convert to advanced orders.
new CriteriaResolver[](0), // No criteria resolvers supplied.
offerFulfillments,
considerationFulfillments,
fulfillerConduitKey,
msg.sender,
maximumFulfilled
);
}
/**
* @notice Attempt to fill a group of orders, fully or partially, with an
* arbitrary number of items for offer and consideration per order
* alongside criteria resolvers containing specific token
* identifiers and associated proofs. Any order that is not
* currently active, has already been fully filled, or has been
* cancelled will be omitted. Remaining offer and consideration
* items will then be aggregated where possible as indicated by the
* supplied offer and consideration component arrays and aggregated
* items will be transferred to the fulfiller or to each intended
* recipient, respectively. Note that a failing item transfer or an
* issue with order formatting will cause the entire batch to fail.
*
* @param advancedOrders The orders to fulfill along with the
* fraction of those orders to attempt to
* fill. Note that both the offerer and the
* fulfiller must first approve this
* contract (or their conduit if indicated
* by the order) to transfer any relevant
* tokens on their behalf and that
* contracts must implement
* `onERC1155Received` in order to receive
* ERC1155 tokens as consideration. Also
* note that all offer and consideration
* components must have no remainder after
* multiplication of the respective amount
* with the supplied fraction for an
* order's partial fill amount to be
* considered valid.
* @param criteriaResolvers An array where each element contains a
* reference to a specific offer or
* consideration, a token identifier, and a
* proof that the supplied token identifier
* is contained in the merkle root held by
* the item in question's criteria element.
* Note that an empty criteria indicates
* that any (transferable) token
* identifier on the token in question is
* valid and that no associated proof needs
* to be supplied.
* @param offerFulfillments An array of FulfillmentComponent arrays
* indicating which offer items to attempt
* to aggregate when preparing executions.
* @param considerationFulfillments An array of FulfillmentComponent arrays
* indicating which consideration items to
* attempt to aggregate when preparing
* executions.
* @param fulfillerConduitKey A bytes32 value indicating what conduit,
* if any, to source the fulfiller's token
* approvals from. The zero hash signifies
* that no conduit should be used (and
* direct approvals set on Consideration).
* @param recipient The intended recipient for all received
* items, with `address(0)` indicating that
* the caller should receive the items.
* @param maximumFulfilled The maximum number of orders to fulfill.
*
* @return availableOrders An array of booleans indicating if each order
* with an index corresponding to the index of the
* returned boolean was fulfillable or not.
* @return executions An array of elements indicating the sequence of
* transfers performed as part of matching the given
* orders.
*/
function fulfillAvailableAdvancedOrders(
AdvancedOrder[] memory advancedOrders,
CriteriaResolver[] calldata criteriaResolvers,
FulfillmentComponent[][] calldata offerFulfillments,
FulfillmentComponent[][] calldata considerationFulfillments,
bytes32 fulfillerConduitKey,
address recipient,
uint256 maximumFulfilled
)
external
payable
override
returns (bool[] memory availableOrders, Execution[] memory executions)
{
// Fulfill all available orders.
return
_fulfillAvailableAdvancedOrders(
advancedOrders,
criteriaResolvers,
offerFulfillments,
considerationFulfillments,
fulfillerConduitKey,
recipient == address(0) ? msg.sender : recipient,
maximumFulfilled
);
}
/**
* @notice Match an arbitrary number of orders, each with an arbitrary
* number of items for offer and consideration along with a set of
* fulfillments allocating offer components to consideration
* components. Note that this function does not support
* criteria-based or partial filling of orders (though filling the
* remainder of a partially-filled order is supported).
*
* @param orders The orders to match. Note that both the offerer
* and fulfiller on each order must first approve
* this contract (or their conduit if indicated by
* the order) to transfer any relevant tokens on
* their behalf and each consideration recipient
* must implement `onERC1155Received` in order to
* receive ERC1155 tokens.
* @param fulfillments An array of elements allocating offer components
* to consideration components. Note that each
* consideration component must be fully met in
* order for the match operation to be valid.
*
* @return executions An array of elements indicating the sequence of
* transfers performed as part of matching the given
* orders.
*/
function matchOrders(
Order[] calldata orders,
Fulfillment[] calldata fulfillments
) external payable override returns (Execution[] memory executions) {
// Convert to advanced, validate, and match orders using fulfillments.
return
_matchAdvancedOrders(
_convertOrdersToAdvanced(orders),
new CriteriaResolver[](0), // No criteria resolvers supplied.
fulfillments
);
}
/**
* @notice Match an arbitrary number of full or partial orders, each with an
* arbitrary number of items for offer and consideration, supplying
* criteria resolvers containing specific token identifiers and
* associated proofs as well as fulfillments allocating offer
* components to consideration components.
*
* @param advancedOrders The advanced orders to match. Note that both the
* offerer and fulfiller on each order must first
* approve this contract (or their conduit if
* indicated by the order) to transfer any relevant
* tokens on their behalf and each consideration
* recipient must implement `onERC1155Received` in
* order to receive ERC1155 tokens. Also note that
* the offer and consideration components for each
* order must have no remainder after multiplying
* the respective amount with the supplied fraction
* in order for the group of partial fills to be
* considered valid.
* @param criteriaResolvers An array where each element contains a reference
* to a specific order as well as that order's
* offer or consideration, a token identifier, and
* a proof that the supplied token identifier is
* contained in the order's merkle root. Note that
* an empty root indicates that any (transferable)
* token identifier is valid and that no associated
* proof needs to be supplied.
* @param fulfillments An array of elements allocating offer components
* to consideration components. Note that each
* consideration component must be fully met in
* order for the match operation to be valid.
*
* @return executions An array of elements indicating the sequence of
* transfers performed as part of matching the given
* orders.
*/
function matchAdvancedOrders(
AdvancedOrder[] memory advancedOrders,
CriteriaResolver[] calldata criteriaResolvers,
Fulfillment[] calldata fulfillments
) external payable override returns (Execution[] memory executions) {
// Validate and match the advanced orders using supplied fulfillments.
return
_matchAdvancedOrders(
advancedOrders,
criteriaResolvers,
fulfillments
);
}
/**
* @notice Cancel an arbitrary number of orders. Note that only the offerer
* or the zone of a given order may cancel it. Callers should ensure
* that the intended order was cancelled by calling `getOrderStatus`
* and confirming that `isCancelled` returns `true`.
*
* @param orders The orders to cancel.
*
* @return cancelled A boolean indicating whether the supplied orders have
* been successfully cancelled.
*/
function cancel(OrderComponents[] calldata orders)
external
override
returns (bool cancelled)
{
// Cancel the orders.
cancelled = _cancel(orders);
}
/**
* @notice Validate an arbitrary number of orders, thereby registering their
* signatures as valid and allowing the fulfiller to skip signature
* verification on fulfillment. Note that validated orders may still
* be unfulfillable due to invalid item amounts or other factors;
* callers should determine whether validated orders are fulfillable
* by simulating the fulfillment call prior to execution. Also note
* that anyone can validate a signed order, but only the offerer can
* validate an order without supplying a signature.
*
* @param orders The orders to validate.
*
* @return validated A boolean indicating whether the supplied orders have
* been successfully validated.
*/
function validate(Order[] calldata orders)
external
override
returns (bool validated)
{
// Validate the orders.
validated = _validate(orders);
}
/**
* @notice Cancel all orders from a given offerer with a given zone in bulk
* by incrementing a counter. Note that only the offerer may
* increment the counter.
*
* @return newCounter The new counter.
*/
function incrementCounter() external override returns (uint256 newCounter) {
// Increment current counter for the supplied offerer.
newCounter = _incrementCounter();
}
/**
* @notice Retrieve the order hash for a given order.
*
* @param order The components of the order.
*
* @return orderHash The order hash.
*/
function getOrderHash(OrderComponents calldata order)
external
view
override
returns (bytes32 orderHash)
{
// Derive order hash by supplying order parameters along with counter.
orderHash = _deriveOrderHash(
OrderParameters(
order.offerer,
order.zone,
order.offer,
order.consideration,
order.orderType,
order.startTime,
order.endTime,
order.zoneHash,
order.salt,
order.conduitKey,
order.consideration.length
),
order.counter
);
}
/**
* @notice Retrieve the status of a given order by hash, including whether
* the order has been cancelled or validated and the fraction of the
* order that has been filled.
*
* @param orderHash The order hash in question.
*
* @return isValidated A boolean indicating whether the order in question
* has been validated (i.e. previously approved or
* partially filled).
* @return isCancelled A boolean indicating whether the order in question
* has been cancelled.
* @return totalFilled The total portion of the order that has been filled
* (i.e. the "numerator").
* @return totalSize The total size of the order that is either filled or
* unfilled (i.e. the "denominator").
*/
function getOrderStatus(bytes32 orderHash)
external
view
override
returns (
bool isValidated,
bool isCancelled,
uint256 totalFilled,
uint256 totalSize
)
{
// Retrieve the order status using the order hash.
return _getOrderStatus(orderHash);
}
/**
* @notice Retrieve the current counter for a given offerer.
*
* @param offerer The offerer in question.
*
* @return counter The current counter.
*/
function getCounter(address offerer)
external
view
override
returns (uint256 counter)
{
// Return the counter for the supplied offerer.
counter = _getCounter(offerer);
}
/**
* @notice Retrieve configuration information for this contract.
*
* @return version The contract version.
* @return domainSeparator The domain separator for this contract.
* @return conduitController The conduit Controller set for this contract.
*/
function information()
external
view
override
returns (
string memory version,
bytes32 domainSeparator,
address conduitController
)
{
// Return the information for this contract.
return _information();
}
/**
* @notice Retrieve the name of this contract.
*
* @return contractName The name of this contract.
*/
function name()
external
pure
override
returns (string memory contractName)
{
// Return the name of the contract.
contractName = _name();
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { Side, ItemType } from "./ConsiderationEnums.sol";
// prettier-ignore
import {
OfferItem,
ConsiderationItem,
ReceivedItem,
OrderParameters,
Fulfillment,
FulfillmentComponent,
Execution,
Order,
AdvancedOrder,
CriteriaResolver
} from "./ConsiderationStructs.sol";
import { OrderFulfiller } from "./OrderFulfiller.sol";
import { FulfillmentApplier } from "./FulfillmentApplier.sol";
import "./ConsiderationConstants.sol";
/**
* @title OrderCombiner
* @author 0age
* @notice OrderCombiner contains logic for fulfilling combinations of orders,
* either by matching offer items to consideration items or by
* fulfilling orders where available.
*/
contract OrderCombiner is OrderFulfiller, FulfillmentApplier {
/**
* @dev Derive and set hashes, reference chainId, and associated domain
* separator during deployment.
*
* @param conduitController A contract that deploys conduits, or proxies
* that may optionally be used to transfer approved
* ERC20/721/1155 tokens.
*/
constructor(address conduitController) OrderFulfiller(conduitController) {}
/**
* @notice Internal function to attempt to fill a group of orders, fully or
* partially, with an arbitrary number of items for offer and
* consideration per order alongside criteria resolvers containing
* specific token identifiers and associated proofs. Any order that
* is not currently active, has already been fully filled, or has
* been cancelled will be omitted. Remaining offer and consideration
* items will then be aggregated where possible as indicated by the
* supplied offer and consideration component arrays and aggregated
* items will be transferred to the fulfiller or to each intended
* recipient, respectively. Note that a failing item transfer or an
* issue with order formatting will cause the entire batch to fail.
*
* @param advancedOrders The orders to fulfill along with the
* fraction of those orders to attempt to
* fill. Note that both the offerer and the
* fulfiller must first approve this
* contract (or a conduit if indicated by
* the order) to transfer any relevant
* tokens on their behalf and that
* contracts must implement
* `onERC1155Received` in order to receive
* ERC1155 tokens as consideration. Also
* note that all offer and consideration
* components must have no remainder after
* multiplication of the respective amount
* with the supplied fraction for an
* order's partial fill amount to be
* considered valid.
* @param criteriaResolvers An array where each element contains a
* reference to a specific offer or
* consideration, a token identifier, and a
* proof that the supplied token identifier
* is contained in the merkle root held by
* the item in question's criteria element.
* Note that an empty criteria indicates
* that any (transferable) token
* identifier on the token in question is
* valid and that no associated proof needs
* to be supplied.
* @param offerFulfillments An array of FulfillmentComponent arrays
* indicating which offer items to attempt
* to aggregate when preparing executions.
* @param considerationFulfillments An array of FulfillmentComponent arrays
* indicating which consideration items to
* attempt to aggregate when preparing
* executions.
* @param fulfillerConduitKey A bytes32 value indicating what conduit,
* if any, to source the fulfiller's token
* approvals from. The zero hash signifies
* that no conduit should be used (and
* direct approvals set on Consideration).
* @param recipient The intended recipient for all received
* items.
* @param maximumFulfilled The maximum number of orders to fulfill.
*
* @return availableOrders An array of booleans indicating if each order
* with an index corresponding to the index of the
* returned boolean was fulfillable or not.
* @return executions An array of elements indicating the sequence of
* transfers performed as part of matching the given
* orders.
*/
function _fulfillAvailableAdvancedOrders(
AdvancedOrder[] memory advancedOrders,
CriteriaResolver[] memory criteriaResolvers,
FulfillmentComponent[][] calldata offerFulfillments,
FulfillmentComponent[][] calldata considerationFulfillments,
bytes32 fulfillerConduitKey,
address recipient,
uint256 maximumFulfilled
)
internal
returns (bool[] memory availableOrders, Execution[] memory executions)
{
// Validate orders, apply amounts, & determine if they utilize conduits.
_validateOrdersAndPrepareToFulfill(
advancedOrders,
criteriaResolvers,
false, // Signifies that invalid orders should NOT revert.
maximumFulfilled,
recipient
);
// Aggregate used offer and consideration items and execute transfers.
(availableOrders, executions) = _executeAvailableFulfillments(
advancedOrders,
offerFulfillments,
considerationFulfillments,
fulfillerConduitKey,
recipient
);
// Return order fulfillment details and executions.
return (availableOrders, executions);
}
/**
* @dev Internal function to validate a group of orders, update their
* statuses, reduce amounts by their previously filled fractions, apply
* criteria resolvers, and emit OrderFulfilled events.
*
* @param advancedOrders The advanced orders to validate and reduce by
* their previously filled amounts.
* @param criteriaResolvers An array where each element contains a reference
* to a specific order as well as that order's
* offer or consideration, a token identifier, and
* a proof that the supplied token identifier is
* contained in the order's merkle root. Note that
* a root of zero indicates that any transferable
* token identifier is valid and that no proof
* needs to be supplied.
* @param revertOnInvalid A boolean indicating whether to revert on any
* order being invalid; setting this to false will
* instead cause the invalid order to be skipped.
* @param maximumFulfilled The maximum number of orders to fulfill.
* @param recipient The intended recipient for all received items.
*/
function _validateOrdersAndPrepareToFulfill(
AdvancedOrder[] memory advancedOrders,
CriteriaResolver[] memory criteriaResolvers,
bool revertOnInvalid,
uint256 maximumFulfilled,
address recipient
) internal {
// Ensure this function cannot be triggered during a reentrant call.
_setReentrancyGuard();
// Read length of orders array and place on the stack.
uint256 totalOrders = advancedOrders.length;
// Track the order hash for each order being fulfilled.
bytes32[] memory orderHashes = new bytes32[](totalOrders);
// Override orderHashes length to zero after memory has been allocated.
assembly {
mstore(orderHashes, 0)
}
// Declare an error buffer indicating status of any native offer items.
// {00} == 0 => In a match function, no native offer items: allow.
// {01} == 1 => In a match function, some native offer items: allow.
// {10} == 2 => Not in a match function, no native offer items: allow.
// {11} == 3 => Not in a match function, some native offer items: THROW.
uint256 invalidNativeOfferItemErrorBuffer;
// Use assembly to set the value for the second bit of the error buffer.
assembly {
// Use the second bit of the error buffer to indicate whether the
// current function is not matchAdvancedOrders or matchOrders.
invalidNativeOfferItemErrorBuffer := shl(
1,
gt(
// Take the remainder of the selector modulo a magic value.
mod(
shr(NumBitsAfterSelector, calldataload(0)),
NonMatchSelector_MagicModulus
),
// Check if remainder is higher than the greatest remainder
// of the two match selectors modulo the magic value.
NonMatchSelector_MagicRemainder
)
)
}
// Skip overflow checks as all for loops are indexed starting at zero.
unchecked {
// Iterate over each order.
for (uint256 i = 0; i < totalOrders; ++i) {
// Retrieve the current order.
AdvancedOrder memory advancedOrder = advancedOrders[i];
// Determine if max number orders have already been fulfilled.
if (maximumFulfilled == 0) {
// Mark fill fraction as zero as the order will not be used.
advancedOrder.numerator = 0;
// Update the length of the orderHashes array.
assembly {
mstore(orderHashes, add(i, 1))
}
// Continue iterating through the remaining orders.
continue;
}
// Validate it, update status, and determine fraction to fill.
(
bytes32 orderHash,
uint256 numerator,
uint256 denominator
) = _validateOrderAndUpdateStatus(
advancedOrder,
criteriaResolvers,
revertOnInvalid,
orderHashes
);
// Update the length of the orderHashes array.
assembly {
mstore(orderHashes, add(i, 1))
}
// Do not track hash or adjust prices if order is not fulfilled.
if (numerator == 0) {
// Mark fill fraction as zero if the order is not fulfilled.
advancedOrder.numerator = 0;
// Continue iterating through the remaining orders.
continue;
}
// Otherwise, track the order hash in question.
orderHashes[i] = orderHash;
// Decrement the number of fulfilled orders.
// Skip underflow check as the condition before
// implies that maximumFulfilled > 0.
maximumFulfilled--;
// Place the start time for the order on the stack.
uint256 startTime = advancedOrder.parameters.startTime;
// Place the end time for the order on the stack.
uint256 endTime = advancedOrder.parameters.endTime;
// Retrieve array of offer items for the order in question.
OfferItem[] memory offer = advancedOrder.parameters.offer;
// Read length of offer array and place on the stack.
uint256 totalOfferItems = offer.length;
// Iterate over each offer item on the order.
for (uint256 j = 0; j < totalOfferItems; ++j) {
// Retrieve the offer item.
OfferItem memory offerItem = offer[j];
assembly {
// If the offer item is for the native token, set the
// first bit of the error buffer to true.
invalidNativeOfferItemErrorBuffer := or(
invalidNativeOfferItemErrorBuffer,
iszero(mload(offerItem))
)
}
// Apply order fill fraction to offer item end amount.
uint256 endAmount = _getFraction(
numerator,
denominator,
offerItem.endAmount
);
// Reuse same fraction if start and end amounts are equal.
if (offerItem.startAmount == offerItem.endAmount) {
// Apply derived amount to both start and end amount.
offerItem.startAmount = endAmount;
} else {
// Apply order fill fraction to offer item start amount.
offerItem.startAmount = _getFraction(
numerator,
denominator,
offerItem.startAmount
);
}
// Update end amount in memory to match the derived amount.
offerItem.endAmount = endAmount;
// Adjust offer amount using current time; round down.
offerItem.startAmount = _locateCurrentAmount(
offerItem.startAmount,
offerItem.endAmount,
startTime,
endTime,
false // round down
);
}
// Retrieve array of consideration items for order in question.
ConsiderationItem[] memory consideration = (
advancedOrder.parameters.consideration
);
// Read length of consideration array and place on the stack.
uint256 totalConsiderationItems = consideration.length;
// Iterate over each consideration item on the order.
for (uint256 j = 0; j < totalConsiderationItems; ++j) {
// Retrieve the consideration item.
ConsiderationItem memory considerationItem = (
consideration[j]
);
// Apply fraction to consideration item end amount.
uint256 endAmount = _getFraction(
numerator,
denominator,
considerationItem.endAmount
);
// Reuse same fraction if start and end amounts are equal.
if (
considerationItem.startAmount ==
considerationItem.endAmount
) {
// Apply derived amount to both start and end amount.
considerationItem.startAmount = endAmount;
} else {
// Apply fraction to consideration item start amount.
considerationItem.startAmount = _getFraction(
numerator,
denominator,
considerationItem.startAmount
);
}
// Update end amount in memory to match the derived amount.
considerationItem.endAmount = endAmount;
// Adjust consideration amount using current time; round up.
considerationItem.startAmount = (
_locateCurrentAmount(
considerationItem.startAmount,
considerationItem.endAmount,
startTime,
endTime,
true // round up
)
);
// Utilize assembly to manually "shift" the recipient value.
assembly {
// Write recipient to endAmount, as endAmount is not
// used from this point on and can be repurposed to fit
// the layout of a ReceivedItem.
mstore(
add(
considerationItem,
ReceivedItem_recipient_offset // old endAmount
),
mload(
add(
considerationItem,
ConsiderationItem_recipient_offset
)
)
)
}
}
}
}
// If the first bit is set, a native offer item was encountered. If the
// second bit is set in the error buffer, the current function is not
// matchOrders or matchAdvancedOrders. If the value is three, both the
// first and second bits were set; in that case, revert with an error.
if (invalidNativeOfferItemErrorBuffer == 3) {
revert InvalidNativeOfferItem();
}
// Apply criteria resolvers to each order as applicable.
_applyCriteriaResolvers(advancedOrders, criteriaResolvers);
// Emit an event for each order signifying that it has been fulfilled.
// Skip overflow checks as all for loops are indexed starting at zero.
unchecked {
// Iterate over each order.
for (uint256 i = 0; i < totalOrders; ++i) {
// Do not emit an event if no order hash is present.
if (orderHashes[i] == bytes32(0)) {
continue;
}
// Retrieve parameters for the order in question.
OrderParameters memory orderParameters = (
advancedOrders[i].parameters
);
// Emit an OrderFulfilled event.
_emitOrderFulfilledEvent(
orderHashes[i],
orderParameters.offerer,
orderParameters.zone,
recipient,
orderParameters.offer,
orderParameters.consideration
);
}
}
}
/**
* @dev Internal function to fulfill a group of validated orders, fully or
* partially, with an arbitrary number of items for offer and
* consideration per order and to execute transfers. Any order that is
* not currently active, has already been fully filled, or has been
* cancelled will be omitted. Remaining offer and consideration items
* will then be aggregated where possible as indicated by the supplied
* offer and consideration component arrays and aggregated items will
* be transferred to the fulfiller or to each intended recipient,
* respectively. Note that a failing item transfer or an issue with
* order formatting will cause the entire batch to fail.
*
* @param advancedOrders The orders to fulfill along with the
* fraction of those orders to attempt to
* fill. Note that both the offerer and the
* fulfiller must first approve this
* contract (or the conduit if indicated by
* the order) to transfer any relevant
* tokens on their behalf and that
* contracts must implement
* `onERC1155Received` in order to receive
* ERC1155 tokens as consideration. Also
* note that all offer and consideration
* components must have no remainder after
* multiplication of the respective amount
* with the supplied fraction for an
* order's partial fill amount to be
* considered valid.
* @param offerFulfillments An array of FulfillmentComponent arrays
* indicating which offer items to attempt
* to aggregate when preparing executions.
* @param considerationFulfillments An array of FulfillmentComponent arrays
* indicating which consideration items to
* attempt to aggregate when preparing
* executions.
* @param fulfillerConduitKey A bytes32 value indicating what conduit,
* if any, to source the fulfiller's token
* approvals from. The zero hash signifies
* that no conduit should be used, with
* direct approvals set on Consideration.
* @param recipient The intended recipient for all received
* items.
*
* @return availableOrders An array of booleans indicating if each order
* with an index corresponding to the index of the
* returned boolean was fulfillable or not.
* @return executions An array of elements indicating the sequence of
* transfers performed as part of matching the given
* orders.
*/
function _executeAvailableFulfillments(
AdvancedOrder[] memory advancedOrders,
FulfillmentComponent[][] memory offerFulfillments,
FulfillmentComponent[][] memory considerationFulfillments,
bytes32 fulfillerConduitKey,
address recipient
)
internal
returns (bool[] memory availableOrders, Execution[] memory executions)
{
// Retrieve length of offer fulfillments array and place on the stack.
uint256 totalOfferFulfillments = offerFulfillments.length;
// Retrieve length of consideration fulfillments array & place on stack.
uint256 totalConsiderationFulfillments = (
considerationFulfillments.length
);
// Allocate an execution for each offer and consideration fulfillment.
executions = new Execution[](
totalOfferFulfillments + totalConsiderationFulfillments
);
// Skip overflow checks as all for loops are indexed starting at zero.
unchecked {
// Track number of filtered executions.
uint256 totalFilteredExecutions = 0;
// Iterate over each offer fulfillment.
for (uint256 i = 0; i < totalOfferFulfillments; ++i) {
/// Retrieve the offer fulfillment components in question.
FulfillmentComponent[] memory components = (
offerFulfillments[i]
);
// Derive aggregated execution corresponding with fulfillment.
Execution memory execution = _aggregateAvailable(
advancedOrders,
Side.OFFER,
components,
fulfillerConduitKey,
recipient
);
// If offerer and recipient on the execution are the same...
if (execution.item.recipient == execution.offerer) {
// Increment total filtered executions.
++totalFilteredExecutions;
} else {
// Otherwise, assign the execution to the executions array.
executions[i - totalFilteredExecutions] = execution;
}
}
// Iterate over each consideration fulfillment.
for (uint256 i = 0; i < totalConsiderationFulfillments; ++i) {
/// Retrieve consideration fulfillment components in question.
FulfillmentComponent[] memory components = (
considerationFulfillments[i]
);
// Derive aggregated execution corresponding with fulfillment.
Execution memory execution = _aggregateAvailable(
advancedOrders,
Side.CONSIDERATION,
components,
fulfillerConduitKey,
address(0) // unused
);
// If offerer and recipient on the execution are the same...
if (execution.item.recipient == execution.offerer) {
// Increment total filtered executions.
++totalFilteredExecutions;
} else {
// Otherwise, assign the execution to the executions array.
executions[
i + totalOfferFulfillments - totalFilteredExecutions
] = execution;
}
}
// If some number of executions have been filtered...
if (totalFilteredExecutions != 0) {
// reduce the total length of the executions array.
assembly {
mstore(
executions,
sub(mload(executions), totalFilteredExecutions)
)
}
}
}
// Revert if no orders are available.
if (executions.length == 0) {
revert NoSpecifiedOrdersAvailable();
}
// Perform final checks and return.
availableOrders = _performFinalChecksAndExecuteOrders(
advancedOrders,
executions
);
return (availableOrders, executions);
}
/**
* @dev Internal function to perform a final check that each consideration
* item for an arbitrary number of fulfilled orders has been met and to
* trigger associated executions, transferring the respective items.
*
* @param advancedOrders The orders to check and perform executions for.
* @param executions An array of elements indicating the sequence of
* transfers to perform when fulfilling the given
* orders.
*
* @return availableOrders An array of booleans indicating if each order
* with an index corresponding to the index of the
* returned boolean was fulfillable or not.
*/
function _performFinalChecksAndExecuteOrders(
AdvancedOrder[] memory advancedOrders,
Execution[] memory executions
) internal returns (bool[] memory availableOrders) {
// Retrieve the length of the advanced orders array and place on stack.
uint256 totalOrders = advancedOrders.length;
// Initialize array for tracking available orders.
availableOrders = new bool[](totalOrders);
// Skip overflow checks as all for loops are indexed starting at zero.
unchecked {
// Iterate over orders to ensure all considerations are met.
for (uint256 i = 0; i < totalOrders; ++i) {
// Retrieve the order in question.
AdvancedOrder memory advancedOrder = advancedOrders[i];
// Skip consideration item checks for order if not fulfilled.
if (advancedOrder.numerator == 0) {
// Note: orders do not need to be marked as unavailable as a
// new memory region has been allocated. Review carefully if
// altering compiler version or managing memory manually.
continue;
}
// Mark the order as available.
availableOrders[i] = true;
// Retrieve consideration items to ensure they are fulfilled.
ConsiderationItem[] memory consideration = (
advancedOrder.parameters.consideration
);
// Read length of consideration array and place on the stack.
uint256 totalConsiderationItems = consideration.length;
// Iterate over each consideration item to ensure it is met.
for (uint256 j = 0; j < totalConsiderationItems; ++j) {
// Retrieve remaining amount on the consideration item.
uint256 unmetAmount = consideration[j].startAmount;
// Revert if the remaining amount is not zero.
if (unmetAmount != 0) {
revert ConsiderationNotMet(i, j, unmetAmount);
}
}
}
}
// Put ether value supplied by the caller on the stack.
uint256 etherRemaining = msg.value;
// Initialize an accumulator array. From this point forward, no new
// memory regions can be safely allocated until the accumulator is no
// longer being utilized, as the accumulator operates in an open-ended
// fashion from this memory pointer; existing memory may still be
// accessed and modified, however.
bytes memory accumulator = new bytes(AccumulatorDisarmed);
// Retrieve the length of the executions array and place on stack.
uint256 totalExecutions = executions.length;
// Iterate over each execution.
for (uint256 i = 0; i < totalExecutions; ) {
// Retrieve the execution and the associated received item.
Execution memory execution = executions[i];
ReceivedItem memory item = execution.item;
// If execution transfers native tokens, reduce value available.
if (item.itemType == ItemType.NATIVE) {
// Ensure that sufficient native tokens are still available.
if (item.amount > etherRemaining) {
revert InsufficientEtherSupplied();
}
// Skip underflow check as amount is less than ether remaining.
unchecked {
etherRemaining -= item.amount;
}
}
// Transfer the item specified by the execution.
_transfer(
item,
execution.offerer,
execution.conduitKey,
accumulator
);
// Skip overflow check as for loop is indexed starting at zero.
unchecked {
++i;
}
}
// Trigger any remaining accumulated transfers via call to the conduit.
_triggerIfArmed(accumulator);
// If any ether remains after fulfillments, return it to the caller.
if (etherRemaining != 0) {
_transferEth(payable(msg.sender), etherRemaining);
}
// Clear the reentrancy guard.
_clearReentrancyGuard();
// Return the array containing available orders.
return (availableOrders);
}
/**
* @dev Internal function to match an arbitrary number of full or partial
* orders, each with an arbitrary number of items for offer and
* consideration, supplying criteria resolvers containing specific
* token identifiers and associated proofs as well as fulfillments
* allocating offer components to consideration components.
*
* @param advancedOrders The advanced orders to match. Note that both the
* offerer and fulfiller on each order must first
* approve this contract (or their conduit if
* indicated by the order) to transfer any relevant
* tokens on their behalf and each consideration
* recipient must implement `onERC1155Received` in
* order to receive ERC1155 tokens. Also note that
* the offer and consideration components for each
* order must have no remainder after multiplying
* the respective amount with the supplied fraction
* in order for the group of partial fills to be
* considered valid.
* @param criteriaResolvers An array where each element contains a reference
* to a specific order as well as that order's
* offer or consideration, a token identifier, and
* a proof that the supplied token identifier is
* contained in the order's merkle root. Note that
* an empty root indicates that any (transferable)
* token identifier is valid and that no associated
* proof needs to be supplied.
* @param fulfillments An array of elements allocating offer components
* to consideration components. Note that each
* consideration component must be fully met in
* order for the match operation to be valid.
*
* @return executions An array of elements indicating the sequence of
* transfers performed as part of matching the given
* orders.
*/
function _matchAdvancedOrders(
AdvancedOrder[] memory advancedOrders,
CriteriaResolver[] memory criteriaResolvers,
Fulfillment[] calldata fulfillments
) internal returns (Execution[] memory executions) {
// Validate orders, update order status, and determine item amounts.
_validateOrdersAndPrepareToFulfill(
advancedOrders,
criteriaResolvers,
true, // Signifies that invalid orders should revert.
advancedOrders.length,
address(0) // OrderFulfilled event has no recipient when matching.
);
// Fulfill the orders using the supplied fulfillments.
return _fulfillAdvancedOrders(advancedOrders, fulfillments);
}
/**
* @dev Internal function to fulfill an arbitrary number of orders, either
* full or partial, after validating, adjusting amounts, and applying
* criteria resolvers.
*
* @param advancedOrders The orders to match, including a fraction to
* attempt to fill for each order.
* @param fulfillments An array of elements allocating offer
* components to consideration components. Note
* that the final amount of each consideration
* component must be zero for a match operation to
* be considered valid.
*
* @return executions An array of elements indicating the sequence of
* transfers performed as part of matching the given
* orders.
*/
function _fulfillAdvancedOrders(
AdvancedOrder[] memory advancedOrders,
Fulfillment[] calldata fulfillments
) internal returns (Execution[] memory executions) {
// Retrieve fulfillments array length and place on the stack.
uint256 totalFulfillments = fulfillments.length;
// Allocate executions by fulfillment and apply them to each execution.
executions = new Execution[](totalFulfillments);
// Skip overflow checks as all for loops are indexed starting at zero.
unchecked {
// Track number of filtered executions.
uint256 totalFilteredExecutions = 0;
// Iterate over each fulfillment.
for (uint256 i = 0; i < totalFulfillments; ++i) {
/// Retrieve the fulfillment in question.
Fulfillment calldata fulfillment = fulfillments[i];
// Derive the execution corresponding with the fulfillment.
Execution memory execution = _applyFulfillment(
advancedOrders,
fulfillment.offerComponents,
fulfillment.considerationComponents
);
// If offerer and recipient on the execution are the same...
if (execution.item.recipient == execution.offerer) {
// Increment total filtered executions.
++totalFilteredExecutions;
} else {
// Otherwise, assign the execution to the executions array.
executions[i - totalFilteredExecutions] = execution;
}
}
// If some number of executions have been filtered...
if (totalFilteredExecutions != 0) {
// reduce the total length of the executions array.
assembly {
mstore(
executions,
sub(mload(executions), totalFilteredExecutions)
)
}
}
}
// Perform final checks and execute orders.
_performFinalChecksAndExecuteOrders(advancedOrders, executions);
// Return the executions array.
return (executions);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
// prettier-ignore
import {
OrderType,
BasicOrderType,
ItemType,
Side
} from "./ConsiderationEnums.sol";
/**
* @dev An order contains eleven components: an offerer, a zone (or account that
* can cancel the order or restrict who can fulfill the order depending on
* the type), the order type (specifying partial fill support as well as
* restricted order status), the start and end time, a hash that will be
* provided to the zone when validating restricted orders, a salt, a key
* corresponding to a given conduit, a counter, and an arbitrary number of
* offer items that can be spent along with consideration items that must
* be received by their respective recipient.
*/
struct OrderComponents {
address offerer;
address zone;
OfferItem[] offer;
ConsiderationItem[] consideration;
OrderType orderType;
uint256 startTime;
uint256 endTime;
bytes32 zoneHash;
uint256 salt;
bytes32 conduitKey;
uint256 counter;
}
/**
* @dev An offer item has five components: an item type (ETH or other native
* tokens, ERC20, ERC721, and ERC1155, as well as criteria-based ERC721 and
* ERC1155), a token address, a dual-purpose "identifierOrCriteria"
* component that will either represent a tokenId or a merkle root
* depending on the item type, and a start and end amount that support
* increasing or decreasing amounts over the duration of the respective
* order.
*/
struct OfferItem {
ItemType itemType;
address token;
uint256 identifierOrCriteria;
uint256 startAmount;
uint256 endAmount;
}
/**
* @dev A consideration item has the same five components as an offer item and
* an additional sixth component designating the required recipient of the
* item.
*/
struct ConsiderationItem {
ItemType itemType;
address token;
uint256 identifierOrCriteria;
uint256 startAmount;
uint256 endAmount;
address payable recipient;
}
/**
* @dev A spent item is translated from a utilized offer item and has four
* components: an item type (ETH or other native tokens, ERC20, ERC721, and
* ERC1155), a token address, a tokenId, and an amount.
*/
struct SpentItem {
ItemType itemType;
address token;
uint256 identifier;
uint256 amount;
}
/**
* @dev A received item is translated from a utilized consideration item and has
* the same four components as a spent item, as well as an additional fifth
* component designating the required recipient of the item.
*/
struct ReceivedItem {
ItemType itemType;
address token;
uint256 identifier;
uint256 amount;
address payable recipient;
}
/**
* @dev For basic orders involving ETH / native / ERC20 <=> ERC721 / ERC1155
* matching, a group of six functions may be called that only requires a
* subset of the usual order arguments. Note the use of a "basicOrderType"
* enum; this represents both the usual order type as well as the "route"
* of the basic order (a simple derivation function for the basic order
* type is `basicOrderType = orderType + (4 * basicOrderRoute)`.)
*/
struct BasicOrderParameters {
// calldata offset
address considerationToken; // 0x24
uint256 considerationIdentifier; // 0x44
uint256 considerationAmount; // 0x64
address payable offerer; // 0x84
address zone; // 0xa4
address offerToken; // 0xc4
uint256 offerIdentifier; // 0xe4
uint256 offerAmount; // 0x104
BasicOrderType basicOrderType; // 0x124
uint256 startTime; // 0x144
uint256 endTime; // 0x164
bytes32 zoneHash; // 0x184
uint256 salt; // 0x1a4
bytes32 offererConduitKey; // 0x1c4
bytes32 fulfillerConduitKey; // 0x1e4
uint256 totalOriginalAdditionalRecipients; // 0x204
AdditionalRecipient[] additionalRecipients; // 0x224
bytes signature; // 0x244
// Total length, excluding dynamic array data: 0x264 (580)
}
/**
* @dev Basic orders can supply any number of additional recipients, with the
* implied assumption that they are supplied from the offered ETH (or other
* native token) or ERC20 token for the order.
*/
struct AdditionalRecipient {
uint256 amount;
address payable recipient;
}
/**
* @dev The full set of order components, with the exception of the counter,
* must be supplied when fulfilling more sophisticated orders or groups of
* orders. The total number of original consideration items must also be
* supplied, as the caller may specify additional consideration items.
*/
struct OrderParameters {
address offerer; // 0x00
address zone; // 0x20
OfferItem[] offer; // 0x40
ConsiderationItem[] consideration; // 0x60
OrderType orderType; // 0x80
uint256 startTime; // 0xa0
uint256 endTime; // 0xc0
bytes32 zoneHash; // 0xe0
uint256 salt; // 0x100
bytes32 conduitKey; // 0x120
uint256 totalOriginalConsiderationItems; // 0x140
// offer.length // 0x160
}
/**
* @dev Orders require a signature in addition to the other order parameters.
*/
struct Order {
OrderParameters parameters;
bytes signature;
}
/**
* @dev Advanced orders include a numerator (i.e. a fraction to attempt to fill)
* and a denominator (the total size of the order) in addition to the
* signature and other order parameters. It also supports an optional field
* for supplying extra data; this data will be included in a staticcall to
* `isValidOrderIncludingExtraData` on the zone for the order if the order
* type is restricted and the offerer or zone are not the caller.
*/
struct AdvancedOrder {
OrderParameters parameters;
uint120 numerator;
uint120 denominator;
bytes signature;
bytes extraData;
}
/**
* @dev Orders can be validated (either explicitly via `validate`, or as a
* consequence of a full or partial fill), specifically cancelled (they can
* also be cancelled in bulk via incrementing a per-zone counter), and
* partially or fully filled (with the fraction filled represented by a
* numerator and denominator).
*/
struct OrderStatus {
bool isValidated;
bool isCancelled;
uint120 numerator;
uint120 denominator;
}
/**
* @dev A criteria resolver specifies an order, side (offer vs. consideration),
* and item index. It then provides a chosen identifier (i.e. tokenId)
* alongside a merkle proof demonstrating the identifier meets the required
* criteria.
*/
struct CriteriaResolver {
uint256 orderIndex;
Side side;
uint256 index;
uint256 identifier;
bytes32[] criteriaProof;
}
/**
* @dev A fulfillment is applied to a group of orders. It decrements a series of
* offer and consideration items, then generates a single execution
* element. A given fulfillment can be applied to as many offer and
* consideration items as desired, but must contain at least one offer and
* at least one consideration that match. The fulfillment must also remain
* consistent on all key parameters across all offer items (same offerer,
* token, type, tokenId, and conduit preference) as well as across all
* consideration items (token, type, tokenId, and recipient).
*/
struct Fulfillment {
FulfillmentComponent[] offerComponents;
FulfillmentComponent[] considerationComponents;
}
/**
* @dev Each fulfillment component contains one index referencing a specific
* order and another referencing a specific offer or consideration item.
*/
struct FulfillmentComponent {
uint256 orderIndex;
uint256 itemIndex;
}
/**
* @dev An execution is triggered once all consideration items have been zeroed
* out. It sends the item in question from the offerer to the item's
* recipient, optionally sourcing approvals from either this contract
* directly or from the offerer's chosen conduit if one is specified. An
* execution is not provided as an argument, but rather is derived via
* orders, criteria resolvers, and fulfillments (where the total number of
* executions will be less than or equal to the total number of indicated
* fulfillments) and returned as part of `matchOrders`.
*/
struct Execution {
ReceivedItem item;
address offerer;
bytes32 conduitKey;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
// prettier-ignore
import {
BasicOrderParameters,
OrderComponents,
Fulfillment,
FulfillmentComponent,
Execution,
Order,
AdvancedOrder,
OrderStatus,
CriteriaResolver
} from "./ConsiderationStructs.sol";
/**
* @title ConsiderationInterface
* @author 0age
* @custom:version 1.1
* @notice Consideration is a generalized ETH/ERC20/ERC721/ERC1155 marketplace.
* It minimizes external calls to the greatest extent possible and
* provides lightweight methods for common routes as well as more
* flexible methods for composing advanced orders.
*
* @dev ConsiderationInterface contains all external function interfaces for
* Consideration.
*/
interface ConsiderationInterface {
/**
* @notice Fulfill an order offering an ERC721 token by supplying Ether (or
* the native token for the given chain) as consideration for the
* order. An arbitrary number of "additional recipients" may also be
* supplied which will each receive native tokens from the fulfiller
* as consideration.
*
* @param parameters Additional information on the fulfilled order. Note
* that the offerer must first approve this contract (or
* their preferred conduit if indicated by the order) for
* their offered ERC721 token to be transferred.
*
* @return fulfilled A boolean indicating whether the order has been
* successfully fulfilled.
*/
function fulfillBasicOrder(BasicOrderParameters calldata parameters)
external
payable
returns (bool fulfilled);
/**
* @notice Fulfill an order with an arbitrary number of items for offer and
* consideration. Note that this function does not support
* criteria-based orders or partial filling of orders (though
* filling the remainder of a partially-filled order is supported).
*
* @param order The order to fulfill. Note that both the
* offerer and the fulfiller must first approve
* this contract (or the corresponding conduit if
* indicated) to transfer any relevant tokens on
* their behalf and that contracts must implement
* `onERC1155Received` to receive ERC1155 tokens
* as consideration.
* @param fulfillerConduitKey A bytes32 value indicating what conduit, if
* any, to source the fulfiller's token approvals
* from. The zero hash signifies that no conduit
* should be used, with direct approvals set on
* Consideration.
*
* @return fulfilled A boolean indicating whether the order has been
* successfully fulfilled.
*/
function fulfillOrder(Order calldata order, bytes32 fulfillerConduitKey)
external
payable
returns (bool fulfilled);
/**
* @notice Fill an order, fully or partially, with an arbitrary number of
* items for offer and consideration alongside criteria resolvers
* containing specific token identifiers and associated proofs.
*
* @param advancedOrder The order to fulfill along with the fraction
* of the order to attempt to fill. Note that
* both the offerer and the fulfiller must first
* approve this contract (or their preferred
* conduit if indicated by the order) to transfer
* any relevant tokens on their behalf and that
* contracts must implement `onERC1155Received`
* to receive ERC1155 tokens as consideration.
* Also note that all offer and consideration
* components must have no remainder after
* multiplication of the respective amount with
* the supplied fraction for the partial fill to
* be considered valid.
* @param criteriaResolvers An array where each element contains a
* reference to a specific offer or
* consideration, a token identifier, and a proof
* that the supplied token identifier is
* contained in the merkle root held by the item
* in question's criteria element. Note that an
* empty criteria indicates that any
* (transferable) token identifier on the token
* in question is valid and that no associated
* proof needs to be supplied.
* @param fulfillerConduitKey A bytes32 value indicating what conduit, if
* any, to source the fulfiller's token approvals
* from. The zero hash signifies that no conduit
* should be used, with direct approvals set on
* Consideration.
* @param recipient The intended recipient for all received items,
* with `address(0)` indicating that the caller
* should receive the items.
*
* @return fulfilled A boolean indicating whether the order has been
* successfully fulfilled.
*/
function fulfillAdvancedOrder(
AdvancedOrder calldata advancedOrder,
CriteriaResolver[] calldata criteriaResolvers,
bytes32 fulfillerConduitKey,
address recipient
) external payable returns (bool fulfilled);
/**
* @notice Attempt to fill a group of orders, each with an arbitrary number
* of items for offer and consideration. Any order that is not
* currently active, has already been fully filled, or has been
* cancelled will be omitted. Remaining offer and consideration
* items will then be aggregated where possible as indicated by the
* supplied offer and consideration component arrays and aggregated
* items will be transferred to the fulfiller or to each intended
* recipient, respectively. Note that a failing item transfer or an
* issue with order formatting will cause the entire batch to fail.
* Note that this function does not support criteria-based orders or
* partial filling of orders (though filling the remainder of a
* partially-filled order is supported).
*
* @param orders The orders to fulfill. Note that both
* the offerer and the fulfiller must first
* approve this contract (or the
* corresponding conduit if indicated) to
* transfer any relevant tokens on their
* behalf and that contracts must implement
* `onERC1155Received` to receive ERC1155
* tokens as consideration.
* @param offerFulfillments An array of FulfillmentComponent arrays
* indicating which offer items to attempt
* to aggregate when preparing executions.
* @param considerationFulfillments An array of FulfillmentComponent arrays
* indicating which consideration items to
* attempt to aggregate when preparing
* executions.
* @param fulfillerConduitKey A bytes32 value indicating what conduit,
* if any, to source the fulfiller's token
* approvals from. The zero hash signifies
* that no conduit should be used, with
* direct approvals set on this contract.
* @param maximumFulfilled The maximum number of orders to fulfill.
*
* @return availableOrders An array of booleans indicating if each order
* with an index corresponding to the index of the
* returned boolean was fulfillable or not.
* @return executions An array of elements indicating the sequence of
* transfers performed as part of matching the given
* orders.
*/
function fulfillAvailableOrders(
Order[] calldata orders,
FulfillmentComponent[][] calldata offerFulfillments,
FulfillmentComponent[][] calldata considerationFulfillments,
bytes32 fulfillerConduitKey,
uint256 maximumFulfilled
)
external
payable
returns (bool[] memory availableOrders, Execution[] memory executions);
/**
* @notice Attempt to fill a group of orders, fully or partially, with an
* arbitrary number of items for offer and consideration per order
* alongside criteria resolvers containing specific token
* identifiers and associated proofs. Any order that is not
* currently active, has already been fully filled, or has been
* cancelled will be omitted. Remaining offer and consideration
* items will then be aggregated where possible as indicated by the
* supplied offer and consideration component arrays and aggregated
* items will be transferred to the fulfiller or to each intended
* recipient, respectively. Note that a failing item transfer or an
* issue with order formatting will cause the entire batch to fail.
*
* @param advancedOrders The orders to fulfill along with the
* fraction of those orders to attempt to
* fill. Note that both the offerer and the
* fulfiller must first approve this
* contract (or their preferred conduit if
* indicated by the order) to transfer any
* relevant tokens on their behalf and that
* contracts must implement
* `onERC1155Received` to enable receipt of
* ERC1155 tokens as consideration. Also
* note that all offer and consideration
* components must have no remainder after
* multiplication of the respective amount
* with the supplied fraction for an
* order's partial fill amount to be
* considered valid.
* @param criteriaResolvers An array where each element contains a
* reference to a specific offer or
* consideration, a token identifier, and a
* proof that the supplied token identifier
* is contained in the merkle root held by
* the item in question's criteria element.
* Note that an empty criteria indicates
* that any (transferable) token
* identifier on the token in question is
* valid and that no associated proof needs
* to be supplied.
* @param offerFulfillments An array of FulfillmentComponent arrays
* indicating which offer items to attempt
* to aggregate when preparing executions.
* @param considerationFulfillments An array of FulfillmentComponent arrays
* indicating which consideration items to
* attempt to aggregate when preparing
* executions.
* @param fulfillerConduitKey A bytes32 value indicating what conduit,
* if any, to source the fulfiller's token
* approvals from. The zero hash signifies
* that no conduit should be used, with
* direct approvals set on this contract.
* @param recipient The intended recipient for all received
* items, with `address(0)` indicating that
* the caller should receive the items.
* @param maximumFulfilled The maximum number of orders to fulfill.
*
* @return availableOrders An array of booleans indicating if each order
* with an index corresponding to the index of the
* returned boolean was fulfillable or not.
* @return executions An array of elements indicating the sequence of
* transfers performed as part of matching the given
* orders.
*/
function fulfillAvailableAdvancedOrders(
AdvancedOrder[] calldata advancedOrders,
CriteriaResolver[] calldata criteriaResolvers,
FulfillmentComponent[][] calldata offerFulfillments,
FulfillmentComponent[][] calldata considerationFulfillments,
bytes32 fulfillerConduitKey,
address recipient,
uint256 maximumFulfilled
)
external
payable
returns (bool[] memory availableOrders, Execution[] memory executions);
/**
* @notice Match an arbitrary number of orders, each with an arbitrary
* number of items for offer and consideration along with as set of
* fulfillments allocating offer components to consideration
* components. Note that this function does not support
* criteria-based or partial filling of orders (though filling the
* remainder of a partially-filled order is supported).
*
* @param orders The orders to match. Note that both the offerer and
* fulfiller on each order must first approve this
* contract (or their conduit if indicated by the order)
* to transfer any relevant tokens on their behalf and
* each consideration recipient must implement
* `onERC1155Received` to enable ERC1155 token receipt.
* @param fulfillments An array of elements allocating offer components to
* consideration components. Note that each
* consideration component must be fully met for the
* match operation to be valid.
*
* @return executions An array of elements indicating the sequence of
* transfers performed as part of matching the given
* orders.
*/
function matchOrders(
Order[] calldata orders,
Fulfillment[] calldata fulfillments
) external payable returns (Execution[] memory executions);
/**
* @notice Match an arbitrary number of full or partial orders, each with an
* arbitrary number of items for offer and consideration, supplying
* criteria resolvers containing specific token identifiers and
* associated proofs as well as fulfillments allocating offer
* components to consideration components.
*
* @param orders The advanced orders to match. Note that both the
* offerer and fulfiller on each order must first
* approve this contract (or a preferred conduit if
* indicated by the order) to transfer any relevant
* tokens on their behalf and each consideration
* recipient must implement `onERC1155Received` in
* order to receive ERC1155 tokens. Also note that
* the offer and consideration components for each
* order must have no remainder after multiplying
* the respective amount with the supplied fraction
* in order for the group of partial fills to be
* considered valid.
* @param criteriaResolvers An array where each element contains a reference
* to a specific order as well as that order's
* offer or consideration, a token identifier, and
* a proof that the supplied token identifier is
* contained in the order's merkle root. Note that
* an empty root indicates that any (transferable)
* token identifier is valid and that no associated
* proof needs to be supplied.
* @param fulfillments An array of elements allocating offer components
* to consideration components. Note that each
* consideration component must be fully met in
* order for the match operation to be valid.
*
* @return executions An array of elements indicating the sequence of
* transfers performed as part of matching the given
* orders.
*/
function matchAdvancedOrders(
AdvancedOrder[] calldata orders,
CriteriaResolver[] calldata criteriaResolvers,
Fulfillment[] calldata fulfillments
) external payable returns (Execution[] memory executions);
/**
* @notice Cancel an arbitrary number of orders. Note that only the offerer
* or the zone of a given order may cancel it. Callers should ensure
* that the intended order was cancelled by calling `getOrderStatus`
* and confirming that `isCancelled` returns `true`.
*
* @param orders The orders to cancel.
*
* @return cancelled A boolean indicating whether the supplied orders have
* been successfully cancelled.
*/
function cancel(OrderComponents[] calldata orders)
external
returns (bool cancelled);
/**
* @notice Validate an arbitrary number of orders, thereby registering their
* signatures as valid and allowing the fulfiller to skip signature
* verification on fulfillment. Note that validated orders may still
* be unfulfillable due to invalid item amounts or other factors;
* callers should determine whether validated orders are fulfillable
* by simulating the fulfillment call prior to execution. Also note
* that anyone can validate a signed order, but only the offerer can
* validate an order without supplying a signature.
*
* @param orders The orders to validate.
*
* @return validated A boolean indicating whether the supplied orders have
* been successfully validated.
*/
function validate(Order[] calldata orders)
external
returns (bool validated);
/**
* @notice Cancel all orders from a given offerer with a given zone in bulk
* by incrementing a counter. Note that only the offerer may
* increment the counter.
*
* @return newCounter The new counter.
*/
function incrementCounter() external returns (uint256 newCounter);
/**
* @notice Retrieve the order hash for a given order.
*
* @param order The components of the order.
*
* @return orderHash The order hash.
*/
function getOrderHash(OrderComponents calldata order)
external
view
returns (bytes32 orderHash);
/**
* @notice Retrieve the status of a given order by hash, including whether
* the order has been cancelled or validated and the fraction of the
* order that has been filled.
*
* @param orderHash The order hash in question.
*
* @return isValidated A boolean indicating whether the order in question
* has been validated (i.e. previously approved or
* partially filled).
* @return isCancelled A boolean indicating whether the order in question
* has been cancelled.
* @return totalFilled The total portion of the order that has been filled
* (i.e. the "numerator").
* @return totalSize The total size of the order that is either filled or
* unfilled (i.e. the "denominator").
*/
function getOrderStatus(bytes32 orderHash)
external
view
returns (
bool isValidated,
bool isCancelled,
uint256 totalFilled,
uint256 totalSize
);
/**
* @notice Retrieve the current counter for a given offerer.
*
* @param offerer The offerer in question.
*
* @return counter The current counter.
*/
function getCounter(address offerer)
external
view
returns (uint256 counter);
/**
* @notice Retrieve configuration information for this contract.
*
* @return version The contract version.
* @return domainSeparator The domain separator for this contract.
* @return conduitController The conduit Controller set for this contract.
*/
function information()
external
view
returns (
string memory version,
bytes32 domainSeparator,
address conduitController
);
/**
* @notice Retrieve the name of this contract.
*
* @return contractName The name of this contract.
*/
function name() external view returns (string memory contractName);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
/*
* -------------------------- Disambiguation & Other Notes ---------------------
* - The term "head" is used as it is in the documentation for ABI encoding,
* but only in reference to dynamic types, i.e. it always refers to the
* offset or pointer to the body of a dynamic type. In calldata, the head
* is always an offset (relative to the parent object), while in memory,
* the head is always the pointer to the body. More information found here:
* https://docs.soliditylang.org/en/v0.8.14/abi-spec.html#argument-encoding
* - Note that the length of an array is separate from and precedes the
* head of the array.
*
* - The term "body" is used in place of the term "head" used in the ABI
* documentation. It refers to the start of the data for a dynamic type,
* e.g. the first word of a struct or the first word of the first element
* in an array.
*
* - The term "pointer" is used to describe the absolute position of a value
* and never an offset relative to another value.
* - The suffix "_ptr" refers to a memory pointer.
* - The suffix "_cdPtr" refers to a calldata pointer.
*
* - The term "offset" is used to describe the position of a value relative
* to some parent value. For example, OrderParameters_conduit_offset is the
* offset to the "conduit" value in the OrderParameters struct relative to
* the start of the body.
* - Note: Offsets are used to derive pointers.
*
* - Some structs have pointers defined for all of their fields in this file.
* Lines which are commented out are fields that are not used in the
* codebase but have been left in for readability.
*/
// Declare constants for name, version, and reentrancy sentinel values.
// Name is right padded, so it touches the length which is left padded. This
// enables writing both values at once. Length goes at byte 95 in memory, and
// name fills bytes 96-109, so both values can be written left-padded to 77.
uint256 constant NameLengthPtr = 77;
uint256 constant NameWithLength = 0x0d436F6E73696465726174696F6E;
uint256 constant Version = 0x312e31;
uint256 constant Version_length = 3;
uint256 constant Version_shift = 0xe8;
uint256 constant _NOT_ENTERED = 1;
uint256 constant _ENTERED = 2;
// Common Offsets
// Offsets for identically positioned fields shared by:
// OfferItem, ConsiderationItem, SpentItem, ReceivedItem
uint256 constant Common_token_offset = 0x20;
uint256 constant Common_identifier_offset = 0x40;
uint256 constant Common_amount_offset = 0x60;
uint256 constant ReceivedItem_size = 0xa0;
uint256 constant ReceivedItem_amount_offset = 0x60;
uint256 constant ReceivedItem_recipient_offset = 0x80;
uint256 constant ReceivedItem_CommonParams_size = 0x60;
uint256 constant ConsiderationItem_recipient_offset = 0xa0;
// Store the same constant in an abbreviated format for a line length fix.
uint256 constant ConsiderItem_recipient_offset = 0xa0;
uint256 constant Execution_offerer_offset = 0x20;
uint256 constant Execution_conduit_offset = 0x40;
uint256 constant InvalidFulfillmentComponentData_error_signature = (
0x7fda727900000000000000000000000000000000000000000000000000000000
);
uint256 constant InvalidFulfillmentComponentData_error_len = 0x04;
uint256 constant Panic_error_signature = (
0x4e487b7100000000000000000000000000000000000000000000000000000000
);
uint256 constant Panic_error_offset = 0x04;
uint256 constant Panic_error_length = 0x24;
uint256 constant Panic_arithmetic = 0x11;
uint256 constant MissingItemAmount_error_signature = (
0x91b3e51400000000000000000000000000000000000000000000000000000000
);
uint256 constant MissingItemAmount_error_len = 0x04;
uint256 constant OrderParameters_offer_head_offset = 0x40;
uint256 constant OrderParameters_consideration_head_offset = 0x60;
uint256 constant OrderParameters_conduit_offset = 0x120;
uint256 constant OrderParameters_counter_offset = 0x140;
uint256 constant Fulfillment_itemIndex_offset = 0x20;
uint256 constant AdvancedOrder_numerator_offset = 0x20;
uint256 constant AlmostOneWord = 0x1f;
uint256 constant OneWord = 0x20;
uint256 constant TwoWords = 0x40;
uint256 constant ThreeWords = 0x60;
uint256 constant FourWords = 0x80;
uint256 constant FiveWords = 0xa0;
uint256 constant FreeMemoryPointerSlot = 0x40;
uint256 constant ZeroSlot = 0x60;
uint256 constant DefaultFreeMemoryPointer = 0x80;
uint256 constant Slot0x80 = 0x80;
uint256 constant Slot0xA0 = 0xa0;
uint256 constant BasicOrder_endAmount_cdPtr = 0x104;
uint256 constant BasicOrder_common_params_size = 0xa0;
uint256 constant BasicOrder_considerationHashesArray_ptr = 0x160;
uint256 constant EIP712_Order_size = 0x180;
uint256 constant EIP712_OfferItem_size = 0xc0;
uint256 constant EIP712_ConsiderationItem_size = 0xe0;
uint256 constant AdditionalRecipients_size = 0x40;
uint256 constant EIP712_DomainSeparator_offset = 0x02;
uint256 constant EIP712_OrderHash_offset = 0x22;
uint256 constant EIP712_DigestPayload_size = 0x42;
uint256 constant receivedItemsHash_ptr = 0x60;
/*
* Memory layout in _prepareBasicFulfillmentFromCalldata of
* data for OrderFulfilled
*
* event OrderFulfilled(
* bytes32 orderHash,
* address indexed offerer,
* address indexed zone,
* address fulfiller,
* SpentItem[] offer,
* > (itemType, token, id, amount)
* ReceivedItem[] consideration
* > (itemType, token, id, amount, recipient)
* )
*
* - 0x00: orderHash
* - 0x20: fulfiller
* - 0x40: offer offset (0x80)
* - 0x60: consideration offset (0x120)
* - 0x80: offer.length (1)
* - 0xa0: offerItemType
* - 0xc0: offerToken
* - 0xe0: offerIdentifier
* - 0x100: offerAmount
* - 0x120: consideration.length (1 + additionalRecipients.length)
* - 0x140: considerationItemType
* - 0x160: considerationToken
* - 0x180: considerationIdentifier
* - 0x1a0: considerationAmount
* - 0x1c0: considerationRecipient
* - ...
*/
// Minimum length of the OrderFulfilled event data.
// Must be added to the size of the ReceivedItem array for additionalRecipients
// (0xa0 * additionalRecipients.length) to calculate full size of the buffer.
uint256 constant OrderFulfilled_baseSize = 0x1e0;
uint256 constant OrderFulfilled_selector = (
0x9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f31
);
// Minimum offset in memory to OrderFulfilled event data.
// Must be added to the size of the EIP712 hash array for additionalRecipients
// (32 * additionalRecipients.length) to calculate the pointer to event data.
uint256 constant OrderFulfilled_baseOffset = 0x180;
uint256 constant OrderFulfilled_consideration_length_baseOffset = 0x2a0;
uint256 constant OrderFulfilled_offer_length_baseOffset = 0x200;
// uint256 constant OrderFulfilled_orderHash_offset = 0x00;
uint256 constant OrderFulfilled_fulfiller_offset = 0x20;
uint256 constant OrderFulfilled_offer_head_offset = 0x40;
uint256 constant OrderFulfilled_offer_body_offset = 0x80;
uint256 constant OrderFulfilled_consideration_head_offset = 0x60;
uint256 constant OrderFulfilled_consideration_body_offset = 0x120;
// BasicOrderParameters
uint256 constant BasicOrder_parameters_cdPtr = 0x04;
uint256 constant BasicOrder_considerationToken_cdPtr = 0x24;
// uint256 constant BasicOrder_considerationIdentifier_cdPtr = 0x44;
uint256 constant BasicOrder_considerationAmount_cdPtr = 0x64;
uint256 constant BasicOrder_offerer_cdPtr = 0x84;
uint256 constant BasicOrder_zone_cdPtr = 0xa4;
uint256 constant BasicOrder_offerToken_cdPtr = 0xc4;
// uint256 constant BasicOrder_offerIdentifier_cdPtr = 0xe4;
uint256 constant BasicOrder_offerAmount_cdPtr = 0x104;
uint256 constant BasicOrder_basicOrderType_cdPtr = 0x124;
uint256 constant BasicOrder_startTime_cdPtr = 0x144;
// uint256 constant BasicOrder_endTime_cdPtr = 0x164;
// uint256 constant BasicOrder_zoneHash_cdPtr = 0x184;
// uint256 constant BasicOrder_salt_cdPtr = 0x1a4;
uint256 constant BasicOrder_offererConduit_cdPtr = 0x1c4;
uint256 constant BasicOrder_fulfillerConduit_cdPtr = 0x1e4;
uint256 constant BasicOrder_totalOriginalAdditionalRecipients_cdPtr = 0x204;
uint256 constant BasicOrder_additionalRecipients_head_cdPtr = 0x224;
uint256 constant BasicOrder_signature_cdPtr = 0x244;
uint256 constant BasicOrder_additionalRecipients_length_cdPtr = 0x264;
uint256 constant BasicOrder_additionalRecipients_data_cdPtr = 0x284;
uint256 constant BasicOrder_parameters_ptr = 0x20;
uint256 constant BasicOrder_basicOrderType_range = 0x18; // 24 values
/*
* Memory layout in _prepareBasicFulfillmentFromCalldata of
* EIP712 data for ConsiderationItem
* - 0x80: ConsiderationItem EIP-712 typehash (constant)
* - 0xa0: itemType
* - 0xc0: token
* - 0xe0: identifier
* - 0x100: startAmount
* - 0x120: endAmount
* - 0x140: recipient
*/
uint256 constant BasicOrder_considerationItem_typeHash_ptr = 0x80; // memoryPtr
uint256 constant BasicOrder_considerationItem_itemType_ptr = 0xa0;
uint256 constant BasicOrder_considerationItem_token_ptr = 0xc0;
uint256 constant BasicOrder_considerationItem_identifier_ptr = 0xe0;
uint256 constant BasicOrder_considerationItem_startAmount_ptr = 0x100;
uint256 constant BasicOrder_considerationItem_endAmount_ptr = 0x120;
// uint256 constant BasicOrder_considerationItem_recipient_ptr = 0x140;
/*
* Memory layout in _prepareBasicFulfillmentFromCalldata of
* EIP712 data for OfferItem
* - 0x80: OfferItem EIP-712 typehash (constant)
* - 0xa0: itemType
* - 0xc0: token
* - 0xe0: identifier (reused for offeredItemsHash)
* - 0x100: startAmount
* - 0x120: endAmount
*/
uint256 constant BasicOrder_offerItem_typeHash_ptr = DefaultFreeMemoryPointer;
uint256 constant BasicOrder_offerItem_itemType_ptr = 0xa0;
uint256 constant BasicOrder_offerItem_token_ptr = 0xc0;
// uint256 constant BasicOrder_offerItem_identifier_ptr = 0xe0;
// uint256 constant BasicOrder_offerItem_startAmount_ptr = 0x100;
uint256 constant BasicOrder_offerItem_endAmount_ptr = 0x120;
/*
* Memory layout in _prepareBasicFulfillmentFromCalldata of
* EIP712 data for Order
* - 0x80: Order EIP-712 typehash (constant)
* - 0xa0: orderParameters.offerer
* - 0xc0: orderParameters.zone
* - 0xe0: keccak256(abi.encodePacked(offerHashes))
* - 0x100: keccak256(abi.encodePacked(considerationHashes))
* - 0x120: orderType
* - 0x140: startTime
* - 0x160: endTime
* - 0x180: zoneHash
* - 0x1a0: salt
* - 0x1c0: conduit
* - 0x1e0: _counters[orderParameters.offerer] (from storage)
*/
uint256 constant BasicOrder_order_typeHash_ptr = 0x80;
uint256 constant BasicOrder_order_offerer_ptr = 0xa0;
// uint256 constant BasicOrder_order_zone_ptr = 0xc0;
uint256 constant BasicOrder_order_offerHashes_ptr = 0xe0;
uint256 constant BasicOrder_order_considerationHashes_ptr = 0x100;
uint256 constant BasicOrder_order_orderType_ptr = 0x120;
uint256 constant BasicOrder_order_startTime_ptr = 0x140;
// uint256 constant BasicOrder_order_endTime_ptr = 0x160;
// uint256 constant BasicOrder_order_zoneHash_ptr = 0x180;
// uint256 constant BasicOrder_order_salt_ptr = 0x1a0;
// uint256 constant BasicOrder_order_conduitKey_ptr = 0x1c0;
uint256 constant BasicOrder_order_counter_ptr = 0x1e0;
uint256 constant BasicOrder_additionalRecipients_head_ptr = 0x240;
uint256 constant BasicOrder_signature_ptr = 0x260;
// Signature-related
bytes32 constant EIP2098_allButHighestBitMask = (
0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
);
bytes32 constant ECDSA_twentySeventhAndTwentyEighthBytesSet = (
0x0000000000000000000000000000000000000000000000000000000101000000
);
uint256 constant ECDSA_MaxLength = 65;
uint256 constant ECDSA_signature_s_offset = 0x40;
uint256 constant ECDSA_signature_v_offset = 0x60;
bytes32 constant EIP1271_isValidSignature_selector = (
0x1626ba7e00000000000000000000000000000000000000000000000000000000
);
uint256 constant EIP1271_isValidSignature_signatureHead_negativeOffset = 0x20;
uint256 constant EIP1271_isValidSignature_digest_negativeOffset = 0x40;
uint256 constant EIP1271_isValidSignature_selector_negativeOffset = 0x44;
uint256 constant EIP1271_isValidSignature_calldata_baseLength = 0x64;
uint256 constant EIP1271_isValidSignature_signature_head_offset = 0x40;
// abi.encodeWithSignature("NoContract(address)")
uint256 constant NoContract_error_signature = (
0x5f15d67200000000000000000000000000000000000000000000000000000000
);
uint256 constant NoContract_error_sig_ptr = 0x0;
uint256 constant NoContract_error_token_ptr = 0x4;
uint256 constant NoContract_error_length = 0x24; // 4 + 32 == 36
uint256 constant EIP_712_PREFIX = (
0x1901000000000000000000000000000000000000000000000000000000000000
);
uint256 constant ExtraGasBuffer = 0x20;
uint256 constant CostPerWord = 3;
uint256 constant MemoryExpansionCoefficient = 0x200; // 512
uint256 constant Create2AddressDerivation_ptr = 0x0b;
uint256 constant Create2AddressDerivation_length = 0x55;
uint256 constant MaskOverByteTwelve = (
0x0000000000000000000000ff0000000000000000000000000000000000000000
);
uint256 constant MaskOverLastTwentyBytes = (
0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff
);
uint256 constant MaskOverFirstFourBytes = (
0xffffffff00000000000000000000000000000000000000000000000000000000
);
uint256 constant Conduit_execute_signature = (
0x4ce34aa200000000000000000000000000000000000000000000000000000000
);
uint256 constant MaxUint8 = 0xff;
uint256 constant MaxUint120 = 0xffffffffffffffffffffffffffffff;
uint256 constant Conduit_execute_ConduitTransfer_ptr = 0x20;
uint256 constant Conduit_execute_ConduitTransfer_length = 0x01;
uint256 constant Conduit_execute_ConduitTransfer_offset_ptr = 0x04;
uint256 constant Conduit_execute_ConduitTransfer_length_ptr = 0x24;
uint256 constant Conduit_execute_transferItemType_ptr = 0x44;
uint256 constant Conduit_execute_transferToken_ptr = 0x64;
uint256 constant Conduit_execute_transferFrom_ptr = 0x84;
uint256 constant Conduit_execute_transferTo_ptr = 0xa4;
uint256 constant Conduit_execute_transferIdentifier_ptr = 0xc4;
uint256 constant Conduit_execute_transferAmount_ptr = 0xe4;
uint256 constant OneConduitExecute_size = 0x104;
// Sentinel value to indicate that the conduit accumulator is not armed.
uint256 constant AccumulatorDisarmed = 0x20;
uint256 constant AccumulatorArmed = 0x40;
uint256 constant Accumulator_conduitKey_ptr = 0x20;
uint256 constant Accumulator_selector_ptr = 0x40;
uint256 constant Accumulator_array_offset_ptr = 0x44;
uint256 constant Accumulator_array_length_ptr = 0x64;
uint256 constant Accumulator_itemSizeOffsetDifference = 0x3c;
uint256 constant Accumulator_array_offset = 0x20;
uint256 constant Conduit_transferItem_size = 0xc0;
uint256 constant Conduit_transferItem_token_ptr = 0x20;
uint256 constant Conduit_transferItem_from_ptr = 0x40;
uint256 constant Conduit_transferItem_to_ptr = 0x60;
uint256 constant Conduit_transferItem_identifier_ptr = 0x80;
uint256 constant Conduit_transferItem_amount_ptr = 0xa0;
// Declare constant for errors related to amount derivation.
// error InexactFraction() @ AmountDerivationErrors.sol
uint256 constant InexactFraction_error_signature = (
0xc63cf08900000000000000000000000000000000000000000000000000000000
);
uint256 constant InexactFraction_error_len = 0x04;
// Declare constant for errors related to signature verification.
uint256 constant Ecrecover_precompile = 1;
uint256 constant Ecrecover_args_size = 0x80;
uint256 constant Signature_lower_v = 27;
// error BadSignatureV(uint8) @ SignatureVerificationErrors.sol
uint256 constant BadSignatureV_error_signature = (
0x1f003d0a00000000000000000000000000000000000000000000000000000000
);
uint256 constant BadSignatureV_error_offset = 0x04;
uint256 constant BadSignatureV_error_length = 0x24;
// error InvalidSigner() @ SignatureVerificationErrors.sol
uint256 constant InvalidSigner_error_signature = (
0x815e1d6400000000000000000000000000000000000000000000000000000000
);
uint256 constant InvalidSigner_error_length = 0x04;
// error InvalidSignature() @ SignatureVerificationErrors.sol
uint256 constant InvalidSignature_error_signature = (
0x8baa579f00000000000000000000000000000000000000000000000000000000
);
uint256 constant InvalidSignature_error_length = 0x04;
// error BadContractSignature() @ SignatureVerificationErrors.sol
uint256 constant BadContractSignature_error_signature = (
0x4f7fb80d00000000000000000000000000000000000000000000000000000000
);
uint256 constant BadContractSignature_error_length = 0x04;
uint256 constant NumBitsAfterSelector = 0xe0;
// 69 is the lowest modulus for which the remainder
// of every selector other than the two match functions
// is greater than those of the match functions.
uint256 constant NonMatchSelector_MagicModulus = 69;
// Of the two match function selectors, the highest
// remainder modulo 69 is 29.
uint256 constant NonMatchSelector_MagicRemainder = 0x1d;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import { ItemType, Side } from "./ConsiderationEnums.sol";
import {
OfferItem,
ConsiderationItem,
ReceivedItem,
OrderParameters,
AdvancedOrder,
Execution,
FulfillmentComponent
} from "./ConsiderationStructs.sol";
import "./ConsiderationConstants.sol";
import {
FulfillmentApplicationErrors
} from "./FulfillmentApplicationErrors.sol";
/**
* @title FulfillmentApplier
* @author 0age
* @notice FulfillmentApplier contains logic related to applying fulfillments,
* both as part of order matching (where offer items are matched to
* consideration items) as well as fulfilling available orders (where
* order items and consideration items are independently aggregated).
*/
contract FulfillmentApplier is FulfillmentApplicationErrors {
/**
* @dev Internal pure function to match offer items to consideration items
* on a group of orders via a supplied fulfillment.
*
* @param advancedOrders The orders to match.
* @param offerComponents An array designating offer components to
* match to consideration components.
* @param considerationComponents An array designating consideration
* components to match to offer components.
* Note that each consideration amount must
* be zero in order for the match operation
* to be valid.
*
* @return execution The transfer performed as a result of the fulfillment.
*/
function _applyFulfillment(
AdvancedOrder[] memory advancedOrders,
FulfillmentComponent[] calldata offerComponents,
FulfillmentComponent[] calldata considerationComponents
) internal pure returns (Execution memory execution) {
// Ensure 1+ of both offer and consideration components are supplied.
if (
offerComponents.length == 0 || considerationComponents.length == 0
) {
revert OfferAndConsiderationRequiredOnFulfillment();
}
// Declare a new Execution struct.
Execution memory considerationExecution;
// Validate & aggregate consideration items to new Execution object.
_aggregateValidFulfillmentConsiderationItems(
advancedOrders,
considerationComponents,
considerationExecution
);
// Retrieve the consideration item from the execution struct.
ReceivedItem memory considerationItem = considerationExecution.item;
// Recipient does not need to be specified because it will always be set
// to that of the consideration.
// Validate & aggregate offer items to Execution object.
_aggregateValidFulfillmentOfferItems(
advancedOrders,
offerComponents,
execution
);
// Ensure offer and consideration share types, tokens and identifiers.
if (
execution.item.itemType != considerationItem.itemType ||
execution.item.token != considerationItem.token ||
execution.item.identifier != considerationItem.identifier
) {
revert MismatchedFulfillmentOfferAndConsiderationComponents();
}
// If total consideration amount exceeds the offer amount...
if (considerationItem.amount > execution.item.amount) {
// Retrieve the first consideration component from the fulfillment.
FulfillmentComponent memory targetComponent = (
considerationComponents[0]
);
// Skip underflow check as the conditional being true implies that
// considerationItem.amount > execution.item.amount.
unchecked {
// Add excess consideration item amount to original order array.
advancedOrders[targetComponent.orderIndex]
.parameters
.consideration[targetComponent.itemIndex]
.startAmount = (considerationItem.amount -
execution.item.amount);
}
// Reduce total consideration amount to equal the offer amount.
considerationItem.amount = execution.item.amount;
} else {
// Retrieve the first offer component from the fulfillment.
FulfillmentComponent memory targetComponent = offerComponents[0];
// Skip underflow check as the conditional being false implies that
// execution.item.amount >= considerationItem.amount.
unchecked {
// Add excess offer item amount to the original array of orders.
advancedOrders[targetComponent.orderIndex]
.parameters
.offer[targetComponent.itemIndex]
.startAmount = (execution.item.amount -
considerationItem.amount);
}
// Reduce total offer amount to equal the consideration amount.
execution.item.amount = considerationItem.amount;
}
// Reuse consideration recipient.
execution.item.recipient = considerationItem.recipient;
// Return the final execution that will be triggered for relevant items.
return execution; // Execution(considerationItem, offerer, conduitKey);
}
/**
* @dev Internal view function to aggregate offer or consideration items
* from a group of orders into a single execution via a supplied array
* of fulfillment components. Items that are not available to aggregate
* will not be included in the aggregated execution.
*
* @param advancedOrders The orders to aggregate.
* @param side The side (i.e. offer or consideration).
* @param fulfillmentComponents An array designating item components to
* aggregate if part of an available order.
* @param fulfillerConduitKey A bytes32 value indicating what conduit, if
* any, to source the fulfiller's token
* approvals from. The zero hash signifies that
* no conduit should be used, with approvals
* set directly on this contract.
* @param recipient The intended recipient for all received
* items.
*
* @return execution The transfer performed as a result of the fulfillment.
*/
function _aggregateAvailable(
AdvancedOrder[] memory advancedOrders,
Side side,
FulfillmentComponent[] memory fulfillmentComponents,
bytes32 fulfillerConduitKey,
address recipient
) internal view returns (Execution memory execution) {
// Skip overflow / underflow checks; conditions checked or unreachable.
unchecked {
// Retrieve fulfillment components array length and place on stack.
// Ensure at least one fulfillment component has been supplied.
if (fulfillmentComponents.length == 0) {
revert MissingFulfillmentComponentOnAggregation(side);
}
// If the fulfillment components are offer components...
if (side == Side.OFFER) {
// Set the supplied recipient on the execution item.
execution.item.recipient = payable(recipient);
// Return execution for aggregated items provided by offerer.
_aggregateValidFulfillmentOfferItems(
advancedOrders,
fulfillmentComponents,
execution
);
} else {
// Otherwise, fulfillment components are consideration
// components. Return execution for aggregated items provided by
// the fulfiller.
_aggregateValidFulfillmentConsiderationItems(
advancedOrders,
fulfillmentComponents,
execution
);
// Set the caller as the offerer on the execution.
execution.offerer = msg.sender;
// Set fulfiller conduit key as the conduit key on execution.
execution.conduitKey = fulfillerConduitKey;
}
// Set the offerer and recipient to null address if execution
// amount is zero. This will cause the execution item to be skipped.
if (execution.item.amount == 0) {
execution.offerer = address(0);
execution.item.recipient = payable(0);
}
}
}
/**
* @dev Internal pure function to aggregate a group of offer items using
* supplied directives on which component items are candidates for
* aggregation, skipping items on orders that are not available.
*
* @param advancedOrders The orders to aggregate offer items from.
* @param offerComponents An array of FulfillmentComponent structs
* indicating the order index and item index of each
* candidate offer item for aggregation.
* @param execution The execution to apply the aggregation to.
*/
function _aggregateValidFulfillmentOfferItems(
AdvancedOrder[] memory advancedOrders,
FulfillmentComponent[] memory offerComponents,
Execution memory execution
) internal pure {
assembly {
// Declare function for reverts on invalid fulfillment data.
function throwInvalidFulfillmentComponentData() {
// Store the InvalidFulfillmentComponentData error signature.
mstore(0, InvalidFulfillmentComponentData_error_signature)
// Return, supplying InvalidFulfillmentComponentData signature.
revert(0, InvalidFulfillmentComponentData_error_len)
}
// Declare function for reverts due to arithmetic overflows.
function throwOverflow() {
// Store the Panic error signature.
mstore(0, Panic_error_signature)
// Store the arithmetic (0x11) panic code as initial argument.
mstore(Panic_error_offset, Panic_arithmetic)
// Return, supplying Panic signature and arithmetic code.
revert(0, Panic_error_length)
}
// Get position in offerComponents head.
let fulfillmentHeadPtr := add(offerComponents, OneWord)
// Retrieve the order index using the fulfillment pointer.
let orderIndex := mload(mload(fulfillmentHeadPtr))
// Ensure that the order index is not out of range.
if iszero(lt(orderIndex, mload(advancedOrders))) {
throwInvalidFulfillmentComponentData()
}
// Read advancedOrders[orderIndex] pointer from its array head.
let orderPtr := mload(
// Calculate head position of advancedOrders[orderIndex].
add(add(advancedOrders, OneWord), mul(orderIndex, OneWord))
)
// Read the pointer to OrderParameters from the AdvancedOrder.
let paramsPtr := mload(orderPtr)
// Load the offer array pointer.
let offerArrPtr := mload(
add(paramsPtr, OrderParameters_offer_head_offset)
)
// Retrieve item index using an offset of the fulfillment pointer.
let itemIndex := mload(
add(mload(fulfillmentHeadPtr), Fulfillment_itemIndex_offset)
)
// Only continue if the fulfillment is not invalid.
if iszero(lt(itemIndex, mload(offerArrPtr))) {
throwInvalidFulfillmentComponentData()
}
// Retrieve consideration item pointer using the item index.
let offerItemPtr := mload(
add(
// Get pointer to beginning of receivedItem.
add(offerArrPtr, OneWord),
// Calculate offset to pointer for desired order.
mul(itemIndex, OneWord)
)
)
// Declare a variable for the final aggregated item amount.
let amount := 0
// Create variable to track errors encountered with amount.
let errorBuffer := 0
// Only add offer amount to execution amount on a nonzero numerator.
if mload(add(orderPtr, AdvancedOrder_numerator_offset)) {
// Retrieve amount pointer using consideration item pointer.
let amountPtr := add(offerItemPtr, Common_amount_offset)
// Set the amount.
amount := mload(amountPtr)
// Zero out amount on item to indicate it is credited.
mstore(amountPtr, 0)
// Buffer indicating whether issues were found.
errorBuffer := iszero(amount)
}
// Retrieve the received item pointer.
let receivedItemPtr := mload(execution)
// Set the item type on the received item.
mstore(receivedItemPtr, mload(offerItemPtr))
// Set the token on the received item.
mstore(
add(receivedItemPtr, Common_token_offset),
mload(add(offerItemPtr, Common_token_offset))
)
// Set the identifier on the received item.
mstore(
add(receivedItemPtr, Common_identifier_offset),
mload(add(offerItemPtr, Common_identifier_offset))
)
// Set the offerer on returned execution using order pointer.
mstore(add(execution, Execution_offerer_offset), mload(paramsPtr))
// Set conduitKey on returned execution via offset of order pointer.
mstore(
add(execution, Execution_conduit_offset),
mload(add(paramsPtr, OrderParameters_conduit_offset))
)
// Calculate the hash of (itemType, token, identifier).
let dataHash := keccak256(
receivedItemPtr,
ReceivedItem_CommonParams_size
)
// Get position one word past last element in head of array.
let endPtr := add(
offerComponents,
mul(mload(offerComponents), OneWord)
)
// Iterate over remaining offer components.
// prettier-ignore
for {} lt(fulfillmentHeadPtr, endPtr) {} {
// Increment the pointer to the fulfillment head by one word.
fulfillmentHeadPtr := add(fulfillmentHeadPtr, OneWord)
// Get the order index using the fulfillment pointer.
orderIndex := mload(mload(fulfillmentHeadPtr))
// Ensure the order index is in range.
if iszero(lt(orderIndex, mload(advancedOrders))) {
throwInvalidFulfillmentComponentData()
}
// Get pointer to AdvancedOrder element.
orderPtr := mload(
add(
add(advancedOrders, OneWord),
mul(orderIndex, OneWord)
)
)
// Only continue if numerator is not zero.
if iszero(mload(
add(orderPtr, AdvancedOrder_numerator_offset)
)) {
continue
}
// Read the pointer to OrderParameters from the AdvancedOrder.
paramsPtr := mload(orderPtr)
// Load offer array pointer.
offerArrPtr := mload(
add(
paramsPtr,
OrderParameters_offer_head_offset
)
)
// Get the item index using the fulfillment pointer.
itemIndex := mload(add(mload(fulfillmentHeadPtr), OneWord))
// Throw if itemIndex is out of the range of array.
if iszero(
lt(itemIndex, mload(offerArrPtr))
) {
throwInvalidFulfillmentComponentData()
}
// Retrieve offer item pointer using index.
offerItemPtr := mload(
add(
// Get pointer to beginning of receivedItem.
add(offerArrPtr, OneWord),
// Use offset to pointer for desired order.
mul(itemIndex, OneWord)
)
)
// Retrieve amount pointer using offer item pointer.
let amountPtr := add(
offerItemPtr,
Common_amount_offset
)
// Add offer amount to execution amount.
let newAmount := add(amount, mload(amountPtr))
// Update error buffer: 1 = zero amount, 2 = overflow, 3 = both.
errorBuffer := or(
errorBuffer,
or(
shl(1, lt(newAmount, amount)),
iszero(mload(amountPtr))
)
)
// Update the amount to the new, summed amount.
amount := newAmount
// Zero out amount on original item to indicate it is credited.
mstore(amountPtr, 0)
// Ensure the indicated item matches original item.
if iszero(
and(
and(
// The offerer must match on both items.
eq(
mload(paramsPtr),
mload(
add(execution, Execution_offerer_offset)
)
),
// The conduit key must match on both items.
eq(
mload(
add(
paramsPtr,
OrderParameters_conduit_offset
)
),
mload(
add(
execution,
Execution_conduit_offset
)
)
)
),
// The itemType, token, and identifier must match.
eq(
dataHash,
keccak256(
offerItemPtr,
ReceivedItem_CommonParams_size
)
)
)
) {
// Throw if any of the requirements are not met.
throwInvalidFulfillmentComponentData()
}
}
// Write final amount to execution.
mstore(add(mload(execution), Common_amount_offset), amount)
// Determine whether the error buffer contains a nonzero error code.
if errorBuffer {
// If errorBuffer is 1, an item had an amount of zero.
if eq(errorBuffer, 1) {
// Store the MissingItemAmount error signature.
mstore(0, MissingItemAmount_error_signature)
// Return, supplying MissingItemAmount signature.
revert(0, MissingItemAmount_error_len)
}
// If errorBuffer is not 1 or 0, the sum overflowed.
// Panic!
throwOverflow()
}
}
}
/**
* @dev Internal pure function to aggregate a group of consideration items
* using supplied directives on which component items are candidates
* for aggregation, skipping items on orders that are not available.
*
* @param advancedOrders The orders to aggregate consideration
* items from.
* @param considerationComponents An array of FulfillmentComponent structs
* indicating the order index and item index
* of each candidate consideration item for
* aggregation.
* @param execution The execution to apply the aggregation to.
*/
function _aggregateValidFulfillmentConsiderationItems(
AdvancedOrder[] memory advancedOrders,
FulfillmentComponent[] memory considerationComponents,
Execution memory execution
) internal pure {
// Utilize assembly in order to efficiently aggregate the items.
assembly {
// Declare function for reverts on invalid fulfillment data.
function throwInvalidFulfillmentComponentData() {
// Store the InvalidFulfillmentComponentData error signature.
mstore(0, InvalidFulfillmentComponentData_error_signature)
// Return, supplying InvalidFulfillmentComponentData signature.
revert(0, InvalidFulfillmentComponentData_error_len)
}
// Declare function for reverts due to arithmetic overflows.
function throwOverflow() {
// Store the Panic error signature.
mstore(0, Panic_error_signature)
// Store the arithmetic (0x11) panic code as initial argument.
mstore(Panic_error_offset, Panic_arithmetic)
// Return, supplying Panic signature and arithmetic code.
revert(0, Panic_error_length)
}
// Get position in considerationComponents head.
let fulfillmentHeadPtr := add(considerationComponents, OneWord)
// Retrieve the order index using the fulfillment pointer.
let orderIndex := mload(mload(fulfillmentHeadPtr))
// Ensure that the order index is not out of range.
if iszero(lt(orderIndex, mload(advancedOrders))) {
throwInvalidFulfillmentComponentData()
}
// Read advancedOrders[orderIndex] pointer from its array head.
let orderPtr := mload(
// Calculate head position of advancedOrders[orderIndex].
add(add(advancedOrders, OneWord), mul(orderIndex, OneWord))
)
// Load consideration array pointer.
let considerationArrPtr := mload(
add(
// Read pointer to OrderParameters from the AdvancedOrder.
mload(orderPtr),
OrderParameters_consideration_head_offset
)
)
// Retrieve item index using an offset of the fulfillment pointer.
let itemIndex := mload(
add(mload(fulfillmentHeadPtr), Fulfillment_itemIndex_offset)
)
// Ensure that the order index is not out of range.
if iszero(lt(itemIndex, mload(considerationArrPtr))) {
throwInvalidFulfillmentComponentData()
}
// Retrieve consideration item pointer using the item index.
let considerationItemPtr := mload(
add(
// Get pointer to beginning of receivedItem.
add(considerationArrPtr, OneWord),
// Calculate offset to pointer for desired order.
mul(itemIndex, OneWord)
)
)
// Declare a variable for the final aggregated item amount.
let amount := 0
// Create variable to track errors encountered with amount.
let errorBuffer := 0
// Only add consideration amount to execution amount if numerator is
// greater than zero.
if mload(add(orderPtr, AdvancedOrder_numerator_offset)) {
// Retrieve amount pointer using consideration item pointer.
let amountPtr := add(considerationItemPtr, Common_amount_offset)
// Set the amount.
amount := mload(amountPtr)
// Set error bit if amount is zero.
errorBuffer := iszero(amount)
// Zero out amount on item to indicate it is credited.
mstore(amountPtr, 0)
}
// Retrieve ReceivedItem pointer from Execution.
let receivedItem := mload(execution)
// Set the item type on the received item.
mstore(receivedItem, mload(considerationItemPtr))
// Set the token on the received item.
mstore(
add(receivedItem, Common_token_offset),
mload(add(considerationItemPtr, Common_token_offset))
)
// Set the identifier on the received item.
mstore(
add(receivedItem, Common_identifier_offset),
mload(add(considerationItemPtr, Common_identifier_offset))
)
// Set the recipient on the received item.
mstore(
add(receivedItem, ReceivedItem_recipient_offset),
mload(
add(
considerationItemPtr,
ConsiderationItem_recipient_offset
)
)
)
// Calculate the hash of (itemType, token, identifier).
let dataHash := keccak256(
receivedItem,
ReceivedItem_CommonParams_size
)
// Get position one word past last element in head of array.
let endPtr := add(
considerationComponents,
mul(mload(considerationComponents), OneWord)
)
// Iterate over remaining offer components.
// prettier-ignore
for {} lt(fulfillmentHeadPtr, endPtr) {} {
// Increment position in considerationComponents head.
fulfillmentHeadPtr := add(fulfillmentHeadPtr, OneWord)
// Get the order index using the fulfillment pointer.
orderIndex := mload(mload(fulfillmentHeadPtr))
// Ensure the order index is in range.
if iszero(lt(orderIndex, mload(advancedOrders))) {
throwInvalidFulfillmentComponentData()
}
// Get pointer to AdvancedOrder element.
orderPtr := mload(
add(
add(advancedOrders, OneWord),
mul(orderIndex, OneWord)
)
)
// Only continue if numerator is not zero.
if iszero(
mload(add(orderPtr, AdvancedOrder_numerator_offset))
) {
continue
}
// Load consideration array pointer from OrderParameters.
considerationArrPtr := mload(
add(
// Get pointer to OrderParameters from AdvancedOrder.
mload(orderPtr),
OrderParameters_consideration_head_offset
)
)
// Get the item index using the fulfillment pointer.
itemIndex := mload(add(mload(fulfillmentHeadPtr), OneWord))
// Check if itemIndex is within the range of array.
if iszero(lt(itemIndex, mload(considerationArrPtr))) {
throwInvalidFulfillmentComponentData()
}
// Retrieve consideration item pointer using index.
considerationItemPtr := mload(
add(
// Get pointer to beginning of receivedItem.
add(considerationArrPtr, OneWord),
// Use offset to pointer for desired order.
mul(itemIndex, OneWord)
)
)
// Retrieve amount pointer using consideration item pointer.
let amountPtr := add(
considerationItemPtr,
Common_amount_offset
)
// Add offer amount to execution amount.
let newAmount := add(amount, mload(amountPtr))
// Update error buffer: 1 = zero amount, 2 = overflow, 3 = both.
errorBuffer := or(
errorBuffer,
or(
shl(1, lt(newAmount, amount)),
iszero(mload(amountPtr))
)
)
// Update the amount to the new, summed amount.
amount := newAmount
// Zero out amount on original item to indicate it is credited.
mstore(amountPtr, 0)
// Ensure the indicated item matches original item.
if iszero(
and(
// Item recipients must match.
eq(
mload(
add(
considerationItemPtr,
ConsiderItem_recipient_offset
)
),
mload(
add(
receivedItem,
ReceivedItem_recipient_offset
)
)
),
// The itemType, token, identifier must match.
eq(
dataHash,
keccak256(
considerationItemPtr,
ReceivedItem_CommonParams_size
)
)
)
) {
// Throw if any of the requirements are not met.
throwInvalidFulfillmentComponentData()
}
}
// Write final amount to execution.
mstore(add(receivedItem, Common_amount_offset), amount)
// Determine whether the error buffer contains a nonzero error code.
if errorBuffer {
// If errorBuffer is 1, an item had an amount of zero.
if eq(errorBuffer, 1) {
// Store the MissingItemAmount error signature.
mstore(0, MissingItemAmount_error_signature)
// Return, supplying MissingItemAmount signature.
revert(0, MissingItemAmount_error_len)
}
// If errorBuffer is not 1 or 0, the sum overflowed.
// Panic!
throwOverflow()
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { ItemType } from "./ConsiderationEnums.sol";
// prettier-ignore
import {
OfferItem,
ConsiderationItem,
SpentItem,
ReceivedItem,
OrderParameters,
Order,
AdvancedOrder,
CriteriaResolver
} from "./ConsiderationStructs.sol";
import { BasicOrderFulfiller } from "./BasicOrderFulfiller.sol";
import { CriteriaResolution } from "./CriteriaResolution.sol";
import { AmountDeriver } from "./AmountDeriver.sol";
import "./ConsiderationConstants.sol";
/**
* @title OrderFulfiller
* @author 0age
* @notice OrderFulfiller contains logic related to order fulfillment where a
* single order is being fulfilled and where basic order fulfillment is
* not available as an option.
*/
contract OrderFulfiller is
BasicOrderFulfiller,
CriteriaResolution,
AmountDeriver
{
/**
* @dev Derive and set hashes, reference chainId, and associated domain
* separator during deployment.
*
* @param conduitController A contract that deploys conduits, or proxies
* that may optionally be used to transfer approved
* ERC20/721/1155 tokens.
*/
constructor(address conduitController)
BasicOrderFulfiller(conduitController)
{}
/**
* @dev Internal function to validate an order and update its status, adjust
* prices based on current time, apply criteria resolvers, determine
* what portion to fill, and transfer relevant tokens.
*
* @param advancedOrder The order to fulfill as well as the fraction
* to fill. Note that all offer and consideration
* components must divide with no remainder for
* the partial fill to be valid.
* @param criteriaResolvers An array where each element contains a
* reference to a specific offer or
* consideration, a token identifier, and a proof
* that the supplied token identifier is
* contained in the order's merkle root. Note
* that a criteria of zero indicates that any
* (transferable) token identifier is valid and
* that no proof needs to be supplied.
* @param fulfillerConduitKey A bytes32 value indicating what conduit, if
* any, to source the fulfiller's token approvals
* from. The zero hash signifies that no conduit
* should be used, with direct approvals set on
* Consideration.
* @param recipient The intended recipient for all received items.
*
* @return A boolean indicating whether the order has been fulfilled.
*/
function _validateAndFulfillAdvancedOrder(
AdvancedOrder memory advancedOrder,
CriteriaResolver[] memory criteriaResolvers,
bytes32 fulfillerConduitKey,
address recipient
) internal returns (bool) {
// Ensure this function cannot be triggered during a reentrant call.
_setReentrancyGuard();
// Declare empty bytes32 array (unused, will remain empty).
bytes32[] memory priorOrderHashes;
// Validate order, update status, and determine fraction to fill.
(
bytes32 orderHash,
uint256 fillNumerator,
uint256 fillDenominator
) = _validateOrderAndUpdateStatus(
advancedOrder,
criteriaResolvers,
true,
priorOrderHashes
);
// Create an array with length 1 containing the order.
AdvancedOrder[] memory advancedOrders = new AdvancedOrder[](1);
// Populate the order as the first and only element of the new array.
advancedOrders[0] = advancedOrder;
// Apply criteria resolvers using generated orders and details arrays.
_applyCriteriaResolvers(advancedOrders, criteriaResolvers);
// Retrieve the order parameters after applying criteria resolvers.
OrderParameters memory orderParameters = advancedOrders[0].parameters;
// Perform each item transfer with the appropriate fractional amount.
_applyFractionsAndTransferEach(
orderParameters,
fillNumerator,
fillDenominator,
fulfillerConduitKey,
recipient
);
// Emit an event signifying that the order has been fulfilled.
_emitOrderFulfilledEvent(
orderHash,
orderParameters.offerer,
orderParameters.zone,
recipient,
orderParameters.offer,
orderParameters.consideration
);
// Clear the reentrancy guard.
_clearReentrancyGuard();
return true;
}
/**
* @dev Internal function to transfer each item contained in a given single
* order fulfillment after applying a respective fraction to the amount
* being transferred.
*
* @param orderParameters The parameters for the fulfilled order.
* @param numerator A value indicating the portion of the order
* that should be filled.
* @param denominator A value indicating the total order size.
* @param fulfillerConduitKey A bytes32 value indicating what conduit, if
* any, to source the fulfiller's token approvals
* from. The zero hash signifies that no conduit
* should be used, with direct approvals set on
* Consideration.
* @param recipient The intended recipient for all received items.
*/
function _applyFractionsAndTransferEach(
OrderParameters memory orderParameters,
uint256 numerator,
uint256 denominator,
bytes32 fulfillerConduitKey,
address recipient
) internal {
// Read start time & end time from order parameters and place on stack.
uint256 startTime = orderParameters.startTime;
uint256 endTime = orderParameters.endTime;
// Initialize an accumulator array. From this point forward, no new
// memory regions can be safely allocated until the accumulator is no
// longer being utilized, as the accumulator operates in an open-ended
// fashion from this memory pointer; existing memory may still be
// accessed and modified, however.
bytes memory accumulator = new bytes(AccumulatorDisarmed);
// As of solidity 0.6.0, inline assembly cannot directly access function
// definitions, but can still access locally scoped function variables.
// This means that in order to recast the type of a function, we need to
// create a local variable to reference the internal function definition
// (using the same type) and a local variable with the desired type,
// and then cast the original function pointer to the desired type.
/**
* Repurpose existing OfferItem memory regions on the offer array for
* the order by overriding the _transfer function pointer to accept a
* modified OfferItem argument in place of the usual ReceivedItem:
*
* ========= OfferItem ========== ====== ReceivedItem ======
* ItemType itemType; ------------> ItemType itemType;
* address token; ----------------> address token;
* uint256 identifierOrCriteria; -> uint256 identifier;
* uint256 startAmount; ----------> uint256 amount;
* uint256 endAmount; ------------> address recipient;
*/
// Declare a nested scope to minimize stack depth.
unchecked {
// Declare a virtual function pointer taking an OfferItem argument.
function(OfferItem memory, address, bytes32, bytes memory)
internal _transferOfferItem;
{
// Assign _transfer function to a new function pointer (it takes
// a ReceivedItem as its initial argument)
function(ReceivedItem memory, address, bytes32, bytes memory)
internal _transferReceivedItem = _transfer;
// Utilize assembly to override the virtual function pointer.
assembly {
// Cast initial ReceivedItem type to an OfferItem type.
_transferOfferItem := _transferReceivedItem
}
}
// Read offer array length from memory and place on stack.
uint256 totalOfferItems = orderParameters.offer.length;
// Iterate over each offer on the order.
// Skip overflow check as for loop is indexed starting at zero.
for (uint256 i = 0; i < totalOfferItems; ++i) {
// Retrieve the offer item.
OfferItem memory offerItem = orderParameters.offer[i];
// Offer items for the native token can not be received
// outside of a match order function.
if (offerItem.itemType == ItemType.NATIVE) {
revert InvalidNativeOfferItem();
}
// Declare an additional nested scope to minimize stack depth.
{
// Apply fill fraction to get offer item amount to transfer.
uint256 amount = _applyFraction(
offerItem.startAmount,
offerItem.endAmount,
numerator,
denominator,
startTime,
endTime,
false
);
// Utilize assembly to set overloaded offerItem arguments.
assembly {
// Write new fractional amount to startAmount as amount.
mstore(
add(offerItem, ReceivedItem_amount_offset),
amount
)
// Write recipient to endAmount.
mstore(
add(offerItem, ReceivedItem_recipient_offset),
recipient
)
}
}
// Transfer the item from the offerer to the recipient.
_transferOfferItem(
offerItem,
orderParameters.offerer,
orderParameters.conduitKey,
accumulator
);
}
}
// Put ether value supplied by the caller on the stack.
uint256 etherRemaining = msg.value;
/**
* Repurpose existing ConsiderationItem memory regions on the
* consideration array for the order by overriding the _transfer
* function pointer to accept a modified ConsiderationItem argument in
* place of the usual ReceivedItem:
*
* ====== ConsiderationItem ===== ====== ReceivedItem ======
* ItemType itemType; ------------> ItemType itemType;
* address token; ----------------> address token;
* uint256 identifierOrCriteria;--> uint256 identifier;
* uint256 startAmount; ----------> uint256 amount;
* uint256 endAmount; /----> address recipient;
* address recipient; ------/
*/
// Declare a nested scope to minimize stack depth.
unchecked {
// Declare virtual function pointer with ConsiderationItem argument.
function(ConsiderationItem memory, address, bytes32, bytes memory)
internal _transferConsiderationItem;
{
// Reassign _transfer function to a new function pointer (it
// takes a ReceivedItem as its initial argument).
function(ReceivedItem memory, address, bytes32, bytes memory)
internal _transferReceivedItem = _transfer;
// Utilize assembly to override the virtual function pointer.
assembly {
// Cast ReceivedItem type to ConsiderationItem type.
_transferConsiderationItem := _transferReceivedItem
}
}
// Read consideration array length from memory and place on stack.
uint256 totalConsiderationItems = orderParameters
.consideration
.length;
// Iterate over each consideration item on the order.
// Skip overflow check as for loop is indexed starting at zero.
for (uint256 i = 0; i < totalConsiderationItems; ++i) {
// Retrieve the consideration item.
ConsiderationItem memory considerationItem = (
orderParameters.consideration[i]
);
// Apply fraction & derive considerationItem amount to transfer.
uint256 amount = _applyFraction(
considerationItem.startAmount,
considerationItem.endAmount,
numerator,
denominator,
startTime,
endTime,
true
);
// Use assembly to set overloaded considerationItem arguments.
assembly {
// Write derived fractional amount to startAmount as amount.
mstore(
add(considerationItem, ReceivedItem_amount_offset),
amount
)
// Write original recipient to endAmount as recipient.
mstore(
add(considerationItem, ReceivedItem_recipient_offset),
mload(
add(
considerationItem,
ConsiderationItem_recipient_offset
)
)
)
}
// Reduce available value if offer spent ETH or a native token.
if (considerationItem.itemType == ItemType.NATIVE) {
// Ensure that sufficient native tokens are still available.
if (amount > etherRemaining) {
revert InsufficientEtherSupplied();
}
// Skip underflow check as a comparison has just been made.
etherRemaining -= amount;
}
// Transfer item from caller to recipient specified by the item.
_transferConsiderationItem(
considerationItem,
msg.sender,
fulfillerConduitKey,
accumulator
);
}
}
// Trigger any remaining accumulated transfers via call to the conduit.
_triggerIfArmed(accumulator);
// If any ether remains after fulfillments...
if (etherRemaining != 0) {
// return it to the caller.
_transferEth(payable(msg.sender), etherRemaining);
}
}
/**
* @dev Internal function to emit an OrderFulfilled event. OfferItems are
* translated into SpentItems and ConsiderationItems are translated
* into ReceivedItems.
*
* @param orderHash The order hash.
* @param offerer The offerer for the order.
* @param zone The zone for the order.
* @param fulfiller The fulfiller of the order, or the null address if
* the order was fulfilled via order matching.
* @param offer The offer items for the order.
* @param consideration The consideration items for the order.
*/
function _emitOrderFulfilledEvent(
bytes32 orderHash,
address offerer,
address zone,
address fulfiller,
OfferItem[] memory offer,
ConsiderationItem[] memory consideration
) internal {
// Cast already-modified offer memory region as spent items.
SpentItem[] memory spentItems;
assembly {
spentItems := offer
}
// Cast already-modified consideration memory region as received items.
ReceivedItem[] memory receivedItems;
assembly {
receivedItems := consideration
}
// Emit an event signifying that the order has been fulfilled.
emit OrderFulfilled(
orderHash,
offerer,
zone,
fulfiller,
spentItems,
receivedItems
);
}
/**
* @dev Internal pure function to convert an order to an advanced order with
* numerator and denominator of 1 and empty extraData.
*
* @param order The order to convert.
*
* @return advancedOrder The new advanced order.
*/
function _convertOrderToAdvanced(Order calldata order)
internal
pure
returns (AdvancedOrder memory advancedOrder)
{
// Convert to partial order (1/1 or full fill) and return new value.
advancedOrder = AdvancedOrder(
order.parameters,
1,
1,
order.signature,
""
);
}
/**
* @dev Internal pure function to convert an array of orders to an array of
* advanced orders with numerator and denominator of 1.
*
* @param orders The orders to convert.
*
* @return advancedOrders The new array of partial orders.
*/
function _convertOrdersToAdvanced(Order[] calldata orders)
internal
pure
returns (AdvancedOrder[] memory advancedOrders)
{
// Read the number of orders from calldata and place on the stack.
uint256 totalOrders = orders.length;
// Allocate new empty array for each partial order in memory.
advancedOrders = new AdvancedOrder[](totalOrders);
// Skip overflow check as the index for the loop starts at zero.
unchecked {
// Iterate over the given orders.
for (uint256 i = 0; i < totalOrders; ++i) {
// Convert to partial order (1/1 or full fill) and update array.
advancedOrders[i] = _convertOrderToAdvanced(orders[i]);
}
}
// Return the array of advanced orders.
return advancedOrders;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
// prettier-ignore
enum OrderType {
// 0: no partial fills, anyone can execute
FULL_OPEN,
// 1: partial fills supported, anyone can execute
PARTIAL_OPEN,
// 2: no partial fills, only offerer or zone can execute
FULL_RESTRICTED,
// 3: partial fills supported, only offerer or zone can execute
PARTIAL_RESTRICTED
}
// prettier-ignore
enum BasicOrderType {
// 0: no partial fills, anyone can execute
ETH_TO_ERC721_FULL_OPEN,
// 1: partial fills supported, anyone can execute
ETH_TO_ERC721_PARTIAL_OPEN,
// 2: no partial fills, only offerer or zone can execute
ETH_TO_ERC721_FULL_RESTRICTED,
// 3: partial fills supported, only offerer or zone can execute
ETH_TO_ERC721_PARTIAL_RESTRICTED,
// 4: no partial fills, anyone can execute
ETH_TO_ERC1155_FULL_OPEN,
// 5: partial fills supported, anyone can execute
ETH_TO_ERC1155_PARTIAL_OPEN,
// 6: no partial fills, only offerer or zone can execute
ETH_TO_ERC1155_FULL_RESTRICTED,
// 7: partial fills supported, only offerer or zone can execute
ETH_TO_ERC1155_PARTIAL_RESTRICTED,
// 8: no partial fills, anyone can execute
ERC20_TO_ERC721_FULL_OPEN,
// 9: partial fills supported, anyone can execute
ERC20_TO_ERC721_PARTIAL_OPEN,
// 10: no partial fills, only offerer or zone can execute
ERC20_TO_ERC721_FULL_RESTRICTED,
// 11: partial fills supported, only offerer or zone can execute
ERC20_TO_ERC721_PARTIAL_RESTRICTED,
// 12: no partial fills, anyone can execute
ERC20_TO_ERC1155_FULL_OPEN,
// 13: partial fills supported, anyone can execute
ERC20_TO_ERC1155_PARTIAL_OPEN,
// 14: no partial fills, only offerer or zone can execute
ERC20_TO_ERC1155_FULL_RESTRICTED,
// 15: partial fills supported, only offerer or zone can execute
ERC20_TO_ERC1155_PARTIAL_RESTRICTED,
// 16: no partial fills, anyone can execute
ERC721_TO_ERC20_FULL_OPEN,
// 17: partial fills supported, anyone can execute
ERC721_TO_ERC20_PARTIAL_OPEN,
// 18: no partial fills, only offerer or zone can execute
ERC721_TO_ERC20_FULL_RESTRICTED,
// 19: partial fills supported, only offerer or zone can execute
ERC721_TO_ERC20_PARTIAL_RESTRICTED,
// 20: no partial fills, anyone can execute
ERC1155_TO_ERC20_FULL_OPEN,
// 21: partial fills supported, anyone can execute
ERC1155_TO_ERC20_PARTIAL_OPEN,
// 22: no partial fills, only offerer or zone can execute
ERC1155_TO_ERC20_FULL_RESTRICTED,
// 23: partial fills supported, only offerer or zone can execute
ERC1155_TO_ERC20_PARTIAL_RESTRICTED
}
// prettier-ignore
enum BasicOrderRouteType {
// 0: provide Ether (or other native token) to receive offered ERC721 item.
ETH_TO_ERC721,
// 1: provide Ether (or other native token) to receive offered ERC1155 item.
ETH_TO_ERC1155,
// 2: provide ERC20 item to receive offered ERC721 item.
ERC20_TO_ERC721,
// 3: provide ERC20 item to receive offered ERC1155 item.
ERC20_TO_ERC1155,
// 4: provide ERC721 item to receive offered ERC20 item.
ERC721_TO_ERC20,
// 5: provide ERC1155 item to receive offered ERC20 item.
ERC1155_TO_ERC20
}
// prettier-ignore
enum ItemType {
// 0: ETH on mainnet, MATIC on polygon, etc.
NATIVE,
// 1: ERC20 items (ERC777 and ERC20 analogues could also technically work)
ERC20,
// 2: ERC721 items
ERC721,
// 3: ERC1155 items
ERC1155,
// 4: ERC721 items where a number of tokenIds are supported
ERC721_WITH_CRITERIA,
// 5: ERC1155 items where a number of ids are supported
ERC1155_WITH_CRITERIA
}
// prettier-ignore
enum Side {
// 0: Items that can be spent
OFFER,
// 1: Items that must be received
CONSIDERATION
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
// prettier-ignore
import {
AmountDerivationErrors
} from "./AmountDerivationErrors.sol";
import "./ConsiderationConstants.sol";
/**
* @title AmountDeriver
* @author 0age
* @notice AmountDeriver contains view and pure functions related to deriving
* item amounts based on partial fill quantity and on linear
* interpolation based on current time when the start amount and end
* amount differ.
*/
contract AmountDeriver is AmountDerivationErrors {
/**
* @dev Internal view function to derive the current amount of a given item
* based on the current price, the starting price, and the ending
* price. If the start and end prices differ, the current price will be
* interpolated on a linear basis. Note that this function expects that
* the startTime parameter of orderParameters is not greater than the
* current block timestamp and that the endTime parameter is greater
* than the current block timestamp. If this condition is not upheld,
* duration / elapsed / remaining variables will underflow.
*
* @param startAmount The starting amount of the item.
* @param endAmount The ending amount of the item.
* @param startTime The starting time of the order.
* @param endTime The end time of the order.
* @param roundUp A boolean indicating whether the resultant amount
* should be rounded up or down.
*
* @return amount The current amount.
*/
function _locateCurrentAmount(
uint256 startAmount,
uint256 endAmount,
uint256 startTime,
uint256 endTime,
bool roundUp
) internal view returns (uint256 amount) {
// Only modify end amount if it doesn't already equal start amount.
if (startAmount != endAmount) {
// Declare variables to derive in the subsequent unchecked scope.
uint256 duration;
uint256 elapsed;
uint256 remaining;
// Skip underflow checks as startTime <= block.timestamp < endTime.
unchecked {
// Derive the duration for the order and place it on the stack.
duration = endTime - startTime;
// Derive time elapsed since the order started & place on stack.
elapsed = block.timestamp - startTime;
// Derive time remaining until order expires and place on stack.
remaining = duration - elapsed;
}
// Aggregate new amounts weighted by time with rounding factor.
uint256 totalBeforeDivision = ((startAmount * remaining) +
(endAmount * elapsed));
// Use assembly to combine operations and skip divide-by-zero check.
assembly {
// Multiply by iszero(iszero(totalBeforeDivision)) to ensure
// amount is set to zero if totalBeforeDivision is zero,
// as intermediate overflow can occur if it is zero.
amount := mul(
iszero(iszero(totalBeforeDivision)),
// Subtract 1 from the numerator and add 1 to the result if
// roundUp is true to get the proper rounding direction.
// Division is performed with no zero check as duration
// cannot be zero as long as startTime < endTime.
add(
div(sub(totalBeforeDivision, roundUp), duration),
roundUp
)
)
}
// Return the current amount.
return amount;
}
// Return the original amount as startAmount == endAmount.
return endAmount;
}
/**
* @dev Internal pure function to return a fraction of a given value and to
* ensure the resultant value does not have any fractional component.
* Note that this function assumes that zero will never be supplied as
* the denominator parameter; invalid / undefined behavior will result
* should a denominator of zero be provided.
*
* @param numerator A value indicating the portion of the order that
* should be filled.
* @param denominator A value indicating the total size of the order. Note
* that this value cannot be equal to zero.
* @param value The value for which to compute the fraction.
*
* @return newValue The value after applying the fraction.
*/
function _getFraction(
uint256 numerator,
uint256 denominator,
uint256 value
) internal pure returns (uint256 newValue) {
// Return value early in cases where the fraction resolves to 1.
if (numerator == denominator) {
return value;
}
// Ensure fraction can be applied to the value with no remainder. Note
// that the denominator cannot be zero.
assembly {
// Ensure new value contains no remainder via mulmod operator.
// Credit to @hrkrshnn + @axic for proposing this optimal solution.
if mulmod(value, numerator, denominator) {
mstore(0, InexactFraction_error_signature)
revert(0, InexactFraction_error_len)
}
}
// Multiply the numerator by the value and ensure no overflow occurs.
uint256 valueTimesNumerator = value * numerator;
// Divide and check for remainder. Note that denominator cannot be zero.
assembly {
// Perform division without zero check.
newValue := div(valueTimesNumerator, denominator)
}
}
/**
* @dev Internal view function to apply a fraction to a consideration
* or offer item.
*
* @param startAmount The starting amount of the item.
* @param endAmount The ending amount of the item.
* @param numerator A value indicating the portion of the order that
* should be filled.
* @param denominator A value indicating the total size of the order.
* @param startTime The starting time of the order.
* @param endTime The end time of the order.
* @param roundUp A boolean indicating whether the resultant
* amount should be rounded up or down.
*
* @return amount The received item to transfer with the final amount.
*/
function _applyFraction(
uint256 startAmount,
uint256 endAmount,
uint256 numerator,
uint256 denominator,
uint256 startTime,
uint256 endTime,
bool roundUp
) internal view returns (uint256 amount) {
// If start amount equals end amount, apply fraction to end amount.
if (startAmount == endAmount) {
// Apply fraction to end amount.
amount = _getFraction(numerator, denominator, endAmount);
} else {
// Otherwise, apply fraction to both and interpolated final amount.
amount = _locateCurrentAmount(
_getFraction(numerator, denominator, startAmount),
_getFraction(numerator, denominator, endAmount),
startTime,
endTime,
roundUp
);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { ItemType, Side } from "./ConsiderationEnums.sol";
// prettier-ignore
import {
OfferItem,
ConsiderationItem,
OrderParameters,
AdvancedOrder,
CriteriaResolver
} from "./ConsiderationStructs.sol";
import "./ConsiderationConstants.sol";
// prettier-ignore
import {
CriteriaResolutionErrors
} from "./CriteriaResolutionErrors.sol";
/**
* @title CriteriaResolution
* @author 0age
* @notice CriteriaResolution contains a collection of pure functions related to
* resolving criteria-based items.
*/
contract CriteriaResolution is CriteriaResolutionErrors {
/**
* @dev Internal pure function to apply criteria resolvers containing
* specific token identifiers and associated proofs to order items.
*
* @param advancedOrders The orders to apply criteria resolvers to.
* @param criteriaResolvers An array where each element contains a
* reference to a specific order as well as that
* order's offer or consideration, a token
* identifier, and a proof that the supplied token
* identifier is contained in the order's merkle
* root. Note that a root of zero indicates that
* any transferable token identifier is valid and
* that no proof needs to be supplied.
*/
function _applyCriteriaResolvers(
AdvancedOrder[] memory advancedOrders,
CriteriaResolver[] memory criteriaResolvers
) internal pure {
// Skip overflow checks as all for loops are indexed starting at zero.
unchecked {
// Retrieve length of criteria resolvers array and place on stack.
uint256 totalCriteriaResolvers = criteriaResolvers.length;
// Retrieve length of orders array and place on stack.
uint256 totalAdvancedOrders = advancedOrders.length;
// Iterate over each criteria resolver.
for (uint256 i = 0; i < totalCriteriaResolvers; ++i) {
// Retrieve the criteria resolver.
CriteriaResolver memory criteriaResolver = (
criteriaResolvers[i]
);
// Read the order index from memory and place it on the stack.
uint256 orderIndex = criteriaResolver.orderIndex;
// Ensure that the order index is in range.
if (orderIndex >= totalAdvancedOrders) {
revert OrderCriteriaResolverOutOfRange();
}
// Skip criteria resolution for order if not fulfilled.
if (advancedOrders[orderIndex].numerator == 0) {
continue;
}
// Retrieve the parameters for the order.
OrderParameters memory orderParameters = (
advancedOrders[orderIndex].parameters
);
// Read component index from memory and place it on the stack.
uint256 componentIndex = criteriaResolver.index;
// Declare values for item's type and criteria.
ItemType itemType;
uint256 identifierOrCriteria;
// If the criteria resolver refers to an offer item...
if (criteriaResolver.side == Side.OFFER) {
// Retrieve the offer.
OfferItem[] memory offer = orderParameters.offer;
// Ensure that the component index is in range.
if (componentIndex >= offer.length) {
revert OfferCriteriaResolverOutOfRange();
}
// Retrieve relevant item using the component index.
OfferItem memory offerItem = offer[componentIndex];
// Read item type and criteria from memory & place on stack.
itemType = offerItem.itemType;
identifierOrCriteria = offerItem.identifierOrCriteria;
// Optimistically update item type to remove criteria usage.
// Use assembly to operate on ItemType enum as a number.
ItemType newItemType;
assembly {
// Item type 4 becomes 2 and item type 5 becomes 3.
newItemType := sub(3, eq(itemType, 4))
}
offerItem.itemType = newItemType;
// Optimistically update identifier w/ supplied identifier.
offerItem.identifierOrCriteria = criteriaResolver
.identifier;
} else {
// Otherwise, the resolver refers to a consideration item.
ConsiderationItem[] memory consideration = (
orderParameters.consideration
);
// Ensure that the component index is in range.
if (componentIndex >= consideration.length) {
revert ConsiderationCriteriaResolverOutOfRange();
}
// Retrieve relevant item using order and component index.
ConsiderationItem memory considerationItem = (
consideration[componentIndex]
);
// Read item type and criteria from memory & place on stack.
itemType = considerationItem.itemType;
identifierOrCriteria = (
considerationItem.identifierOrCriteria
);
// Optimistically update item type to remove criteria usage.
// Use assembly to operate on ItemType enum as a number.
ItemType newItemType;
assembly {
// Item type 4 becomes 2 and item type 5 becomes 3.
newItemType := sub(3, eq(itemType, 4))
}
considerationItem.itemType = newItemType;
// Optimistically update identifier w/ supplied identifier.
considerationItem.identifierOrCriteria = (
criteriaResolver.identifier
);
}
// Ensure the specified item type indicates criteria usage.
if (!_isItemWithCriteria(itemType)) {
revert CriteriaNotEnabledForItem();
}
// If criteria is not 0 (i.e. a collection-wide offer)...
if (identifierOrCriteria != uint256(0)) {
// Verify identifier inclusion in criteria root using proof.
_verifyProof(
criteriaResolver.identifier,
identifierOrCriteria,
criteriaResolver.criteriaProof
);
}
}
// Iterate over each advanced order.
for (uint256 i = 0; i < totalAdvancedOrders; ++i) {
// Retrieve the advanced order.
AdvancedOrder memory advancedOrder = advancedOrders[i];
// Skip criteria resolution for order if not fulfilled.
if (advancedOrder.numerator == 0) {
continue;
}
// Retrieve the parameters for the order.
OrderParameters memory orderParameters = (
advancedOrder.parameters
);
// Read consideration length from memory and place on stack.
uint256 totalItems = orderParameters.consideration.length;
// Iterate over each consideration item on the order.
for (uint256 j = 0; j < totalItems; ++j) {
// Ensure item type no longer indicates criteria usage.
if (
_isItemWithCriteria(
orderParameters.consideration[j].itemType
)
) {
revert UnresolvedConsiderationCriteria();
}
}
// Read offer length from memory and place on stack.
totalItems = orderParameters.offer.length;
// Iterate over each offer item on the order.
for (uint256 j = 0; j < totalItems; ++j) {
// Ensure item type no longer indicates criteria usage.
if (
_isItemWithCriteria(orderParameters.offer[j].itemType)
) {
revert UnresolvedOfferCriteria();
}
}
}
}
}
/**
* @dev Internal pure function to check whether a given item type represents
* a criteria-based ERC721 or ERC1155 item (e.g. an item that can be
* resolved to one of a number of different identifiers at the time of
* order fulfillment).
*
* @param itemType The item type in question.
*
* @return withCriteria A boolean indicating that the item type in question
* represents a criteria-based item.
*/
function _isItemWithCriteria(ItemType itemType)
internal
pure
returns (bool withCriteria)
{
// ERC721WithCriteria is ItemType 4. ERC1155WithCriteria is ItemType 5.
assembly {
withCriteria := gt(itemType, 3)
}
}
/**
* @dev Internal pure function to ensure that a given element is contained
* in a merkle root via a supplied proof.
*
* @param leaf The element for which to prove inclusion.
* @param root The merkle root that inclusion will be proved against.
* @param proof The merkle proof.
*/
function _verifyProof(
uint256 leaf,
uint256 root,
bytes32[] memory proof
) internal pure {
// Declare a variable that will be used to determine proof validity.
bool isValid;
// Utilize assembly to efficiently verify the proof against the root.
assembly {
// Store the leaf at the beginning of scratch space.
mstore(0, leaf)
// Derive the hash of the leaf to use as the initial proof element.
let computedHash := keccak256(0, OneWord)
// Based on: https://github.com/Rari-Capital/solmate/blob/v7/src/utils/MerkleProof.sol
// Get memory start location of the first element in proof array.
let data := add(proof, OneWord)
// Iterate over each proof element to compute the root hash.
for {
// Left shift by 5 is equivalent to multiplying by 0x20.
let end := add(data, shl(5, mload(proof)))
} lt(data, end) {
// Increment by one word at a time.
data := add(data, OneWord)
} {
// Get the proof element.
let loadedData := mload(data)
// Sort proof elements and place them in scratch space.
// Slot of `computedHash` in scratch space.
// If the condition is true: 0x20, otherwise: 0x00.
let scratch := shl(5, gt(computedHash, loadedData))
// Store elements to hash contiguously in scratch space. Scratch
// space is 64 bytes (0x00 - 0x3f) & both elements are 32 bytes.
mstore(scratch, computedHash)
mstore(xor(scratch, OneWord), loadedData)
// Derive the updated hash.
computedHash := keccak256(0, TwoWords)
}
// Compare the final hash to the supplied root.
isValid := eq(computedHash, root)
}
// Revert if computed hash does not equal supplied root.
if (!isValid) {
revert InvalidProof();
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { ConduitInterface } from "./ConduitInterface.sol";
// prettier-ignore
import {
OrderType,
ItemType,
BasicOrderRouteType
} from "./ConsiderationEnums.sol";
// prettier-ignore
import {
AdditionalRecipient,
BasicOrderParameters,
OfferItem,
ConsiderationItem,
SpentItem,
ReceivedItem
} from "./ConsiderationStructs.sol";
import { OrderValidator } from "./OrderValidator.sol";
import "./ConsiderationConstants.sol";
/**
* @title BasicOrderFulfiller
* @author 0age
* @notice BasicOrderFulfiller contains functionality for fulfilling "basic"
* orders with minimal overhead. See documentation for details on what
* qualifies as a basic order.
*/
contract BasicOrderFulfiller is OrderValidator {
/**
* @dev Derive and set hashes, reference chainId, and associated domain
* separator during deployment.
*
* @param conduitController A contract that deploys conduits, or proxies
* that may optionally be used to transfer approved
* ERC20/721/1155 tokens.
*/
constructor(address conduitController) OrderValidator(conduitController) {}
/**
* @dev Internal function to fulfill an order offering an ERC20, ERC721, or
* ERC1155 item by supplying Ether (or other native tokens), ERC20
* tokens, an ERC721 item, or an ERC1155 item as consideration. Six
* permutations are supported: Native token to ERC721, Native token to
* ERC1155, ERC20 to ERC721, ERC20 to ERC1155, ERC721 to ERC20, and
* ERC1155 to ERC20 (with native tokens supplied as msg.value). For an
* order to be eligible for fulfillment via this method, it must
* contain a single offer item (though that item may have a greater
* amount if the item is not an ERC721). An arbitrary number of
* "additional recipients" may also be supplied which will each receive
* native tokens or ERC20 items from the fulfiller as consideration.
* Refer to the documentation for a more comprehensive summary of how
* to utilize this method and what orders are compatible with it.
*
* @param parameters Additional information on the fulfilled order. Note
* that the offerer and the fulfiller must first approve
* this contract (or their chosen conduit if indicated)
* before any tokens can be transferred. Also note that
* contract recipients of ERC1155 consideration items must
* implement `onERC1155Received` in order to receive those
* items.
*
* @return A boolean indicating whether the order has been fulfilled.
*/
function _validateAndFulfillBasicOrder(
BasicOrderParameters calldata parameters
) internal returns (bool) {
// Declare enums for order type & route to extract from basicOrderType.
BasicOrderRouteType route;
OrderType orderType;
// Declare additional recipient item type to derive from the route type.
ItemType additionalRecipientsItemType;
// Utilize assembly to extract the order type and the basic order route.
assembly {
// Read basicOrderType from calldata.
let basicOrderType := calldataload(BasicOrder_basicOrderType_cdPtr)
// Mask all but 2 least-significant bits to derive the order type.
orderType := and(basicOrderType, 3)
// Divide basicOrderType by four to derive the route.
route := shr(2, basicOrderType)
// If route > 1 additionalRecipient items are ERC20 (1) else Eth (0)
additionalRecipientsItemType := gt(route, 1)
}
{
// Declare temporary variable for enforcing payable status.
bool correctPayableStatus;
// Utilize assembly to compare the route to the callvalue.
assembly {
// route 0 and 1 are payable, otherwise route is not payable.
correctPayableStatus := eq(
additionalRecipientsItemType,
iszero(callvalue())
)
}
// Revert if msg.value has not been supplied as part of payable
// routes or has been supplied as part of non-payable routes.
if (!correctPayableStatus) {
revert InvalidMsgValue(msg.value);
}
}
// Declare more arguments that will be derived from route and calldata.
address additionalRecipientsToken;
ItemType offeredItemType;
bool offerTypeIsAdditionalRecipientsType;
// Declare scope for received item type to manage stack pressure.
{
ItemType receivedItemType;
// Utilize assembly to retrieve function arguments and cast types.
assembly {
// Check if offered item type == additional recipient item type.
offerTypeIsAdditionalRecipientsType := gt(route, 3)
// If route > 3 additionalRecipientsToken is at 0xc4 else 0x24.
additionalRecipientsToken := calldataload(
add(
BasicOrder_considerationToken_cdPtr,
mul(
offerTypeIsAdditionalRecipientsType,
BasicOrder_common_params_size
)
)
)
// If route > 2, receivedItemType is route - 2. If route is 2,
// the receivedItemType is ERC20 (1). Otherwise, it is Eth (0).
receivedItemType := add(
mul(sub(route, 2), gt(route, 2)),
eq(route, 2)
)
// If route > 3, offeredItemType is ERC20 (1). Route is 2 or 3,
// offeredItemType = route. Route is 0 or 1, it is route + 2.
offeredItemType := sub(
add(route, mul(iszero(additionalRecipientsItemType), 2)),
mul(
offerTypeIsAdditionalRecipientsType,
add(receivedItemType, 1)
)
)
}
// Derive & validate order using parameters and update order status.
_prepareBasicFulfillmentFromCalldata(
parameters,
orderType,
receivedItemType,
additionalRecipientsItemType,
additionalRecipientsToken,
offeredItemType
);
}
// Declare conduitKey argument used by transfer functions.
bytes32 conduitKey;
// Utilize assembly to derive conduit (if relevant) based on route.
assembly {
// use offerer conduit for routes 0-3, fulfiller conduit otherwise.
conduitKey := calldataload(
add(
BasicOrder_offererConduit_cdPtr,
mul(offerTypeIsAdditionalRecipientsType, OneWord)
)
)
}
// Transfer tokens based on the route.
if (additionalRecipientsItemType == ItemType.NATIVE) {
// Ensure neither the token nor the identifier parameters are set.
if (
(uint160(parameters.considerationToken) |
parameters.considerationIdentifier) != 0
) {
revert UnusedItemParameters();
}
// Transfer the ERC721 or ERC1155 item, bypassing the accumulator.
_transferIndividual721Or1155Item(
offeredItemType,
parameters.offerToken,
parameters.offerer,
msg.sender,
parameters.offerIdentifier,
parameters.offerAmount,
conduitKey
);
// Transfer native to recipients, return excess to caller & wrap up.
_transferEthAndFinalize(
parameters.considerationAmount,
parameters.offerer,
parameters.additionalRecipients
);
} else {
// Initialize an accumulator array. From this point forward, no new
// memory regions can be safely allocated until the accumulator is
// no longer being utilized, as the accumulator operates in an
// open-ended fashion from this memory pointer; existing memory may
// still be accessed and modified, however.
bytes memory accumulator = new bytes(AccumulatorDisarmed);
// Choose transfer method for ERC721 or ERC1155 item based on route.
if (route == BasicOrderRouteType.ERC20_TO_ERC721) {
// Transfer ERC721 to caller using offerer's conduit preference.
_transferERC721(
parameters.offerToken,
parameters.offerer,
msg.sender,
parameters.offerIdentifier,
parameters.offerAmount,
conduitKey,
accumulator
);
} else if (route == BasicOrderRouteType.ERC20_TO_ERC1155) {
// Transfer ERC1155 to caller with offerer's conduit preference.
_transferERC1155(
parameters.offerToken,
parameters.offerer,
msg.sender,
parameters.offerIdentifier,
parameters.offerAmount,
conduitKey,
accumulator
);
} else if (route == BasicOrderRouteType.ERC721_TO_ERC20) {
// Transfer ERC721 to offerer using caller's conduit preference.
_transferERC721(
parameters.considerationToken,
msg.sender,
parameters.offerer,
parameters.considerationIdentifier,
parameters.considerationAmount,
conduitKey,
accumulator
);
} else {
// route == BasicOrderRouteType.ERC1155_TO_ERC20
// Transfer ERC1155 to offerer with caller's conduit preference.
_transferERC1155(
parameters.considerationToken,
msg.sender,
parameters.offerer,
parameters.considerationIdentifier,
parameters.considerationAmount,
conduitKey,
accumulator
);
}
// Transfer ERC20 tokens to all recipients and wrap up.
_transferERC20AndFinalize(
parameters.offerer,
parameters,
offerTypeIsAdditionalRecipientsType,
accumulator
);
// Trigger any remaining accumulated transfers via call to conduit.
_triggerIfArmed(accumulator);
}
// Clear the reentrancy guard.
_clearReentrancyGuard();
return true;
}
/**
* @dev Internal function to prepare fulfillment of a basic order with
* manual calldata and memory access. This calculates the order hash,
* emits an OrderFulfilled event, and asserts basic order validity.
* Note that calldata offsets must be validated as this function
* accesses constant calldata pointers for dynamic types that match
* default ABI encoding, but valid ABI encoding can use arbitrary
* offsets. Checking that the offsets were produced by default encoding
* will ensure that other functions using Solidity's calldata accessors
* (which calculate pointers from the stored offsets) are reading the
* same data as the order hash is derived from. Also note that This
* function accesses memory directly. It does not clear the expanded
* memory regions used, nor does it update the free memory pointer, so
* other direct memory access must not assume that unused memory is
* empty.
*
* @param parameters The parameters of the basic order.
* @param orderType The order type.
* @param receivedItemType The item type of the initial
* consideration item on the order.
* @param additionalRecipientsItemType The item type of any additional
* consideration item on the order.
* @param additionalRecipientsToken The ERC20 token contract address (if
* applicable) for any additional
* consideration item on the order.
* @param offeredItemType The item type of the offered item on
* the order.
*/
function _prepareBasicFulfillmentFromCalldata(
BasicOrderParameters calldata parameters,
OrderType orderType,
ItemType receivedItemType,
ItemType additionalRecipientsItemType,
address additionalRecipientsToken,
ItemType offeredItemType
) internal {
// Ensure this function cannot be triggered during a reentrant call.
_setReentrancyGuard();
// Ensure current timestamp falls between order start time and end time.
_verifyTime(parameters.startTime, parameters.endTime, true);
// Verify that calldata offsets for all dynamic types were produced by
// default encoding. This ensures that the constants we use for calldata
// pointers to dynamic types are the same as those calculated by
// Solidity using their offsets. Also verify that the basic order type
// is within range.
_assertValidBasicOrderParameters();
// Ensure supplied consideration array length is not less than original.
_assertConsiderationLengthIsNotLessThanOriginalConsiderationLength(
parameters.additionalRecipients.length,
parameters.totalOriginalAdditionalRecipients
);
// Declare stack element for the order hash.
bytes32 orderHash;
{
/**
* First, handle consideration items. Memory Layout:
* 0x60: final hash of the array of consideration item hashes
* 0x80-0x160: reused space for EIP712 hashing of each item
* - 0x80: ConsiderationItem EIP-712 typehash (constant)
* - 0xa0: itemType
* - 0xc0: token
* - 0xe0: identifier
* - 0x100: startAmount
* - 0x120: endAmount
* - 0x140: recipient
* 0x160-END_ARR: array of consideration item hashes
* - 0x160: primary consideration item EIP712 hash
* - 0x180-END_ARR: additional recipient item EIP712 hashes
* END_ARR: beginning of data for OrderFulfilled event
* - END_ARR + 0x120: length of ReceivedItem array
* - END_ARR + 0x140: beginning of data for first ReceivedItem
* (Note: END_ARR = 0x180 + RECIPIENTS_LENGTH * 0x20)
*/
// Load consideration item typehash from runtime and place on stack.
bytes32 typeHash = _CONSIDERATION_ITEM_TYPEHASH;
// Utilize assembly to enable reuse of memory regions and use
// constant pointers when possible.
assembly {
/*
* 1. Calculate the EIP712 ConsiderationItem hash for the
* primary consideration item of the basic order.
*/
// Write ConsiderationItem type hash and item type to memory.
mstore(BasicOrder_considerationItem_typeHash_ptr, typeHash)
mstore(
BasicOrder_considerationItem_itemType_ptr,
receivedItemType
)
// Copy calldata region with (token, identifier, amount) from
// BasicOrderParameters to ConsiderationItem. The
// considerationAmount is written to startAmount and endAmount
// as basic orders do not have dynamic amounts.
calldatacopy(
BasicOrder_considerationItem_token_ptr,
BasicOrder_considerationToken_cdPtr,
ThreeWords
)
// Copy calldata region with considerationAmount and offerer
// from BasicOrderParameters to endAmount and recipient in
// ConsiderationItem.
calldatacopy(
BasicOrder_considerationItem_endAmount_ptr,
BasicOrder_considerationAmount_cdPtr,
TwoWords
)
// Calculate EIP712 ConsiderationItem hash and store it in the
// array of EIP712 consideration hashes.
mstore(
BasicOrder_considerationHashesArray_ptr,
keccak256(
BasicOrder_considerationItem_typeHash_ptr,
EIP712_ConsiderationItem_size
)
)
/*
* 2. Write a ReceivedItem struct for the primary consideration
* item to the consideration array in OrderFulfilled.
*/
// Get the length of the additional recipients array.
let totalAdditionalRecipients := calldataload(
BasicOrder_additionalRecipients_length_cdPtr
)
// Calculate pointer to length of OrderFulfilled consideration
// array.
let eventConsiderationArrPtr := add(
OrderFulfilled_consideration_length_baseOffset,
mul(totalAdditionalRecipients, OneWord)
)
// Set the length of the consideration array to the number of
// additional recipients, plus one for the primary consideration
// item.
mstore(
eventConsiderationArrPtr,
add(
calldataload(
BasicOrder_additionalRecipients_length_cdPtr
),
1
)
)
// Overwrite the consideration array pointer so it points to the
// body of the first element
eventConsiderationArrPtr := add(
eventConsiderationArrPtr,
OneWord
)
// Set itemType at start of the ReceivedItem memory region.
mstore(eventConsiderationArrPtr, receivedItemType)
// Copy calldata region (token, identifier, amount & recipient)
// from BasicOrderParameters to ReceivedItem memory.
calldatacopy(
add(eventConsiderationArrPtr, Common_token_offset),
BasicOrder_considerationToken_cdPtr,
FourWords
)
/*
* 3. Calculate EIP712 ConsiderationItem hashes for original
* additional recipients and add a ReceivedItem for each to the
* consideration array in the OrderFulfilled event. The original
* additional recipients are all the considerations signed by
* the offerer aside from the primary consideration of the
* order. Uses memory region from 0x80-0x160 as a buffer for
* calculating EIP712 ConsiderationItem hashes.
*/
// Put pointer to consideration hashes array on the stack.
// This will be updated as each additional recipient is hashed
let
considerationHashesPtr
:= BasicOrder_considerationHashesArray_ptr
// Write item type, token, & identifier for additional recipient
// to memory region for hashing EIP712 ConsiderationItem; these
// values will be reused for each recipient.
mstore(
BasicOrder_considerationItem_itemType_ptr,
additionalRecipientsItemType
)
mstore(
BasicOrder_considerationItem_token_ptr,
additionalRecipientsToken
)
mstore(BasicOrder_considerationItem_identifier_ptr, 0)
// Read length of the additionalRecipients array from calldata
// and iterate.
totalAdditionalRecipients := calldataload(
BasicOrder_totalOriginalAdditionalRecipients_cdPtr
)
let i := 0
// prettier-ignore
for {} lt(i, totalAdditionalRecipients) {
i := add(i, 1)
} {
/*
* Calculate EIP712 ConsiderationItem hash for recipient.
*/
// Retrieve calldata pointer for additional recipient.
let additionalRecipientCdPtr := add(
BasicOrder_additionalRecipients_data_cdPtr,
mul(AdditionalRecipients_size, i)
)
// Copy startAmount from calldata to the ConsiderationItem
// struct.
calldatacopy(
BasicOrder_considerationItem_startAmount_ptr,
additionalRecipientCdPtr,
OneWord
)
// Copy endAmount and recipient from calldata to the
// ConsiderationItem struct.
calldatacopy(
BasicOrder_considerationItem_endAmount_ptr,
additionalRecipientCdPtr,
AdditionalRecipients_size
)
// Add 1 word to the pointer as part of each loop to reduce
// operations needed to get local offset into the array.
considerationHashesPtr := add(
considerationHashesPtr,
OneWord
)
// Calculate EIP712 ConsiderationItem hash and store it in
// the array of consideration hashes.
mstore(
considerationHashesPtr,
keccak256(
BasicOrder_considerationItem_typeHash_ptr,
EIP712_ConsiderationItem_size
)
)
/*
* Write ReceivedItem to OrderFulfilled data.
*/
// At this point, eventConsiderationArrPtr points to the
// beginning of the ReceivedItem struct of the previous
// element in the array. Increase it by the size of the
// struct to arrive at the pointer for the current element.
eventConsiderationArrPtr := add(
eventConsiderationArrPtr,
ReceivedItem_size
)
// Write itemType to the ReceivedItem struct.
mstore(
eventConsiderationArrPtr,
additionalRecipientsItemType
)
// Write token to the next word of the ReceivedItem struct.
mstore(
add(eventConsiderationArrPtr, OneWord),
additionalRecipientsToken
)
// Copy endAmount & recipient words to ReceivedItem struct.
calldatacopy(
add(
eventConsiderationArrPtr,
ReceivedItem_amount_offset
),
additionalRecipientCdPtr,
TwoWords
)
}
/*
* 4. Hash packed array of ConsiderationItem EIP712 hashes:
* `keccak256(abi.encodePacked(receivedItemHashes))`
* Note that it is set at 0x60 — all other memory begins at
* 0x80. 0x60 is the "zero slot" and will be restored at the end
* of the assembly section and before required by the compiler.
*/
mstore(
receivedItemsHash_ptr,
keccak256(
BasicOrder_considerationHashesArray_ptr,
mul(add(totalAdditionalRecipients, 1), OneWord)
)
)
/*
* 5. Add a ReceivedItem for each tip to the consideration array
* in the OrderFulfilled event. The tips are all the
* consideration items that were not signed by the offerer and
* were provided by the fulfiller.
*/
// Overwrite length to length of the additionalRecipients array.
totalAdditionalRecipients := calldataload(
BasicOrder_additionalRecipients_length_cdPtr
)
// prettier-ignore
for {} lt(i, totalAdditionalRecipients) {
i := add(i, 1)
} {
// Retrieve calldata pointer for additional recipient.
let additionalRecipientCdPtr := add(
BasicOrder_additionalRecipients_data_cdPtr,
mul(AdditionalRecipients_size, i)
)
// At this point, eventConsiderationArrPtr points to the
// beginning of the ReceivedItem struct of the previous
// element in the array. Increase it by the size of the
// struct to arrive at the pointer for the current element.
eventConsiderationArrPtr := add(
eventConsiderationArrPtr,
ReceivedItem_size
)
// Write itemType to the ReceivedItem struct.
mstore(
eventConsiderationArrPtr,
additionalRecipientsItemType
)
// Write token to the next word of the ReceivedItem struct.
mstore(
add(eventConsiderationArrPtr, OneWord),
additionalRecipientsToken
)
// Copy endAmount & recipient words to ReceivedItem struct.
calldatacopy(
add(
eventConsiderationArrPtr,
ReceivedItem_amount_offset
),
additionalRecipientCdPtr,
TwoWords
)
}
}
}
{
/**
* Next, handle offered items. Memory Layout:
* EIP712 data for OfferItem
* - 0x80: OfferItem EIP-712 typehash (constant)
* - 0xa0: itemType
* - 0xc0: token
* - 0xe0: identifier (reused for offeredItemsHash)
* - 0x100: startAmount
* - 0x120: endAmount
*/
// Place offer item typehash on the stack.
bytes32 typeHash = _OFFER_ITEM_TYPEHASH;
// Utilize assembly to enable reuse of memory regions when possible.
assembly {
/*
* 1. Calculate OfferItem EIP712 hash
*/
// Write the OfferItem typeHash to memory.
mstore(BasicOrder_offerItem_typeHash_ptr, typeHash)
// Write the OfferItem item type to memory.
mstore(BasicOrder_offerItem_itemType_ptr, offeredItemType)
// Copy calldata region with (offerToken, offerIdentifier,
// offerAmount) from OrderParameters to (token, identifier,
// startAmount) in OfferItem struct. The offerAmount is written
// to startAmount and endAmount as basic orders do not have
// dynamic amounts.
calldatacopy(
BasicOrder_offerItem_token_ptr,
BasicOrder_offerToken_cdPtr,
ThreeWords
)
// Copy offerAmount from calldata to endAmount in OfferItem
// struct.
calldatacopy(
BasicOrder_offerItem_endAmount_ptr,
BasicOrder_offerAmount_cdPtr,
OneWord
)
// Compute EIP712 OfferItem hash, write result to scratch space:
// `keccak256(abi.encode(offeredItem))`
mstore(
0,
keccak256(
BasicOrder_offerItem_typeHash_ptr,
EIP712_OfferItem_size
)
)
/*
* 2. Calculate hash of array of EIP712 hashes and write the
* result to the corresponding OfferItem struct:
* `keccak256(abi.encodePacked(offerItemHashes))`
*/
mstore(BasicOrder_order_offerHashes_ptr, keccak256(0, OneWord))
/*
* 3. Write SpentItem to offer array in OrderFulfilled event.
*/
let eventConsiderationArrPtr := add(
OrderFulfilled_offer_length_baseOffset,
mul(
calldataload(
BasicOrder_additionalRecipients_length_cdPtr
),
OneWord
)
)
// Set a length of 1 for the offer array.
mstore(eventConsiderationArrPtr, 1)
// Write itemType to the SpentItem struct.
mstore(add(eventConsiderationArrPtr, OneWord), offeredItemType)
// Copy calldata region with (offerToken, offerIdentifier,
// offerAmount) from OrderParameters to (token, identifier,
// amount) in SpentItem struct.
calldatacopy(
add(eventConsiderationArrPtr, AdditionalRecipients_size),
BasicOrder_offerToken_cdPtr,
ThreeWords
)
}
}
{
/**
* Once consideration items and offer items have been handled,
* derive the final order hash. Memory Layout:
* 0x80-0x1c0: EIP712 data for order
* - 0x80: Order EIP-712 typehash (constant)
* - 0xa0: orderParameters.offerer
* - 0xc0: orderParameters.zone
* - 0xe0: keccak256(abi.encodePacked(offerHashes))
* - 0x100: keccak256(abi.encodePacked(considerationHashes))
* - 0x120: orderParameters.basicOrderType (% 4 = orderType)
* - 0x140: orderParameters.startTime
* - 0x160: orderParameters.endTime
* - 0x180: orderParameters.zoneHash
* - 0x1a0: orderParameters.salt
* - 0x1c0: orderParameters.conduitKey
* - 0x1e0: _counters[orderParameters.offerer] (from storage)
*/
// Read the offerer from calldata and place on the stack.
address offerer;
assembly {
offerer := calldataload(BasicOrder_offerer_cdPtr)
}
// Read offerer's current counter from storage and place on stack.
uint256 counter = _getCounter(offerer);
// Load order typehash from runtime code and place on stack.
bytes32 typeHash = _ORDER_TYPEHASH;
assembly {
// Set the OrderItem typeHash in memory.
mstore(BasicOrder_order_typeHash_ptr, typeHash)
// Copy offerer and zone from OrderParameters in calldata to the
// Order struct.
calldatacopy(
BasicOrder_order_offerer_ptr,
BasicOrder_offerer_cdPtr,
TwoWords
)
// Copy receivedItemsHash from zero slot to the Order struct.
mstore(
BasicOrder_order_considerationHashes_ptr,
mload(receivedItemsHash_ptr)
)
// Write the supplied orderType to the Order struct.
mstore(BasicOrder_order_orderType_ptr, orderType)
// Copy startTime, endTime, zoneHash, salt & conduit from
// calldata to the Order struct.
calldatacopy(
BasicOrder_order_startTime_ptr,
BasicOrder_startTime_cdPtr,
FiveWords
)
// Write offerer's counter, retrieved from storage, to struct.
mstore(BasicOrder_order_counter_ptr, counter)
// Compute the EIP712 Order hash.
orderHash := keccak256(
BasicOrder_order_typeHash_ptr,
EIP712_Order_size
)
}
}
assembly {
/**
* After the order hash has been derived, emit OrderFulfilled event:
* event OrderFulfilled(
* bytes32 orderHash,
* address indexed offerer,
* address indexed zone,
* address fulfiller,
* SpentItem[] offer,
* > (itemType, token, id, amount)
* ReceivedItem[] consideration
* > (itemType, token, id, amount, recipient)
* )
* topic0 - OrderFulfilled event signature
* topic1 - offerer
* topic2 - zone
* data:
* - 0x00: orderHash
* - 0x20: fulfiller
* - 0x40: offer arr ptr (0x80)
* - 0x60: consideration arr ptr (0x120)
* - 0x80: offer arr len (1)
* - 0xa0: offer.itemType
* - 0xc0: offer.token
* - 0xe0: offer.identifier
* - 0x100: offer.amount
* - 0x120: 1 + recipients.length
* - 0x140: recipient 0
*/
// Derive pointer to start of OrderFulfilled event data
let eventDataPtr := add(
OrderFulfilled_baseOffset,
mul(
calldataload(BasicOrder_additionalRecipients_length_cdPtr),
OneWord
)
)
// Write the order hash to the head of the event's data region.
mstore(eventDataPtr, orderHash)
// Write the fulfiller (i.e. the caller) next for receiver argument.
mstore(add(eventDataPtr, OrderFulfilled_fulfiller_offset), caller())
// Write the SpentItem and ReceivedItem array offsets (constants).
mstore(
// SpentItem array offset
add(eventDataPtr, OrderFulfilled_offer_head_offset),
OrderFulfilled_offer_body_offset
)
mstore(
// ReceivedItem array offset
add(eventDataPtr, OrderFulfilled_consideration_head_offset),
OrderFulfilled_consideration_body_offset
)
// Derive total data size including SpentItem and ReceivedItem data.
// SpentItem portion is already included in the baseSize constant,
// as there can only be one element in the array.
let dataSize := add(
OrderFulfilled_baseSize,
mul(
calldataload(BasicOrder_additionalRecipients_length_cdPtr),
ReceivedItem_size
)
)
// Emit OrderFulfilled log with three topics (the event signature
// as well as the two indexed arguments, the offerer and the zone).
log3(
// Supply the pointer for event data in memory.
eventDataPtr,
// Supply the size of event data in memory.
dataSize,
// Supply the OrderFulfilled event signature.
OrderFulfilled_selector,
// Supply the first topic (the offerer).
calldataload(BasicOrder_offerer_cdPtr),
// Supply the second topic (the zone).
calldataload(BasicOrder_zone_cdPtr)
)
// Restore the zero slot.
mstore(ZeroSlot, 0)
}
// Determine whether order is restricted and, if so, that it is valid.
_assertRestrictedBasicOrderValidity(
orderHash,
parameters.zoneHash,
orderType,
parameters.offerer,
parameters.zone
);
// Verify and update the status of the derived order.
_validateBasicOrderAndUpdateStatus(
orderHash,
parameters.offerer,
parameters.signature
);
}
/**
* @dev Internal function to transfer Ether (or other native tokens) to a
* given recipient as part of basic order fulfillment. Note that
* conduits are not utilized for native tokens as the transferred
* amount must be provided as msg.value.
*
* @param amount The amount to transfer.
* @param to The recipient of the native token transfer.
* @param additionalRecipients The additional recipients of the order.
*/
function _transferEthAndFinalize(
uint256 amount,
address payable to,
AdditionalRecipient[] calldata additionalRecipients
) internal {
// Put ether value supplied by the caller on the stack.
uint256 etherRemaining = msg.value;
// Retrieve total number of additional recipients and place on stack.
uint256 totalAdditionalRecipients = additionalRecipients.length;
// Skip overflow check as for loop is indexed starting at zero.
unchecked {
// Iterate over each additional recipient.
for (uint256 i = 0; i < totalAdditionalRecipients; ++i) {
// Retrieve the additional recipient.
AdditionalRecipient calldata additionalRecipient = (
additionalRecipients[i]
);
// Read ether amount to transfer to recipient & place on stack.
uint256 additionalRecipientAmount = additionalRecipient.amount;
// Ensure that sufficient Ether is available.
if (additionalRecipientAmount > etherRemaining) {
revert InsufficientEtherSupplied();
}
// Transfer Ether to the additional recipient.
_transferEth(
additionalRecipient.recipient,
additionalRecipientAmount
);
// Reduce ether value available. Skip underflow check as
// subtracted value is confirmed above as less than remaining.
etherRemaining -= additionalRecipientAmount;
}
}
// Ensure that sufficient Ether is still available.
if (amount > etherRemaining) {
revert InsufficientEtherSupplied();
}
// Transfer Ether to the offerer.
_transferEth(to, amount);
// If any Ether remains after transfers, return it to the caller.
if (etherRemaining > amount) {
// Skip underflow check as etherRemaining > amount.
unchecked {
// Transfer remaining Ether to the caller.
_transferEth(payable(msg.sender), etherRemaining - amount);
}
}
}
/**
* @dev Internal function to transfer ERC20 tokens to a given recipient as
* part of basic order fulfillment.
*
* @param offerer The offerer of the fulfiller order.
* @param parameters The basic order parameters.
* @param fromOfferer A boolean indicating whether to decrement amount from
* the offered amount.
* @param accumulator An open-ended array that collects transfers to execute
* against a given conduit in a single call.
*/
function _transferERC20AndFinalize(
address offerer,
BasicOrderParameters calldata parameters,
bool fromOfferer,
bytes memory accumulator
) internal {
// Declare from and to variables determined by fromOfferer value.
address from;
address to;
// Declare token and amount variables determined by fromOfferer value.
address token;
uint256 amount;
// Declare and check identifier variable within an isolated scope.
{
// Declare identifier variable determined by fromOfferer value.
uint256 identifier;
// Set ERC20 token transfer variables based on fromOfferer boolean.
if (fromOfferer) {
// Use offerer as from value and msg.sender as to value.
from = offerer;
to = msg.sender;
// Use offer token and related values if token is from offerer.
token = parameters.offerToken;
identifier = parameters.offerIdentifier;
amount = parameters.offerAmount;
} else {
// Use msg.sender as from value and offerer as to value.
from = msg.sender;
to = offerer;
// Otherwise, use consideration token and related values.
token = parameters.considerationToken;
identifier = parameters.considerationIdentifier;
amount = parameters.considerationAmount;
}
// Ensure that no identifier is supplied.
if (identifier != 0) {
revert UnusedItemParameters();
}
}
// Determine the appropriate conduit to utilize.
bytes32 conduitKey;
// Utilize assembly to derive conduit (if relevant) based on route.
assembly {
// Use offerer conduit if fromOfferer, fulfiller conduit otherwise.
conduitKey := calldataload(
sub(
BasicOrder_fulfillerConduit_cdPtr,
mul(fromOfferer, OneWord)
)
)
}
// Retrieve total number of additional recipients and place on stack.
uint256 totalAdditionalRecipients = (
parameters.additionalRecipients.length
);
// Iterate over each additional recipient.
for (uint256 i = 0; i < totalAdditionalRecipients; ) {
// Retrieve the additional recipient.
AdditionalRecipient calldata additionalRecipient = (
parameters.additionalRecipients[i]
);
uint256 additionalRecipientAmount = additionalRecipient.amount;
// Decrement the amount to transfer to fulfiller if indicated.
if (fromOfferer) {
amount -= additionalRecipientAmount;
}
// Transfer ERC20 tokens to additional recipient given approval.
_transferERC20(
token,
from,
additionalRecipient.recipient,
additionalRecipientAmount,
conduitKey,
accumulator
);
// Skip overflow check as for loop is indexed starting at zero.
unchecked {
++i;
}
}
// Transfer ERC20 token amount (from account must have proper approval).
_transferERC20(token, from, to, amount, conduitKey, accumulator);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
import { Side } from "./ConsiderationEnums.sol";
/**
* @title FulfillmentApplicationErrors
* @author 0age
* @notice FulfillmentApplicationErrors contains errors related to fulfillment
* application and aggregation.
*/
interface FulfillmentApplicationErrors {
/**
* @dev Revert with an error when a fulfillment is provided that does not
* declare at least one component as part of a call to fulfill
* available orders.
*/
error MissingFulfillmentComponentOnAggregation(Side side);
/**
* @dev Revert with an error when a fulfillment is provided that does not
* declare at least one offer component and at least one consideration
* component.
*/
error OfferAndConsiderationRequiredOnFulfillment();
/**
* @dev Revert with an error when the initial offer item named by a
* fulfillment component does not match the type, token, identifier,
* or conduit preference of the initial consideration item.
*/
error MismatchedFulfillmentOfferAndConsiderationComponents();
/**
* @dev Revert with an error when an order or item index are out of range
* or a fulfillment component does not match the type, token,
* identifier, or conduit preference of the initial consideration item.
*/
error InvalidFulfillmentComponentData();
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
/**
* @title CriteriaResolutionErrors
* @author 0age
* @notice CriteriaResolutionErrors contains all errors related to criteria
* resolution.
*/
interface CriteriaResolutionErrors {
/**
* @dev Revert with an error when providing a criteria resolver that refers
* to an order that has not been supplied.
*/
error OrderCriteriaResolverOutOfRange();
/**
* @dev Revert with an error if an offer item still has unresolved criteria
* after applying all criteria resolvers.
*/
error UnresolvedOfferCriteria();
/**
* @dev Revert with an error if a consideration item still has unresolved
* criteria after applying all criteria resolvers.
*/
error UnresolvedConsiderationCriteria();
/**
* @dev Revert with an error when providing a criteria resolver that refers
* to an order with an offer item that has not been supplied.
*/
error OfferCriteriaResolverOutOfRange();
/**
* @dev Revert with an error when providing a criteria resolver that refers
* to an order with a consideration item that has not been supplied.
*/
error ConsiderationCriteriaResolverOutOfRange();
/**
* @dev Revert with an error when providing a criteria resolver that refers
* to an order with an item that does not expect a criteria to be
* resolved.
*/
error CriteriaNotEnabledForItem();
/**
* @dev Revert with an error when providing a criteria resolver that
* contains an invalid proof with respect to the given item and
* chosen identifier.
*/
error InvalidProof();
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { OrderType } from "./ConsiderationEnums.sol";
// prettier-ignore
import {
OrderParameters,
Order,
AdvancedOrder,
OrderComponents,
OrderStatus,
CriteriaResolver
} from "./ConsiderationStructs.sol";
import "./ConsiderationConstants.sol";
import { Executor } from "./Executor.sol";
import { ZoneInteraction } from "./ZoneInteraction.sol";
/**
* @title OrderValidator
* @author 0age
* @notice OrderValidator contains functionality related to validating orders
* and updating their status.
*/
contract OrderValidator is Executor, ZoneInteraction {
// Track status of each order (validated, cancelled, and fraction filled).
mapping(bytes32 => OrderStatus) private _orderStatus;
/**
* @dev Derive and set hashes, reference chainId, and associated domain
* separator during deployment.
*
* @param conduitController A contract that deploys conduits, or proxies
* that may optionally be used to transfer approved
* ERC20/721/1155 tokens.
*/
constructor(address conduitController) Executor(conduitController) {}
/**
* @dev Internal function to verify and update the status of a basic order.
*
* @param orderHash The hash of the order.
* @param offerer The offerer of the order.
* @param signature A signature from the offerer indicating that the order
* has been approved.
*/
function _validateBasicOrderAndUpdateStatus(
bytes32 orderHash,
address offerer,
bytes memory signature
) internal {
// Retrieve the order status for the given order hash.
OrderStatus storage orderStatus = _orderStatus[orderHash];
// Ensure order is fillable and is not cancelled.
_verifyOrderStatus(
orderHash,
orderStatus,
true, // Only allow unused orders when fulfilling basic orders.
true // Signifies to revert if the order is invalid.
);
// If the order is not already validated, verify the supplied signature.
if (!orderStatus.isValidated) {
_verifySignature(offerer, orderHash, signature);
}
// Update order status as fully filled, packing struct values.
orderStatus.isValidated = true;
orderStatus.isCancelled = false;
orderStatus.numerator = 1;
orderStatus.denominator = 1;
}
/**
* @dev Internal function to validate an order, determine what portion to
* fill, and update its status. The desired fill amount is supplied as
* a fraction, as is the returned amount to fill.
*
* @param advancedOrder The order to fulfill as well as the fraction to
* fill. Note that all offer and consideration
* amounts must divide with no remainder in order
* for a partial fill to be valid.
* @param criteriaResolvers An array where each element contains a reference
* to a specific offer or consideration, a token
* identifier, and a proof that the supplied token
* identifier is contained in the order's merkle
* root. Note that a criteria of zero indicates
* that any (transferable) token identifier is
* valid and that no proof needs to be supplied.
* @param revertOnInvalid A boolean indicating whether to revert if the
* order is invalid due to the time or status.
* @param priorOrderHashes The order hashes of each order supplied prior to
* the current order as part of a "match" variety
* of order fulfillment (e.g. this array will be
* empty for single or "fulfill available").
*
* @return orderHash The order hash.
* @return newNumerator A value indicating the portion of the order that
* will be filled.
* @return newDenominator A value indicating the total size of the order.
*/
function _validateOrderAndUpdateStatus(
AdvancedOrder memory advancedOrder,
CriteriaResolver[] memory criteriaResolvers,
bool revertOnInvalid,
bytes32[] memory priorOrderHashes
)
internal
returns (
bytes32 orderHash,
uint256 newNumerator,
uint256 newDenominator
)
{
// Retrieve the parameters for the order.
OrderParameters memory orderParameters = advancedOrder.parameters;
// Ensure current timestamp falls between order start time and end time.
if (
!_verifyTime(
orderParameters.startTime,
orderParameters.endTime,
revertOnInvalid
)
) {
// Assuming an invalid time and no revert, return zeroed out values.
return (bytes32(0), 0, 0);
}
// Read numerator and denominator from memory and place on the stack.
uint256 numerator = uint256(advancedOrder.numerator);
uint256 denominator = uint256(advancedOrder.denominator);
// Ensure that the supplied numerator and denominator are valid.
if (numerator > denominator || numerator == 0) {
revert BadFraction();
}
// If attempting partial fill (n < d) check order type & ensure support.
if (
numerator < denominator &&
_doesNotSupportPartialFills(orderParameters.orderType)
) {
// Revert if partial fill was attempted on an unsupported order.
revert PartialFillsNotEnabledForOrder();
}
// Retrieve current counter & use it w/ parameters to derive order hash.
orderHash = _assertConsiderationLengthAndGetOrderHash(orderParameters);
// Ensure restricted orders have a valid submitter or pass a zone check.
_assertRestrictedAdvancedOrderValidity(
advancedOrder,
criteriaResolvers,
priorOrderHashes,
orderHash,
orderParameters.zoneHash,
orderParameters.orderType,
orderParameters.offerer,
orderParameters.zone
);
// Retrieve the order status using the derived order hash.
OrderStatus storage orderStatus = _orderStatus[orderHash];
// Ensure order is fillable and is not cancelled.
if (
!_verifyOrderStatus(
orderHash,
orderStatus,
false, // Allow partially used orders to be filled.
revertOnInvalid
)
) {
// Assuming an invalid order status and no revert, return zero fill.
return (orderHash, 0, 0);
}
// If the order is not already validated, verify the supplied signature.
if (!orderStatus.isValidated) {
_verifySignature(
orderParameters.offerer,
orderHash,
advancedOrder.signature
);
}
// Read filled amount as numerator and denominator and put on the stack.
uint256 filledNumerator = orderStatus.numerator;
uint256 filledDenominator = orderStatus.denominator;
// If order (orderStatus) currently has a non-zero denominator it is
// partially filled.
if (filledDenominator != 0) {
// If denominator of 1 supplied, fill all remaining amount on order.
if (denominator == 1) {
// Scale numerator & denominator to match current denominator.
numerator = filledDenominator;
denominator = filledDenominator;
}
// Otherwise, if supplied denominator differs from current one...
else if (filledDenominator != denominator) {
// scale current numerator by the supplied denominator, then...
filledNumerator *= denominator;
// the supplied numerator & denominator by current denominator.
numerator *= filledDenominator;
denominator *= filledDenominator;
}
// Once adjusted, if current+supplied numerator exceeds denominator:
if (filledNumerator + numerator > denominator) {
// Skip underflow check: denominator >= orderStatus.numerator
unchecked {
// Reduce current numerator so it + supplied = denominator.
numerator = denominator - filledNumerator;
}
}
// Increment the filled numerator by the new numerator.
filledNumerator += numerator;
// Use assembly to ensure fractional amounts are below max uint120.
assembly {
// Check filledNumerator and denominator for uint120 overflow.
if or(
gt(filledNumerator, MaxUint120),
gt(denominator, MaxUint120)
) {
// Derive greatest common divisor using euclidean algorithm.
function gcd(_a, _b) -> out {
for {
} _b {
} {
let _c := _b
_b := mod(_a, _c)
_a := _c
}
out := _a
}
let scaleDown := gcd(
numerator,
gcd(filledNumerator, denominator)
)
// Ensure that the divisor is at least one.
let safeScaleDown := add(scaleDown, iszero(scaleDown))
// Scale all fractional values down by gcd.
numerator := div(numerator, safeScaleDown)
filledNumerator := div(filledNumerator, safeScaleDown)
denominator := div(denominator, safeScaleDown)
// Perform the overflow check a second time.
if or(
gt(filledNumerator, MaxUint120),
gt(denominator, MaxUint120)
) {
// Store the Panic error signature.
mstore(0, Panic_error_signature)
// Set arithmetic (0x11) panic code as initial argument.
mstore(Panic_error_offset, Panic_arithmetic)
// Return, supplying Panic signature & arithmetic code.
revert(0, Panic_error_length)
}
}
}
// Skip overflow check: checked above unless numerator is reduced.
unchecked {
// Update order status and fill amount, packing struct values.
orderStatus.isValidated = true;
orderStatus.isCancelled = false;
orderStatus.numerator = uint120(filledNumerator);
orderStatus.denominator = uint120(denominator);
}
} else {
// Update order status and fill amount, packing struct values.
orderStatus.isValidated = true;
orderStatus.isCancelled = false;
orderStatus.numerator = uint120(numerator);
orderStatus.denominator = uint120(denominator);
}
// Return order hash, a modified numerator, and a modified denominator.
return (orderHash, numerator, denominator);
}
/**
* @dev Internal function to cancel an arbitrary number of orders. Note that
* only the offerer or the zone of a given order may cancel it. Callers
* should ensure that the intended order was cancelled by calling
* `getOrderStatus` and confirming that `isCancelled` returns `true`.
*
* @param orders The orders to cancel.
*
* @return cancelled A boolean indicating whether the supplied orders were
* successfully cancelled.
*/
function _cancel(OrderComponents[] calldata orders)
internal
returns (bool cancelled)
{
// Ensure that the reentrancy guard is not currently set.
_assertNonReentrant();
// Declare variables outside of the loop.
OrderStatus storage orderStatus;
address offerer;
address zone;
// Skip overflow check as for loop is indexed starting at zero.
unchecked {
// Read length of the orders array from memory and place on stack.
uint256 totalOrders = orders.length;
// Iterate over each order.
for (uint256 i = 0; i < totalOrders; ) {
// Retrieve the order.
OrderComponents calldata order = orders[i];
offerer = order.offerer;
zone = order.zone;
// Ensure caller is either offerer or zone of the order.
if (msg.sender != offerer && msg.sender != zone) {
revert InvalidCanceller();
}
// Derive order hash using the order parameters and the counter.
bytes32 orderHash = _deriveOrderHash(
OrderParameters(
offerer,
zone,
order.offer,
order.consideration,
order.orderType,
order.startTime,
order.endTime,
order.zoneHash,
order.salt,
order.conduitKey,
order.consideration.length
),
order.counter
);
// Retrieve the order status using the derived order hash.
orderStatus = _orderStatus[orderHash];
// Update the order status as not valid and cancelled.
orderStatus.isValidated = false;
orderStatus.isCancelled = true;
// Emit an event signifying that the order has been cancelled.
emit OrderCancelled(orderHash, offerer, zone);
// Increment counter inside body of loop for gas efficiency.
++i;
}
}
// Return a boolean indicating that orders were successfully cancelled.
cancelled = true;
}
/**
* @dev Internal function to validate an arbitrary number of orders, thereby
* registering their signatures as valid and allowing the fulfiller to
* skip signature verification on fulfillment. Note that validated
* orders may still be unfulfillable due to invalid item amounts or
* other factors; callers should determine whether validated orders are
* fulfillable by simulating the fulfillment call prior to execution.
* Also note that anyone can validate a signed order, but only the
* offerer can validate an order without supplying a signature.
*
* @param orders The orders to validate.
*
* @return validated A boolean indicating whether the supplied orders were
* successfully validated.
*/
function _validate(Order[] calldata orders)
internal
returns (bool validated)
{
// Ensure that the reentrancy guard is not currently set.
_assertNonReentrant();
// Declare variables outside of the loop.
OrderStatus storage orderStatus;
bytes32 orderHash;
address offerer;
// Skip overflow check as for loop is indexed starting at zero.
unchecked {
// Read length of the orders array from memory and place on stack.
uint256 totalOrders = orders.length;
// Iterate over each order.
for (uint256 i = 0; i < totalOrders; ) {
// Retrieve the order.
Order calldata order = orders[i];
// Retrieve the order parameters.
OrderParameters calldata orderParameters = order.parameters;
// Move offerer from memory to the stack.
offerer = orderParameters.offerer;
// Get current counter & use it w/ params to derive order hash.
orderHash = _assertConsiderationLengthAndGetOrderHash(
orderParameters
);
// Retrieve the order status using the derived order hash.
orderStatus = _orderStatus[orderHash];
// Ensure order is fillable and retrieve the filled amount.
_verifyOrderStatus(
orderHash,
orderStatus,
false, // Signifies that partially filled orders are valid.
true // Signifies to revert if the order is invalid.
);
// If the order has not already been validated...
if (!orderStatus.isValidated) {
// Verify the supplied signature.
_verifySignature(offerer, orderHash, order.signature);
// Update order status to mark the order as valid.
orderStatus.isValidated = true;
// Emit an event signifying the order has been validated.
emit OrderValidated(
orderHash,
offerer,
orderParameters.zone
);
}
// Increment counter inside body of the loop for gas efficiency.
++i;
}
}
// Return a boolean indicating that orders were successfully validated.
validated = true;
}
/**
* @dev Internal view function to retrieve the status of a given order by
* hash, including whether the order has been cancelled or validated
* and the fraction of the order that has been filled.
*
* @param orderHash The order hash in question.
*
* @return isValidated A boolean indicating whether the order in question
* has been validated (i.e. previously approved or
* partially filled).
* @return isCancelled A boolean indicating whether the order in question
* has been cancelled.
* @return totalFilled The total portion of the order that has been filled
* (i.e. the "numerator").
* @return totalSize The total size of the order that is either filled or
* unfilled (i.e. the "denominator").
*/
function _getOrderStatus(bytes32 orderHash)
internal
view
returns (
bool isValidated,
bool isCancelled,
uint256 totalFilled,
uint256 totalSize
)
{
// Retrieve the order status using the order hash.
OrderStatus storage orderStatus = _orderStatus[orderHash];
// Return the fields on the order status.
return (
orderStatus.isValidated,
orderStatus.isCancelled,
orderStatus.numerator,
orderStatus.denominator
);
}
/**
* @dev Internal pure function to check whether a given order type indicates
* that partial fills are not supported (e.g. only "full fills" are
* allowed for the order in question).
*
* @param orderType The order type in question.
*
* @return isFullOrder A boolean indicating whether the order type only
* supports full fills.
*/
function _doesNotSupportPartialFills(OrderType orderType)
internal
pure
returns (bool isFullOrder)
{
// The "full" order types are even, while "partial" order types are odd.
// Bitwise and by 1 is equivalent to modulo by 2, but 2 gas cheaper.
assembly {
// Equivalent to `uint256(orderType) & 1 == 0`.
isFullOrder := iszero(and(orderType, 1))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
// prettier-ignore
import {
ConduitTransfer,
ConduitBatch1155Transfer
} from "./ConduitStructs.sol";
/**
* @title ConduitInterface
* @author 0age
* @notice ConduitInterface contains all external function interfaces, events,
* and errors for conduit contracts.
*/
interface ConduitInterface {
/**
* @dev Revert with an error when attempting to execute transfers using a
* caller that does not have an open channel.
*/
error ChannelClosed(address channel);
/**
* @dev Revert with an error when attempting to update a channel to the
* current status of that channel.
*/
error ChannelStatusAlreadySet(address channel, bool isOpen);
/**
* @dev Revert with an error when attempting to execute a transfer for an
* item that does not have an ERC20/721/1155 item type.
*/
error InvalidItemType();
/**
* @dev Revert with an error when attempting to update the status of a
* channel from a caller that is not the conduit controller.
*/
error InvalidController();
/**
* @dev Emit an event whenever a channel is opened or closed.
*
* @param channel The channel that has been updated.
* @param open A boolean indicating whether the conduit is open or not.
*/
event ChannelUpdated(address indexed channel, bool open);
/**
* @notice Execute a sequence of ERC20/721/1155 transfers. Only a caller
* with an open channel can call this function.
*
* @param transfers The ERC20/721/1155 transfers to perform.
*
* @return magicValue A magic value indicating that the transfers were
* performed successfully.
*/
function execute(ConduitTransfer[] calldata transfers)
external
returns (bytes4 magicValue);
/**
* @notice Execute a sequence of batch 1155 transfers. Only a caller with an
* open channel can call this function.
*
* @param batch1155Transfers The 1155 batch transfers to perform.
*
* @return magicValue A magic value indicating that the transfers were
* performed successfully.
*/
function executeBatch1155(
ConduitBatch1155Transfer[] calldata batch1155Transfers
) external returns (bytes4 magicValue);
/**
* @notice Execute a sequence of transfers, both single and batch 1155. Only
* a caller with an open channel can call this function.
*
* @param standardTransfers The ERC20/721/1155 transfers to perform.
* @param batch1155Transfers The 1155 batch transfers to perform.
*
* @return magicValue A magic value indicating that the transfers were
* performed successfully.
*/
function executeWithBatch1155(
ConduitTransfer[] calldata standardTransfers,
ConduitBatch1155Transfer[] calldata batch1155Transfers
) external returns (bytes4 magicValue);
/**
* @notice Open or close a given channel. Only callable by the controller.
*
* @param channel The channel to open or close.
* @param isOpen The status of the channel (either open or closed).
*/
function updateChannel(address channel, bool isOpen) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
/**
* @title AmountDerivationErrors
* @author 0age
* @notice AmountDerivationErrors contains errors related to amount derivation.
*/
interface AmountDerivationErrors {
/**
* @dev Revert with an error when attempting to apply a fraction as part of
* a partial fill that does not divide the target amount cleanly.
*/
error InexactFraction();
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { ZoneInterface } from "./ZoneInterface.sol";
import { OrderType } from "./ConsiderationEnums.sol";
// prettier-ignore
import { AdvancedOrder, CriteriaResolver } from "./ConsiderationStructs.sol";
import "./ConsiderationConstants.sol";
// prettier-ignore
import {
ZoneInteractionErrors
} from "./ZoneInteractionErrors.sol";
import { LowLevelHelpers } from "./LowLevelHelpers.sol";
/**
* @title ZoneInteraction
* @author 0age
* @notice ZoneInteraction contains logic related to interacting with zones.
*/
contract ZoneInteraction is ZoneInteractionErrors, LowLevelHelpers {
/**
* @dev Internal view function to determine if an order has a restricted
* order type and, if so, to ensure that either the offerer or the zone
* are the fulfiller or that a staticcall to `isValidOrder` on the zone
* returns a magic value indicating that the order is currently valid.
*
* @param orderHash The hash of the order.
* @param zoneHash The hash to provide upon calling the zone.
* @param orderType The type of the order.
* @param offerer The offerer in question.
* @param zone The zone in question.
*/
function _assertRestrictedBasicOrderValidity(
bytes32 orderHash,
bytes32 zoneHash,
OrderType orderType,
address offerer,
address zone
) internal view {
// Order type 2-3 require zone or offerer be caller or zone to approve.
if (
uint256(orderType) > 1 &&
msg.sender != zone &&
msg.sender != offerer
) {
// Perform minimal staticcall to the zone.
_callIsValidOrder(zone, orderHash, offerer, zoneHash);
}
}
function _callIsValidOrder(
address zone,
bytes32 orderHash,
address offerer,
bytes32 zoneHash
) internal view {
// Perform minimal staticcall to the zone.
bool success = _staticcall(
zone,
abi.encodeWithSelector(
ZoneInterface.isValidOrder.selector,
orderHash,
msg.sender,
offerer,
zoneHash
)
);
// Ensure call was successful and returned the correct magic value.
_assertIsValidOrderStaticcallSuccess(success, orderHash);
}
/**
* @dev Internal view function to determine whether an order is a restricted
* order and, if so, to ensure that it was either submitted by the
* offerer or the zone for the order, or that the zone returns the
* expected magic value upon performing a staticcall to `isValidOrder`
* or `isValidOrderIncludingExtraData` depending on whether the order
* fulfillment specifies extra data or criteria resolvers.
*
* @param advancedOrder The advanced order in question.
* @param criteriaResolvers An array where each element contains a reference
* to a specific offer or consideration, a token
* identifier, and a proof that the supplied token
* identifier is contained in the order's merkle
* root. Note that a criteria of zero indicates
* that any (transferable) token identifier is
* valid and that no proof needs to be supplied.
* @param priorOrderHashes The order hashes of each order supplied prior to
* the current order as part of a "match" variety
* of order fulfillment (e.g. this array will be
* empty for single or "fulfill available").
* @param orderHash The hash of the order.
* @param zoneHash The hash to provide upon calling the zone.
* @param orderType The type of the order.
* @param offerer The offerer in question.
* @param zone The zone in question.
*/
function _assertRestrictedAdvancedOrderValidity(
AdvancedOrder memory advancedOrder,
CriteriaResolver[] memory criteriaResolvers,
bytes32[] memory priorOrderHashes,
bytes32 orderHash,
bytes32 zoneHash,
OrderType orderType,
address offerer,
address zone
) internal view {
// Order type 2-3 require zone or offerer be caller or zone to approve.
if (
uint256(orderType) > 1 &&
msg.sender != zone &&
msg.sender != offerer
) {
// If no extraData or criteria resolvers are supplied...
if (
advancedOrder.extraData.length == 0 &&
criteriaResolvers.length == 0
) {
// Perform minimal staticcall to the zone.
_callIsValidOrder(zone, orderHash, offerer, zoneHash);
} else {
// Otherwise, extra data or criteria resolvers were supplied; in
// that event, perform a more verbose staticcall to the zone.
bool success = _staticcall(
zone,
abi.encodeWithSelector(
ZoneInterface.isValidOrderIncludingExtraData.selector,
orderHash,
msg.sender,
advancedOrder,
priorOrderHashes,
criteriaResolvers
)
);
// Ensure call was successful and returned correct magic value.
_assertIsValidOrderStaticcallSuccess(success, orderHash);
}
}
}
/**
* @dev Internal view function to ensure that a staticcall to `isValidOrder`
* or `isValidOrderIncludingExtraData` as part of validating a
* restricted order that was not submitted by the named offerer or zone
* was successful and returned the required magic value.
*
* @param success A boolean indicating the status of the staticcall.
* @param orderHash The order hash of the order in question.
*/
function _assertIsValidOrderStaticcallSuccess(
bool success,
bytes32 orderHash
) internal view {
// If the call failed...
if (!success) {
// Revert and pass reason along if one was returned.
_revertWithReasonIfOneIsReturned();
// Otherwise, revert with a generic error message.
revert InvalidRestrictedOrder(orderHash);
}
// Ensure result was extracted and matches isValidOrder magic value.
if (_doesNotMatchMagic(ZoneInterface.isValidOrder.selector)) {
revert InvalidRestrictedOrder(orderHash);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { ConduitInterface } from "./ConduitInterface.sol";
import { ConduitItemType } from "./ConduitEnums.sol";
import { ItemType } from "./ConsiderationEnums.sol";
import { ReceivedItem } from "./ConsiderationStructs.sol";
import { Verifiers } from "./Verifiers.sol";
import { TokenTransferrer } from "./TokenTransferrer.sol";
import "./ConsiderationConstants.sol";
/**
* @title Executor
* @author 0age
* @notice Executor contains functions related to processing executions (i.e.
* transferring items, either directly or via conduits).
*/
contract Executor is Verifiers, TokenTransferrer {
/**
* @dev Derive and set hashes, reference chainId, and associated domain
* separator during deployment.
*
* @param conduitController A contract that deploys conduits, or proxies
* that may optionally be used to transfer approved
* ERC20/721/1155 tokens.
*/
constructor(address conduitController) Verifiers(conduitController) {}
/**
* @dev Internal function to transfer a given item, either directly or via
* a corresponding conduit.
*
* @param item The item to transfer, including an amount and a
* recipient.
* @param from The account supplying the item.
* @param conduitKey A bytes32 value indicating what corresponding conduit,
* if any, to source token approvals from. The zero hash
* signifies that no conduit should be used, with direct
* approvals set on this contract.
* @param accumulator An open-ended array that collects transfers to execute
* against a given conduit in a single call.
*/
function _transfer(
ReceivedItem memory item,
address from,
bytes32 conduitKey,
bytes memory accumulator
) internal {
// If the item type indicates Ether or a native token...
if (item.itemType == ItemType.NATIVE) {
// Ensure neither the token nor the identifier parameters are set.
if ((uint160(item.token) | item.identifier) != 0) {
revert UnusedItemParameters();
}
// transfer the native tokens to the recipient.
_transferEth(item.recipient, item.amount);
} else if (item.itemType == ItemType.ERC20) {
// Ensure that no identifier is supplied.
if (item.identifier != 0) {
revert UnusedItemParameters();
}
// Transfer ERC20 tokens from the source to the recipient.
_transferERC20(
item.token,
from,
item.recipient,
item.amount,
conduitKey,
accumulator
);
} else if (item.itemType == ItemType.ERC721) {
// Transfer ERC721 token from the source to the recipient.
_transferERC721(
item.token,
from,
item.recipient,
item.identifier,
item.amount,
conduitKey,
accumulator
);
} else {
// Transfer ERC1155 token from the source to the recipient.
_transferERC1155(
item.token,
from,
item.recipient,
item.identifier,
item.amount,
conduitKey,
accumulator
);
}
}
/**
* @dev Internal function to transfer an individual ERC721 or ERC1155 item
* from a given originator to a given recipient. The accumulator will
* be bypassed, meaning that this function should be utilized in cases
* where multiple item transfers can be accumulated into a single
* conduit call. Sufficient approvals must be set, either on the
* respective conduit or on this contract itself.
*
* @param itemType The type of item to transfer, either ERC721 or ERC1155.
* @param token The token to transfer.
* @param from The originator of the transfer.
* @param to The recipient of the transfer.
* @param identifier The tokenId to transfer.
* @param amount The amount to transfer.
* @param conduitKey A bytes32 value indicating what corresponding conduit,
* if any, to source token approvals from. The zero hash
* signifies that no conduit should be used, with direct
* approvals set on this contract.
*/
function _transferIndividual721Or1155Item(
ItemType itemType,
address token,
address from,
address to,
uint256 identifier,
uint256 amount,
bytes32 conduitKey
) internal {
// Determine if the transfer is to be performed via a conduit.
if (conduitKey != bytes32(0)) {
// Use free memory pointer as calldata offset for the conduit call.
uint256 callDataOffset;
// Utilize assembly to place each argument in free memory.
assembly {
// Retrieve the free memory pointer and use it as the offset.
callDataOffset := mload(FreeMemoryPointerSlot)
// Write ConduitInterface.execute.selector to memory.
mstore(callDataOffset, Conduit_execute_signature)
// Write the offset to the ConduitTransfer array in memory.
mstore(
add(
callDataOffset,
Conduit_execute_ConduitTransfer_offset_ptr
),
Conduit_execute_ConduitTransfer_ptr
)
// Write the length of the ConduitTransfer array to memory.
mstore(
add(
callDataOffset,
Conduit_execute_ConduitTransfer_length_ptr
),
Conduit_execute_ConduitTransfer_length
)
// Write the item type to memory.
mstore(
add(callDataOffset, Conduit_execute_transferItemType_ptr),
itemType
)
// Write the token to memory.
mstore(
add(callDataOffset, Conduit_execute_transferToken_ptr),
token
)
// Write the transfer source to memory.
mstore(
add(callDataOffset, Conduit_execute_transferFrom_ptr),
from
)
// Write the transfer recipient to memory.
mstore(add(callDataOffset, Conduit_execute_transferTo_ptr), to)
// Write the token identifier to memory.
mstore(
add(callDataOffset, Conduit_execute_transferIdentifier_ptr),
identifier
)
// Write the transfer amount to memory.
mstore(
add(callDataOffset, Conduit_execute_transferAmount_ptr),
amount
)
}
// Perform the call to the conduit.
_callConduitUsingOffsets(
conduitKey,
callDataOffset,
OneConduitExecute_size
);
} else {
// Otherwise, determine whether it is an ERC721 or ERC1155 item.
if (itemType == ItemType.ERC721) {
// Ensure that exactly one 721 item is being transferred.
if (amount != 1) {
revert InvalidERC721TransferAmount();
}
// Perform transfer via the token contract directly.
_performERC721Transfer(token, from, to, identifier);
} else {
// Perform transfer via the token contract directly.
_performERC1155Transfer(token, from, to, identifier, amount);
}
}
}
/**
* @dev Internal function to transfer Ether or other native tokens to a
* given recipient.
*
* @param to The recipient of the transfer.
* @param amount The amount to transfer.
*/
function _transferEth(address payable to, uint256 amount) internal {
// Ensure that the supplied amount is non-zero.
_assertNonZeroAmount(amount);
// Declare a variable indicating whether the call was successful or not.
bool success;
assembly {
// Transfer the ETH and store if it succeeded or not.
success := call(gas(), to, amount, 0, 0, 0, 0)
}
// If the call fails...
if (!success) {
// Revert and pass the revert reason along if one was returned.
_revertWithReasonIfOneIsReturned();
// Otherwise, revert with a generic error message.
revert EtherTransferGenericFailure(to, amount);
}
}
/**
* @dev Internal function to transfer ERC20 tokens from a given originator
* to a given recipient using a given conduit if applicable. Sufficient
* approvals must be set on this contract or on a respective conduit.
*
* @param token The ERC20 token to transfer.
* @param from The originator of the transfer.
* @param to The recipient of the transfer.
* @param amount The amount to transfer.
* @param conduitKey A bytes32 value indicating what corresponding conduit,
* if any, to source token approvals from. The zero hash
* signifies that no conduit should be used, with direct
* approvals set on this contract.
* @param accumulator An open-ended array that collects transfers to execute
* against a given conduit in a single call.
*/
function _transferERC20(
address token,
address from,
address to,
uint256 amount,
bytes32 conduitKey,
bytes memory accumulator
) internal {
// Ensure that the supplied amount is non-zero.
_assertNonZeroAmount(amount);
// Trigger accumulated transfers if the conduits differ.
_triggerIfArmedAndNotAccumulatable(accumulator, conduitKey);
// If no conduit has been specified...
if (conduitKey == bytes32(0)) {
// Perform the token transfer directly.
_performERC20Transfer(token, from, to, amount);
} else {
// Insert the call to the conduit into the accumulator.
_insert(
conduitKey,
accumulator,
ConduitItemType.ERC20,
token,
from,
to,
uint256(0),
amount
);
}
}
/**
* @dev Internal function to transfer a single ERC721 token from a given
* originator to a given recipient. Sufficient approvals must be set,
* either on the respective conduit or on this contract itself.
*
* @param token The ERC721 token to transfer.
* @param from The originator of the transfer.
* @param to The recipient of the transfer.
* @param identifier The tokenId to transfer (must be 1 for ERC721).
* @param amount The amount to transfer.
* @param conduitKey A bytes32 value indicating what corresponding conduit,
* if any, to source token approvals from. The zero hash
* signifies that no conduit should be used, with direct
* approvals set on this contract.
* @param accumulator An open-ended array that collects transfers to execute
* against a given conduit in a single call.
*/
function _transferERC721(
address token,
address from,
address to,
uint256 identifier,
uint256 amount,
bytes32 conduitKey,
bytes memory accumulator
) internal {
// Trigger accumulated transfers if the conduits differ.
_triggerIfArmedAndNotAccumulatable(accumulator, conduitKey);
// If no conduit has been specified...
if (conduitKey == bytes32(0)) {
// Ensure that exactly one 721 item is being transferred.
if (amount != 1) {
revert InvalidERC721TransferAmount();
}
// Perform transfer via the token contract directly.
_performERC721Transfer(token, from, to, identifier);
} else {
// Insert the call to the conduit into the accumulator.
_insert(
conduitKey,
accumulator,
ConduitItemType.ERC721,
token,
from,
to,
identifier,
amount
);
}
}
/**
* @dev Internal function to transfer ERC1155 tokens from a given originator
* to a given recipient. Sufficient approvals must be set, either on
* the respective conduit or on this contract itself.
*
* @param token The ERC1155 token to transfer.
* @param from The originator of the transfer.
* @param to The recipient of the transfer.
* @param identifier The id to transfer.
* @param amount The amount to transfer.
* @param conduitKey A bytes32 value indicating what corresponding conduit,
* if any, to source token approvals from. The zero hash
* signifies that no conduit should be used, with direct
* approvals set on this contract.
* @param accumulator An open-ended array that collects transfers to execute
* against a given conduit in a single call.
*/
function _transferERC1155(
address token,
address from,
address to,
uint256 identifier,
uint256 amount,
bytes32 conduitKey,
bytes memory accumulator
) internal {
// Ensure that the supplied amount is non-zero.
_assertNonZeroAmount(amount);
// Trigger accumulated transfers if the conduits differ.
_triggerIfArmedAndNotAccumulatable(accumulator, conduitKey);
// If no conduit has been specified...
if (conduitKey == bytes32(0)) {
// Perform transfer via the token contract directly.
_performERC1155Transfer(token, from, to, identifier, amount);
} else {
// Insert the call to the conduit into the accumulator.
_insert(
conduitKey,
accumulator,
ConduitItemType.ERC1155,
token,
from,
to,
identifier,
amount
);
}
}
/**
* @dev Internal function to trigger a call to the conduit currently held by
* the accumulator if the accumulator contains item transfers (i.e. it
* is "armed") and the supplied conduit key does not match the key held
* by the accumulator.
*
* @param accumulator An open-ended array that collects transfers to execute
* against a given conduit in a single call.
* @param conduitKey A bytes32 value indicating what corresponding conduit,
* if any, to source token approvals from. The zero hash
* signifies that no conduit should be used, with direct
* approvals set on this contract.
*/
function _triggerIfArmedAndNotAccumulatable(
bytes memory accumulator,
bytes32 conduitKey
) internal {
// Retrieve the current conduit key from the accumulator.
bytes32 accumulatorConduitKey = _getAccumulatorConduitKey(accumulator);
// Perform conduit call if the set key does not match the supplied key.
if (accumulatorConduitKey != conduitKey) {
_triggerIfArmed(accumulator);
}
}
/**
* @dev Internal function to trigger a call to the conduit currently held by
* the accumulator if the accumulator contains item transfers (i.e. it
* is "armed").
*
* @param accumulator An open-ended array that collects transfers to execute
* against a given conduit in a single call.
*/
function _triggerIfArmed(bytes memory accumulator) internal {
// Exit if the accumulator is not "armed".
if (accumulator.length != AccumulatorArmed) {
return;
}
// Retrieve the current conduit key from the accumulator.
bytes32 accumulatorConduitKey = _getAccumulatorConduitKey(accumulator);
// Perform conduit call.
_trigger(accumulatorConduitKey, accumulator);
}
/**
* @dev Internal function to trigger a call to the conduit corresponding to
* a given conduit key, supplying all accumulated item transfers. The
* accumulator will be "disarmed" and reset in the process.
*
* @param conduitKey A bytes32 value indicating what corresponding conduit,
* if any, to source token approvals from. The zero hash
* signifies that no conduit should be used, with direct
* approvals set on this contract.
* @param accumulator An open-ended array that collects transfers to execute
* against a given conduit in a single call.
*/
function _trigger(bytes32 conduitKey, bytes memory accumulator) internal {
// Declare variables for offset in memory & size of calldata to conduit.
uint256 callDataOffset;
uint256 callDataSize;
// Call the conduit with all the accumulated transfers.
assembly {
// Call begins at third word; the first is length or "armed" status,
// and the second is the current conduit key.
callDataOffset := add(accumulator, TwoWords)
// 68 + items * 192
callDataSize := add(
Accumulator_array_offset_ptr,
mul(
mload(add(accumulator, Accumulator_array_length_ptr)),
Conduit_transferItem_size
)
)
}
// Call conduit derived from conduit key & supply accumulated transfers.
_callConduitUsingOffsets(conduitKey, callDataOffset, callDataSize);
// Reset accumulator length to signal that it is now "disarmed".
assembly {
mstore(accumulator, AccumulatorDisarmed)
}
}
/**
* @dev Internal function to perform a call to the conduit corresponding to
* a given conduit key based on the offset and size of the calldata in
* question in memory.
*
* @param conduitKey A bytes32 value indicating what corresponding
* conduit, if any, to source token approvals from.
* The zero hash signifies that no conduit should be
* used, with direct approvals set on this contract.
* @param callDataOffset The memory pointer where calldata is contained.
* @param callDataSize The size of calldata in memory.
*/
function _callConduitUsingOffsets(
bytes32 conduitKey,
uint256 callDataOffset,
uint256 callDataSize
) internal {
// Derive the address of the conduit using the conduit key.
address conduit = _deriveConduit(conduitKey);
bool success;
bytes4 result;
// call the conduit.
assembly {
// Ensure first word of scratch space is empty.
mstore(0, 0)
// Perform call, placing first word of return data in scratch space.
success := call(
gas(),
conduit,
0,
callDataOffset,
callDataSize,
0,
OneWord
)
// Take value from scratch space and place it on the stack.
result := mload(0)
}
// If the call failed...
if (!success) {
// Pass along whatever revert reason was given by the conduit.
_revertWithReasonIfOneIsReturned();
// Otherwise, revert with a generic error.
revert InvalidCallToConduit(conduit);
}
// Ensure result was extracted and matches EIP-1271 magic value.
if (result != ConduitInterface.execute.selector) {
revert InvalidConduit(conduitKey, conduit);
}
}
/**
* @dev Internal pure function to retrieve the current conduit key set for
* the accumulator.
*
* @param accumulator An open-ended array that collects transfers to execute
* against a given conduit in a single call.
*
* @return accumulatorConduitKey The conduit key currently set for the
* accumulator.
*/
function _getAccumulatorConduitKey(bytes memory accumulator)
internal
pure
returns (bytes32 accumulatorConduitKey)
{
// Retrieve the current conduit key from the accumulator.
assembly {
accumulatorConduitKey := mload(
add(accumulator, Accumulator_conduitKey_ptr)
)
}
}
/**
* @dev Internal pure function to place an item transfer into an accumulator
* that collects a series of transfers to execute against a given
* conduit in a single call.
*
* @param conduitKey A bytes32 value indicating what corresponding conduit,
* if any, to source token approvals from. The zero hash
* signifies that no conduit should be used, with direct
* approvals set on this contract.
* @param accumulator An open-ended array that collects transfers to execute
* against a given conduit in a single call.
* @param itemType The type of the item to transfer.
* @param token The token to transfer.
* @param from The originator of the transfer.
* @param to The recipient of the transfer.
* @param identifier The tokenId to transfer.
* @param amount The amount to transfer.
*/
function _insert(
bytes32 conduitKey,
bytes memory accumulator,
ConduitItemType itemType,
address token,
address from,
address to,
uint256 identifier,
uint256 amount
) internal pure {
uint256 elements;
// "Arm" and prime accumulator if it's not already armed. The sentinel
// value is held in the length of the accumulator array.
if (accumulator.length == AccumulatorDisarmed) {
elements = 1;
bytes4 selector = ConduitInterface.execute.selector;
assembly {
mstore(accumulator, AccumulatorArmed) // "arm" the accumulator.
mstore(add(accumulator, Accumulator_conduitKey_ptr), conduitKey)
mstore(add(accumulator, Accumulator_selector_ptr), selector)
mstore(
add(accumulator, Accumulator_array_offset_ptr),
Accumulator_array_offset
)
mstore(add(accumulator, Accumulator_array_length_ptr), elements)
}
} else {
// Otherwise, increase the number of elements by one.
assembly {
elements := add(
mload(add(accumulator, Accumulator_array_length_ptr)),
1
)
mstore(add(accumulator, Accumulator_array_length_ptr), elements)
}
}
// Insert the item.
assembly {
let itemPointer := sub(
add(accumulator, mul(elements, Conduit_transferItem_size)),
Accumulator_itemSizeOffsetDifference
)
mstore(itemPointer, itemType)
mstore(add(itemPointer, Conduit_transferItem_token_ptr), token)
mstore(add(itemPointer, Conduit_transferItem_from_ptr), from)
mstore(add(itemPointer, Conduit_transferItem_to_ptr), to)
mstore(
add(itemPointer, Conduit_transferItem_identifier_ptr),
identifier
)
mstore(add(itemPointer, Conduit_transferItem_amount_ptr), amount)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
import { ConduitItemType } from "./ConduitEnums.sol";
struct ConduitTransfer {
ConduitItemType itemType;
address token;
address from;
address to;
uint256 identifier;
uint256 amount;
}
struct ConduitBatch1155Transfer {
address token;
address from;
address to;
uint256[] ids;
uint256[] amounts;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import "./ConsiderationConstants.sol";
/**
* @title LowLevelHelpers
* @author 0age
* @notice LowLevelHelpers contains logic for performing various low-level
* operations.
*/
contract LowLevelHelpers {
/**
* @dev Internal view function to staticcall an arbitrary target with given
* calldata. Note that no data is written to memory and no contract
* size check is performed.
*
* @param target The account to staticcall.
* @param callData The calldata to supply when staticcalling the target.
*
* @return success The status of the staticcall to the target.
*/
function _staticcall(address target, bytes memory callData)
internal
view
returns (bool success)
{
assembly {
// Perform the staticcall.
success := staticcall(
gas(),
target,
add(callData, OneWord),
mload(callData),
0,
0
)
}
}
/**
* @dev Internal view function to revert and pass along the revert reason if
* data was returned by the last call and that the size of that data
* does not exceed the currently allocated memory size.
*/
function _revertWithReasonIfOneIsReturned() internal view {
assembly {
// If it returned a message, bubble it up as long as sufficient gas
// remains to do so:
if returndatasize() {
// Ensure that sufficient gas is available to copy returndata
// while expanding memory where necessary. Start by computing
// the word size of returndata and allocated memory.
let returnDataWords := div(
add(returndatasize(), AlmostOneWord),
OneWord
)
// Note: use the free memory pointer in place of msize() to work
// around a Yul warning that prevents accessing msize directly
// when the IR pipeline is activated.
let msizeWords := div(mload(FreeMemoryPointerSlot), OneWord)
// Next, compute the cost of the returndatacopy.
let cost := mul(CostPerWord, returnDataWords)
// Then, compute cost of new memory allocation.
if gt(returnDataWords, msizeWords) {
cost := add(
cost,
add(
mul(sub(returnDataWords, msizeWords), CostPerWord),
div(
sub(
mul(returnDataWords, returnDataWords),
mul(msizeWords, msizeWords)
),
MemoryExpansionCoefficient
)
)
)
}
// Finally, add a small constant and compare to gas remaining;
// bubble up the revert data if enough gas is still available.
if lt(add(cost, ExtraGasBuffer), gas()) {
// Copy returndata to memory; overwrite existing memory.
returndatacopy(0, 0, returndatasize())
// Revert, specifying memory region with copied returndata.
revert(0, returndatasize())
}
}
}
}
/**
* @dev Internal pure function to determine if the first word of returndata
* matches an expected magic value.
*
* @param expected The expected magic value.
*
* @return A boolean indicating whether the expected value matches the one
* located in the first word of returndata.
*/
function _doesNotMatchMagic(bytes4 expected) internal pure returns (bool) {
// Declare a variable for the value held by the return data buffer.
bytes4 result;
// Utilize assembly in order to read directly from returndata buffer.
assembly {
// Only put result on stack if return data is exactly one word.
if eq(returndatasize(), OneWord) {
// Copy the word directly from return data into scratch space.
returndatacopy(0, 0, OneWord)
// Take value from scratch space and place it on the stack.
result := mload(0)
}
}
// Return a boolean indicating whether expected and located value match.
return result != expected;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
/**
* @title ZoneInteractionErrors
* @author 0age
* @notice ZoneInteractionErrors contains errors related to zone interaction.
*/
interface ZoneInteractionErrors {
/**
* @dev Revert with an error when attempting to fill an order that specifies
* a restricted submitter as its order type when not submitted by
* either the offerer or the order's zone or approved as valid by the
* zone in question via a staticcall to `isValidOrder`.
*
* @param orderHash The order hash for the invalid restricted order.
*/
error InvalidRestrictedOrder(bytes32 orderHash);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
// prettier-ignore
import {
AdvancedOrder,
CriteriaResolver
} from "./ConsiderationStructs.sol";
interface ZoneInterface {
// Called by Consideration whenever extraData is not provided by the caller.
function isValidOrder(
bytes32 orderHash,
address caller,
address offerer,
bytes32 zoneHash
) external view returns (bytes4 validOrderMagicValue);
// Called by Consideration whenever any extraData is provided by the caller.
function isValidOrderIncludingExtraData(
bytes32 orderHash,
address caller,
AdvancedOrder calldata order,
bytes32[] calldata priorOrderHashes,
CriteriaResolver[] calldata criteriaResolvers
) external view returns (bytes4 validOrderMagicValue);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
import "./TokenTransferrerConstants.sol";
// prettier-ignore
import {
TokenTransferrerErrors
} from "./TokenTransferrerErrors.sol";
import { ConduitBatch1155Transfer } from "./ConduitStructs.sol";
/**
* @title TokenTransferrer
* @author 0age
* @custom:coauthor d1ll0n
* @custom:coauthor transmissions11
* @notice TokenTransferrer is a library for performing optimized ERC20, ERC721,
* ERC1155, and batch ERC1155 transfers, used by both Seaport as well as
* by conduits deployed by the ConduitController. Use great caution when
* considering these functions for use in other codebases, as there are
* significant side effects and edge cases that need to be thoroughly
* understood and carefully addressed.
*/
contract TokenTransferrer is TokenTransferrerErrors {
/**
* @dev Internal function to transfer ERC20 tokens from a given originator
* to a given recipient. Sufficient approvals must be set on the
* contract performing the transfer.
*
* @param token The ERC20 token to transfer.
* @param from The originator of the transfer.
* @param to The recipient of the transfer.
* @param amount The amount to transfer.
*/
function _performERC20Transfer(
address token,
address from,
address to,
uint256 amount
) internal {
// Utilize assembly to perform an optimized ERC20 token transfer.
assembly {
// The free memory pointer memory slot will be used when populating
// call data for the transfer; read the value and restore it later.
let memPointer := mload(FreeMemoryPointerSlot)
// Write call data into memory, starting with function selector.
mstore(ERC20_transferFrom_sig_ptr, ERC20_transferFrom_signature)
mstore(ERC20_transferFrom_from_ptr, from)
mstore(ERC20_transferFrom_to_ptr, to)
mstore(ERC20_transferFrom_amount_ptr, amount)
// Make call & copy up to 32 bytes of return data to scratch space.
// Scratch space does not need to be cleared ahead of time, as the
// subsequent check will ensure that either at least a full word of
// return data is received (in which case it will be overwritten) or
// that no data is received (in which case scratch space will be
// ignored) on a successful call to the given token.
let callStatus := call(
gas(),
token,
0,
ERC20_transferFrom_sig_ptr,
ERC20_transferFrom_length,
0,
OneWord
)
// Determine whether transfer was successful using status & result.
let success := and(
// Set success to whether the call reverted, if not check it
// either returned exactly 1 (can't just be non-zero data), or
// had no return data.
or(
and(eq(mload(0), 1), gt(returndatasize(), 31)),
iszero(returndatasize())
),
callStatus
)
// Handle cases where either the transfer failed or no data was
// returned. Group these, as most transfers will succeed with data.
// Equivalent to `or(iszero(success), iszero(returndatasize()))`
// but after it's inverted for JUMPI this expression is cheaper.
if iszero(and(success, iszero(iszero(returndatasize())))) {
// If the token has no code or the transfer failed: Equivalent
// to `or(iszero(success), iszero(extcodesize(token)))` but
// after it's inverted for JUMPI this expression is cheaper.
if iszero(and(iszero(iszero(extcodesize(token))), success)) {
// If the transfer failed:
if iszero(success) {
// If it was due to a revert:
if iszero(callStatus) {
// If it returned a message, bubble it up as long as
// sufficient gas remains to do so:
if returndatasize() {
// Ensure that sufficient gas is available to
// copy returndata while expanding memory where
// necessary. Start by computing the word size
// of returndata and allocated memory. Round up
// to the nearest full word.
let returnDataWords := div(
add(returndatasize(), AlmostOneWord),
OneWord
)
// Note: use the free memory pointer in place of
// msize() to work around a Yul warning that
// prevents accessing msize directly when the IR
// pipeline is activated.
let msizeWords := div(memPointer, OneWord)
// Next, compute the cost of the returndatacopy.
let cost := mul(CostPerWord, returnDataWords)
// Then, compute cost of new memory allocation.
if gt(returnDataWords, msizeWords) {
cost := add(
cost,
add(
mul(
sub(
returnDataWords,
msizeWords
),
CostPerWord
),
div(
sub(
mul(
returnDataWords,
returnDataWords
),
mul(msizeWords, msizeWords)
),
MemoryExpansionCoefficient
)
)
)
}
// Finally, add a small constant and compare to
// gas remaining; bubble up the revert data if
// enough gas is still available.
if lt(add(cost, ExtraGasBuffer), gas()) {
// Copy returndata to memory; overwrite
// existing memory.
returndatacopy(0, 0, returndatasize())
// Revert, specifying memory region with
// copied returndata.
revert(0, returndatasize())
}
}
// Otherwise revert with a generic error message.
mstore(
TokenTransferGenericFailure_error_sig_ptr,
TokenTransferGenericFailure_error_signature
)
mstore(
TokenTransferGenericFailure_error_token_ptr,
token
)
mstore(
TokenTransferGenericFailure_error_from_ptr,
from
)
mstore(TokenTransferGenericFailure_error_to_ptr, to)
mstore(TokenTransferGenericFailure_error_id_ptr, 0)
mstore(
TokenTransferGenericFailure_error_amount_ptr,
amount
)
revert(
TokenTransferGenericFailure_error_sig_ptr,
TokenTransferGenericFailure_error_length
)
}
// Otherwise revert with a message about the token
// returning false or non-compliant return values.
mstore(
BadReturnValueFromERC20OnTransfer_error_sig_ptr,
BadReturnValueFromERC20OnTransfer_error_signature
)
mstore(
BadReturnValueFromERC20OnTransfer_error_token_ptr,
token
)
mstore(
BadReturnValueFromERC20OnTransfer_error_from_ptr,
from
)
mstore(
BadReturnValueFromERC20OnTransfer_error_to_ptr,
to
)
mstore(
BadReturnValueFromERC20OnTransfer_error_amount_ptr,
amount
)
revert(
BadReturnValueFromERC20OnTransfer_error_sig_ptr,
BadReturnValueFromERC20OnTransfer_error_length
)
}
// Otherwise, revert with error about token not having code:
mstore(NoContract_error_sig_ptr, NoContract_error_signature)
mstore(NoContract_error_token_ptr, token)
revert(NoContract_error_sig_ptr, NoContract_error_length)
}
// Otherwise, the token just returned no data despite the call
// having succeeded; no need to optimize for this as it's not
// technically ERC20 compliant.
}
// Restore the original free memory pointer.
mstore(FreeMemoryPointerSlot, memPointer)
// Restore the zero slot to zero.
mstore(ZeroSlot, 0)
}
}
/**
* @dev Internal function to transfer an ERC721 token from a given
* originator to a given recipient. Sufficient approvals must be set on
* the contract performing the transfer. Note that this function does
* not check whether the receiver can accept the ERC721 token (i.e. it
* does not use `safeTransferFrom`).
*
* @param token The ERC721 token to transfer.
* @param from The originator of the transfer.
* @param to The recipient of the transfer.
* @param identifier The tokenId to transfer.
*/
function _performERC721Transfer(
address token,
address from,
address to,
uint256 identifier
) internal {
// Utilize assembly to perform an optimized ERC721 token transfer.
assembly {
// If the token has no code, revert.
if iszero(extcodesize(token)) {
mstore(NoContract_error_sig_ptr, NoContract_error_signature)
mstore(NoContract_error_token_ptr, token)
revert(NoContract_error_sig_ptr, NoContract_error_length)
}
// The free memory pointer memory slot will be used when populating
// call data for the transfer; read the value and restore it later.
let memPointer := mload(FreeMemoryPointerSlot)
// Write call data to memory starting with function selector.
mstore(ERC721_transferFrom_sig_ptr, ERC721_transferFrom_signature)
mstore(ERC721_transferFrom_from_ptr, from)
mstore(ERC721_transferFrom_to_ptr, to)
mstore(ERC721_transferFrom_id_ptr, identifier)
// Perform the call, ignoring return data.
let success := call(
gas(),
token,
0,
ERC721_transferFrom_sig_ptr,
ERC721_transferFrom_length,
0,
0
)
// If the transfer reverted:
if iszero(success) {
// If it returned a message, bubble it up as long as sufficient
// gas remains to do so:
if returndatasize() {
// Ensure that sufficient gas is available to copy
// returndata while expanding memory where necessary. Start
// by computing word size of returndata & allocated memory.
// Round up to the nearest full word.
let returnDataWords := div(
add(returndatasize(), AlmostOneWord),
OneWord
)
// Note: use the free memory pointer in place of msize() to
// work around a Yul warning that prevents accessing msize
// directly when the IR pipeline is activated.
let msizeWords := div(memPointer, OneWord)
// Next, compute the cost of the returndatacopy.
let cost := mul(CostPerWord, returnDataWords)
// Then, compute cost of new memory allocation.
if gt(returnDataWords, msizeWords) {
cost := add(
cost,
add(
mul(
sub(returnDataWords, msizeWords),
CostPerWord
),
div(
sub(
mul(returnDataWords, returnDataWords),
mul(msizeWords, msizeWords)
),
MemoryExpansionCoefficient
)
)
)
}
// Finally, add a small constant and compare to gas
// remaining; bubble up the revert data if enough gas is
// still available.
if lt(add(cost, ExtraGasBuffer), gas()) {
// Copy returndata to memory; overwrite existing memory.
returndatacopy(0, 0, returndatasize())
// Revert, giving memory region with copied returndata.
revert(0, returndatasize())
}
}
// Otherwise revert with a generic error message.
mstore(
TokenTransferGenericFailure_error_sig_ptr,
TokenTransferGenericFailure_error_signature
)
mstore(TokenTransferGenericFailure_error_token_ptr, token)
mstore(TokenTransferGenericFailure_error_from_ptr, from)
mstore(TokenTransferGenericFailure_error_to_ptr, to)
mstore(TokenTransferGenericFailure_error_id_ptr, identifier)
mstore(TokenTransferGenericFailure_error_amount_ptr, 1)
revert(
TokenTransferGenericFailure_error_sig_ptr,
TokenTransferGenericFailure_error_length
)
}
// Restore the original free memory pointer.
mstore(FreeMemoryPointerSlot, memPointer)
// Restore the zero slot to zero.
mstore(ZeroSlot, 0)
}
}
/**
* @dev Internal function to transfer ERC1155 tokens from a given
* originator to a given recipient. Sufficient approvals must be set on
* the contract performing the transfer and contract recipients must
* implement the ERC1155TokenReceiver interface to indicate that they
* are willing to accept the transfer.
*
* @param token The ERC1155 token to transfer.
* @param from The originator of the transfer.
* @param to The recipient of the transfer.
* @param identifier The id to transfer.
* @param amount The amount to transfer.
*/
function _performERC1155Transfer(
address token,
address from,
address to,
uint256 identifier,
uint256 amount
) internal {
// Utilize assembly to perform an optimized ERC1155 token transfer.
assembly {
// If the token has no code, revert.
if iszero(extcodesize(token)) {
mstore(NoContract_error_sig_ptr, NoContract_error_signature)
mstore(NoContract_error_token_ptr, token)
revert(NoContract_error_sig_ptr, NoContract_error_length)
}
// The following memory slots will be used when populating call data
// for the transfer; read the values and restore them later.
let memPointer := mload(FreeMemoryPointerSlot)
let slot0x80 := mload(Slot0x80)
let slot0xA0 := mload(Slot0xA0)
let slot0xC0 := mload(Slot0xC0)
// Write call data into memory, beginning with function selector.
mstore(
ERC1155_safeTransferFrom_sig_ptr,
ERC1155_safeTransferFrom_signature
)
mstore(ERC1155_safeTransferFrom_from_ptr, from)
mstore(ERC1155_safeTransferFrom_to_ptr, to)
mstore(ERC1155_safeTransferFrom_id_ptr, identifier)
mstore(ERC1155_safeTransferFrom_amount_ptr, amount)
mstore(
ERC1155_safeTransferFrom_data_offset_ptr,
ERC1155_safeTransferFrom_data_length_offset
)
mstore(ERC1155_safeTransferFrom_data_length_ptr, 0)
// Perform the call, ignoring return data.
let success := call(
gas(),
token,
0,
ERC1155_safeTransferFrom_sig_ptr,
ERC1155_safeTransferFrom_length,
0,
0
)
// If the transfer reverted:
if iszero(success) {
// If it returned a message, bubble it up as long as sufficient
// gas remains to do so:
if returndatasize() {
// Ensure that sufficient gas is available to copy
// returndata while expanding memory where necessary. Start
// by computing word size of returndata & allocated memory.
// Round up to the nearest full word.
let returnDataWords := div(
add(returndatasize(), AlmostOneWord),
OneWord
)
// Note: use the free memory pointer in place of msize() to
// work around a Yul warning that prevents accessing msize
// directly when the IR pipeline is activated.
let msizeWords := div(memPointer, OneWord)
// Next, compute the cost of the returndatacopy.
let cost := mul(CostPerWord, returnDataWords)
// Then, compute cost of new memory allocation.
if gt(returnDataWords, msizeWords) {
cost := add(
cost,
add(
mul(
sub(returnDataWords, msizeWords),
CostPerWord
),
div(
sub(
mul(returnDataWords, returnDataWords),
mul(msizeWords, msizeWords)
),
MemoryExpansionCoefficient
)
)
)
}
// Finally, add a small constant and compare to gas
// remaining; bubble up the revert data if enough gas is
// still available.
if lt(add(cost, ExtraGasBuffer), gas()) {
// Copy returndata to memory; overwrite existing memory.
returndatacopy(0, 0, returndatasize())
// Revert, giving memory region with copied returndata.
revert(0, returndatasize())
}
}
// Otherwise revert with a generic error message.
mstore(
TokenTransferGenericFailure_error_sig_ptr,
TokenTransferGenericFailure_error_signature
)
mstore(TokenTransferGenericFailure_error_token_ptr, token)
mstore(TokenTransferGenericFailure_error_from_ptr, from)
mstore(TokenTransferGenericFailure_error_to_ptr, to)
mstore(TokenTransferGenericFailure_error_id_ptr, identifier)
mstore(TokenTransferGenericFailure_error_amount_ptr, amount)
revert(
TokenTransferGenericFailure_error_sig_ptr,
TokenTransferGenericFailure_error_length
)
}
mstore(Slot0x80, slot0x80) // Restore slot 0x80.
mstore(Slot0xA0, slot0xA0) // Restore slot 0xA0.
mstore(Slot0xC0, slot0xC0) // Restore slot 0xC0.
// Restore the original free memory pointer.
mstore(FreeMemoryPointerSlot, memPointer)
// Restore the zero slot to zero.
mstore(ZeroSlot, 0)
}
}
/**
* @dev Internal function to transfer ERC1155 tokens from a given
* originator to a given recipient. Sufficient approvals must be set on
* the contract performing the transfer and contract recipients must
* implement the ERC1155TokenReceiver interface to indicate that they
* are willing to accept the transfer. NOTE: this function is not
* memory-safe; it will overwrite existing memory, restore the free
* memory pointer to the default value, and overwrite the zero slot.
* This function should only be called once memory is no longer
* required and when uninitialized arrays are not utilized, and memory
* should be considered fully corrupted (aside from the existence of a
* default-value free memory pointer) after calling this function.
*
* @param batchTransfers The group of 1155 batch transfers to perform.
*/
function _performERC1155BatchTransfers(
ConduitBatch1155Transfer[] calldata batchTransfers
) internal {
// Utilize assembly to perform optimized batch 1155 transfers.
assembly {
let len := batchTransfers.length
// Pointer to first head in the array, which is offset to the struct
// at each index. This gets incremented after each loop to avoid
// multiplying by 32 to get the offset for each element.
let nextElementHeadPtr := batchTransfers.offset
// Pointer to beginning of the head of the array. This is the
// reference position each offset references. It's held static to
// let each loop calculate the data position for an element.
let arrayHeadPtr := nextElementHeadPtr
// Write the function selector, which will be reused for each call:
// safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)
mstore(
ConduitBatch1155Transfer_from_offset,
ERC1155_safeBatchTransferFrom_signature
)
// Iterate over each batch transfer.
for {
let i := 0
} lt(i, len) {
i := add(i, 1)
} {
// Read the offset to the beginning of the element and add
// it to pointer to the beginning of the array head to get
// the absolute position of the element in calldata.
let elementPtr := add(
arrayHeadPtr,
calldataload(nextElementHeadPtr)
)
// Retrieve the token from calldata.
let token := calldataload(elementPtr)
// If the token has no code, revert.
if iszero(extcodesize(token)) {
mstore(NoContract_error_sig_ptr, NoContract_error_signature)
mstore(NoContract_error_token_ptr, token)
revert(NoContract_error_sig_ptr, NoContract_error_length)
}
// Get the total number of supplied ids.
let idsLength := calldataload(
add(elementPtr, ConduitBatch1155Transfer_ids_length_offset)
)
// Determine the expected offset for the amounts array.
let expectedAmountsOffset := add(
ConduitBatch1155Transfer_amounts_length_baseOffset,
mul(idsLength, OneWord)
)
// Validate struct encoding.
let invalidEncoding := iszero(
and(
// ids.length == amounts.length
eq(
idsLength,
calldataload(add(elementPtr, expectedAmountsOffset))
),
and(
// ids_offset == 0xa0
eq(
calldataload(
add(
elementPtr,
ConduitBatch1155Transfer_ids_head_offset
)
),
ConduitBatch1155Transfer_ids_length_offset
),
// amounts_offset == 0xc0 + ids.length*32
eq(
calldataload(
add(
elementPtr,
ConduitBatchTransfer_amounts_head_offset
)
),
expectedAmountsOffset
)
)
)
)
// Revert with an error if the encoding is not valid.
if invalidEncoding {
mstore(
Invalid1155BatchTransferEncoding_ptr,
Invalid1155BatchTransferEncoding_selector
)
revert(
Invalid1155BatchTransferEncoding_ptr,
Invalid1155BatchTransferEncoding_length
)
}
// Update the offset position for the next loop
nextElementHeadPtr := add(nextElementHeadPtr, OneWord)
// Copy the first section of calldata (before dynamic values).
calldatacopy(
BatchTransfer1155Params_ptr,
add(elementPtr, ConduitBatch1155Transfer_from_offset),
ConduitBatch1155Transfer_usable_head_size
)
// Determine size of calldata required for ids and amounts. Note
// that the size includes both lengths as well as the data.
let idsAndAmountsSize := add(TwoWords, mul(idsLength, TwoWords))
// Update the offset for the data array in memory.
mstore(
BatchTransfer1155Params_data_head_ptr,
add(
BatchTransfer1155Params_ids_length_offset,
idsAndAmountsSize
)
)
// Set the length of the data array in memory to zero.
mstore(
add(
BatchTransfer1155Params_data_length_basePtr,
idsAndAmountsSize
),
0
)
// Determine the total calldata size for the call to transfer.
let transferDataSize := add(
BatchTransfer1155Params_calldata_baseSize,
idsAndAmountsSize
)
// Copy second section of calldata (including dynamic values).
calldatacopy(
BatchTransfer1155Params_ids_length_ptr,
add(elementPtr, ConduitBatch1155Transfer_ids_length_offset),
idsAndAmountsSize
)
// Perform the call to transfer 1155 tokens.
let success := call(
gas(),
token,
0,
ConduitBatch1155Transfer_from_offset, // Data portion start.
transferDataSize, // Location of the length of callData.
0,
0
)
// If the transfer reverted:
if iszero(success) {
// If it returned a message, bubble it up as long as
// sufficient gas remains to do so:
if returndatasize() {
// Ensure that sufficient gas is available to copy
// returndata while expanding memory where necessary.
// Start by computing word size of returndata and
// allocated memory. Round up to the nearest full word.
let returnDataWords := div(
add(returndatasize(), AlmostOneWord),
OneWord
)
// Note: use transferDataSize in place of msize() to
// work around a Yul warning that prevents accessing
// msize directly when the IR pipeline is activated.
// The free memory pointer is not used here because
// this function does almost all memory management
// manually and does not update it, and transferDataSize
// should be the largest memory value used (unless a
// previous batch was larger).
let msizeWords := div(transferDataSize, OneWord)
// Next, compute the cost of the returndatacopy.
let cost := mul(CostPerWord, returnDataWords)
// Then, compute cost of new memory allocation.
if gt(returnDataWords, msizeWords) {
cost := add(
cost,
add(
mul(
sub(returnDataWords, msizeWords),
CostPerWord
),
div(
sub(
mul(
returnDataWords,
returnDataWords
),
mul(msizeWords, msizeWords)
),
MemoryExpansionCoefficient
)
)
)
}
// Finally, add a small constant and compare to gas
// remaining; bubble up the revert data if enough gas is
// still available.
if lt(add(cost, ExtraGasBuffer), gas()) {
// Copy returndata to memory; overwrite existing.
returndatacopy(0, 0, returndatasize())
// Revert with memory region containing returndata.
revert(0, returndatasize())
}
}
// Set the error signature.
mstore(
0,
ERC1155BatchTransferGenericFailure_error_signature
)
// Write the token.
mstore(ERC1155BatchTransferGenericFailure_token_ptr, token)
// Increase the offset to ids by 32.
mstore(
BatchTransfer1155Params_ids_head_ptr,
ERC1155BatchTransferGenericFailure_ids_offset
)
// Increase the offset to amounts by 32.
mstore(
BatchTransfer1155Params_amounts_head_ptr,
add(
OneWord,
mload(BatchTransfer1155Params_amounts_head_ptr)
)
)
// Return modified region. The total size stays the same as
// `token` uses the same number of bytes as `data.length`.
revert(0, transferDataSize)
}
}
// Reset the free memory pointer to the default value; memory must
// be assumed to be dirtied and not reused from this point forward.
// Also note that the zero slot is not reset to zero, meaning empty
// arrays cannot be safely created or utilized until it is restored.
mstore(FreeMemoryPointerSlot, DefaultFreeMemoryPointer)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { OrderStatus } from "./ConsiderationStructs.sol";
import { Assertions } from "./Assertions.sol";
import { SignatureVerification } from "./SignatureVerification.sol";
/**
* @title Verifiers
* @author 0age
* @notice Verifiers contains functions for performing verifications.
*/
contract Verifiers is Assertions, SignatureVerification {
/**
* @dev Derive and set hashes, reference chainId, and associated domain
* separator during deployment.
*
* @param conduitController A contract that deploys conduits, or proxies
* that may optionally be used to transfer approved
* ERC20/721/1155 tokens.
*/
constructor(address conduitController) Assertions(conduitController) {}
/**
* @dev Internal view function to ensure that the current time falls within
* an order's valid timespan.
*
* @param startTime The time at which the order becomes active.
* @param endTime The time at which the order becomes inactive.
* @param revertOnInvalid A boolean indicating whether to revert if the
* order is not active.
*
* @return valid A boolean indicating whether the order is active.
*/
function _verifyTime(
uint256 startTime,
uint256 endTime,
bool revertOnInvalid
) internal view returns (bool valid) {
// Revert if order's timespan hasn't started yet or has already ended.
if (startTime > block.timestamp || endTime <= block.timestamp) {
// Only revert if revertOnInvalid has been supplied as true.
if (revertOnInvalid) {
revert InvalidTime();
}
// Return false as the order is invalid.
return false;
}
// Return true as the order time is valid.
valid = true;
}
/**
* @dev Internal view function to verify the signature of an order. An
* ERC-1271 fallback will be attempted if either the signature length
* is not 32 or 33 bytes or if the recovered signer does not match the
* supplied offerer. Note that in cases where a 32 or 33 byte signature
* is supplied, only standard ECDSA signatures that recover to a
* non-zero address are supported.
*
* @param offerer The offerer for the order.
* @param orderHash The order hash.
* @param signature A signature from the offerer indicating that the order
* has been approved.
*/
function _verifySignature(
address offerer,
bytes32 orderHash,
bytes memory signature
) internal view {
// Skip signature verification if the offerer is the caller.
if (offerer == msg.sender) {
return;
}
// Derive EIP-712 digest using the domain separator and the order hash.
bytes32 digest = _deriveEIP712Digest(_domainSeparator(), orderHash);
// Ensure that the signature for the digest is valid for the offerer.
_assertValidSignature(offerer, digest, signature);
}
/**
* @dev Internal view function to validate that a given order is fillable
* and not cancelled based on the order status.
*
* @param orderHash The order hash.
* @param orderStatus The status of the order, including whether it has
* been cancelled and the fraction filled.
* @param onlyAllowUnused A boolean flag indicating whether partial fills
* are supported by the calling function.
* @param revertOnInvalid A boolean indicating whether to revert if the
* order has been cancelled or filled beyond the
* allowable amount.
*
* @return valid A boolean indicating whether the order is valid.
*/
function _verifyOrderStatus(
bytes32 orderHash,
OrderStatus storage orderStatus,
bool onlyAllowUnused,
bool revertOnInvalid
) internal view returns (bool valid) {
// Ensure that the order has not been cancelled.
if (orderStatus.isCancelled) {
// Only revert if revertOnInvalid has been supplied as true.
if (revertOnInvalid) {
revert OrderIsCancelled(orderHash);
}
// Return false as the order status is invalid.
return false;
}
// Read order status numerator from storage and place on stack.
uint256 orderStatusNumerator = orderStatus.numerator;
// If the order is not entirely unused...
if (orderStatusNumerator != 0) {
// ensure the order has not been partially filled when not allowed.
if (onlyAllowUnused) {
// Always revert on partial fills when onlyAllowUnused is true.
revert OrderPartiallyFilled(orderHash);
}
// Otherwise, ensure that order has not been entirely filled.
else if (orderStatusNumerator >= orderStatus.denominator) {
// Only revert if revertOnInvalid has been supplied as true.
if (revertOnInvalid) {
revert OrderAlreadyFilled(orderHash);
}
// Return false as the order status is invalid.
return false;
}
}
// Return true as the order status is valid.
valid = true;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
enum ConduitItemType {
NATIVE, // unused
ERC20,
ERC721,
ERC1155
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { EIP1271Interface } from "./EIP1271Interface.sol";
// prettier-ignore
import {
SignatureVerificationErrors
} from "./SignatureVerificationErrors.sol";
import { LowLevelHelpers } from "./LowLevelHelpers.sol";
import "./ConsiderationConstants.sol";
/**
* @title SignatureVerification
* @author 0age
* @notice SignatureVerification contains logic for verifying signatures.
*/
contract SignatureVerification is SignatureVerificationErrors, LowLevelHelpers {
/**
* @dev Internal view function to verify the signature of an order. An
* ERC-1271 fallback will be attempted if either the signature length
* is not 64 or 65 bytes or if the recovered signer does not match the
* supplied signer.
*
* @param signer The signer for the order.
* @param digest The digest to verify the signature against.
* @param signature A signature from the signer indicating that the order
* has been approved.
*/
function _assertValidSignature(
address signer,
bytes32 digest,
bytes memory signature
) internal view {
// Declare value for ecrecover equality or 1271 call success status.
bool success;
// Utilize assembly to perform optimized signature verification check.
assembly {
// Ensure that first word of scratch space is empty.
mstore(0, 0)
// Declare value for v signature parameter.
let v
// Get the length of the signature.
let signatureLength := mload(signature)
// Get the pointer to the value preceding the signature length.
// This will be used for temporary memory overrides - either the
// signature head for isValidSignature or the digest for ecrecover.
let wordBeforeSignaturePtr := sub(signature, OneWord)
// Cache the current value behind the signature to restore it later.
let cachedWordBeforeSignature := mload(wordBeforeSignaturePtr)
// Declare lenDiff + recoveredSigner scope to manage stack pressure.
{
// Take the difference between the max ECDSA signature length
// and the actual signature length. Overflow desired for any
// values > 65. If the diff is not 0 or 1, it is not a valid
// ECDSA signature - move on to EIP1271 check.
let lenDiff := sub(ECDSA_MaxLength, signatureLength)
// Declare variable for recovered signer.
let recoveredSigner
// If diff is 0 or 1, it may be an ECDSA signature.
// Try to recover signer.
if iszero(gt(lenDiff, 1)) {
// Read the signature `s` value.
let originalSignatureS := mload(
add(signature, ECDSA_signature_s_offset)
)
// Read the first byte of the word after `s`. If the
// signature is 65 bytes, this will be the real `v` value.
// If not, it will need to be modified - doing it this way
// saves an extra condition.
v := byte(
0,
mload(add(signature, ECDSA_signature_v_offset))
)
// If lenDiff is 1, parse 64-byte signature as ECDSA.
if lenDiff {
// Extract yParity from highest bit of vs and add 27 to
// get v.
v := add(
shr(MaxUint8, originalSignatureS),
Signature_lower_v
)
// Extract canonical s from vs, all but the highest bit.
// Temporarily overwrite the original `s` value in the
// signature.
mstore(
add(signature, ECDSA_signature_s_offset),
and(
originalSignatureS,
EIP2098_allButHighestBitMask
)
)
}
// Temporarily overwrite the signature length with `v` to
// conform to the expected input for ecrecover.
mstore(signature, v)
// Temporarily overwrite the word before the length with
// `digest` to conform to the expected input for ecrecover.
mstore(wordBeforeSignaturePtr, digest)
// Attempt to recover the signer for the given signature. Do
// not check the call status as ecrecover will return a null
// address if the signature is invalid.
pop(
staticcall(
gas(),
Ecrecover_precompile, // Call ecrecover precompile.
wordBeforeSignaturePtr, // Use data memory location.
Ecrecover_args_size, // Size of digest, v, r, and s.
0, // Write result to scratch space.
OneWord // Provide size of returned result.
)
)
// Restore cached word before signature.
mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature)
// Restore cached signature length.
mstore(signature, signatureLength)
// Restore cached signature `s` value.
mstore(
add(signature, ECDSA_signature_s_offset),
originalSignatureS
)
// Read the recovered signer from the buffer given as return
// space for ecrecover.
recoveredSigner := mload(0)
}
// Set success to true if the signature provided was a valid
// ECDSA signature and the signer is not the null address. Use
// gt instead of direct as success is used outside of assembly.
success := and(eq(signer, recoveredSigner), gt(signer, 0))
}
// If the signature was not verified with ecrecover, try EIP1271.
if iszero(success) {
// Temporarily overwrite the word before the signature length
// and use it as the head of the signature input to
// `isValidSignature`, which has a value of 64.
mstore(
wordBeforeSignaturePtr,
EIP1271_isValidSignature_signature_head_offset
)
// Get pointer to use for the selector of `isValidSignature`.
let selectorPtr := sub(
signature,
EIP1271_isValidSignature_selector_negativeOffset
)
// Cache the value currently stored at the selector pointer.
let cachedWordOverwrittenBySelector := mload(selectorPtr)
// Get pointer to use for `digest` input to `isValidSignature`.
let digestPtr := sub(
signature,
EIP1271_isValidSignature_digest_negativeOffset
)
// Cache the value currently stored at the digest pointer.
let cachedWordOverwrittenByDigest := mload(digestPtr)
// Write the selector first, since it overlaps the digest.
mstore(selectorPtr, EIP1271_isValidSignature_selector)
// Next, write the digest.
mstore(digestPtr, digest)
// Call signer with `isValidSignature` to validate signature.
success := staticcall(
gas(),
signer,
selectorPtr,
add(
signatureLength,
EIP1271_isValidSignature_calldata_baseLength
),
0,
OneWord
)
// Determine if the signature is valid on successful calls.
if success {
// If first word of scratch space does not contain EIP-1271
// signature selector, revert.
if iszero(eq(mload(0), EIP1271_isValidSignature_selector)) {
// Revert with bad 1271 signature if signer has code.
if extcodesize(signer) {
// Bad contract signature.
mstore(0, BadContractSignature_error_signature)
revert(0, BadContractSignature_error_length)
}
// Check if signature length was invalid.
if gt(sub(ECDSA_MaxLength, signatureLength), 1) {
// Revert with generic invalid signature error.
mstore(0, InvalidSignature_error_signature)
revert(0, InvalidSignature_error_length)
}
// Check if v was invalid.
if iszero(
byte(v, ECDSA_twentySeventhAndTwentyEighthBytesSet)
) {
// Revert with invalid v value.
mstore(0, BadSignatureV_error_signature)
mstore(BadSignatureV_error_offset, v)
revert(0, BadSignatureV_error_length)
}
// Revert with generic invalid signer error message.
mstore(0, InvalidSigner_error_signature)
revert(0, InvalidSigner_error_length)
}
}
// Restore the cached values overwritten by selector, digest and
// signature head.
mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature)
mstore(selectorPtr, cachedWordOverwrittenBySelector)
mstore(digestPtr, cachedWordOverwrittenByDigest)
}
}
// If the call failed...
if (!success) {
// Revert and pass reason along if one was returned.
_revertWithReasonIfOneIsReturned();
// Otherwise, revert with error indicating bad contract signature.
assembly {
mstore(0, BadContractSignature_error_signature)
revert(0, BadContractSignature_error_length)
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { OrderParameters } from "./ConsiderationStructs.sol";
import { GettersAndDerivers } from "./GettersAndDerivers.sol";
// prettier-ignore
import {
TokenTransferrerErrors
} from "./TokenTransferrerErrors.sol";
import { CounterManager } from "./CounterManager.sol";
import "./ConsiderationConstants.sol";
/**
* @title Assertions
* @author 0age
* @notice Assertions contains logic for making various assertions that do not
* fit neatly within a dedicated semantic scope.
*/
contract Assertions is
GettersAndDerivers,
CounterManager,
TokenTransferrerErrors
{
/**
* @dev Derive and set hashes, reference chainId, and associated domain
* separator during deployment.
*
* @param conduitController A contract that deploys conduits, or proxies
* that may optionally be used to transfer approved
* ERC20/721/1155 tokens.
*/
constructor(address conduitController)
GettersAndDerivers(conduitController)
{}
/**
* @dev Internal view function to ensure that the supplied consideration
* array length on a given set of order parameters is not less than the
* original consideration array length for that order and to retrieve
* the current counter for a given order's offerer and zone and use it
* to derive the order hash.
*
* @param orderParameters The parameters of the order to hash.
*
* @return The hash.
*/
function _assertConsiderationLengthAndGetOrderHash(
OrderParameters memory orderParameters
) internal view returns (bytes32) {
// Ensure supplied consideration array length is not less than original.
_assertConsiderationLengthIsNotLessThanOriginalConsiderationLength(
orderParameters.consideration.length,
orderParameters.totalOriginalConsiderationItems
);
// Derive and return order hash using current counter for the offerer.
return
_deriveOrderHash(
orderParameters,
_getCounter(orderParameters.offerer)
);
}
/**
* @dev Internal pure function to ensure that the supplied consideration
* array length for an order to be fulfilled is not less than the
* original consideration array length for that order.
*
* @param suppliedConsiderationItemTotal The number of consideration items
* supplied when fulfilling the order.
* @param originalConsiderationItemTotal The number of consideration items
* supplied on initial order creation.
*/
function _assertConsiderationLengthIsNotLessThanOriginalConsiderationLength(
uint256 suppliedConsiderationItemTotal,
uint256 originalConsiderationItemTotal
) internal pure {
// Ensure supplied consideration array length is not less than original.
if (suppliedConsiderationItemTotal < originalConsiderationItemTotal) {
revert MissingOriginalConsiderationItems();
}
}
/**
* @dev Internal pure function to ensure that a given item amount is not
* zero.
*
* @param amount The amount to check.
*/
function _assertNonZeroAmount(uint256 amount) internal pure {
// Revert if the supplied amount is equal to zero.
if (amount == 0) {
revert MissingItemAmount();
}
}
/**
* @dev Internal pure function to validate calldata offsets for dynamic
* types in BasicOrderParameters and other parameters. This ensures
* that functions using the calldata object normally will be using the
* same data as the assembly functions and that values that are bound
* to a given range are within that range. Note that no parameters are
* supplied as all basic order functions use the same calldata
* encoding.
*/
function _assertValidBasicOrderParameters() internal pure {
// Declare a boolean designating basic order parameter offset validity.
bool validOffsets;
// Utilize assembly in order to read offset data directly from calldata.
assembly {
/*
* Checks:
* 1. Order parameters struct offset == 0x20
* 2. Additional recipients arr offset == 0x240
* 3. Signature offset == 0x260 + (recipients.length * 0x40)
* 4. BasicOrderType between 0 and 23 (i.e. < 24)
*/
validOffsets := and(
// Order parameters at calldata 0x04 must have offset of 0x20.
eq(
calldataload(BasicOrder_parameters_cdPtr),
BasicOrder_parameters_ptr
),
// Additional recipients at cd 0x224 must have offset of 0x240.
eq(
calldataload(BasicOrder_additionalRecipients_head_cdPtr),
BasicOrder_additionalRecipients_head_ptr
)
)
validOffsets := and(
validOffsets,
eq(
// Load signature offset from calldata 0x244.
calldataload(BasicOrder_signature_cdPtr),
// Derive expected offset as start of recipients + len * 64.
add(
BasicOrder_signature_ptr,
mul(
// Additional recipients length at calldata 0x264.
calldataload(
BasicOrder_additionalRecipients_length_cdPtr
),
// Each additional recipient has a length of 0x40.
AdditionalRecipients_size
)
)
)
)
validOffsets := and(
validOffsets,
lt(
// BasicOrderType parameter at calldata offset 0x124.
calldataload(BasicOrder_basicOrderType_cdPtr),
// Value should be less than 24.
BasicOrder_basicOrderType_range
)
)
}
// Revert with an error if basic order parameter offsets are invalid.
if (!validOffsets) {
revert InvalidBasicOrderParameterEncoding();
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
/**
* @title TokenTransferrerErrors
*/
interface TokenTransferrerErrors {
/**
* @dev Revert with an error when an ERC721 transfer with amount other than
* one is attempted.
*/
error InvalidERC721TransferAmount();
/**
* @dev Revert with an error when attempting to fulfill an order where an
* item has an amount of zero.
*/
error MissingItemAmount();
/**
* @dev Revert with an error when attempting to fulfill an order where an
* item has unused parameters. This includes both the token and the
* identifier parameters for native transfers as well as the identifier
* parameter for ERC20 transfers. Note that the conduit does not
* perform this check, leaving it up to the calling channel to enforce
* when desired.
*/
error UnusedItemParameters();
/**
* @dev Revert with an error when an ERC20, ERC721, or ERC1155 token
* transfer reverts.
*
* @param token The token for which the transfer was attempted.
* @param from The source of the attempted transfer.
* @param to The recipient of the attempted transfer.
* @param identifier The identifier for the attempted transfer.
* @param amount The amount for the attempted transfer.
*/
error TokenTransferGenericFailure(
address token,
address from,
address to,
uint256 identifier,
uint256 amount
);
/**
* @dev Revert with an error when a batch ERC1155 token transfer reverts.
*
* @param token The token for which the transfer was attempted.
* @param from The source of the attempted transfer.
* @param to The recipient of the attempted transfer.
* @param identifiers The identifiers for the attempted transfer.
* @param amounts The amounts for the attempted transfer.
*/
error ERC1155BatchTransferGenericFailure(
address token,
address from,
address to,
uint256[] identifiers,
uint256[] amounts
);
/**
* @dev Revert with an error when an ERC20 token transfer returns a falsey
* value.
*
* @param token The token for which the ERC20 transfer was attempted.
* @param from The source of the attempted ERC20 transfer.
* @param to The recipient of the attempted ERC20 transfer.
* @param amount The amount for the attempted ERC20 transfer.
*/
error BadReturnValueFromERC20OnTransfer(
address token,
address from,
address to,
uint256 amount
);
/**
* @dev Revert with an error when an account being called as an assumed
* contract does not have code and returns no data.
*
* @param account The account that should contain code.
*/
error NoContract(address account);
/**
* @dev Revert with an error when attempting to execute an 1155 batch
* transfer using calldata not produced by default ABI encoding or with
* different lengths for ids and amounts arrays.
*/
error Invalid1155BatchTransferEncoding();
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
/*
* -------------------------- Disambiguation & Other Notes ---------------------
* - The term "head" is used as it is in the documentation for ABI encoding,
* but only in reference to dynamic types, i.e. it always refers to the
* offset or pointer to the body of a dynamic type. In calldata, the head
* is always an offset (relative to the parent object), while in memory,
* the head is always the pointer to the body. More information found here:
* https://docs.soliditylang.org/en/v0.8.14/abi-spec.html#argument-encoding
* - Note that the length of an array is separate from and precedes the
* head of the array.
*
* - The term "body" is used in place of the term "head" used in the ABI
* documentation. It refers to the start of the data for a dynamic type,
* e.g. the first word of a struct or the first word of the first element
* in an array.
*
* - The term "pointer" is used to describe the absolute position of a value
* and never an offset relative to another value.
* - The suffix "_ptr" refers to a memory pointer.
* - The suffix "_cdPtr" refers to a calldata pointer.
*
* - The term "offset" is used to describe the position of a value relative
* to some parent value. For example, OrderParameters_conduit_offset is the
* offset to the "conduit" value in the OrderParameters struct relative to
* the start of the body.
* - Note: Offsets are used to derive pointers.
*
* - Some structs have pointers defined for all of their fields in this file.
* Lines which are commented out are fields that are not used in the
* codebase but have been left in for readability.
*/
uint256 constant AlmostOneWord = 0x1f;
uint256 constant OneWord = 0x20;
uint256 constant TwoWords = 0x40;
uint256 constant ThreeWords = 0x60;
uint256 constant FreeMemoryPointerSlot = 0x40;
uint256 constant ZeroSlot = 0x60;
uint256 constant DefaultFreeMemoryPointer = 0x80;
uint256 constant Slot0x80 = 0x80;
uint256 constant Slot0xA0 = 0xa0;
uint256 constant Slot0xC0 = 0xc0;
// abi.encodeWithSignature("transferFrom(address,address,uint256)")
uint256 constant ERC20_transferFrom_signature = (
0x23b872dd00000000000000000000000000000000000000000000000000000000
);
uint256 constant ERC20_transferFrom_sig_ptr = 0x0;
uint256 constant ERC20_transferFrom_from_ptr = 0x04;
uint256 constant ERC20_transferFrom_to_ptr = 0x24;
uint256 constant ERC20_transferFrom_amount_ptr = 0x44;
uint256 constant ERC20_transferFrom_length = 0x64; // 4 + 32 * 3 == 100
// abi.encodeWithSignature(
// "safeTransferFrom(address,address,uint256,uint256,bytes)"
// )
uint256 constant ERC1155_safeTransferFrom_signature = (
0xf242432a00000000000000000000000000000000000000000000000000000000
);
uint256 constant ERC1155_safeTransferFrom_sig_ptr = 0x0;
uint256 constant ERC1155_safeTransferFrom_from_ptr = 0x04;
uint256 constant ERC1155_safeTransferFrom_to_ptr = 0x24;
uint256 constant ERC1155_safeTransferFrom_id_ptr = 0x44;
uint256 constant ERC1155_safeTransferFrom_amount_ptr = 0x64;
uint256 constant ERC1155_safeTransferFrom_data_offset_ptr = 0x84;
uint256 constant ERC1155_safeTransferFrom_data_length_ptr = 0xa4;
uint256 constant ERC1155_safeTransferFrom_length = 0xc4; // 4 + 32 * 6 == 196
uint256 constant ERC1155_safeTransferFrom_data_length_offset = 0xa0;
// abi.encodeWithSignature(
// "safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)"
// )
uint256 constant ERC1155_safeBatchTransferFrom_signature = (
0x2eb2c2d600000000000000000000000000000000000000000000000000000000
);
bytes4 constant ERC1155_safeBatchTransferFrom_selector = bytes4(
bytes32(ERC1155_safeBatchTransferFrom_signature)
);
uint256 constant ERC721_transferFrom_signature = ERC20_transferFrom_signature;
uint256 constant ERC721_transferFrom_sig_ptr = 0x0;
uint256 constant ERC721_transferFrom_from_ptr = 0x04;
uint256 constant ERC721_transferFrom_to_ptr = 0x24;
uint256 constant ERC721_transferFrom_id_ptr = 0x44;
uint256 constant ERC721_transferFrom_length = 0x64; // 4 + 32 * 3 == 100
// abi.encodeWithSignature("NoContract(address)")
uint256 constant NoContract_error_signature = (
0x5f15d67200000000000000000000000000000000000000000000000000000000
);
uint256 constant NoContract_error_sig_ptr = 0x0;
uint256 constant NoContract_error_token_ptr = 0x4;
uint256 constant NoContract_error_length = 0x24; // 4 + 32 == 36
// abi.encodeWithSignature(
// "TokenTransferGenericFailure(address,address,address,uint256,uint256)"
// )
uint256 constant TokenTransferGenericFailure_error_signature = (
0xf486bc8700000000000000000000000000000000000000000000000000000000
);
uint256 constant TokenTransferGenericFailure_error_sig_ptr = 0x0;
uint256 constant TokenTransferGenericFailure_error_token_ptr = 0x4;
uint256 constant TokenTransferGenericFailure_error_from_ptr = 0x24;
uint256 constant TokenTransferGenericFailure_error_to_ptr = 0x44;
uint256 constant TokenTransferGenericFailure_error_id_ptr = 0x64;
uint256 constant TokenTransferGenericFailure_error_amount_ptr = 0x84;
// 4 + 32 * 5 == 164
uint256 constant TokenTransferGenericFailure_error_length = 0xa4;
// abi.encodeWithSignature(
// "BadReturnValueFromERC20OnTransfer(address,address,address,uint256)"
// )
uint256 constant BadReturnValueFromERC20OnTransfer_error_signature = (
0x9889192300000000000000000000000000000000000000000000000000000000
);
uint256 constant BadReturnValueFromERC20OnTransfer_error_sig_ptr = 0x0;
uint256 constant BadReturnValueFromERC20OnTransfer_error_token_ptr = 0x4;
uint256 constant BadReturnValueFromERC20OnTransfer_error_from_ptr = 0x24;
uint256 constant BadReturnValueFromERC20OnTransfer_error_to_ptr = 0x44;
uint256 constant BadReturnValueFromERC20OnTransfer_error_amount_ptr = 0x64;
// 4 + 32 * 4 == 132
uint256 constant BadReturnValueFromERC20OnTransfer_error_length = 0x84;
uint256 constant ExtraGasBuffer = 0x20;
uint256 constant CostPerWord = 3;
uint256 constant MemoryExpansionCoefficient = 0x200;
// Values are offset by 32 bytes in order to write the token to the beginning
// in the event of a revert
uint256 constant BatchTransfer1155Params_ptr = 0x24;
uint256 constant BatchTransfer1155Params_ids_head_ptr = 0x64;
uint256 constant BatchTransfer1155Params_amounts_head_ptr = 0x84;
uint256 constant BatchTransfer1155Params_data_head_ptr = 0xa4;
uint256 constant BatchTransfer1155Params_data_length_basePtr = 0xc4;
uint256 constant BatchTransfer1155Params_calldata_baseSize = 0xc4;
uint256 constant BatchTransfer1155Params_ids_length_ptr = 0xc4;
uint256 constant BatchTransfer1155Params_ids_length_offset = 0xa0;
uint256 constant BatchTransfer1155Params_amounts_length_baseOffset = 0xc0;
uint256 constant BatchTransfer1155Params_data_length_baseOffset = 0xe0;
uint256 constant ConduitBatch1155Transfer_usable_head_size = 0x80;
uint256 constant ConduitBatch1155Transfer_from_offset = 0x20;
uint256 constant ConduitBatch1155Transfer_ids_head_offset = 0x60;
uint256 constant ConduitBatch1155Transfer_amounts_head_offset = 0x80;
uint256 constant ConduitBatch1155Transfer_ids_length_offset = 0xa0;
uint256 constant ConduitBatch1155Transfer_amounts_length_baseOffset = 0xc0;
uint256 constant ConduitBatch1155Transfer_calldata_baseSize = 0xc0;
// Note: abbreviated version of above constant to adhere to line length limit.
uint256 constant ConduitBatchTransfer_amounts_head_offset = 0x80;
uint256 constant Invalid1155BatchTransferEncoding_ptr = 0x00;
uint256 constant Invalid1155BatchTransferEncoding_length = 0x04;
uint256 constant Invalid1155BatchTransferEncoding_selector = (
0xeba2084c00000000000000000000000000000000000000000000000000000000
);
uint256 constant ERC1155BatchTransferGenericFailure_error_signature = (
0xafc445e200000000000000000000000000000000000000000000000000000000
);
uint256 constant ERC1155BatchTransferGenericFailure_token_ptr = 0x04;
uint256 constant ERC1155BatchTransferGenericFailure_ids_offset = 0xc0;// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
/**
* @title SignatureVerificationErrors
* @author 0age
* @notice SignatureVerificationErrors contains all errors related to signature
* verification.
*/
interface SignatureVerificationErrors {
/**
* @dev Revert with an error when a signature that does not contain a v
* value of 27 or 28 has been supplied.
*
* @param v The invalid v value.
*/
error BadSignatureV(uint8 v);
/**
* @dev Revert with an error when the signer recovered by the supplied
* signature does not match the offerer or an allowed EIP-1271 signer
* as specified by the offerer in the event they are a contract.
*/
error InvalidSigner();
/**
* @dev Revert with an error when a signer cannot be recovered from the
* supplied signature.
*/
error InvalidSignature();
/**
* @dev Revert with an error when an EIP-1271 call to an account fails.
*/
error BadContractSignature();
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
interface EIP1271Interface {
function isValidSignature(bytes32 digest, bytes calldata signature)
external
view
returns (bytes4);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
// prettier-ignore
import {
ConsiderationEventsAndErrors
} from "./ConsiderationEventsAndErrors.sol";
import { ReentrancyGuard } from "./ReentrancyGuard.sol";
/**
* @title CounterManager
* @author 0age
* @notice CounterManager contains a storage mapping and related functionality
* for retrieving and incrementing a per-offerer counter.
*/
contract CounterManager is ConsiderationEventsAndErrors, ReentrancyGuard {
// Only orders signed using an offerer's current counter are fulfillable.
mapping(address => uint256) private _counters;
/**
* @dev Internal function to cancel all orders from a given offerer with a
* given zone in bulk by incrementing a counter. Note that only the
* offerer may increment the counter.
*
* @return newCounter The new counter.
*/
function _incrementCounter() internal returns (uint256 newCounter) {
// Ensure that the reentrancy guard is not currently set.
_assertNonReentrant();
// Skip overflow check as counter cannot be incremented that far.
unchecked {
// Increment current counter for the supplied offerer.
newCounter = ++_counters[msg.sender];
}
// Emit an event containing the new counter.
emit CounterIncremented(newCounter, msg.sender);
}
/**
* @dev Internal view function to retrieve the current counter for a given
* offerer.
*
* @param offerer The offerer in question.
*
* @return currentCounter The current counter.
*/
function _getCounter(address offerer)
internal
view
returns (uint256 currentCounter)
{
// Return the counter for the supplied offerer.
currentCounter = _counters[offerer];
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { OrderParameters } from "./ConsiderationStructs.sol";
import { ConsiderationBase } from "./ConsiderationBase.sol";
import "./ConsiderationConstants.sol";
/**
* @title GettersAndDerivers
* @author 0age
* @notice ConsiderationInternal contains pure and internal view functions
* related to getting or deriving various values.
*/
contract GettersAndDerivers is ConsiderationBase {
/**
* @dev Derive and set hashes, reference chainId, and associated domain
* separator during deployment.
*
* @param conduitController A contract that deploys conduits, or proxies
* that may optionally be used to transfer approved
* ERC20/721/1155 tokens.
*/
constructor(address conduitController)
ConsiderationBase(conduitController)
{}
/**
* @dev Internal view function to derive the order hash for a given order.
* Note that only the original consideration items are included in the
* order hash, as additional consideration items may be supplied by the
* caller.
*
* @param orderParameters The parameters of the order to hash.
* @param counter The counter of the order to hash.
*
* @return orderHash The hash.
*/
function _deriveOrderHash(
OrderParameters memory orderParameters,
uint256 counter
) internal view returns (bytes32 orderHash) {
// Get length of original consideration array and place it on the stack.
uint256 originalConsiderationLength = (
orderParameters.totalOriginalConsiderationItems
);
/*
* Memory layout for an array of structs (dynamic or not) is similar
* to ABI encoding of dynamic types, with a head segment followed by
* a data segment. The main difference is that the head of an element
* is a memory pointer rather than an offset.
*/
// Declare a variable for the derived hash of the offer array.
bytes32 offerHash;
// Read offer item EIP-712 typehash from runtime code & place on stack.
bytes32 typeHash = _OFFER_ITEM_TYPEHASH;
// Utilize assembly so that memory regions can be reused across hashes.
assembly {
// Retrieve the free memory pointer and place on the stack.
let hashArrPtr := mload(FreeMemoryPointerSlot)
// Get the pointer to the offers array.
let offerArrPtr := mload(
add(orderParameters, OrderParameters_offer_head_offset)
)
// Load the length.
let offerLength := mload(offerArrPtr)
// Set the pointer to the first offer's head.
offerArrPtr := add(offerArrPtr, OneWord)
// Iterate over the offer items.
// prettier-ignore
for { let i := 0 } lt(i, offerLength) {
i := add(i, 1)
} {
// Read the pointer to the offer data and subtract one word
// to get typeHash pointer.
let ptr := sub(mload(offerArrPtr), OneWord)
// Read the current value before the offer data.
let value := mload(ptr)
// Write the type hash to the previous word.
mstore(ptr, typeHash)
// Take the EIP712 hash and store it in the hash array.
mstore(hashArrPtr, keccak256(ptr, EIP712_OfferItem_size))
// Restore the previous word.
mstore(ptr, value)
// Increment the array pointers by one word.
offerArrPtr := add(offerArrPtr, OneWord)
hashArrPtr := add(hashArrPtr, OneWord)
}
// Derive the offer hash using the hashes of each item.
offerHash := keccak256(
mload(FreeMemoryPointerSlot),
mul(offerLength, OneWord)
)
}
// Declare a variable for the derived hash of the consideration array.
bytes32 considerationHash;
// Read consideration item typehash from runtime code & place on stack.
typeHash = _CONSIDERATION_ITEM_TYPEHASH;
// Utilize assembly so that memory regions can be reused across hashes.
assembly {
// Retrieve the free memory pointer and place on the stack.
let hashArrPtr := mload(FreeMemoryPointerSlot)
// Get the pointer to the consideration array.
let considerationArrPtr := add(
mload(
add(
orderParameters,
OrderParameters_consideration_head_offset
)
),
OneWord
)
// Iterate over the consideration items (not including tips).
// prettier-ignore
for { let i := 0 } lt(i, originalConsiderationLength) {
i := add(i, 1)
} {
// Read the pointer to the consideration data and subtract one
// word to get typeHash pointer.
let ptr := sub(mload(considerationArrPtr), OneWord)
// Read the current value before the consideration data.
let value := mload(ptr)
// Write the type hash to the previous word.
mstore(ptr, typeHash)
// Take the EIP712 hash and store it in the hash array.
mstore(
hashArrPtr,
keccak256(ptr, EIP712_ConsiderationItem_size)
)
// Restore the previous word.
mstore(ptr, value)
// Increment the array pointers by one word.
considerationArrPtr := add(considerationArrPtr, OneWord)
hashArrPtr := add(hashArrPtr, OneWord)
}
// Derive the consideration hash using the hashes of each item.
considerationHash := keccak256(
mload(FreeMemoryPointerSlot),
mul(originalConsiderationLength, OneWord)
)
}
// Read order item EIP-712 typehash from runtime code & place on stack.
typeHash = _ORDER_TYPEHASH;
// Utilize assembly to access derived hashes & other arguments directly.
assembly {
// Retrieve pointer to the region located just behind parameters.
let typeHashPtr := sub(orderParameters, OneWord)
// Store the value at that pointer location to restore later.
let previousValue := mload(typeHashPtr)
// Store the order item EIP-712 typehash at the typehash location.
mstore(typeHashPtr, typeHash)
// Retrieve the pointer for the offer array head.
let offerHeadPtr := add(
orderParameters,
OrderParameters_offer_head_offset
)
// Retrieve the data pointer referenced by the offer head.
let offerDataPtr := mload(offerHeadPtr)
// Store the offer hash at the retrieved memory location.
mstore(offerHeadPtr, offerHash)
// Retrieve the pointer for the consideration array head.
let considerationHeadPtr := add(
orderParameters,
OrderParameters_consideration_head_offset
)
// Retrieve the data pointer referenced by the consideration head.
let considerationDataPtr := mload(considerationHeadPtr)
// Store the consideration hash at the retrieved memory location.
mstore(considerationHeadPtr, considerationHash)
// Retrieve the pointer for the counter.
let counterPtr := add(
orderParameters,
OrderParameters_counter_offset
)
// Store the counter at the retrieved memory location.
mstore(counterPtr, counter)
// Derive the order hash using the full range of order parameters.
orderHash := keccak256(typeHashPtr, EIP712_Order_size)
// Restore the value previously held at typehash pointer location.
mstore(typeHashPtr, previousValue)
// Restore offer data pointer at the offer head pointer location.
mstore(offerHeadPtr, offerDataPtr)
// Restore consideration data pointer at the consideration head ptr.
mstore(considerationHeadPtr, considerationDataPtr)
// Restore consideration item length at the counter pointer.
mstore(counterPtr, originalConsiderationLength)
}
}
/**
* @dev Internal view function to derive the address of a given conduit
* using a corresponding conduit key.
*
* @param conduitKey A bytes32 value indicating what corresponding conduit,
* if any, to source token approvals from. This value is
* the "salt" parameter supplied by the deployer (i.e. the
* conduit controller) when deploying the given conduit.
*
* @return conduit The address of the conduit associated with the given
* conduit key.
*/
function _deriveConduit(bytes32 conduitKey)
internal
view
returns (address conduit)
{
// Read conduit controller address from runtime and place on the stack.
address conduitController = address(_CONDUIT_CONTROLLER);
// Read conduit creation code hash from runtime and place on the stack.
bytes32 conduitCreationCodeHash = _CONDUIT_CREATION_CODE_HASH;
// Leverage scratch space to perform an efficient hash.
assembly {
// Retrieve the free memory pointer; it will be replaced afterwards.
let freeMemoryPointer := mload(FreeMemoryPointerSlot)
// Place the control character and the conduit controller in scratch
// space; note that eleven bytes at the beginning are left unused.
mstore(0, or(MaskOverByteTwelve, conduitController))
// Place the conduit key in the next region of scratch space.
mstore(OneWord, conduitKey)
// Place conduit creation code hash in free memory pointer location.
mstore(TwoWords, conduitCreationCodeHash)
// Derive conduit by hashing and applying a mask over last 20 bytes.
conduit := and(
// Hash the relevant region.
keccak256(
// The region starts at memory pointer 11.
Create2AddressDerivation_ptr,
// The region is 85 bytes long (1 + 20 + 32 + 32).
Create2AddressDerivation_length
),
// The address equals the last twenty bytes of the hash.
MaskOverLastTwentyBytes
)
// Restore the free memory pointer.
mstore(FreeMemoryPointerSlot, freeMemoryPointer)
}
}
/**
* @dev Internal view function to get the EIP-712 domain separator. If the
* chainId matches the chainId set on deployment, the cached domain
* separator will be returned; otherwise, it will be derived from
* scratch.
*
* @return The domain separator.
*/
function _domainSeparator() internal view returns (bytes32) {
// prettier-ignore
return block.chainid == _CHAIN_ID
? _DOMAIN_SEPARATOR
: _deriveDomainSeparator();
}
/**
* @dev Internal view function to retrieve configuration information for
* this contract.
*
* @return version The contract version.
* @return domainSeparator The domain separator for this contract.
* @return conduitController The conduit Controller set for this contract.
*/
function _information()
internal
view
returns (
string memory version,
bytes32 domainSeparator,
address conduitController
)
{
// Derive the domain separator.
domainSeparator = _domainSeparator();
// Declare variable as immutables cannot be accessed within assembly.
conduitController = address(_CONDUIT_CONTROLLER);
// Allocate a string with the intended length.
version = new string(Version_length);
// Set the version as data on the newly allocated string.
assembly {
mstore(add(version, OneWord), shl(Version_shift, Version))
}
}
/**
* @dev Internal pure function to efficiently derive an digest to sign for
* an order in accordance with EIP-712.
*
* @param domainSeparator The domain separator.
* @param orderHash The order hash.
*
* @return value The hash.
*/
function _deriveEIP712Digest(bytes32 domainSeparator, bytes32 orderHash)
internal
pure
returns (bytes32 value)
{
// Leverage scratch space to perform an efficient hash.
assembly {
// Place the EIP-712 prefix at the start of scratch space.
mstore(0, EIP_712_PREFIX)
// Place the domain separator in the next region of scratch space.
mstore(EIP712_DomainSeparator_offset, domainSeparator)
// Place the order hash in scratch space, spilling into the first
// two bytes of the free memory pointer — this should never be set
// as memory cannot be expanded to that size, and will be zeroed out
// after the hash is performed.
mstore(EIP712_OrderHash_offset, orderHash)
// Hash the relevant region (65 bytes).
value := keccak256(0, EIP712_DigestPayload_size)
// Clear out the dirtied bits in the memory pointer.
mstore(EIP712_OrderHash_offset, 0)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
// prettier-ignore
import {
ConduitControllerInterface
} from "./ConduitControllerInterface.sol";
// prettier-ignore
import {
ConsiderationEventsAndErrors
} from "./ConsiderationEventsAndErrors.sol";
import "./ConsiderationConstants.sol";
/**
* @title ConsiderationBase
* @author 0age
* @notice ConsiderationBase contains immutable constants and constructor logic.
*/
contract ConsiderationBase is ConsiderationEventsAndErrors {
// Precompute hashes, original chainId, and domain separator on deployment.
bytes32 internal immutable _NAME_HASH;
bytes32 internal immutable _VERSION_HASH;
bytes32 internal immutable _EIP_712_DOMAIN_TYPEHASH;
bytes32 internal immutable _OFFER_ITEM_TYPEHASH;
bytes32 internal immutable _CONSIDERATION_ITEM_TYPEHASH;
bytes32 internal immutable _ORDER_TYPEHASH;
uint256 internal immutable _CHAIN_ID;
bytes32 internal immutable _DOMAIN_SEPARATOR;
// Allow for interaction with the conduit controller.
ConduitControllerInterface internal immutable _CONDUIT_CONTROLLER;
// Cache the conduit creation code hash used by the conduit controller.
bytes32 internal immutable _CONDUIT_CREATION_CODE_HASH;
/**
* @dev Derive and set hashes, reference chainId, and associated domain
* separator during deployment.
*
* @param conduitController A contract that deploys conduits, or proxies
* that may optionally be used to transfer approved
* ERC20/721/1155 tokens.
*/
constructor(address conduitController) {
// Derive name and version hashes alongside required EIP-712 typehashes.
(
_NAME_HASH,
_VERSION_HASH,
_EIP_712_DOMAIN_TYPEHASH,
_OFFER_ITEM_TYPEHASH,
_CONSIDERATION_ITEM_TYPEHASH,
_ORDER_TYPEHASH
) = _deriveTypehashes();
// Store the current chainId and derive the current domain separator.
_CHAIN_ID = block.chainid;
_DOMAIN_SEPARATOR = _deriveDomainSeparator();
// Set the supplied conduit controller.
_CONDUIT_CONTROLLER = ConduitControllerInterface(conduitController);
// Retrieve the conduit creation code hash from the supplied controller.
(_CONDUIT_CREATION_CODE_HASH, ) = (
_CONDUIT_CONTROLLER.getConduitCodeHashes()
);
}
/**
* @dev Internal view function to derive the EIP-712 domain separator.
*
* @return The derived domain separator.
*/
function _deriveDomainSeparator() internal view returns (bytes32) {
// prettier-ignore
return keccak256(
abi.encode(
_EIP_712_DOMAIN_TYPEHASH,
_NAME_HASH,
_VERSION_HASH,
block.chainid,
address(this)
)
);
}
/**
* @dev Internal pure function to retrieve the default name of this
* contract and return.
*
* @return The name of this contract.
*/
function _name() internal pure virtual returns (string memory) {
// Return the name of the contract.
assembly {
// First element is the offset for the returned string. Offset the
// value in memory by one word so that the free memory pointer will
// be overwritten by the next write.
mstore(OneWord, OneWord)
// Name is right padded, so it touches the length which is left
// padded. This enables writing both values at once. The free memory
// pointer will be overwritten in the process.
mstore(NameLengthPtr, NameWithLength)
// Standard ABI encoding pads returned data to the nearest word. Use
// the already empty zero slot memory region for this purpose and
// return the final name string, offset by the original single word.
return(OneWord, ThreeWords)
}
}
/**
* @dev Internal pure function to retrieve the default name of this contract
* as a string that can be used internally.
*
* @return The name of this contract.
*/
function _nameString() internal pure virtual returns (string memory) {
// Return the name of the contract.
return "Consideration";
}
/**
* @dev Internal pure function to derive required EIP-712 typehashes and
* other hashes during contract creation.
*
* @return nameHash The hash of the name of the contract.
* @return versionHash The hash of the version string of the
* contract.
* @return eip712DomainTypehash The primary EIP-712 domain typehash.
* @return offerItemTypehash The EIP-712 typehash for OfferItem
* types.
* @return considerationItemTypehash The EIP-712 typehash for
* ConsiderationItem types.
* @return orderTypehash The EIP-712 typehash for Order types.
*/
function _deriveTypehashes()
internal
pure
returns (
bytes32 nameHash,
bytes32 versionHash,
bytes32 eip712DomainTypehash,
bytes32 offerItemTypehash,
bytes32 considerationItemTypehash,
bytes32 orderTypehash
)
{
// Derive hash of the name of the contract.
nameHash = keccak256(bytes(_nameString()));
// Derive hash of the version string of the contract.
versionHash = keccak256(bytes("1.1"));
// Construct the OfferItem type string.
// prettier-ignore
bytes memory offerItemTypeString = abi.encodePacked(
"OfferItem(",
"uint8 itemType,",
"address token,",
"uint256 identifierOrCriteria,",
"uint256 startAmount,",
"uint256 endAmount",
")"
);
// Construct the ConsiderationItem type string.
// prettier-ignore
bytes memory considerationItemTypeString = abi.encodePacked(
"ConsiderationItem(",
"uint8 itemType,",
"address token,",
"uint256 identifierOrCriteria,",
"uint256 startAmount,",
"uint256 endAmount,",
"address recipient",
")"
);
// Construct the OrderComponents type string, not including the above.
// prettier-ignore
bytes memory orderComponentsPartialTypeString = abi.encodePacked(
"OrderComponents(",
"address offerer,",
"address zone,",
"OfferItem[] offer,",
"ConsiderationItem[] consideration,",
"uint8 orderType,",
"uint256 startTime,",
"uint256 endTime,",
"bytes32 zoneHash,",
"uint256 salt,",
"bytes32 conduitKey,",
"uint256 counter",
")"
);
// Construct the primary EIP-712 domain type string.
// prettier-ignore
eip712DomainTypehash = keccak256(
abi.encodePacked(
"EIP712Domain(",
"string name,",
"string version,",
"uint256 chainId,",
"address verifyingContract",
")"
)
);
// Derive the OfferItem type hash using the corresponding type string.
offerItemTypehash = keccak256(offerItemTypeString);
// Derive ConsiderationItem type hash using corresponding type string.
considerationItemTypehash = keccak256(considerationItemTypeString);
// Derive OrderItem type hash via combination of relevant type strings.
orderTypehash = keccak256(
abi.encodePacked(
orderComponentsPartialTypeString,
considerationItemTypeString,
offerItemTypeString
)
);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { ReentrancyErrors } from "./ReentrancyErrors.sol";
import "./ConsiderationConstants.sol";
/**
* @title ReentrancyGuard
* @author 0age
* @notice ReentrancyGuard contains a storage variable and related functionality
* for protecting against reentrancy.
*/
contract ReentrancyGuard is ReentrancyErrors {
// Prevent reentrant calls on protected functions.
uint256 private _reentrancyGuard;
/**
* @dev Initialize the reentrancy guard during deployment.
*/
constructor() {
// Initialize the reentrancy guard in a cleared state.
_reentrancyGuard = _NOT_ENTERED;
}
/**
* @dev Internal function to ensure that the sentinel value for the
* reentrancy guard is not currently set and, if not, to set the
* sentinel value for the reentrancy guard.
*/
function _setReentrancyGuard() internal {
// Ensure that the reentrancy guard is not already set.
_assertNonReentrant();
// Set the reentrancy guard.
_reentrancyGuard = _ENTERED;
}
/**
* @dev Internal function to unset the reentrancy guard sentinel value.
*/
function _clearReentrancyGuard() internal {
// Clear the reentrancy guard.
_reentrancyGuard = _NOT_ENTERED;
}
/**
* @dev Internal view function to ensure that the sentinel value for the
reentrancy guard is not currently set.
*/
function _assertNonReentrant() internal view {
// Ensure that the reentrancy guard is not currently set.
if (_reentrancyGuard != _NOT_ENTERED) {
revert NoReentrantCalls();
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
import { SpentItem, ReceivedItem } from "./ConsiderationStructs.sol";
/**
* @title ConsiderationEventsAndErrors
* @author 0age
* @notice ConsiderationEventsAndErrors contains all events and errors.
*/
interface ConsiderationEventsAndErrors {
/**
* @dev Emit an event whenever an order is successfully fulfilled.
*
* @param orderHash The hash of the fulfilled order.
* @param offerer The offerer of the fulfilled order.
* @param zone The zone of the fulfilled order.
* @param recipient The recipient of each spent item on the fulfilled
* order, or the null address if there is no specific
* fulfiller (i.e. the order is part of a group of
* orders). Defaults to the caller unless explicitly
* specified otherwise by the fulfiller.
* @param offer The offer items spent as part of the order.
* @param consideration The consideration items received as part of the
* order along with the recipients of each item.
*/
event OrderFulfilled(
bytes32 orderHash,
address indexed offerer,
address indexed zone,
address recipient,
SpentItem[] offer,
ReceivedItem[] consideration
);
/**
* @dev Emit an event whenever an order is successfully cancelled.
*
* @param orderHash The hash of the cancelled order.
* @param offerer The offerer of the cancelled order.
* @param zone The zone of the cancelled order.
*/
event OrderCancelled(
bytes32 orderHash,
address indexed offerer,
address indexed zone
);
/**
* @dev Emit an event whenever an order is explicitly validated. Note that
* this event will not be emitted on partial fills even though they do
* validate the order as part of partial fulfillment.
*
* @param orderHash The hash of the validated order.
* @param offerer The offerer of the validated order.
* @param zone The zone of the validated order.
*/
event OrderValidated(
bytes32 orderHash,
address indexed offerer,
address indexed zone
);
/**
* @dev Emit an event whenever a counter for a given offerer is incremented.
*
* @param newCounter The new counter for the offerer.
* @param offerer The offerer in question.
*/
event CounterIncremented(uint256 newCounter, address indexed offerer);
/**
* @dev Revert with an error when attempting to fill an order that has
* already been fully filled.
*
* @param orderHash The order hash on which a fill was attempted.
*/
error OrderAlreadyFilled(bytes32 orderHash);
/**
* @dev Revert with an error when attempting to fill an order outside the
* specified start time and end time.
*/
error InvalidTime();
/**
* @dev Revert with an error when attempting to fill an order referencing an
* invalid conduit (i.e. one that has not been deployed).
*/
error InvalidConduit(bytes32 conduitKey, address conduit);
/**
* @dev Revert with an error when an order is supplied for fulfillment with
* a consideration array that is shorter than the original array.
*/
error MissingOriginalConsiderationItems();
/**
* @dev Revert with an error when a call to a conduit fails with revert data
* that is too expensive to return.
*/
error InvalidCallToConduit(address conduit);
/**
* @dev Revert with an error if a consideration amount has not been fully
* zeroed out after applying all fulfillments.
*
* @param orderIndex The index of the order with the consideration
* item with a shortfall.
* @param considerationIndex The index of the consideration item on the
* order.
* @param shortfallAmount The unfulfilled consideration amount.
*/
error ConsiderationNotMet(
uint256 orderIndex,
uint256 considerationIndex,
uint256 shortfallAmount
);
/**
* @dev Revert with an error when insufficient ether is supplied as part of
* msg.value when fulfilling orders.
*/
error InsufficientEtherSupplied();
/**
* @dev Revert with an error when an ether transfer reverts.
*/
error EtherTransferGenericFailure(address account, uint256 amount);
/**
* @dev Revert with an error when a partial fill is attempted on an order
* that does not specify partial fill support in its order type.
*/
error PartialFillsNotEnabledForOrder();
/**
* @dev Revert with an error when attempting to fill an order that has been
* cancelled.
*
* @param orderHash The hash of the cancelled order.
*/
error OrderIsCancelled(bytes32 orderHash);
/**
* @dev Revert with an error when attempting to fill a basic order that has
* been partially filled.
*
* @param orderHash The hash of the partially used order.
*/
error OrderPartiallyFilled(bytes32 orderHash);
/**
* @dev Revert with an error when attempting to cancel an order as a caller
* other than the indicated offerer or zone.
*/
error InvalidCanceller();
/**
* @dev Revert with an error when supplying a fraction with a value of zero
* for the numerator or denominator, or one where the numerator exceeds
* the denominator.
*/
error BadFraction();
/**
* @dev Revert with an error when a caller attempts to supply callvalue to a
* non-payable basic order route or does not supply any callvalue to a
* payable basic order route.
*/
error InvalidMsgValue(uint256 value);
/**
* @dev Revert with an error when attempting to fill a basic order using
* calldata not produced by default ABI encoding.
*/
error InvalidBasicOrderParameterEncoding();
/**
* @dev Revert with an error when attempting to fulfill any number of
* available orders when none are fulfillable.
*/
error NoSpecifiedOrdersAvailable();
/**
* @dev Revert with an error when attempting to fulfill an order with an
* offer for ETH outside of matching orders.
*/
error InvalidNativeOfferItem();
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
/**
* @title ReentrancyErrors
* @author 0age
* @notice ReentrancyErrors contains errors related to reentrancy.
*/
interface ReentrancyErrors {
/**
* @dev Revert with an error when a caller attempts to reenter a protected
* function.
*/
error NoReentrantCalls();
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
/**
* @title ConduitControllerInterface
* @author 0age
* @notice ConduitControllerInterface contains all external function interfaces,
* structs, events, and errors for the conduit controller.
*/
interface ConduitControllerInterface {
/**
* @dev Track the conduit key, current owner, new potential owner, and open
* channels for each deployed conduit.
*/
struct ConduitProperties {
bytes32 key;
address owner;
address potentialOwner;
address[] channels;
mapping(address => uint256) channelIndexesPlusOne;
}
/**
* @dev Emit an event whenever a new conduit is created.
*
* @param conduit The newly created conduit.
* @param conduitKey The conduit key used to create the new conduit.
*/
event NewConduit(address conduit, bytes32 conduitKey);
/**
* @dev Emit an event whenever conduit ownership is transferred.
*
* @param conduit The conduit for which ownership has been
* transferred.
* @param previousOwner The previous owner of the conduit.
* @param newOwner The new owner of the conduit.
*/
event OwnershipTransferred(
address indexed conduit,
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev Emit an event whenever a conduit owner registers a new potential
* owner for that conduit.
*
* @param newPotentialOwner The new potential owner of the conduit.
*/
event PotentialOwnerUpdated(address indexed newPotentialOwner);
/**
* @dev Revert with an error when attempting to create a new conduit using a
* conduit key where the first twenty bytes of the key do not match the
* address of the caller.
*/
error InvalidCreator();
/**
* @dev Revert with an error when attempting to create a new conduit when no
* initial owner address is supplied.
*/
error InvalidInitialOwner();
/**
* @dev Revert with an error when attempting to set a new potential owner
* that is already set.
*/
error NewPotentialOwnerAlreadySet(
address conduit,
address newPotentialOwner
);
/**
* @dev Revert with an error when attempting to cancel ownership transfer
* when no new potential owner is currently set.
*/
error NoPotentialOwnerCurrentlySet(address conduit);
/**
* @dev Revert with an error when attempting to interact with a conduit that
* does not yet exist.
*/
error NoConduit();
/**
* @dev Revert with an error when attempting to create a conduit that
* already exists.
*/
error ConduitAlreadyExists(address conduit);
/**
* @dev Revert with an error when attempting to update channels or transfer
* ownership of a conduit when the caller is not the owner of the
* conduit in question.
*/
error CallerIsNotOwner(address conduit);
/**
* @dev Revert with an error when attempting to register a new potential
* owner and supplying the null address.
*/
error NewPotentialOwnerIsZeroAddress(address conduit);
/**
* @dev Revert with an error when attempting to claim ownership of a conduit
* with a caller that is not the current potential owner for the
* conduit in question.
*/
error CallerIsNotNewPotentialOwner(address conduit);
/**
* @dev Revert with an error when attempting to retrieve a channel using an
* index that is out of range.
*/
error ChannelOutOfRange(address conduit);
/**
* @notice Deploy a new conduit using a supplied conduit key and assigning
* an initial owner for the deployed conduit. Note that the first
* twenty bytes of the supplied conduit key must match the caller
* and that a new conduit cannot be created if one has already been
* deployed using the same conduit key.
*
* @param conduitKey The conduit key used to deploy the conduit. Note that
* the first twenty bytes of the conduit key must match
* the caller of this contract.
* @param initialOwner The initial owner to set for the new conduit.
*
* @return conduit The address of the newly deployed conduit.
*/
function createConduit(bytes32 conduitKey, address initialOwner)
external
returns (address conduit);
/**
* @notice Open or close a channel on a given conduit, thereby allowing the
* specified account to execute transfers against that conduit.
* Extreme care must be taken when updating channels, as malicious
* or vulnerable channels can transfer any ERC20, ERC721 and ERC1155
* tokens where the token holder has granted the conduit approval.
* Only the owner of the conduit in question may call this function.
*
* @param conduit The conduit for which to open or close the channel.
* @param channel The channel to open or close on the conduit.
* @param isOpen A boolean indicating whether to open or close the channel.
*/
function updateChannel(
address conduit,
address channel,
bool isOpen
) external;
/**
* @notice Initiate conduit ownership transfer by assigning a new potential
* owner for the given conduit. Once set, the new potential owner
* may call `acceptOwnership` to claim ownership of the conduit.
* Only the owner of the conduit in question may call this function.
*
* @param conduit The conduit for which to initiate ownership transfer.
* @param newPotentialOwner The new potential owner of the conduit.
*/
function transferOwnership(address conduit, address newPotentialOwner)
external;
/**
* @notice Clear the currently set potential owner, if any, from a conduit.
* Only the owner of the conduit in question may call this function.
*
* @param conduit The conduit for which to cancel ownership transfer.
*/
function cancelOwnershipTransfer(address conduit) external;
/**
* @notice Accept ownership of a supplied conduit. Only accounts that the
* current owner has set as the new potential owner may call this
* function.
*
* @param conduit The conduit for which to accept ownership.
*/
function acceptOwnership(address conduit) external;
/**
* @notice Retrieve the current owner of a deployed conduit.
*
* @param conduit The conduit for which to retrieve the associated owner.
*
* @return owner The owner of the supplied conduit.
*/
function ownerOf(address conduit) external view returns (address owner);
/**
* @notice Retrieve the conduit key for a deployed conduit via reverse
* lookup.
*
* @param conduit The conduit for which to retrieve the associated conduit
* key.
*
* @return conduitKey The conduit key used to deploy the supplied conduit.
*/
function getKey(address conduit) external view returns (bytes32 conduitKey);
/**
* @notice Derive the conduit associated with a given conduit key and
* determine whether that conduit exists (i.e. whether it has been
* deployed).
*
* @param conduitKey The conduit key used to derive the conduit.
*
* @return conduit The derived address of the conduit.
* @return exists A boolean indicating whether the derived conduit has been
* deployed or not.
*/
function getConduit(bytes32 conduitKey)
external
view
returns (address conduit, bool exists);
/**
* @notice Retrieve the potential owner, if any, for a given conduit. The
* current owner may set a new potential owner via
* `transferOwnership` and that owner may then accept ownership of
* the conduit in question via `acceptOwnership`.
*
* @param conduit The conduit for which to retrieve the potential owner.
*
* @return potentialOwner The potential owner, if any, for the conduit.
*/
function getPotentialOwner(address conduit)
external
view
returns (address potentialOwner);
/**
* @notice Retrieve the status (either open or closed) of a given channel on
* a conduit.
*
* @param conduit The conduit for which to retrieve the channel status.
* @param channel The channel for which to retrieve the status.
*
* @return isOpen The status of the channel on the given conduit.
*/
function getChannelStatus(address conduit, address channel)
external
view
returns (bool isOpen);
/**
* @notice Retrieve the total number of open channels for a given conduit.
*
* @param conduit The conduit for which to retrieve the total channel count.
*
* @return totalChannels The total number of open channels for the conduit.
*/
function getTotalChannels(address conduit)
external
view
returns (uint256 totalChannels);
/**
* @notice Retrieve an open channel at a specific index for a given conduit.
* Note that the index of a channel can change as a result of other
* channels being closed on the conduit.
*
* @param conduit The conduit for which to retrieve the open channel.
* @param channelIndex The index of the channel in question.
*
* @return channel The open channel, if any, at the specified channel index.
*/
function getChannel(address conduit, uint256 channelIndex)
external
view
returns (address channel);
/**
* @notice Retrieve all open channels for a given conduit. Note that calling
* this function for a conduit with many channels will revert with
* an out-of-gas error.
*
* @param conduit The conduit for which to retrieve open channels.
*
* @return channels An array of open channels on the given conduit.
*/
function getChannels(address conduit)
external
view
returns (address[] memory channels);
/**
* @dev Retrieve the conduit creation code and runtime code hashes.
*/
function getConduitCodeHashes()
external
view
returns (bytes32 creationCodeHash, bytes32 runtimeCodeHash);
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"conduitController","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BadContractSignature","type":"error"},{"inputs":[],"name":"BadFraction","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BadReturnValueFromERC20OnTransfer","type":"error"},{"inputs":[{"internalType":"uint8","name":"v","type":"uint8"}],"name":"BadSignatureV","type":"error"},{"inputs":[],"name":"ConsiderationCriteriaResolverOutOfRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"considerationIndex","type":"uint256"},{"internalType":"uint256","name":"shortfallAmount","type":"uint256"}],"name":"ConsiderationNotMet","type":"error"},{"inputs":[],"name":"CriteriaNotEnabledForItem","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"identifiers","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"ERC1155BatchTransferGenericFailure","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EtherTransferGenericFailure","type":"error"},{"inputs":[],"name":"InexactFraction","type":"error"},{"inputs":[],"name":"InsufficientEtherSupplied","type":"error"},{"inputs":[],"name":"Invalid1155BatchTransferEncoding","type":"error"},{"inputs":[],"name":"InvalidBasicOrderParameterEncoding","type":"error"},{"inputs":[{"internalType":"address","name":"conduit","type":"address"}],"name":"InvalidCallToConduit","type":"error"},{"inputs":[],"name":"InvalidCanceller","type":"error"},{"inputs":[{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"address","name":"conduit","type":"address"}],"name":"InvalidConduit","type":"error"},{"inputs":[],"name":"InvalidERC721TransferAmount","type":"error"},{"inputs":[],"name":"InvalidFulfillmentComponentData","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"InvalidMsgValue","type":"error"},{"inputs":[],"name":"InvalidNativeOfferItem","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"InvalidRestrictedOrder","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidTime","type":"error"},{"inputs":[],"name":"MismatchedFulfillmentOfferAndConsiderationComponents","type":"error"},{"inputs":[{"internalType":"enum Side","name":"side","type":"uint8"}],"name":"MissingFulfillmentComponentOnAggregation","type":"error"},{"inputs":[],"name":"MissingItemAmount","type":"error"},{"inputs":[],"name":"MissingOriginalConsiderationItems","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NoContract","type":"error"},{"inputs":[],"name":"NoReentrantCalls","type":"error"},{"inputs":[],"name":"NoSpecifiedOrdersAvailable","type":"error"},{"inputs":[],"name":"OfferAndConsiderationRequiredOnFulfillment","type":"error"},{"inputs":[],"name":"OfferCriteriaResolverOutOfRange","type":"error"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"OrderAlreadyFilled","type":"error"},{"inputs":[],"name":"OrderCriteriaResolverOutOfRange","type":"error"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"OrderIsCancelled","type":"error"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"OrderPartiallyFilled","type":"error"},{"inputs":[],"name":"PartialFillsNotEnabledForOrder","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenTransferGenericFailure","type":"error"},{"inputs":[],"name":"UnresolvedConsiderationCriteria","type":"error"},{"inputs":[],"name":"UnresolvedOfferCriteria","type":"error"},{"inputs":[],"name":"UnusedItemParameters","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newCounter","type":"uint256"},{"indexed":true,"internalType":"address","name":"offerer","type":"address"}],"name":"CounterIncremented","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"offerer","type":"address"},{"indexed":true,"internalType":"address","name":"zone","type":"address"}],"name":"OrderCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"offerer","type":"address"},{"indexed":true,"internalType":"address","name":"zone","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"indexed":false,"internalType":"struct SpentItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"indexed":false,"internalType":"struct ReceivedItem[]","name":"consideration","type":"tuple[]"}],"name":"OrderFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"offerer","type":"address"},{"indexed":true,"internalType":"address","name":"zone","type":"address"}],"name":"OrderValidated","type":"event"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"counter","type":"uint256"}],"internalType":"struct OrderComponents[]","name":"orders","type":"tuple[]"}],"name":"cancel","outputs":[{"internalType":"bool","name":"cancelled","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"parameters","type":"tuple"},{"internalType":"uint120","name":"numerator","type":"uint120"},{"internalType":"uint120","name":"denominator","type":"uint120"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct AdvancedOrder","name":"advancedOrder","type":"tuple"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"enum Side","name":"side","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"bytes32[]","name":"criteriaProof","type":"bytes32[]"}],"internalType":"struct CriteriaResolver[]","name":"criteriaResolvers","type":"tuple[]"},{"internalType":"bytes32","name":"fulfillerConduitKey","type":"bytes32"},{"internalType":"address","name":"recipient","type":"address"}],"name":"fulfillAdvancedOrder","outputs":[{"internalType":"bool","name":"fulfilled","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"parameters","type":"tuple"},{"internalType":"uint120","name":"numerator","type":"uint120"},{"internalType":"uint120","name":"denominator","type":"uint120"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct AdvancedOrder[]","name":"advancedOrders","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"enum Side","name":"side","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"bytes32[]","name":"criteriaProof","type":"bytes32[]"}],"internalType":"struct CriteriaResolver[]","name":"criteriaResolvers","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct FulfillmentComponent[][]","name":"offerFulfillments","type":"tuple[][]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct FulfillmentComponent[][]","name":"considerationFulfillments","type":"tuple[][]"},{"internalType":"bytes32","name":"fulfillerConduitKey","type":"bytes32"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"maximumFulfilled","type":"uint256"}],"name":"fulfillAvailableAdvancedOrders","outputs":[{"internalType":"bool[]","name":"availableOrders","type":"bool[]"},{"components":[{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ReceivedItem","name":"item","type":"tuple"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"}],"internalType":"struct Execution[]","name":"executions","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Order[]","name":"orders","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct FulfillmentComponent[][]","name":"offerFulfillments","type":"tuple[][]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct FulfillmentComponent[][]","name":"considerationFulfillments","type":"tuple[][]"},{"internalType":"bytes32","name":"fulfillerConduitKey","type":"bytes32"},{"internalType":"uint256","name":"maximumFulfilled","type":"uint256"}],"name":"fulfillAvailableOrders","outputs":[{"internalType":"bool[]","name":"availableOrders","type":"bool[]"},{"components":[{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ReceivedItem","name":"item","type":"tuple"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"}],"internalType":"struct Execution[]","name":"executions","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"considerationToken","type":"address"},{"internalType":"uint256","name":"considerationIdentifier","type":"uint256"},{"internalType":"uint256","name":"considerationAmount","type":"uint256"},{"internalType":"address payable","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"internalType":"address","name":"offerToken","type":"address"},{"internalType":"uint256","name":"offerIdentifier","type":"uint256"},{"internalType":"uint256","name":"offerAmount","type":"uint256"},{"internalType":"enum BasicOrderType","name":"basicOrderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"offererConduitKey","type":"bytes32"},{"internalType":"bytes32","name":"fulfillerConduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalAdditionalRecipients","type":"uint256"},{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct AdditionalRecipient[]","name":"additionalRecipients","type":"tuple[]"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct BasicOrderParameters","name":"parameters","type":"tuple"}],"name":"fulfillBasicOrder","outputs":[{"internalType":"bool","name":"fulfilled","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Order","name":"order","type":"tuple"},{"internalType":"bytes32","name":"fulfillerConduitKey","type":"bytes32"}],"name":"fulfillOrder","outputs":[{"internalType":"bool","name":"fulfilled","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"offerer","type":"address"}],"name":"getCounter","outputs":[{"internalType":"uint256","name":"counter","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"counter","type":"uint256"}],"internalType":"struct OrderComponents","name":"order","type":"tuple"}],"name":"getOrderHash","outputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"getOrderStatus","outputs":[{"internalType":"bool","name":"isValidated","type":"bool"},{"internalType":"bool","name":"isCancelled","type":"bool"},{"internalType":"uint256","name":"totalFilled","type":"uint256"},{"internalType":"uint256","name":"totalSize","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"incrementCounter","outputs":[{"internalType":"uint256","name":"newCounter","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"information","outputs":[{"internalType":"string","name":"version","type":"string"},{"internalType":"bytes32","name":"domainSeparator","type":"bytes32"},{"internalType":"address","name":"conduitController","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"parameters","type":"tuple"},{"internalType":"uint120","name":"numerator","type":"uint120"},{"internalType":"uint120","name":"denominator","type":"uint120"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct AdvancedOrder[]","name":"advancedOrders","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"enum Side","name":"side","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"bytes32[]","name":"criteriaProof","type":"bytes32[]"}],"internalType":"struct CriteriaResolver[]","name":"criteriaResolvers","type":"tuple[]"},{"components":[{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct FulfillmentComponent[]","name":"offerComponents","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct FulfillmentComponent[]","name":"considerationComponents","type":"tuple[]"}],"internalType":"struct Fulfillment[]","name":"fulfillments","type":"tuple[]"}],"name":"matchAdvancedOrders","outputs":[{"components":[{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ReceivedItem","name":"item","type":"tuple"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"}],"internalType":"struct Execution[]","name":"executions","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Order[]","name":"orders","type":"tuple[]"},{"components":[{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct FulfillmentComponent[]","name":"offerComponents","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"orderIndex","type":"uint256"},{"internalType":"uint256","name":"itemIndex","type":"uint256"}],"internalType":"struct FulfillmentComponent[]","name":"considerationComponents","type":"tuple[]"}],"internalType":"struct Fulfillment[]","name":"fulfillments","type":"tuple[]"}],"name":"matchOrders","outputs":[{"components":[{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ReceivedItem","name":"item","type":"tuple"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"}],"internalType":"struct Execution[]","name":"executions","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"contractName","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Order[]","name":"orders","type":"tuple[]"}],"name":"validate","outputs":[{"internalType":"bool","name":"validated","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6101c06040523480156200001257600080fd5b5060405162005b9b38038062005b9b8339810160408190526200003591620005c6565b808080808080808080806200004962000132565b610120526101005260e05260c081815260a0838152608085815246610140819052604080516020818101979097528082019890985260608801969096529086015230858201528351808603909101815293019091528151910120610160526001600160a01b03811661018081905260408051630a96ad3960e01b81528151630a96ad39926004808401939192918290030181865afa158015620000f0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001169190620005f8565b506101a052505060016000555062000688975050505050505050565b600080808080806200015e60408051808201909152600781526614d9585c1bdc9d60ca1b602082015290565b80516020918201206040805180820182526003815262312e3160e81b90840152519097507f722c0e0c80487266e8c6a45e3a1a803aab23378a9c32e6ebe029d4fad7bfc96596506000916200026391016909ecccccae492e8cada560b31b81526e1d5a5b9d0e081a5d195b551e5c194b608a1b600a8201526d1859191c995cdcc81d1bdad95b8b60921b60198201527f75696e74323536206964656e7469666965724f7243726974657269612c00000060278201527f75696e74323536207374617274416d6f756e742c0000000000000000000000006044820152701d5a5b9d0c8d4d88195b99105b5bdd5b9d607a1b6058820152602960f81b6069820152606a0190565b60408051601f1981840301815282825271086dedce6d2c8cae4c2e8d2dedc92e8cada560731b60208401526e1d5a5b9d0e081a5d195b551e5c194b608a1b60328401526d1859191c995cdcc81d1bdad95b8b60921b60418401527f75696e74323536206964656e7469666965724f7243726974657269612c000000604f8401527f75696e74323536207374617274416d6f756e742c000000000000000000000000606c840152711d5a5b9d0c8d4d88195b99105b5bdd5b9d0b60721b6080840152701859191c995cdcc81c9958da5c1a595b9d607a1b6092840152602960f81b60a384018190528251808503608401815260a485019093526f09ee4c8cae486dedae0dedccadce8e6560831b60c48501526f1859191c995cdcc81bd999995c995c8b60821b60d48501526c1859191c995cdcc81e9bdb994b609a1b60e48501527113d999995c925d195b56d7481bd999995c8b60721b60f18501527f436f6e73696465726174696f6e4974656d5b5d20636f6e73696465726174696f610103850152611b8b60f21b6101238501526f1d5a5b9d0e081bdc99195c951e5c194b60821b610125850152711d5a5b9d0c8d4d881cdd185c9d151a5b594b60721b6101358501526f1d5a5b9d0c8d4d88195b99151a5b594b60821b61014785015270189e5d195ccccc881e9bdb9952185cda0b607a1b6101578501526c1d5a5b9d0c8d4d881cd85b1d0b609a1b6101688501527f6279746573333220636f6e647569744b65792c000000000000000000000000006101758501526e3ab4b73a191a9b1031b7bab73a32b960891b6101888501526101978401529250906000906101980160408051601f19818403018152908290526c08a92a06e626488dedac2d2dc5609b1b60208301526b1cdd1c9a5b99c81b985b594b60a21b602d8301526e1cdd1c9a5b99c81d995c9cda5bdb8b608a1b60398301526f1d5a5b9d0c8d4d8818da185a5b92590b60821b60488301527f6164647265737320766572696679696e67436f6e7472616374000000000000006058830152602960f81b6071830152915060720160408051601f19818403018152908290528051602091820120855186830120855186840120919a5098509650620005a391839185918791016200065b565b604051602081830303815290604052805190602001209350505050909192939495565b600060208284031215620005d957600080fd5b81516001600160a01b0381168114620005f157600080fd5b9392505050565b600080604083850312156200060c57600080fd5b505080516020909101519092909150565b6000815160005b8181101562000640576020818501810151868301520162000624565b8181111562000650576000828601525b509290920192915050565b60006200067f620006786200067184886200061d565b866200061d565b846200061d565b95945050505050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a05161547b6200072060003960006135a7015260008181610d21015261357601526000612313015260006122430152600081816108b0015261252101526000818161083f015261237f0152600081816107d8015261249a01526000612271015260006122bf01526000612297015261547b6000f3fe6080604052600436106100e85760003560e01c8063a81744041161008a578063f07ec37311610059578063f07ec37314610290578063f47b7740146102b0578063fb0f3ee1146102d4578063fd9f1e10146102e757600080fd5b8063a817440414610244578063b3a34c4c14610257578063e7acab241461026a578063ed98a5741461027d57600080fd5b80635b34b966116100c65780635b34b966146101b057806379df72bd146101d357806387201b41146101f3578063881477321461021457600080fd5b806306fdde03146100ed57806346423aa71461011857806355944a4214610190575b600080fd5b3480156100f957600080fd5b50610102610307565b60405161010f9190613fe2565b60405180910390f35b34801561012457600080fd5b5061016e610133366004613ff5565b60009081526002602052604090205460ff808216926101008304909116916001600160781b03620100008204811692600160881b9092041690565b604080519415158552921515602085015291830152606082015260800161010f565b6101a361019e3660046145c4565b610316565b60405161010f9190614726565b3480156101bc57600080fd5b506101c5610339565b60405190815260200161010f565b3480156101df57600080fd5b506101c56101ee366004614739565b610343565b610206610201366004614774565b6104da565b60405161010f929190614854565b34801561022057600080fd5b5061023461022f3660046148ad565b610520565b604051901515815260200161010f565b6101a36102523660046148ee565b610533565b610234610265366004614959565b6105b1565b6102346102783660046149a2565b610623565b61020661028b366004614a31565b610657565b34801561029c57600080fd5b506101c56102ab366004614ad9565b6106e1565b3480156102bc57600080fd5b506102c56106ff565b60405161010f93929190614af6565b6102346102e2366004614b29565b610717565b3480156102f357600080fd5b506102346103023660046148ad565b610722565b606061031161072e565b905090565b606061032d866103268688614b64565b8585610746565b90505b95945050505050565b6000610311610763565b6040805161016081019091526000906104d490806103646020860186614ad9565b6001600160a01b031681526020018460200160208101906103859190614ad9565b6001600160a01b031681526020016103a06040860186614c98565b808060200260200160405190810160405280939291908181526020016000905b828210156103ec576103dd60a08302860136819003810190614ce0565b815260200190600101906103c0565b50505091835250506020016104046060860186614cfc565b808060200260200160405190810160405280939291908181526020016000905b828210156104505761044160c08302860136819003810190614d44565b81526020019060010190610424565b505050918352505060200161046b60a0860160808701614d60565b600381111561047c5761047c614658565b81526020018460a0013581526020018460c0013581526020018460e001358152602001846101000135815260200184610120013581526020018480606001906104c59190614cfc565b909152506101408401356107c0565b92915050565b60608061050d8c6104eb8c8e614b64565b8b8b8b8b8b6001600160a01b038c1615610505578b610507565b335b8b610906565b915091509a509a98505050505050505050565b600061052c8383610948565b9392505050565b60606105a66105428686610aad565b604080516000808252602082019092529061059e565b61058b6040805160a081019091526000808252602082019081526020016000815260200160008152602001606081525090565b8152602001906001900390816105585790505b508585610746565b90505b949350505050565b600061052c6105bf84610b68565b604080516000808252602082019092529061061b565b6106086040805160a081019091526000808252602082019081526020016000815260200160008152602001606081525090565b8152602001906001900390816105d55790505b508433610c13565b600061032d61063187614d7b565b61063b8688614b64565b856001600160a01b038616156106515785610c13565b33610c13565b6060806106d06106678b8b610aad565b60408051600080825260208201909252906106c3565b6106b06040805160a081019091526000808252602082019081526020016000815260200160008152602001606081525090565b81526020019060019003908161067d5790505b508a8a8a8a8a338b610906565b915091509850989650505050505050565b6001600160a01b0381166000908152600160205260408120546104d4565b606060008061070c610d00565b925092509250909192565b60006104d482610d61565b600061052c8383611021565b6060602080526707536561706f727460475260606020f35b60606107588585600188516000611227565b6105a6858484611566565b600061076d611691565b503360008181526001602081815260409283902080549092019182905591518181529092917f721c20121297512b72821b97f5326877ea8ecf4bb9948fea5bfcb6453074d37f910160405180910390a290565b610140820151604080519084015180516000939284927f000000000000000000000000000000000000000000000000000000000000000092602090910190845b8181101561082d578251601f1901805186825260c082208652905260209384019390920191600101610800565b506020810260405120945050505060007f00000000000000000000000000000000000000000000000000000000000000009150604051602060608901510160005b8681101561089b578151601f1901805186825260e08220855290526020928301929091019060010161086e565b505060408051602087029020601f198a0180517f00000000000000000000000000000000000000000000000000000000000000008252928b01805197815260608c018051938152610140909c019a8b5261018082209390915295909552939097525050925250919050565b6060806109178b8b60008688611227565b6109368b6109258a8c614dd5565b61092f898b614dd5565b88886116b6565b909c909b509950505050505050505050565b6000610952611691565b6000808084815b81811015610a9f573688888381811061097457610974614ea7565b90506020028101906109869190614ebd565b9050366109938280614edd565b90506109a26020820182614ad9565b94506109b56109b082614ef4565b611896565b600081815260026020526040812098509096506109d7908790899060016118d1565b50865460ff16610a9557610a2d85876109f36020860186614f00565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061199692505050565b865460ff19166001178755610a486040820160208301614ad9565b6001600160a01b0316856001600160a01b03167ffde361574a066b44b3b5fe98a87108b7565e327327954c4faeea56a4e6491a0a88604051610a8c91815260200190565b60405180910390a35b5050600101610959565b506001979650505050505050565b606081806001600160401b03811115610ac857610ac861400e565b604051908082528060200260200182016040528015610b0157816020015b610aee613ea1565b815260200190600190039081610ae65790505b50915060005b81811015610b6057610b3b858583818110610b2457610b24614ea7565b9050602002810190610b369190614ebd565b610b68565b838281518110610b4d57610b4d614ea7565b6020908102919091010152600101610b07565b505092915050565b610b70613ea1565b6040805160a0810190915280610b868480614edd565b610b8f90614ef4565b815260200160016001600160781b0316815260200160016001600160781b03168152602001838060200190610bc49190614f00565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509385525050604080516020818101909252928352909201525092915050565b6000610c1d6119eb565b60606000806000610c3189896001876119fa565b604080516001808252818301909252939650919450925060009190816020015b610c59613ea1565b815260200190600190039081610c515790505090508981600081518110610c8257610c82614ea7565b6020026020010181905250610c97818a611cb3565b600081600081518110610cac57610cac614ea7565b6020026020010151600001519050610cc78185858c8c61200c565b610ce585826000015183602001518b856040015186606001516121da565b610cef6001600055565b5060019a9950505050505050505050565b6060600080610d0d61223f565b6040805160038082528183019092529193507f00000000000000000000000000000000000000000000000000000000000000009250602082018180368337505062312e3160e81b6020830152509391925090565b600061012435600281901c90600316600182113415811480610d9d57604051630a61be9f60e41b81523460048201526024015b60405180910390fd5b5060008060008060038711915060a082026024013593506002871460028811600289030201905060018101820260028615028801039250610de2898783888888612335565b506101c46020820201356000856005811115610e0057610e00614658565b03610ea35760208901803590610e16908b614ad9565b6001600160a01b03161715610e3e57604051636ab37ce760e01b815260040160405180910390fd5b610e7383610e5260c08c0160a08d01614ad9565b610e6260808d0160608e01614ad9565b338d60c001358e60e001358761266b565b610e9e60408a0135610e8b60808c0160608d01614ad9565b610e996102008d018d614f46565b61271f565b611008565b6040805160208082528183019092526000916020820181803683370190505090506002886005811115610ed857610ed8614658565b03610f1757610f12610ef060c08c0160a08d01614ad9565b610f0060808d0160608e01614ad9565b338d60c001358e60e0013587876127da565b610fe2565b6003886005811115610f2b57610f2b614658565b03610f6557610f12610f4360c08c0160a08d01614ad9565b610f5360808d0160608e01614ad9565b338d60c001358e60e001358787612827565b6004886005811115610f7957610f79614658565b03610fb057610f12610f8e60208c018c614ad9565b33610f9f60808e0160608f01614ad9565b8d602001358e6040013587876127da565b610fe2610fc060208c018c614ad9565b33610fd160808e0160608f01614ad9565b8d602001358e604001358787612827565b610ffd610ff560808c0160608d01614ad9565b8b858461285d565b6110068161297e565b505b6110126001600055565b50600198975050505050505050565b600061102b611691565b6000808084815b81811015610a9f573688888381811061104d5761104d614ea7565b905060200281019061105f9190614edd565b905061106e6020820182614ad9565b94506110806040820160208301614ad9565b9350336001600160a01b038616148015906110a45750336001600160a01b03851614155b156110c25760405163203b1cdd60e21b815260040160405180910390fd5b60006111b1604051806101600160405280886001600160a01b03168152602001876001600160a01b031681526020018480604001906111019190614c98565b808060200260200160405190810160405280939291908181526020016000905b8282101561114d5761113e60a08302860136819003810190614ce0565b81526020019060010190611121565b50505091835250506020016111656060860186614cfc565b808060200260200160405190810160405280939291908181526020016000905b82821015610450576111a260c08302860136819003810190614d44565b81526020019060010190611185565b60008181526002602052604090819020805461ffff191661010017815590519098509091506001600160a01b0380871691908816907f6bacc01dbe442496068f7d234edd811f1a5f833243e0aec824f86ab861f3c90d906112159085815260200190565b60405180910390a35050600101611032565b61122f6119eb565b84516000816001600160401b0381111561124b5761124b61400e565b604051908082528060200260200182016040528015611274578160200160208202803683370190505b506000808252909150601d6045823560e01c061160011b905b8381101561149d5760008982815181106112a9576112a9614ea7565b60200260200101519050866000036112ce576000602090910152600181018352611495565b60008060006112df848d8d8a6119fa565b92509250925060018501875281600003611306575050600060209092019190915250611495565b8287868151811061131957611319614ea7565b6020908102919091010152835160a081015160c08201516040909201518051600019909d019c91929160005b818110156113e157600083828151811061136157611361614ea7565b602002602001015190508051158c179b506000611383898984608001516129a7565b905081608001518260600151036113a057606082018190526113b5565b6113af898984606001516129a7565b60608301525b6080820181905260608201516113cf9082898960006129e9565b60609092019190915250600101611345565b50875160600151805160005b8181101561148957600083828151811061140957611409614ea7565b6020026020010151905060006114248b8b84608001516129a7565b905081608001518260600151036114415760608201819052611456565b6114508b8b84606001516129a7565b60608301525b60808201819052606082015161147090828b8b60016129e9565b60608301525060a08101516080909101526001016113ed565b50505050505050505050505b60010161128d565b50806003036114bf576040516312d3f5a360e01b815260040160405180910390fd5b6114c98888611cb3565b60005b8381101561155b576000801b8382815181106114ea576114ea614ea7565b6020026020010151031561155357600089828151811061150c5761150c614ea7565b602002602001015160000151905061155184838151811061152f5761152f614ea7565b60200260200101518260000151836020015189856040015186606001516121da565b505b6001016114cc565b505050505050505050565b606081806001600160401b038111156115815761158161400e565b6040519080825280602002602001820160405280156115ba57816020015b6115a7613ed5565b81526020019060019003908161159f5790505b5091506000805b8281101561166f57368686838181106115dc576115dc614ea7565b90506020028101906115ee9190614ebd565b90506000611612896116008480614f46565b61160d6020870187614f46565b612a3e565b905080602001516001600160a01b03168160000151608001516001600160a01b03160361164457836001019350611665565b80868585038151811061165957611659614ea7565b60200260200101819052505b50506001016115c1565b50801561167d578083510383525b506116888583612d23565b50509392505050565b6001600054146116b457604051637fa8a98760e01b815260040160405180910390fd5b565b8351835160609182916116c98183614fa5565b6001600160401b038111156116e0576116e061400e565b60405190808252806020026020018201604052801561171957816020015b611706613ed5565b8152602001906001900390816116fe5790505b5092506000805b838110156117b35760008a828151811061173c5761173c614ea7565b6020026020010151905060006117568d6000848d8d612f3d565b905080602001516001600160a01b03168160000151608001516001600160a01b031603611788578360010193506117a9565b80878585038151811061179d5761179d614ea7565b60200260200101819052505b5050600101611720565b5060005b8281101561184d5760008982815181106117d3576117d3614ea7565b6020026020010151905060006117ee8d6001848d6000612f3d565b905080602001516001600160a01b03168160000151608001516001600160a01b03160361182057836001019350611843565b808785888601038151811061183757611837614ea7565b60200260200101819052505b50506001016117b7565b50801561185b578084510384525b50825160000361187e5760405163d5da9a1b60e01b815260040160405180910390fd5b6118888984612d23565b935050509550959350505050565b60006118ac826060015151836101400151612fe2565b81516001600160a01b03166000908152600160205260409020546104d49083906107c0565b8254600090610100900460ff161561190d57811561190557604051630694555d60e21b815260048101869052602401610d94565b5060006105a9565b83546201000090046001600160781b0316801561198a5783156119465760405163ee9e0e6360e01b815260048101879052602401610d94565b8454600160881b90046001600160781b0316811061198a578215611980576040516310fda3e160e01b815260048101879052602401610d94565b60009150506105a9565b50600195945050505050565b336001600160a01b038416036119ab57505050565b60006119d86119b861223f565b61190160f01b600090815260029190915260228581526042822091905290565b90506119e5848284613003565b50505050565b6119f3611691565b6002600055565b60008060008087600001519050611a1a8160a001518260c0015188613154565b611a2e575060009250829150819050611ca9565b602088015160408901516001600160781b03918216911680821180611a51575081155b15611a6f57604051632d02959960e11b815260040160405180910390fd5b8082108015611a8357506080830151600116155b15611aa15760405163a11b63ff60e01b815260040160405180910390fd5b611aaa83611896565b9550611acc8a8a89898760e00151886080015189600001518a6020015161319a565b600086815260026020526040812090611ae990889083908c6118d1565b611afe575060009450849350611ca992505050565b805460ff16611b1a57611b1a8460000151888d60600151611996565b80546001600160781b03620100008204811691600160881b9004168015611c635783600103611b4e57809450809350611b7a565b838114611b7a57611b5f8483614fbd565b9150611b6b8186614fbd565b9450611b778185614fbd565b93505b83611b858684614fa5565b1115611b915781840394505b611b9b8583614fa5565b91506001600160781b0384116001600160781b0383111715611c2457611bd6565b60005b8215611bd057908290069190611bbf565b50919050565b611be9611be38584611bbc565b86611bbc565b80150194859004949384900493909104906001600160781b038083119085111715611c2457634e487b7160e01b600052601160045260246000fd5b82546001600160781b03858116600160881b026001600160881b0391851662010000026001600160881b03199093169290921760011716178355611c9e565b82546001600160781b03858116600160881b026001600160881b0391881662010000026001600160881b031990931692909217600117161783555b509295509093505050505b9450945094915050565b8051825160005b82811015611efa576000848281518110611cd657611cd6614ea7565b60200260200101519050600081600001519050838110611d09576040516321a561b160e21b815260040160405180910390fd5b868181518110611d1b57611d1b614ea7565b6020026020010151602001516001600160781b0316600003611d3e575050611ef2565b6000878281518110611d5257611d52614ea7565b60209081029190910101515160408401519091506000808086602001516001811115611d8057611d80614658565b03611e1a57604084015180518410611dab57604051635fd9fc6760e11b815260040160405180910390fd5b6000818581518110611dbf57611dbf614ea7565b602090810291909101015180516040820151909550935090506004841460030381816005811115611df257611df2614658565b90816005811115611e0557611e05614658565b90525050606088015160409091015250611eab565b606084015180518410611e40576040516330446bef60e11b815260040160405180910390fd5b6000818581518110611e5457611e54614ea7565b602090810291909101015180516040820151909550935090506004841460030381816005811115611e8757611e87614658565b90816005811115611e9a57611e9a614658565b905250506060880151604090910152505b611eb58260031090565b611ed257604051634a75b57b60e11b815260040160405180910390fd5b8015611eeb57611eeb866060015182886080015161327a565b5050505050505b600101611cba565b5060005b81811015612005576000858281518110611f1a57611f1a614ea7565b6020026020010151905080602001516001600160781b0316600003611f3f5750611ffd565b805160608101515160005b81811015611fa657611f7d83606001518281518110611f6b57611f6b614ea7565b60200260200101516000015160031090565b15611f9e5760405160016202297360e61b0319815260040160405180910390fd5b600101611f4a565b505060408101515160005b81811015611ff857611fd283604001518281518110611f6b57611f6b614ea7565b15611ff05760405163a6cfc67360e01b815260040160405180910390fd5b600101611fb1565b505050505b600101611efe565b5050505050565b60a085015160c08601516040805160208082528183019092526000916020820181803683375050506040890151519091506132dd9060005b818110156120fa5760008b60400151828151811061206457612064614ea7565b602002602001015190506000600581111561208157612081614658565b8151600581111561209457612094614658565b036120b2576040516312d3f5a360e01b815260040160405180910390fd5b60006120cc826060015183608001518e8e8c8c60006133ef565b606083015250608081018890528b516101208d01516120f19183918863ffffffff8916565b50600101612044565b50505060608801515134906132dd9060005b818110156121be5760008c60600151828151811061212c5761212c614ea7565b602002602001015190506000612150826060015183608001518f8f8d8d60016133ef565b6060830181905260a08301516080840152905060008251600581111561217857612178614658565b036121a4578581111561219e57604051631a783b8d60e01b815260040160405180910390fd5b80860395505b6121b482338d8a8963ffffffff16565b505060010161210c565b5050506121ca8261297e565b801561155b5761155b3382613439565b60608290506060829050856001600160a01b0316876001600160a01b03167f9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f318a88868660405161222d9493929190615016565b60405180910390a35050505050505050565b60007f0000000000000000000000000000000000000000000000000000000000000000461461231057610311604080517f000000000000000000000000000000000000000000000000000000000000000060208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b61233d6119eb565b6123538661012001358761014001356001613154565b5061235c61348d565b61237a61236d610200880188614f46565b9050876101e00135612fe2565b6000807f00000000000000000000000000000000000000000000000000000000000000009050806080528560a0526060602460c037604060646101203760e06080206101605261026435602081026102a0016001610264350181526020810190508781526080602460208301376101608760a0528660c052600060e05261020435925060005b8381101561244b578060400261028401602081610100376040816101203760208301925060e0608020835260a084019350898452886020850152604081606086013750600101612400565b60206001850102610160206060526102643593505b83811015612491578060400261028401915060a0830192508883528760208401526040826060850137600101612460565b505050505060007f00000000000000000000000000000000000000000000000000000000000000009050806080528260a052606060c460c03760206101046101203760c0608020600052602060002060e052602061026435026102000160018152836020820152606060c4604083013750506084356001600160a01b0381166000908152600160205260408120547f000000000000000000000000000000000000000000000000000000000000000060808190529091506040608460a03760605161010052886101205260a061014461014037816101e0526101806080209350505050602061026435026101800181815233602082015260806040820152610120606082015260a061026435026101e00160a4356084357f9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f318385a35050600060605261260681886101600135888a60600160208101906125f19190614ad9565b61260160a08d0160808e01614ad9565b6134d6565b6126628161261a60808a0160608b01614ad9565b6126286102208b018b614f00565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061352692505050565b50505050505050565b80156126c75760006040519050632671a55160e11b815260206004820152600160248201528760448201528660648201528560848201528460a48201528360c48201528260e48201526126c18282610104613570565b50612662565b60028760058111156126db576126db614658565b0361271257816001146127015760405163efcc00b160e01b815260040160405180910390fd5b61270d86868686613669565b612662565b612662868686868661372d565b348160005b81811015612792573685858381811061273f5761273f614ea7565b6040029190910191505080358481111561276c57604051631a783b8d60e01b815260040160405180910390fd5b61278561277f6040840160208501614ad9565b82613439565b9093039250600101612724565b50818611156127b457604051631a783b8d60e01b815260040160405180910390fd5b6127be8587613439565b858211156127d2576127d233878403613439565b505050505050565b6127e48183613814565b81612816578260011461280a5760405163efcc00b160e01b815260040160405180910390fd5b61270d87878787613669565b612662828260028a8a8a8a8a613833565b612830836138b3565b61283a8183613814565b8161284c5761270d878787878761372d565b612662828260038a8a8a8a8a613833565b600080600080600086156128945788945033935061288160c0890160a08a01614ad9565b9250505060e086013560c08701356128b6565b3394508893506128a76020890189614ad9565b92505050604086013560208701355b80156128d557604051636ab37ce760e01b815260040160405180910390fd5b50602086026101e4033560006128ef6102008a018a614f46565b9050905060005b81811015612963573661290d6102008c018c614f46565b8381811061291d5761291d614ea7565b6040029190910191505080358a1561293c5761293981876150b0565b95505b612959878a6129516040860160208701614ad9565b84898f6138d4565b50506001016128f6565b5061297284878786868c6138d4565b50505050505050505050565b604081511461298a5750565b6000612997826020015190565b90506129a3818361390f565b5050565b60008284036129b757508061052c565b82848309156129d15763c63cf08960e01b60005260046000fd5b60006129dd8584614fbd565b93909304949350505050565b6000848614612a3457838303428590038082036000612a08838a614fbd565b612a12838c614fbd565b612a1c9190614fa5565b90508584878303040181151502945050505050610330565b5092949350505050565b612a46613ed5565b831580612a51575081155b15612a6f57604051634c74edb760e11b815260040160405180910390fd5b612a77613ed5565b612ad4878585808060200260200160405190810160405280939291908181526020016000905b82821015612ac957612aba604083028601368190038101906150c7565b81526020019060010190612a9d565b505050505083613933565b805160408051602080890282018101909252878152612b33918a91908a908a90819060009085015b82821015612b2857612b19604083028601368190038101906150c7565b81526020019060010190612afc565b505050505085613ad6565b80516005811115612b4657612b46614658565b8351516005811115612b5a57612b5a614658565b141580612b85575080602001516001600160a01b03168360000151602001516001600160a01b031614155b80612b9c5750806040015183600001516040015114155b15612bba576040516309cfb45560e01b815260040160405180910390fd5b82600001516060015181606001511115612c6857600085856000818110612be357612be3614ea7565b905060400201803603810190612bf991906150c7565b905083600001516060015182606001510389826000015181518110612c2057612c20614ea7565b60200260200101516000015160600151826020015181518110612c4557612c45614ea7565b602090810291909101015160609081019190915284518101519083015250612d03565b600087876000818110612c7d57612c7d614ea7565b905060400201803603810190612c9391906150c7565b905081606001518460000151606001510389826000015181518110612cba57612cba614ea7565b60200260200101516000015160400151826020015181518110612cdf57612cdf614ea7565b60200260200101516060018181525050816060015184600001516060018181525050505b60809081015183516001600160a01b039091169101525095945050505050565b8151606090806001600160401b03811115612d4057612d4061400e565b604051908082528060200260200182016040528015612d69578160200160208202803683370190505b50915060005b81811015612e51576000858281518110612d8b57612d8b614ea7565b6020026020010151905080602001516001600160781b0316600003612db05750612e49565b6001848381518110612dc457612dc4614ea7565b91151560209283029190910190910152805160600151805160005b81811015612e44576000838281518110612dfb57612dfb614ea7565b602002602001015160600151905080600014612e3b576040516314bea84160e31b8152600481018790526024810183905260448101829052606401610d94565b50600101612ddf565b505050505b600101612d6f565b5060408051602080825281830190925234916000919060208201818036833701905050855190915060005b81811015612f0f576000878281518110612e9857612e98614ea7565b60209081029190910101518051909150600081516005811115612ebd57612ebd614658565b03612ef1578581606001511115612ee757604051631a783b8d60e01b815260040160405180910390fd5b8060600151860395505b612f058183602001518460400151886132dd565b5050600101612e7c565b50612f198261297e565b8215612f2957612f293384613439565b612f336001600055565b5050505092915050565b612f45613ed5565b8351600003612f69578460405163375c24c160e01b8152600401610d9491906150f3565b6000856001811115612f7d57612f7d614658565b03612fa45780516001600160a01b038316608090910152612f9f868583613ad6565b612fbd565b612faf868583613933565b336020820152604081018390525b8051606001516000036103305760006020820181905281516080015295945050505050565b808210156129a357604051632335530b60e11b815260040160405180910390fd5b6000806000526000825160208403805182604103600060018211613071576040880151606089015160001a9650821561304f57601b8160ff1c0196506001600160ff1b03811660408a01525b8689528985526020600060808760015afa508385528589526040890152506000515b89148915151695508590506131325760408252604486038051604088038051630b135d3f60e11b84528a82526020600060648901868f5afa9850881561312857630b135d3f60e11b60005114613128578b3b156130d957634f7fb80d60e01b60005260046000fd5b60018760410311156130f657638baa579f60e01b60005260046000fd5b640101000000881a61311757630f801e8560e11b6000528760045260246000fd5b632057875960e21b60005260046000fd5b8486529190925290525b50505050806119e557613143613c67565b634f7fb80d60e01b60005260046000fd5b6000428411806131645750428311155b15613190578115613188576040516337bf561360e11b815260040160405180910390fd5b50600061052c565b5060019392505050565b60018360038111156131ae576131ae614658565b1180156131c45750336001600160a01b03821614155b80156131d95750336001600160a01b03831614155b15613270576080880151511580156131f057508651155b156132065761320181868487613caf565b613270565b600061326482633313157060e01b88338d8c8e60405160240161322d9594939291906152b3565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613cfb565b905061155b8187613d10565b5050505050505050565b600083600052602060002060208301835160051b81015b808210156132b957815180841160051b93845260209384185260406000209290910190613291565b505083149050806119e5576040516309bde33960e01b815260040160405180910390fd5b6000845160058111156132f2576132f2614658565b0361334057604084015160208501516001600160a01b0316171561332957604051636ab37ce760e01b815260040160405180910390fd5b61333b84608001518560600151613439565b6119e5565b60018451600581111561335557613355614658565b036133975760408401511561337d57604051636ab37ce760e01b815260040160405180910390fd5b61333b8460200151848660800151876060015186866138d4565b6002845160058111156133ac576133ac614658565b036133d05761333b84602001518486608001518760400151886060015187876127da565b6119e58460200151848660800151876040015188606001518787612827565b600086880361340a576134038686896129a7565b905061342e565b61342b61341887878b6129a7565b61342388888b6129a7565b8686866129e9565b90505b979650505050505050565b613442816138b3565b600080600080600085875af19050806134885761345d613c67565b60405163470c7c1d60e01b81526001600160a01b038416600482015260248101839052604401610d94565b505050565b60186101243510610244356102606102643560400201146004356020146102243561024014161616806134d3576040516339f3e3fd60e01b815260040160405180910390fd5b50565b60018360038111156134ea576134ea614658565b1180156135005750336001600160a01b03821614155b80156135155750336001600160a01b03831614155b156120055761200581868487613caf565b600083815260026020526040902061354184826001806118d1565b50805460ff1661355657613556838584611996565b710100000000000000000000000000000100019055505050565b604080517f000000000000000000000000000000000000000000000000000000000000000060ff60a01b17600090815260208690527f000000000000000000000000000000000000000000000000000000000000000083526055600b20919092526001600160a01b03169050600080600080526020600085876000875af1915060005190508161362657613602613c67565b60405163344f54f560e21b81526001600160a01b0384166004820152602401610d94565b6001600160e01b03198116632671a55160e11b146127d257604051630e7ccd9360e11b8152600481018790526001600160a01b0384166024820152604401610d94565b833b61368457632f8aeb3960e11b6000528360045260246000fd5b6040516323b872dd60e01b6000528360045282602452816044526000806064600080895af18061371e573d156136f8576020601f3d01046020830481600302818311156136df57818303600302610200838002858002030401015b5a6020820110156136f4573d6000803e3d6000fd5b5050505b63f486bc8760e01b60005285600452846024528360445282606452600160845260a46000fd5b50604052505060006060525050565b843b61374857632f8aeb3960e11b6000528460045260246000fd5b60405160805160a05160c051637921219560e11b6000528760045286602452856044528460645260a0608452600060a45260008060c46000808d5af1806137f8573d156137d3576020601f3d01046020860481600302818311156137ba57818303600302610200838002858002030401015b5a6020820110156137cf573d6000803e3d6000fd5b5050505b63f486bc8760e01b600052896004528860245287604452866064528560845260a46000fd5b5060809290925260a05260c05260405250506000606052505050565b6000613821836020015190565b9050818114613488576134888361297e565b6000602088510361386e5750604080885260208089018a9052632671a55160e11b91890191909152604488015260016064880181905261387d565b50606487018051600101908190525b603c60c082028901038781528660208201528560408201528460608201528360808201528260a082015250505050505050505050565b806000036134d35760405163246cf94560e21b815260040160405180910390fd5b6138dd836138b3565b6138e78183613814565b816138fd576138f886868686613d6a565b6127d2565b6127d28282600189898960008a613833565b6064810151604082019060c00260440161392a848383613570565b50506020905250565b61395f565b637fda727960e01b60005260046000fd5b634e487b7160e01b600052601160045260246000fd5b602082018051518451811061397657613976613938565b602081026020860101516060815101516020845101518151811061399c5761399c613938565b602081026020830101516000806020860151156139c3575050606081018051600090915280155b885183518152602084015160208201526040840151604082015260a084015160808201526060812060208c51028c015b808b1015613a9a5760208b019a508a515199508d518a10613a1657613a16613938565b60208a0260208f01015198506020890151156139f357606089510151975060208b510151965087518710613a4c57613a4c613938565b602087026020890101519550606086018051860181511587821060011b1786179550809650506000815250606086208214608084015160a08801511416613a9557613a95613938565b6139f3565b50506060018290528015613ac95760018103613ac15763246cf94560e21b60005260046000fd5b613ac9613949565b5050505050505050505050565b6020820180515184518110613aed57613aed613938565b602081026020860101518051604081015160208551015181518110613b1457613b14613938565b60208102602083010151600080602087015115613b3b575050606081018051600090915280155b8951835181526020840151602082015260408401516040820152865160208c015261012087015160408c015260608120905060208c51028c015b808b1015613c295760208b019a508a515199508d518a10613b9857613b98613938565b60208a0260208f0101519850602089015115613b7557885197506040880151965060208b510151955086518610613bd157613bd1613938565b602086026020880101519450606085018051850181511586821060011b178517945080955050600081525060608520821460408d01516101208a01511460208e01518a51141616613c2457613c24613938565b613b75565b50508160608b5101528015613c595760018103613c515763246cf94560e21b60005260046000fd5b613c59613949565b505050505050505050505050565b3d156116b4576020601f3d01046020604051048160030281831115613c9a57818303600302610200838002858002030401015b5a602082011015613488573d6000803e3d6000fd5b604051602481018490523360448201526001600160a01b038316606482015260848101829052600090613cef9086906303874c7760e21b9060a40161322d565b90506120058185613d10565b6000806000835160208501865afa9392505050565b81613d3957613d1d613c67565b604051633ed4053f60e21b815260048101829052602401610d94565b613d496303874c7760e21b613e73565b156129a357604051633ed4053f60e21b815260048101829052602401610d94565b6040516323b872dd60e01b600052836004528260245281604452602060006064600080895af1803d15601f3d116001600051141617163d15158116613e635780873b151516613e635780613e4e5781613e2d573d15613e07576020601f3d0104602084048160030281831115613dee57818303600302610200838002858002030401015b5a602082011015613e03573d6000803e3d6000fd5b5050505b63f486bc8760e01b60005286600452856024528460445260006064528360845260a46000fd5b639889192360e01b6000528660045285602452846044528360645260846000fd5b632f8aeb3960e11b6000528660045260246000fd5b5050604052505060006060525050565b60008060203d03613e895760206000803e506000515b6001600160e01b031990811692169190911415919050565b6040518060a00160405280613eb4613f18565b81526000602082018190526040820152606080820181905260809091015290565b60408051610100810182526000606082018181526080830182905260a0830182905260c0830182905260e083018290528252602082018190529181019190915290565b60405180610160016040528060006001600160a01b0316815260200160006001600160a01b03168152602001606081526020016060815260200160006003811115613f6557613f65614658565b815260006020820181905260408201819052606082018190526080820181905260a0820181905260c09091015290565b6000815180845260005b81811015613fbb57602081850181015186830182015201613f9f565b81811115613fcd576000602083870101525b50601f01601f19169290920160200192915050565b60208152600061052c6020830184613f95565b60006020828403121561400757600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60405160a081016001600160401b03811182821017156140465761404661400e565b60405290565b60405161016081016001600160401b03811182821017156140465761404661400e565b604051601f8201601f191681016001600160401b03811182821017156140975761409761400e565b604052919050565b60006001600160401b038211156140b8576140b861400e565b5060051b60200190565b6001600160a01b03811681146134d357600080fd5b80356140e2816140c2565b919050565b8035600681106140e257600080fd5b600060a0828403121561410857600080fd5b614110614024565b905061411b826140e7565b8152602082013561412b816140c2565b8060208301525060408201356040820152606082013560608201526080820135608082015292915050565b600082601f83011261416757600080fd5b8135602061417c6141778361409f565b61406f565b82815260a0928302850182019282820191908785111561419b57600080fd5b8387015b858110156141be576141b189826140f6565b845292840192810161419f565b5090979650505050505050565b600060c082840312156141dd57600080fd5b60405160c081018181106001600160401b03821117156141ff576141ff61400e565b60405290508061420e836140e7565b8152602083013561421e816140c2565b8060208301525060408301356040820152606083013560608201526080830135608082015260a0830135614251816140c2565b60a0919091015292915050565b600082601f83011261426f57600080fd5b8135602061427f6141778361409f565b82815260c0928302850182019282820191908785111561429e57600080fd5b8387015b858110156141be576142b489826141cb565b84529284019281016142a2565b8035600481106140e257600080fd5b600061016082840312156142e357600080fd5b6142eb61404c565b90506142f6826140d7565b8152614304602083016140d7565b602082015260408201356001600160401b038082111561432357600080fd5b61432f85838601614156565b6040840152606084013591508082111561434857600080fd5b506143558482850161425e565b606083015250614367608083016142c1565b608082015260a082013560a082015260c082013560c082015260e082013560e082015261010080830135818301525061012080830135818301525061014080830135818301525092915050565b80356001600160781b03811681146140e257600080fd5b600082601f8301126143dc57600080fd5b81356001600160401b038111156143f5576143f561400e565b614408601f8201601f191660200161406f565b81815284602083860101111561441d57600080fd5b816020850160208301376000918101602001919091529392505050565b600060a0828403121561444c57600080fd5b614454614024565b905081356001600160401b038082111561446d57600080fd5b614479858386016142d0565b8352614487602085016143b4565b6020840152614498604085016143b4565b604084015260608401359150808211156144b157600080fd5b6144bd858386016143cb565b606084015260808401359150808211156144d657600080fd5b506144e3848285016143cb565b60808301525092915050565b600082601f83011261450057600080fd5b813560206145106141778361409f565b82815260059290921b8401810191818101908684111561452f57600080fd5b8286015b8481101561456e5780356001600160401b038111156145525760008081fd5b6145608986838b010161443a565b845250918301918301614533565b509695505050505050565b60008083601f84011261458b57600080fd5b5081356001600160401b038111156145a257600080fd5b6020830191508360208260051b85010111156145bd57600080fd5b9250929050565b6000806000806000606086880312156145dc57600080fd5b85356001600160401b03808211156145f357600080fd5b6145ff89838a016144ef565b9650602088013591508082111561461557600080fd5b61462189838a01614579565b9096509450604088013591508082111561463a57600080fd5b5061464788828901614579565b969995985093965092949392505050565b634e487b7160e01b600052602160045260246000fd5b6006811061467e5761467e614658565b9052565b61468d82825161466e565b6020818101516001600160a01b0390811691840191909152604080830151908401526060808301519084015260809182015116910152565b600081518084526020808501945080840160005b8381101561471b5781516146ee888251614682565b808401516001600160a01b031660a08901526040015160c088015260e090960195908201906001016146d9565b509495945050505050565b60208152600061052c60208301846146c5565b60006020828403121561474b57600080fd5b81356001600160401b0381111561476157600080fd5b8201610160818503121561052c57600080fd5b60008060008060008060008060008060e08b8d03121561479357600080fd5b8a356001600160401b03808211156147aa57600080fd5b6147b68e838f016144ef565b9b5060208d01359150808211156147cc57600080fd5b6147d88e838f01614579565b909b50995060408d01359150808211156147f157600080fd5b6147fd8e838f01614579565b909950975060608d013591508082111561481657600080fd5b506148238d828e01614579565b90965094505060808b0135925061483c60a08c016140d7565b915060c08b013590509295989b9194979a5092959850565b604080825283519082018190526000906020906060840190828701845b8281101561488f578151151584529284019290840190600101614871565b505050838103828501526148a381866146c5565b9695505050505050565b600080602083850312156148c057600080fd5b82356001600160401b038111156148d657600080fd5b6148e285828601614579565b90969095509350505050565b6000806000806040858703121561490457600080fd5b84356001600160401b038082111561491b57600080fd5b61492788838901614579565b9096509450602087013591508082111561494057600080fd5b5061494d87828801614579565b95989497509550505050565b6000806040838503121561496c57600080fd5b82356001600160401b0381111561498257600080fd5b83016040818603121561499457600080fd5b946020939093013593505050565b6000806000806000608086880312156149ba57600080fd5b85356001600160401b03808211156149d157600080fd5b9087019060a0828a0312156149e557600080fd5b909550602087013590808211156149fb57600080fd5b50614a0888828901614579565b909550935050604086013591506060860135614a23816140c2565b809150509295509295909350565b60008060008060008060008060a0898b031215614a4d57600080fd5b88356001600160401b0380821115614a6457600080fd5b614a708c838d01614579565b909a50985060208b0135915080821115614a8957600080fd5b614a958c838d01614579565b909850965060408b0135915080821115614aae57600080fd5b50614abb8b828c01614579565b999c989b509699959896976060870135966080013595509350505050565b600060208284031215614aeb57600080fd5b813561052c816140c2565b606081526000614b096060830186613f95565b6020830194909452506001600160a01b0391909116604090910152919050565b600060208284031215614b3b57600080fd5b81356001600160401b03811115614b5157600080fd5b8201610240818503121561052c57600080fd5b6000614b726141778461409f565b83815260208082019190600586811b860136811115614b9057600080fd5b865b81811015614c8b5780356001600160401b0380821115614bb25760008081fd5b818a01915060a08236031215614bc85760008081fd5b614bd0614024565b823581528683013560028110614be65760008081fd5b81880152604083810135908201526060808401359082015260808084013583811115614c125760008081fd5b939093019236601f850112614c2957600092508283fd5b83359250614c396141778461409f565b83815292871b84018801928881019036851115614c565760008081fd5b948901945b84861015614c7457853582529489019490890190614c5b565b918301919091525088525050948301948301614b92565b5092979650505050505050565b6000808335601e19843603018112614caf57600080fd5b8301803591506001600160401b03821115614cc957600080fd5b602001915060a0810236038213156145bd57600080fd5b600060a08284031215614cf257600080fd5b61052c83836140f6565b6000808335601e19843603018112614d1357600080fd5b8301803591506001600160401b03821115614d2d57600080fd5b602001915060c0810236038213156145bd57600080fd5b600060c08284031215614d5657600080fd5b61052c83836141cb565b600060208284031215614d7257600080fd5b61052c826142c1565b60006104d4368361443a565b600060408284031215614d9957600080fd5b604051604081018181106001600160401b0382111715614dbb57614dbb61400e565b604052823581526020928301359281019290925250919050565b6000614de36141778461409f565b80848252602080830192508560051b850136811115614e0157600080fd5b855b81811015614e9b5780356001600160401b03811115614e225760008081fd5b870136601f820112614e345760008081fd5b8035614e426141778261409f565b81815260069190911b82018501908581019036831115614e625760008081fd5b928601925b82841015614e8b57614e793685614d87565b82528682019150604084019350614e67565b8852505050938201938201614e03565b50919695505050505050565b634e487b7160e01b600052603260045260246000fd5b60008235603e19833603018112614ed357600080fd5b9190910192915050565b6000823561015e19833603018112614ed357600080fd5b60006104d436836142d0565b6000808335601e19843603018112614f1757600080fd5b8301803591506001600160401b03821115614f3157600080fd5b6020019150368190038213156145bd57600080fd5b6000808335601e19843603018112614f5d57600080fd5b8301803591506001600160401b03821115614f7757600080fd5b6020019150600681901b36038213156145bd57600080fd5b634e487b7160e01b600052601160045260246000fd5b60008219821115614fb857614fb8614f8f565b500190565b6000816000190483118215151615614fd757614fd7614f8f565b500290565b600081518084526020808501945080840160005b8381101561471b57615003878351614682565b60a0969096019590820190600101614ff0565b60006080808301878452602060018060a01b03808916828701526040848188015283895180865260a089019150848b01955060005b8181101561508c57865161506084825161466e565b80870151861684880152848101518585015260609081015190840152958501959187019160010161504b565b505087810360608901526150a0818a614fdc565b9c9b505050505050505050505050565b6000828210156150c2576150c2614f8f565b500390565b6000604082840312156150d957600080fd5b61052c8383614d87565b6002811061467e5761467e614658565b602081016104d482846150e3565b600081518084526020808501945080840160005b8381101561471b57815161512a88825161466e565b838101516001600160a01b03168885015260408082015190890152606080820151908901526080908101519088015260a09096019590820190600101615115565b600081518084526020808501945080840160005b8381101561471b57815161519488825161466e565b808401516001600160a01b0390811689860152604080830151908a0152606080830151908a0152608080830151908a015260a091820151169088015260c0909601959082019060010161517f565b6004811061467e5761467e614658565b600081518084526020808501945080840160005b8381101561471b57815187529582019590820190600101615206565b600081518084526020808501808196508360051b8101915082860160005b858110156152a6578284038952815160a08151865286820151615265888801826150e3565b506040828101519087015260608083015190870152608091820151918601819052615292818701836151f2565b9a87019a9550505090840190600101615240565b5091979650505050505050565b85815260018060a01b038516602082015260a060408201526000610140855160a0808501526152ed82850182516001600160a01b03169052565b6020810151610160615309818701836001600160a01b03169052565b6040830151915080610180870152506153266102a0860182615101565b9050606082015161013f19868303016101a0870152615345828261516b565b915050608082015161535b6101c08701826151e2565b5060a08201516101e086015260c082015161020086015260e082015161022086015261010080830151610240870152610120808401516102608801528484015161028088015260208a015194506153bd60c08801866001600160781b03169052565b60408a01516001600160781b031660e088015260608a0151878403609f19908101848a015290955093506153f18386613f95565b945060808a01519250838786030181880152505061540f8382613f95565b92505050828103606084015261542581866151f2565b905082810360808401526154398185615222565b9897505050505050505056fea2646970667358221220d9ec6bf53c7c4dd207e9b7af873aae1b86f9ebf0a16709b20f4f94de3560378664736f6c634300080e0033000000000000000000000000c8ddac143e4da8337ffdea513ba27bf1d0657518
Deployed Bytecode
0x6080604052600436106100e85760003560e01c8063a81744041161008a578063f07ec37311610059578063f07ec37314610290578063f47b7740146102b0578063fb0f3ee1146102d4578063fd9f1e10146102e757600080fd5b8063a817440414610244578063b3a34c4c14610257578063e7acab241461026a578063ed98a5741461027d57600080fd5b80635b34b966116100c65780635b34b966146101b057806379df72bd146101d357806387201b41146101f3578063881477321461021457600080fd5b806306fdde03146100ed57806346423aa71461011857806355944a4214610190575b600080fd5b3480156100f957600080fd5b50610102610307565b60405161010f9190613fe2565b60405180910390f35b34801561012457600080fd5b5061016e610133366004613ff5565b60009081526002602052604090205460ff808216926101008304909116916001600160781b03620100008204811692600160881b9092041690565b604080519415158552921515602085015291830152606082015260800161010f565b6101a361019e3660046145c4565b610316565b60405161010f9190614726565b3480156101bc57600080fd5b506101c5610339565b60405190815260200161010f565b3480156101df57600080fd5b506101c56101ee366004614739565b610343565b610206610201366004614774565b6104da565b60405161010f929190614854565b34801561022057600080fd5b5061023461022f3660046148ad565b610520565b604051901515815260200161010f565b6101a36102523660046148ee565b610533565b610234610265366004614959565b6105b1565b6102346102783660046149a2565b610623565b61020661028b366004614a31565b610657565b34801561029c57600080fd5b506101c56102ab366004614ad9565b6106e1565b3480156102bc57600080fd5b506102c56106ff565b60405161010f93929190614af6565b6102346102e2366004614b29565b610717565b3480156102f357600080fd5b506102346103023660046148ad565b610722565b606061031161072e565b905090565b606061032d866103268688614b64565b8585610746565b90505b95945050505050565b6000610311610763565b6040805161016081019091526000906104d490806103646020860186614ad9565b6001600160a01b031681526020018460200160208101906103859190614ad9565b6001600160a01b031681526020016103a06040860186614c98565b808060200260200160405190810160405280939291908181526020016000905b828210156103ec576103dd60a08302860136819003810190614ce0565b815260200190600101906103c0565b50505091835250506020016104046060860186614cfc565b808060200260200160405190810160405280939291908181526020016000905b828210156104505761044160c08302860136819003810190614d44565b81526020019060010190610424565b505050918352505060200161046b60a0860160808701614d60565b600381111561047c5761047c614658565b81526020018460a0013581526020018460c0013581526020018460e001358152602001846101000135815260200184610120013581526020018480606001906104c59190614cfc565b909152506101408401356107c0565b92915050565b60608061050d8c6104eb8c8e614b64565b8b8b8b8b8b6001600160a01b038c1615610505578b610507565b335b8b610906565b915091509a509a98505050505050505050565b600061052c8383610948565b9392505050565b60606105a66105428686610aad565b604080516000808252602082019092529061059e565b61058b6040805160a081019091526000808252602082019081526020016000815260200160008152602001606081525090565b8152602001906001900390816105585790505b508585610746565b90505b949350505050565b600061052c6105bf84610b68565b604080516000808252602082019092529061061b565b6106086040805160a081019091526000808252602082019081526020016000815260200160008152602001606081525090565b8152602001906001900390816105d55790505b508433610c13565b600061032d61063187614d7b565b61063b8688614b64565b856001600160a01b038616156106515785610c13565b33610c13565b6060806106d06106678b8b610aad565b60408051600080825260208201909252906106c3565b6106b06040805160a081019091526000808252602082019081526020016000815260200160008152602001606081525090565b81526020019060019003908161067d5790505b508a8a8a8a8a338b610906565b915091509850989650505050505050565b6001600160a01b0381166000908152600160205260408120546104d4565b606060008061070c610d00565b925092509250909192565b60006104d482610d61565b600061052c8383611021565b6060602080526707536561706f727460475260606020f35b60606107588585600188516000611227565b6105a6858484611566565b600061076d611691565b503360008181526001602081815260409283902080549092019182905591518181529092917f721c20121297512b72821b97f5326877ea8ecf4bb9948fea5bfcb6453074d37f910160405180910390a290565b610140820151604080519084015180516000939284927fa66999307ad1bb4fde44d13a5d710bd7718e0c87c1eef68a571629fbf5b93d0292602090910190845b8181101561082d578251601f1901805186825260c082208652905260209384019390920191600101610800565b506020810260405120945050505060007f42d81c6929ffdc4eb27a0808e40e82516ad42296c166065de7f812492304ff6e9150604051602060608901510160005b8681101561089b578151601f1901805186825260e08220855290526020928301929091019060010161086e565b505060408051602087029020601f198a0180517ffa445660b7e21515a59617fcd68910b487aa5808b8abda3d78bc85df364b2c2f8252928b01805197815260608c018051938152610140909c019a8b5261018082209390915295909552939097525050925250919050565b6060806109178b8b60008688611227565b6109368b6109258a8c614dd5565b61092f898b614dd5565b88886116b6565b909c909b509950505050505050505050565b6000610952611691565b6000808084815b81811015610a9f573688888381811061097457610974614ea7565b90506020028101906109869190614ebd565b9050366109938280614edd565b90506109a26020820182614ad9565b94506109b56109b082614ef4565b611896565b600081815260026020526040812098509096506109d7908790899060016118d1565b50865460ff16610a9557610a2d85876109f36020860186614f00565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061199692505050565b865460ff19166001178755610a486040820160208301614ad9565b6001600160a01b0316856001600160a01b03167ffde361574a066b44b3b5fe98a87108b7565e327327954c4faeea56a4e6491a0a88604051610a8c91815260200190565b60405180910390a35b5050600101610959565b506001979650505050505050565b606081806001600160401b03811115610ac857610ac861400e565b604051908082528060200260200182016040528015610b0157816020015b610aee613ea1565b815260200190600190039081610ae65790505b50915060005b81811015610b6057610b3b858583818110610b2457610b24614ea7565b9050602002810190610b369190614ebd565b610b68565b838281518110610b4d57610b4d614ea7565b6020908102919091010152600101610b07565b505092915050565b610b70613ea1565b6040805160a0810190915280610b868480614edd565b610b8f90614ef4565b815260200160016001600160781b0316815260200160016001600160781b03168152602001838060200190610bc49190614f00565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509385525050604080516020818101909252928352909201525092915050565b6000610c1d6119eb565b60606000806000610c3189896001876119fa565b604080516001808252818301909252939650919450925060009190816020015b610c59613ea1565b815260200190600190039081610c515790505090508981600081518110610c8257610c82614ea7565b6020026020010181905250610c97818a611cb3565b600081600081518110610cac57610cac614ea7565b6020026020010151600001519050610cc78185858c8c61200c565b610ce585826000015183602001518b856040015186606001516121da565b610cef6001600055565b5060019a9950505050505050505050565b6060600080610d0d61223f565b6040805160038082528183019092529193507f000000000000000000000000c8ddac143e4da8337ffdea513ba27bf1d06575189250602082018180368337505062312e3160e81b6020830152509391925090565b600061012435600281901c90600316600182113415811480610d9d57604051630a61be9f60e41b81523460048201526024015b60405180910390fd5b5060008060008060038711915060a082026024013593506002871460028811600289030201905060018101820260028615028801039250610de2898783888888612335565b506101c46020820201356000856005811115610e0057610e00614658565b03610ea35760208901803590610e16908b614ad9565b6001600160a01b03161715610e3e57604051636ab37ce760e01b815260040160405180910390fd5b610e7383610e5260c08c0160a08d01614ad9565b610e6260808d0160608e01614ad9565b338d60c001358e60e001358761266b565b610e9e60408a0135610e8b60808c0160608d01614ad9565b610e996102008d018d614f46565b61271f565b611008565b6040805160208082528183019092526000916020820181803683370190505090506002886005811115610ed857610ed8614658565b03610f1757610f12610ef060c08c0160a08d01614ad9565b610f0060808d0160608e01614ad9565b338d60c001358e60e0013587876127da565b610fe2565b6003886005811115610f2b57610f2b614658565b03610f6557610f12610f4360c08c0160a08d01614ad9565b610f5360808d0160608e01614ad9565b338d60c001358e60e001358787612827565b6004886005811115610f7957610f79614658565b03610fb057610f12610f8e60208c018c614ad9565b33610f9f60808e0160608f01614ad9565b8d602001358e6040013587876127da565b610fe2610fc060208c018c614ad9565b33610fd160808e0160608f01614ad9565b8d602001358e604001358787612827565b610ffd610ff560808c0160608d01614ad9565b8b858461285d565b6110068161297e565b505b6110126001600055565b50600198975050505050505050565b600061102b611691565b6000808084815b81811015610a9f573688888381811061104d5761104d614ea7565b905060200281019061105f9190614edd565b905061106e6020820182614ad9565b94506110806040820160208301614ad9565b9350336001600160a01b038616148015906110a45750336001600160a01b03851614155b156110c25760405163203b1cdd60e21b815260040160405180910390fd5b60006111b1604051806101600160405280886001600160a01b03168152602001876001600160a01b031681526020018480604001906111019190614c98565b808060200260200160405190810160405280939291908181526020016000905b8282101561114d5761113e60a08302860136819003810190614ce0565b81526020019060010190611121565b50505091835250506020016111656060860186614cfc565b808060200260200160405190810160405280939291908181526020016000905b82821015610450576111a260c08302860136819003810190614d44565b81526020019060010190611185565b60008181526002602052604090819020805461ffff191661010017815590519098509091506001600160a01b0380871691908816907f6bacc01dbe442496068f7d234edd811f1a5f833243e0aec824f86ab861f3c90d906112159085815260200190565b60405180910390a35050600101611032565b61122f6119eb565b84516000816001600160401b0381111561124b5761124b61400e565b604051908082528060200260200182016040528015611274578160200160208202803683370190505b506000808252909150601d6045823560e01c061160011b905b8381101561149d5760008982815181106112a9576112a9614ea7565b60200260200101519050866000036112ce576000602090910152600181018352611495565b60008060006112df848d8d8a6119fa565b92509250925060018501875281600003611306575050600060209092019190915250611495565b8287868151811061131957611319614ea7565b6020908102919091010152835160a081015160c08201516040909201518051600019909d019c91929160005b818110156113e157600083828151811061136157611361614ea7565b602002602001015190508051158c179b506000611383898984608001516129a7565b905081608001518260600151036113a057606082018190526113b5565b6113af898984606001516129a7565b60608301525b6080820181905260608201516113cf9082898960006129e9565b60609092019190915250600101611345565b50875160600151805160005b8181101561148957600083828151811061140957611409614ea7565b6020026020010151905060006114248b8b84608001516129a7565b905081608001518260600151036114415760608201819052611456565b6114508b8b84606001516129a7565b60608301525b60808201819052606082015161147090828b8b60016129e9565b60608301525060a08101516080909101526001016113ed565b50505050505050505050505b60010161128d565b50806003036114bf576040516312d3f5a360e01b815260040160405180910390fd5b6114c98888611cb3565b60005b8381101561155b576000801b8382815181106114ea576114ea614ea7565b6020026020010151031561155357600089828151811061150c5761150c614ea7565b602002602001015160000151905061155184838151811061152f5761152f614ea7565b60200260200101518260000151836020015189856040015186606001516121da565b505b6001016114cc565b505050505050505050565b606081806001600160401b038111156115815761158161400e565b6040519080825280602002602001820160405280156115ba57816020015b6115a7613ed5565b81526020019060019003908161159f5790505b5091506000805b8281101561166f57368686838181106115dc576115dc614ea7565b90506020028101906115ee9190614ebd565b90506000611612896116008480614f46565b61160d6020870187614f46565b612a3e565b905080602001516001600160a01b03168160000151608001516001600160a01b03160361164457836001019350611665565b80868585038151811061165957611659614ea7565b60200260200101819052505b50506001016115c1565b50801561167d578083510383525b506116888583612d23565b50509392505050565b6001600054146116b457604051637fa8a98760e01b815260040160405180910390fd5b565b8351835160609182916116c98183614fa5565b6001600160401b038111156116e0576116e061400e565b60405190808252806020026020018201604052801561171957816020015b611706613ed5565b8152602001906001900390816116fe5790505b5092506000805b838110156117b35760008a828151811061173c5761173c614ea7565b6020026020010151905060006117568d6000848d8d612f3d565b905080602001516001600160a01b03168160000151608001516001600160a01b031603611788578360010193506117a9565b80878585038151811061179d5761179d614ea7565b60200260200101819052505b5050600101611720565b5060005b8281101561184d5760008982815181106117d3576117d3614ea7565b6020026020010151905060006117ee8d6001848d6000612f3d565b905080602001516001600160a01b03168160000151608001516001600160a01b03160361182057836001019350611843565b808785888601038151811061183757611837614ea7565b60200260200101819052505b50506001016117b7565b50801561185b578084510384525b50825160000361187e5760405163d5da9a1b60e01b815260040160405180910390fd5b6118888984612d23565b935050509550959350505050565b60006118ac826060015151836101400151612fe2565b81516001600160a01b03166000908152600160205260409020546104d49083906107c0565b8254600090610100900460ff161561190d57811561190557604051630694555d60e21b815260048101869052602401610d94565b5060006105a9565b83546201000090046001600160781b0316801561198a5783156119465760405163ee9e0e6360e01b815260048101879052602401610d94565b8454600160881b90046001600160781b0316811061198a578215611980576040516310fda3e160e01b815260048101879052602401610d94565b60009150506105a9565b50600195945050505050565b336001600160a01b038416036119ab57505050565b60006119d86119b861223f565b61190160f01b600090815260029190915260228581526042822091905290565b90506119e5848284613003565b50505050565b6119f3611691565b6002600055565b60008060008087600001519050611a1a8160a001518260c0015188613154565b611a2e575060009250829150819050611ca9565b602088015160408901516001600160781b03918216911680821180611a51575081155b15611a6f57604051632d02959960e11b815260040160405180910390fd5b8082108015611a8357506080830151600116155b15611aa15760405163a11b63ff60e01b815260040160405180910390fd5b611aaa83611896565b9550611acc8a8a89898760e00151886080015189600001518a6020015161319a565b600086815260026020526040812090611ae990889083908c6118d1565b611afe575060009450849350611ca992505050565b805460ff16611b1a57611b1a8460000151888d60600151611996565b80546001600160781b03620100008204811691600160881b9004168015611c635783600103611b4e57809450809350611b7a565b838114611b7a57611b5f8483614fbd565b9150611b6b8186614fbd565b9450611b778185614fbd565b93505b83611b858684614fa5565b1115611b915781840394505b611b9b8583614fa5565b91506001600160781b0384116001600160781b0383111715611c2457611bd6565b60005b8215611bd057908290069190611bbf565b50919050565b611be9611be38584611bbc565b86611bbc565b80150194859004949384900493909104906001600160781b038083119085111715611c2457634e487b7160e01b600052601160045260246000fd5b82546001600160781b03858116600160881b026001600160881b0391851662010000026001600160881b03199093169290921760011716178355611c9e565b82546001600160781b03858116600160881b026001600160881b0391881662010000026001600160881b031990931692909217600117161783555b509295509093505050505b9450945094915050565b8051825160005b82811015611efa576000848281518110611cd657611cd6614ea7565b60200260200101519050600081600001519050838110611d09576040516321a561b160e21b815260040160405180910390fd5b868181518110611d1b57611d1b614ea7565b6020026020010151602001516001600160781b0316600003611d3e575050611ef2565b6000878281518110611d5257611d52614ea7565b60209081029190910101515160408401519091506000808086602001516001811115611d8057611d80614658565b03611e1a57604084015180518410611dab57604051635fd9fc6760e11b815260040160405180910390fd5b6000818581518110611dbf57611dbf614ea7565b602090810291909101015180516040820151909550935090506004841460030381816005811115611df257611df2614658565b90816005811115611e0557611e05614658565b90525050606088015160409091015250611eab565b606084015180518410611e40576040516330446bef60e11b815260040160405180910390fd5b6000818581518110611e5457611e54614ea7565b602090810291909101015180516040820151909550935090506004841460030381816005811115611e8757611e87614658565b90816005811115611e9a57611e9a614658565b905250506060880151604090910152505b611eb58260031090565b611ed257604051634a75b57b60e11b815260040160405180910390fd5b8015611eeb57611eeb866060015182886080015161327a565b5050505050505b600101611cba565b5060005b81811015612005576000858281518110611f1a57611f1a614ea7565b6020026020010151905080602001516001600160781b0316600003611f3f5750611ffd565b805160608101515160005b81811015611fa657611f7d83606001518281518110611f6b57611f6b614ea7565b60200260200101516000015160031090565b15611f9e5760405160016202297360e61b0319815260040160405180910390fd5b600101611f4a565b505060408101515160005b81811015611ff857611fd283604001518281518110611f6b57611f6b614ea7565b15611ff05760405163a6cfc67360e01b815260040160405180910390fd5b600101611fb1565b505050505b600101611efe565b5050505050565b60a085015160c08601516040805160208082528183019092526000916020820181803683375050506040890151519091506132dd9060005b818110156120fa5760008b60400151828151811061206457612064614ea7565b602002602001015190506000600581111561208157612081614658565b8151600581111561209457612094614658565b036120b2576040516312d3f5a360e01b815260040160405180910390fd5b60006120cc826060015183608001518e8e8c8c60006133ef565b606083015250608081018890528b516101208d01516120f19183918863ffffffff8916565b50600101612044565b50505060608801515134906132dd9060005b818110156121be5760008c60600151828151811061212c5761212c614ea7565b602002602001015190506000612150826060015183608001518f8f8d8d60016133ef565b6060830181905260a08301516080840152905060008251600581111561217857612178614658565b036121a4578581111561219e57604051631a783b8d60e01b815260040160405180910390fd5b80860395505b6121b482338d8a8963ffffffff16565b505060010161210c565b5050506121ca8261297e565b801561155b5761155b3382613439565b60608290506060829050856001600160a01b0316876001600160a01b03167f9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f318a88868660405161222d9493929190615016565b60405180910390a35050505050505050565b60007f000000000000000000000000000000000000000000000000000000000000a4ba461461231057610311604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f32b5c112df393a49218d7552f96b2eeb829dfb4272f4f24eef510a586b85feef918101919091527f722c0e0c80487266e8c6a45e3a1a803aab23378a9c32e6ebe029d4fad7bfc96560608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b507f1272de176ba30276e3297320d24a6075a4a6a0e56d4cb1ad8a6e509cd821929490565b61233d6119eb565b6123538661012001358761014001356001613154565b5061235c61348d565b61237a61236d610200880188614f46565b9050876101e00135612fe2565b6000807f42d81c6929ffdc4eb27a0808e40e82516ad42296c166065de7f812492304ff6e9050806080528560a0526060602460c037604060646101203760e06080206101605261026435602081026102a0016001610264350181526020810190508781526080602460208301376101608760a0528660c052600060e05261020435925060005b8381101561244b578060400261028401602081610100376040816101203760208301925060e0608020835260a084019350898452886020850152604081606086013750600101612400565b60206001850102610160206060526102643593505b83811015612491578060400261028401915060a0830192508883528760208401526040826060850137600101612460565b505050505060007fa66999307ad1bb4fde44d13a5d710bd7718e0c87c1eef68a571629fbf5b93d029050806080528260a052606060c460c03760206101046101203760c0608020600052602060002060e052602061026435026102000160018152836020820152606060c4604083013750506084356001600160a01b0381166000908152600160205260408120547ffa445660b7e21515a59617fcd68910b487aa5808b8abda3d78bc85df364b2c2f60808190529091506040608460a03760605161010052886101205260a061014461014037816101e0526101806080209350505050602061026435026101800181815233602082015260806040820152610120606082015260a061026435026101e00160a4356084357f9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f318385a35050600060605261260681886101600135888a60600160208101906125f19190614ad9565b61260160a08d0160808e01614ad9565b6134d6565b6126628161261a60808a0160608b01614ad9565b6126286102208b018b614f00565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061352692505050565b50505050505050565b80156126c75760006040519050632671a55160e11b815260206004820152600160248201528760448201528660648201528560848201528460a48201528360c48201528260e48201526126c18282610104613570565b50612662565b60028760058111156126db576126db614658565b0361271257816001146127015760405163efcc00b160e01b815260040160405180910390fd5b61270d86868686613669565b612662565b612662868686868661372d565b348160005b81811015612792573685858381811061273f5761273f614ea7565b6040029190910191505080358481111561276c57604051631a783b8d60e01b815260040160405180910390fd5b61278561277f6040840160208501614ad9565b82613439565b9093039250600101612724565b50818611156127b457604051631a783b8d60e01b815260040160405180910390fd5b6127be8587613439565b858211156127d2576127d233878403613439565b505050505050565b6127e48183613814565b81612816578260011461280a5760405163efcc00b160e01b815260040160405180910390fd5b61270d87878787613669565b612662828260028a8a8a8a8a613833565b612830836138b3565b61283a8183613814565b8161284c5761270d878787878761372d565b612662828260038a8a8a8a8a613833565b600080600080600086156128945788945033935061288160c0890160a08a01614ad9565b9250505060e086013560c08701356128b6565b3394508893506128a76020890189614ad9565b92505050604086013560208701355b80156128d557604051636ab37ce760e01b815260040160405180910390fd5b50602086026101e4033560006128ef6102008a018a614f46565b9050905060005b81811015612963573661290d6102008c018c614f46565b8381811061291d5761291d614ea7565b6040029190910191505080358a1561293c5761293981876150b0565b95505b612959878a6129516040860160208701614ad9565b84898f6138d4565b50506001016128f6565b5061297284878786868c6138d4565b50505050505050505050565b604081511461298a5750565b6000612997826020015190565b90506129a3818361390f565b5050565b60008284036129b757508061052c565b82848309156129d15763c63cf08960e01b60005260046000fd5b60006129dd8584614fbd565b93909304949350505050565b6000848614612a3457838303428590038082036000612a08838a614fbd565b612a12838c614fbd565b612a1c9190614fa5565b90508584878303040181151502945050505050610330565b5092949350505050565b612a46613ed5565b831580612a51575081155b15612a6f57604051634c74edb760e11b815260040160405180910390fd5b612a77613ed5565b612ad4878585808060200260200160405190810160405280939291908181526020016000905b82821015612ac957612aba604083028601368190038101906150c7565b81526020019060010190612a9d565b505050505083613933565b805160408051602080890282018101909252878152612b33918a91908a908a90819060009085015b82821015612b2857612b19604083028601368190038101906150c7565b81526020019060010190612afc565b505050505085613ad6565b80516005811115612b4657612b46614658565b8351516005811115612b5a57612b5a614658565b141580612b85575080602001516001600160a01b03168360000151602001516001600160a01b031614155b80612b9c5750806040015183600001516040015114155b15612bba576040516309cfb45560e01b815260040160405180910390fd5b82600001516060015181606001511115612c6857600085856000818110612be357612be3614ea7565b905060400201803603810190612bf991906150c7565b905083600001516060015182606001510389826000015181518110612c2057612c20614ea7565b60200260200101516000015160600151826020015181518110612c4557612c45614ea7565b602090810291909101015160609081019190915284518101519083015250612d03565b600087876000818110612c7d57612c7d614ea7565b905060400201803603810190612c9391906150c7565b905081606001518460000151606001510389826000015181518110612cba57612cba614ea7565b60200260200101516000015160400151826020015181518110612cdf57612cdf614ea7565b60200260200101516060018181525050816060015184600001516060018181525050505b60809081015183516001600160a01b039091169101525095945050505050565b8151606090806001600160401b03811115612d4057612d4061400e565b604051908082528060200260200182016040528015612d69578160200160208202803683370190505b50915060005b81811015612e51576000858281518110612d8b57612d8b614ea7565b6020026020010151905080602001516001600160781b0316600003612db05750612e49565b6001848381518110612dc457612dc4614ea7565b91151560209283029190910190910152805160600151805160005b81811015612e44576000838281518110612dfb57612dfb614ea7565b602002602001015160600151905080600014612e3b576040516314bea84160e31b8152600481018790526024810183905260448101829052606401610d94565b50600101612ddf565b505050505b600101612d6f565b5060408051602080825281830190925234916000919060208201818036833701905050855190915060005b81811015612f0f576000878281518110612e9857612e98614ea7565b60209081029190910101518051909150600081516005811115612ebd57612ebd614658565b03612ef1578581606001511115612ee757604051631a783b8d60e01b815260040160405180910390fd5b8060600151860395505b612f058183602001518460400151886132dd565b5050600101612e7c565b50612f198261297e565b8215612f2957612f293384613439565b612f336001600055565b5050505092915050565b612f45613ed5565b8351600003612f69578460405163375c24c160e01b8152600401610d9491906150f3565b6000856001811115612f7d57612f7d614658565b03612fa45780516001600160a01b038316608090910152612f9f868583613ad6565b612fbd565b612faf868583613933565b336020820152604081018390525b8051606001516000036103305760006020820181905281516080015295945050505050565b808210156129a357604051632335530b60e11b815260040160405180910390fd5b6000806000526000825160208403805182604103600060018211613071576040880151606089015160001a9650821561304f57601b8160ff1c0196506001600160ff1b03811660408a01525b8689528985526020600060808760015afa508385528589526040890152506000515b89148915151695508590506131325760408252604486038051604088038051630b135d3f60e11b84528a82526020600060648901868f5afa9850881561312857630b135d3f60e11b60005114613128578b3b156130d957634f7fb80d60e01b60005260046000fd5b60018760410311156130f657638baa579f60e01b60005260046000fd5b640101000000881a61311757630f801e8560e11b6000528760045260246000fd5b632057875960e21b60005260046000fd5b8486529190925290525b50505050806119e557613143613c67565b634f7fb80d60e01b60005260046000fd5b6000428411806131645750428311155b15613190578115613188576040516337bf561360e11b815260040160405180910390fd5b50600061052c565b5060019392505050565b60018360038111156131ae576131ae614658565b1180156131c45750336001600160a01b03821614155b80156131d95750336001600160a01b03831614155b15613270576080880151511580156131f057508651155b156132065761320181868487613caf565b613270565b600061326482633313157060e01b88338d8c8e60405160240161322d9594939291906152b3565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613cfb565b905061155b8187613d10565b5050505050505050565b600083600052602060002060208301835160051b81015b808210156132b957815180841160051b93845260209384185260406000209290910190613291565b505083149050806119e5576040516309bde33960e01b815260040160405180910390fd5b6000845160058111156132f2576132f2614658565b0361334057604084015160208501516001600160a01b0316171561332957604051636ab37ce760e01b815260040160405180910390fd5b61333b84608001518560600151613439565b6119e5565b60018451600581111561335557613355614658565b036133975760408401511561337d57604051636ab37ce760e01b815260040160405180910390fd5b61333b8460200151848660800151876060015186866138d4565b6002845160058111156133ac576133ac614658565b036133d05761333b84602001518486608001518760400151886060015187876127da565b6119e58460200151848660800151876040015188606001518787612827565b600086880361340a576134038686896129a7565b905061342e565b61342b61341887878b6129a7565b61342388888b6129a7565b8686866129e9565b90505b979650505050505050565b613442816138b3565b600080600080600085875af19050806134885761345d613c67565b60405163470c7c1d60e01b81526001600160a01b038416600482015260248101839052604401610d94565b505050565b60186101243510610244356102606102643560400201146004356020146102243561024014161616806134d3576040516339f3e3fd60e01b815260040160405180910390fd5b50565b60018360038111156134ea576134ea614658565b1180156135005750336001600160a01b03821614155b80156135155750336001600160a01b03831614155b156120055761200581868487613caf565b600083815260026020526040902061354184826001806118d1565b50805460ff1661355657613556838584611996565b710100000000000000000000000000000100019055505050565b604080517f000000000000000000000000c8ddac143e4da8337ffdea513ba27bf1d065751860ff60a01b17600090815260208690527f6b68d96d7ecc2eeecd3f60a3b682f13661a0ea7d1c90b397ba07dd3b4d114c1883526055600b20919092526001600160a01b03169050600080600080526020600085876000875af1915060005190508161362657613602613c67565b60405163344f54f560e21b81526001600160a01b0384166004820152602401610d94565b6001600160e01b03198116632671a55160e11b146127d257604051630e7ccd9360e11b8152600481018790526001600160a01b0384166024820152604401610d94565b833b61368457632f8aeb3960e11b6000528360045260246000fd5b6040516323b872dd60e01b6000528360045282602452816044526000806064600080895af18061371e573d156136f8576020601f3d01046020830481600302818311156136df57818303600302610200838002858002030401015b5a6020820110156136f4573d6000803e3d6000fd5b5050505b63f486bc8760e01b60005285600452846024528360445282606452600160845260a46000fd5b50604052505060006060525050565b843b61374857632f8aeb3960e11b6000528460045260246000fd5b60405160805160a05160c051637921219560e11b6000528760045286602452856044528460645260a0608452600060a45260008060c46000808d5af1806137f8573d156137d3576020601f3d01046020860481600302818311156137ba57818303600302610200838002858002030401015b5a6020820110156137cf573d6000803e3d6000fd5b5050505b63f486bc8760e01b600052896004528860245287604452866064528560845260a46000fd5b5060809290925260a05260c05260405250506000606052505050565b6000613821836020015190565b9050818114613488576134888361297e565b6000602088510361386e5750604080885260208089018a9052632671a55160e11b91890191909152604488015260016064880181905261387d565b50606487018051600101908190525b603c60c082028901038781528660208201528560408201528460608201528360808201528260a082015250505050505050505050565b806000036134d35760405163246cf94560e21b815260040160405180910390fd5b6138dd836138b3565b6138e78183613814565b816138fd576138f886868686613d6a565b6127d2565b6127d28282600189898960008a613833565b6064810151604082019060c00260440161392a848383613570565b50506020905250565b61395f565b637fda727960e01b60005260046000fd5b634e487b7160e01b600052601160045260246000fd5b602082018051518451811061397657613976613938565b602081026020860101516060815101516020845101518151811061399c5761399c613938565b602081026020830101516000806020860151156139c3575050606081018051600090915280155b885183518152602084015160208201526040840151604082015260a084015160808201526060812060208c51028c015b808b1015613a9a5760208b019a508a515199508d518a10613a1657613a16613938565b60208a0260208f01015198506020890151156139f357606089510151975060208b510151965087518710613a4c57613a4c613938565b602087026020890101519550606086018051860181511587821060011b1786179550809650506000815250606086208214608084015160a08801511416613a9557613a95613938565b6139f3565b50506060018290528015613ac95760018103613ac15763246cf94560e21b60005260046000fd5b613ac9613949565b5050505050505050505050565b6020820180515184518110613aed57613aed613938565b602081026020860101518051604081015160208551015181518110613b1457613b14613938565b60208102602083010151600080602087015115613b3b575050606081018051600090915280155b8951835181526020840151602082015260408401516040820152865160208c015261012087015160408c015260608120905060208c51028c015b808b1015613c295760208b019a508a515199508d518a10613b9857613b98613938565b60208a0260208f0101519850602089015115613b7557885197506040880151965060208b510151955086518610613bd157613bd1613938565b602086026020880101519450606085018051850181511586821060011b178517945080955050600081525060608520821460408d01516101208a01511460208e01518a51141616613c2457613c24613938565b613b75565b50508160608b5101528015613c595760018103613c515763246cf94560e21b60005260046000fd5b613c59613949565b505050505050505050505050565b3d156116b4576020601f3d01046020604051048160030281831115613c9a57818303600302610200838002858002030401015b5a602082011015613488573d6000803e3d6000fd5b604051602481018490523360448201526001600160a01b038316606482015260848101829052600090613cef9086906303874c7760e21b9060a40161322d565b90506120058185613d10565b6000806000835160208501865afa9392505050565b81613d3957613d1d613c67565b604051633ed4053f60e21b815260048101829052602401610d94565b613d496303874c7760e21b613e73565b156129a357604051633ed4053f60e21b815260048101829052602401610d94565b6040516323b872dd60e01b600052836004528260245281604452602060006064600080895af1803d15601f3d116001600051141617163d15158116613e635780873b151516613e635780613e4e5781613e2d573d15613e07576020601f3d0104602084048160030281831115613dee57818303600302610200838002858002030401015b5a602082011015613e03573d6000803e3d6000fd5b5050505b63f486bc8760e01b60005286600452856024528460445260006064528360845260a46000fd5b639889192360e01b6000528660045285602452846044528360645260846000fd5b632f8aeb3960e11b6000528660045260246000fd5b5050604052505060006060525050565b60008060203d03613e895760206000803e506000515b6001600160e01b031990811692169190911415919050565b6040518060a00160405280613eb4613f18565b81526000602082018190526040820152606080820181905260809091015290565b60408051610100810182526000606082018181526080830182905260a0830182905260c0830182905260e083018290528252602082018190529181019190915290565b60405180610160016040528060006001600160a01b0316815260200160006001600160a01b03168152602001606081526020016060815260200160006003811115613f6557613f65614658565b815260006020820181905260408201819052606082018190526080820181905260a0820181905260c09091015290565b6000815180845260005b81811015613fbb57602081850181015186830182015201613f9f565b81811115613fcd576000602083870101525b50601f01601f19169290920160200192915050565b60208152600061052c6020830184613f95565b60006020828403121561400757600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60405160a081016001600160401b03811182821017156140465761404661400e565b60405290565b60405161016081016001600160401b03811182821017156140465761404661400e565b604051601f8201601f191681016001600160401b03811182821017156140975761409761400e565b604052919050565b60006001600160401b038211156140b8576140b861400e565b5060051b60200190565b6001600160a01b03811681146134d357600080fd5b80356140e2816140c2565b919050565b8035600681106140e257600080fd5b600060a0828403121561410857600080fd5b614110614024565b905061411b826140e7565b8152602082013561412b816140c2565b8060208301525060408201356040820152606082013560608201526080820135608082015292915050565b600082601f83011261416757600080fd5b8135602061417c6141778361409f565b61406f565b82815260a0928302850182019282820191908785111561419b57600080fd5b8387015b858110156141be576141b189826140f6565b845292840192810161419f565b5090979650505050505050565b600060c082840312156141dd57600080fd5b60405160c081018181106001600160401b03821117156141ff576141ff61400e565b60405290508061420e836140e7565b8152602083013561421e816140c2565b8060208301525060408301356040820152606083013560608201526080830135608082015260a0830135614251816140c2565b60a0919091015292915050565b600082601f83011261426f57600080fd5b8135602061427f6141778361409f565b82815260c0928302850182019282820191908785111561429e57600080fd5b8387015b858110156141be576142b489826141cb565b84529284019281016142a2565b8035600481106140e257600080fd5b600061016082840312156142e357600080fd5b6142eb61404c565b90506142f6826140d7565b8152614304602083016140d7565b602082015260408201356001600160401b038082111561432357600080fd5b61432f85838601614156565b6040840152606084013591508082111561434857600080fd5b506143558482850161425e565b606083015250614367608083016142c1565b608082015260a082013560a082015260c082013560c082015260e082013560e082015261010080830135818301525061012080830135818301525061014080830135818301525092915050565b80356001600160781b03811681146140e257600080fd5b600082601f8301126143dc57600080fd5b81356001600160401b038111156143f5576143f561400e565b614408601f8201601f191660200161406f565b81815284602083860101111561441d57600080fd5b816020850160208301376000918101602001919091529392505050565b600060a0828403121561444c57600080fd5b614454614024565b905081356001600160401b038082111561446d57600080fd5b614479858386016142d0565b8352614487602085016143b4565b6020840152614498604085016143b4565b604084015260608401359150808211156144b157600080fd5b6144bd858386016143cb565b606084015260808401359150808211156144d657600080fd5b506144e3848285016143cb565b60808301525092915050565b600082601f83011261450057600080fd5b813560206145106141778361409f565b82815260059290921b8401810191818101908684111561452f57600080fd5b8286015b8481101561456e5780356001600160401b038111156145525760008081fd5b6145608986838b010161443a565b845250918301918301614533565b509695505050505050565b60008083601f84011261458b57600080fd5b5081356001600160401b038111156145a257600080fd5b6020830191508360208260051b85010111156145bd57600080fd5b9250929050565b6000806000806000606086880312156145dc57600080fd5b85356001600160401b03808211156145f357600080fd5b6145ff89838a016144ef565b9650602088013591508082111561461557600080fd5b61462189838a01614579565b9096509450604088013591508082111561463a57600080fd5b5061464788828901614579565b969995985093965092949392505050565b634e487b7160e01b600052602160045260246000fd5b6006811061467e5761467e614658565b9052565b61468d82825161466e565b6020818101516001600160a01b0390811691840191909152604080830151908401526060808301519084015260809182015116910152565b600081518084526020808501945080840160005b8381101561471b5781516146ee888251614682565b808401516001600160a01b031660a08901526040015160c088015260e090960195908201906001016146d9565b509495945050505050565b60208152600061052c60208301846146c5565b60006020828403121561474b57600080fd5b81356001600160401b0381111561476157600080fd5b8201610160818503121561052c57600080fd5b60008060008060008060008060008060e08b8d03121561479357600080fd5b8a356001600160401b03808211156147aa57600080fd5b6147b68e838f016144ef565b9b5060208d01359150808211156147cc57600080fd5b6147d88e838f01614579565b909b50995060408d01359150808211156147f157600080fd5b6147fd8e838f01614579565b909950975060608d013591508082111561481657600080fd5b506148238d828e01614579565b90965094505060808b0135925061483c60a08c016140d7565b915060c08b013590509295989b9194979a5092959850565b604080825283519082018190526000906020906060840190828701845b8281101561488f578151151584529284019290840190600101614871565b505050838103828501526148a381866146c5565b9695505050505050565b600080602083850312156148c057600080fd5b82356001600160401b038111156148d657600080fd5b6148e285828601614579565b90969095509350505050565b6000806000806040858703121561490457600080fd5b84356001600160401b038082111561491b57600080fd5b61492788838901614579565b9096509450602087013591508082111561494057600080fd5b5061494d87828801614579565b95989497509550505050565b6000806040838503121561496c57600080fd5b82356001600160401b0381111561498257600080fd5b83016040818603121561499457600080fd5b946020939093013593505050565b6000806000806000608086880312156149ba57600080fd5b85356001600160401b03808211156149d157600080fd5b9087019060a0828a0312156149e557600080fd5b909550602087013590808211156149fb57600080fd5b50614a0888828901614579565b909550935050604086013591506060860135614a23816140c2565b809150509295509295909350565b60008060008060008060008060a0898b031215614a4d57600080fd5b88356001600160401b0380821115614a6457600080fd5b614a708c838d01614579565b909a50985060208b0135915080821115614a8957600080fd5b614a958c838d01614579565b909850965060408b0135915080821115614aae57600080fd5b50614abb8b828c01614579565b999c989b509699959896976060870135966080013595509350505050565b600060208284031215614aeb57600080fd5b813561052c816140c2565b606081526000614b096060830186613f95565b6020830194909452506001600160a01b0391909116604090910152919050565b600060208284031215614b3b57600080fd5b81356001600160401b03811115614b5157600080fd5b8201610240818503121561052c57600080fd5b6000614b726141778461409f565b83815260208082019190600586811b860136811115614b9057600080fd5b865b81811015614c8b5780356001600160401b0380821115614bb25760008081fd5b818a01915060a08236031215614bc85760008081fd5b614bd0614024565b823581528683013560028110614be65760008081fd5b81880152604083810135908201526060808401359082015260808084013583811115614c125760008081fd5b939093019236601f850112614c2957600092508283fd5b83359250614c396141778461409f565b83815292871b84018801928881019036851115614c565760008081fd5b948901945b84861015614c7457853582529489019490890190614c5b565b918301919091525088525050948301948301614b92565b5092979650505050505050565b6000808335601e19843603018112614caf57600080fd5b8301803591506001600160401b03821115614cc957600080fd5b602001915060a0810236038213156145bd57600080fd5b600060a08284031215614cf257600080fd5b61052c83836140f6565b6000808335601e19843603018112614d1357600080fd5b8301803591506001600160401b03821115614d2d57600080fd5b602001915060c0810236038213156145bd57600080fd5b600060c08284031215614d5657600080fd5b61052c83836141cb565b600060208284031215614d7257600080fd5b61052c826142c1565b60006104d4368361443a565b600060408284031215614d9957600080fd5b604051604081018181106001600160401b0382111715614dbb57614dbb61400e565b604052823581526020928301359281019290925250919050565b6000614de36141778461409f565b80848252602080830192508560051b850136811115614e0157600080fd5b855b81811015614e9b5780356001600160401b03811115614e225760008081fd5b870136601f820112614e345760008081fd5b8035614e426141778261409f565b81815260069190911b82018501908581019036831115614e625760008081fd5b928601925b82841015614e8b57614e793685614d87565b82528682019150604084019350614e67565b8852505050938201938201614e03565b50919695505050505050565b634e487b7160e01b600052603260045260246000fd5b60008235603e19833603018112614ed357600080fd5b9190910192915050565b6000823561015e19833603018112614ed357600080fd5b60006104d436836142d0565b6000808335601e19843603018112614f1757600080fd5b8301803591506001600160401b03821115614f3157600080fd5b6020019150368190038213156145bd57600080fd5b6000808335601e19843603018112614f5d57600080fd5b8301803591506001600160401b03821115614f7757600080fd5b6020019150600681901b36038213156145bd57600080fd5b634e487b7160e01b600052601160045260246000fd5b60008219821115614fb857614fb8614f8f565b500190565b6000816000190483118215151615614fd757614fd7614f8f565b500290565b600081518084526020808501945080840160005b8381101561471b57615003878351614682565b60a0969096019590820190600101614ff0565b60006080808301878452602060018060a01b03808916828701526040848188015283895180865260a089019150848b01955060005b8181101561508c57865161506084825161466e565b80870151861684880152848101518585015260609081015190840152958501959187019160010161504b565b505087810360608901526150a0818a614fdc565b9c9b505050505050505050505050565b6000828210156150c2576150c2614f8f565b500390565b6000604082840312156150d957600080fd5b61052c8383614d87565b6002811061467e5761467e614658565b602081016104d482846150e3565b600081518084526020808501945080840160005b8381101561471b57815161512a88825161466e565b838101516001600160a01b03168885015260408082015190890152606080820151908901526080908101519088015260a09096019590820190600101615115565b600081518084526020808501945080840160005b8381101561471b57815161519488825161466e565b808401516001600160a01b0390811689860152604080830151908a0152606080830151908a0152608080830151908a015260a091820151169088015260c0909601959082019060010161517f565b6004811061467e5761467e614658565b600081518084526020808501945080840160005b8381101561471b57815187529582019590820190600101615206565b600081518084526020808501808196508360051b8101915082860160005b858110156152a6578284038952815160a08151865286820151615265888801826150e3565b506040828101519087015260608083015190870152608091820151918601819052615292818701836151f2565b9a87019a9550505090840190600101615240565b5091979650505050505050565b85815260018060a01b038516602082015260a060408201526000610140855160a0808501526152ed82850182516001600160a01b03169052565b6020810151610160615309818701836001600160a01b03169052565b6040830151915080610180870152506153266102a0860182615101565b9050606082015161013f19868303016101a0870152615345828261516b565b915050608082015161535b6101c08701826151e2565b5060a08201516101e086015260c082015161020086015260e082015161022086015261010080830151610240870152610120808401516102608801528484015161028088015260208a015194506153bd60c08801866001600160781b03169052565b60408a01516001600160781b031660e088015260608a0151878403609f19908101848a015290955093506153f18386613f95565b945060808a01519250838786030181880152505061540f8382613f95565b92505050828103606084015261542581866151f2565b905082810360808401526154398185615222565b9897505050505050505056fea2646970667358221220d9ec6bf53c7c4dd207e9b7af873aae1b86f9ebf0a16709b20f4f94de3560378664736f6c634300080e0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c8ddac143e4da8337ffdea513ba27bf1d0657518
-----Decoded View---------------
Arg [0] : conduitController (address): 0xc8ddac143E4da8337FFDeA513Ba27bF1d0657518
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000c8ddac143e4da8337ffdea513ba27bf1d0657518
Deployed Bytecode Sourcemap
3793:1319:29:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;29062:203:8;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;27490:367;;;;;;;;;;-1:-1:-1;27490:367:8;;;;;:::i;:::-;27615:16;19905:23:26;;;:12;:23;;;;;20014;;;;;;;20052;;;;;;-1:-1:-1;;;;;20090:21:26;;;;;;-1:-1:-1;;;20126:23:26;;;;;27490:367:8;;;;;1145:14:39;;1138:22;1120:41;;1204:14;;1197:22;1192:2;1177:18;;1170:50;1236:18;;;1229:34;1294:2;1279:18;;1272:34;1107:3;1092:19;27490:367:8;901:411:39;22904:506:8;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;25473:190::-;;;;;;;;;;;;;:::i;:::-;;;13363:25:39;;;13351:2;13336:18;25473:190:8;13217:177:39;25856:728:8;;;;;;;;;;-1:-1:-1;25856:728:8;;;;;:::i;:::-;;:::i;17479:938::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;25002:199::-;;;;;;;;;;-1:-1:-1;25002:199:8;;;;;:::i;:::-;;:::i;:::-;;;17344:14:39;;17337:22;17319:41;;17307:2;17292:18;25002:199:8;17179:187:39;19944:489:8;;;;;;:::i;:::-;;:::i;5074:495::-;;;;;;:::i;:::-;;:::i;8311:532::-;;;;;;:::i;:::-;;:::i;11883:926::-;;;;;;:::i;:::-;;:::i;28058:233::-;;;;;;;;;;-1:-1:-1;28058:233:8;;;;;:::i;:::-;;:::i;28605:315::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;3409:283::-;;;;;;:::i;:::-;;:::i;23942:203::-;;;;;;;;;;-1:-1:-1;23942:203:8;;;;;:::i;:::-;;:::i;29062:::-;29146:26;29250:7;:5;:7::i;:::-;29235:22;;29062:203;:::o;22904:506::-;23125:29;23267:135;23306:14;23267:135;23339:17;;23267:135;:::i;:::-;23375:12;;23267:20;:135::i;:::-;23247:155;;22904:506;;;;;;;;:::o;25473:190::-;25528:18;25636:19;:17;:19::i;25856:728::-;26136:401;;;;;;;;;25978:17;;26105:471;;26136:401;26170:13;;;;:5;:13;:::i;:::-;-1:-1:-1;;;;;26136:401:8;;;;;26202:5;:10;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;26136:401:8;;;;;26231:11;;;;:5;:11;:::i;:::-;26136:401;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;26136:401:8;;;-1:-1:-1;;26136:401:8;;26261:19;;;;:5;:19;:::i;:::-;26136:401;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;26136:401:8;;;-1:-1:-1;;26136:401:8;;26299:15;;;;;;;;:::i;:::-;26136:401;;;;;;;;:::i;:::-;;;;;26333:5;:15;;;26136:401;;;;26367:5;:13;;;26136:401;;;;26399:5;:14;;;26136:401;;;;26432:5;:10;;;26136:401;;;;26461:5;:16;;;26136:401;;;;26496:5;:19;;;;;;;;:::i;:::-;26136:401;;;-1:-1:-1;26552:13:8;;;;26105:16;:471::i;:::-;26093:483;25856:728;-1:-1:-1;;25856:728:8:o;17479:938::-;17934:29;;18074:335;18124:14;18074:335;18157:17;;18074:335;:::i;:::-;18193:17;;18229:25;;18273:19;-1:-1:-1;;;;;18311:23:8;;;:48;;18350:9;18311:48;;;18337:10;18311:48;18378:16;18074:31;:335::i;:::-;18054:355;;;;17479:938;;;;;;;;;;;;;:::o;25002:199::-;25099:14;25176:17;25186:6;;25176:9;:17::i;:::-;25164:29;25002:199;-1:-1:-1;;;25002:199:8:o;19944:489::-;20087:29;20229:196;20268:32;20293:6;;20268:24;:32::i;:::-;20319:25;;;20342:1;20319:25;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20319:25:8;;;;;;;;;;;;;;;;;20398:12;;20229:20;:196::i;:::-;20209:216;;19944:489;;;;;;;:::o;5074:495::-;5218:14;5339:222;5386:30;5410:5;5386:23;:30::i;:::-;5431:25;;;5454:1;5431:25;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5431:25:8;;;;;;;;;;;;;;;;;5506:19;5540:10;5339:32;:222::i;8311:532::-;8552:14;8635:200;;8682:13;8635:200;:::i;:::-;;8710:17;;8635:200;:::i;:::-;8742:19;-1:-1:-1;;;;;8776:23:8;;;:48;;8815:9;8635:32;:200::i;8776:48::-;8802:10;8635:32;:200::i;11883:926::-;12232:29;12263;12412:389;12462:32;12487:6;;12462:24;:32::i;:::-;12544:25;;;12567:1;12544:25;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12544:25:8;;;;;;;;;;;;;;;;;12623:17;;12659:25;;12703:19;12741:10;12770:16;12412:31;:389::i;:::-;12392:409;;;;11883:926;;;;;;;;;;;:::o;28058:233::-;-1:-1:-1;;;;;1885:18:15;;28163:15:8;1885:18:15;;;:9;:18;;;;;;28263:20:8;1683:228:15;28605:315:8;28710:21;28746:23;28784:25;28898:14;:12;:14::i;:::-;28891:21;;;;;;28605:315;;;:::o;3409:283::-;3549:14;3643:41;3673:10;3643:29;:41::i;23942:203::-;24047:14;24122:15;24130:6;;24122:7;:15::i;4451:258:29:-;4500:13;4608:4;;4595:18;4640;4634:4;4627:32;4686:4;4608;4673:18;36263:757:24;36466:29;36586:290;36635:14;36664:17;36696:4;36763:14;:21;36807:1;36586:34;:290::i;:::-;36960:52;36983:14;36999:12;;36960:22;:52::i;923:516:15:-;970:18;1068:21;:19;:21::i;:::-;-1:-1:-1;1295:10:15;1285:21;;;;:9;:21;;;;;;;;;1283:23;;;;;;;;;1389:42;;13363:25:39;;;1283:23:15;;1295:10;1389:42;;13336:18:39;1389:42:15;;;;;;;923:516;:::o;1411:7606:22:-;1707:47;;;;2532:21;2526:28;;2666:55;;;2642:94;2804:18;;1542:17;;1707:47;1542:17;;2297:20;;2929:7;2912:25;;;;1542:17;3031:911;3056:11;3053:1;3050:18;3031:911;;;3274:18;;-1:-1:-1;;3270:32:22;3401:10;;3493:21;;;3641;3626:37;;3607:57;;3731:18;;-1:-1:-1;3903:24:22;;;;3846:25;;;;3100:1;3093:9;3031:911;;;3035:14;4132:7;4119:11;4115:25;4074:21;4068:28;4040:115;4027:128;;;;;4258:25;4388:28;4377:39;;4631:21;4625:28;4980:7;4878:41;4836:15;4806:136;4778:183;4756:246;5140:1;5125:1036;5150:27;5147:1;5144:34;5125:1036;;;5392:26;;-1:-1:-1;;5388:40:22;5535:10;;5627:21;;;5818:29;5803:45;;5741:126;;5934:18;;-1:-1:-1;6122:24:22;;;;6057:33;;;;5210:1;5203:9;5125:1036;;;-1:-1:-1;;6309:21:22;6303:28;;6383:7;6350:41;;6275:131;;-1:-1:-1;;6753:29:22;;6894:18;;6521:15;7008:29;;7136:104;;;7348:19;;7454:31;;;7656:41;7600:112;;7836:27;;7958:47;;;8149:30;8093:101;;;8278:27;;;8437:17;8414:41;;8551:34;;;;8680;;;;8812:50;;;;-1:-1:-1;;8952:47:22;;-1:-1:-1;8414:41:22;1411:7606;-1:-1:-1;1411:7606:22:o;5886:1254:24:-;6305:29;6336;6465:233;6514:14;6543:17;6575:5;6647:16;6678:9;6465:34;:233::i;:::-;6823:199;6867:14;6823:199;6896:17;;6823:199;:::i;:::-;;6928:25;;6823:199;:::i;:::-;6968:19;7002:9;6823:29;:199::i;:::-;6791:231;;;;-1:-1:-1;5886:1254:24;-1:-1:-1;;;;;;;;;;5886:1254:24:o;16021:2618:26:-;16101:14;16200:21;:19;:21::i;:::-;16285:31;;;16583:6;16285:31;16654:1857;16678:11;16674:1;:15;16654:1857;;;16752:20;16775:6;;16782:1;16775:9;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;16752:32;-1:-1:-1;16856:40:26;16899:16;16752:32;;16899:16;:::i;:::-;16856:59;-1:-1:-1;17005:23:26;;;;16856:59;17005:23;:::i;:::-;16995:33;-1:-1:-1;17142:98:26;;17206:15;17142:98;:::i;:::-;:41;:98::i;:::-;17351:23;;;;:12;:23;;;;;;-1:-1:-1;17130:110:26;;-1:-1:-1;17472:259:26;;17130:110;;17351:23;;17660:4;17472:18;:259::i;:::-;-1:-1:-1;17824:23:26;;;;17819:571;;17927:53;17944:7;17953:9;17964:15;;;;:5;:15;:::i;:::-;17927:53;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;17927:16:26;;-1:-1:-1;;;17927:53:26:i;:::-;18077:30;;-1:-1:-1;;18077:30:26;18103:4;18077:30;;;18327:20;;;;;;;;:::i;:::-;-1:-1:-1;;;;;18216:154:26;18293:7;-1:-1:-1;;;;;18216:154:26;;18257:9;18216:154;;;;13363:25:39;;13351:2;13336:18;;13217:177;18216:154:26;;;;;;;;17819:571;-1:-1:-1;;18492:3:26;;16654:1857;;;-1:-1:-1;18627:4:26;;16021:2618;-1:-1:-1;;;;;;;16021:2618:26:o;18565:881:25:-;18674:37;18827:6;;-1:-1:-1;;;;;18941:32:25;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;18924:49;;19137:9;19132:213;19156:11;19152:1;:15;19132:213;;;19295:34;19319:6;;19326:1;19319:9;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;19295:23;:34::i;:::-;19275:14;19290:1;19275:17;;;;;;;;:::i;:::-;;;;;;;;;;:54;19169:3;;19132:213;;;;19417:21;18565:881;;;;:::o;17874:393::-;17979:34;;:::i;:::-;18125:134;;;;;;;;;;18153:16;:5;;:16;:::i;:::-;18125:134;;;:::i;:::-;;;;;18184:1;-1:-1:-1;;;;;18125:134:25;;;;;18200:1;-1:-1:-1;;;;;18125:134:25;;;;;18216:5;:15;;;;;;;;:::i;:::-;18125:134;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;18125:134:25;;;-1:-1:-1;;18125:134:25;;;;;;;;;;;;;;;;;-1:-1:-1;18109:150:25;17874:393;-1:-1:-1;;17874:393:25:o;3092:2123::-;3324:4;3419:21;:19;:21::i;:::-;3522:33;3658:17;3690:21;3726:23;3763:170;3811:13;3843:17;3879:4;3902:16;3763:29;:170::i;:::-;4050:22;;;4070:1;4050:22;;;;;;;;;3643:290;;-1:-1:-1;3643:290:25;;-1:-1:-1;3643:290:25;-1:-1:-1;4010:37:25;;4050:22;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;4010:62;;4184:13;4164:14;4179:1;4164:17;;;;;;;;:::i;:::-;;;;;;:33;;;;4290:58;4314:14;4330:17;4290:23;:58::i;:::-;4438:38;4479:14;4494:1;4479:17;;;;;;;;:::i;:::-;;;;;;;:28;;;4438:69;;4599:187;4644:15;4674:13;4702:15;4732:19;4766:9;4599:30;:187::i;:::-;4871:236;4910:9;4934:15;:23;;;4972:15;:20;;;5007:9;5031:15;:21;;;5067:15;:29;;;4871:24;:236::i;:::-;5160:23;2393:1:10;1355:16:28;:31;1262:132;5160:23:25;-1:-1:-1;5203:4:25;;3092:2123;-1:-1:-1;;;;;;;;;;3092:2123:25:o;12363:717:22:-;12451:21;12487:23;12525:25;12637:18;:16;:18::i;:::-;12874:26;;;2315:1:10;12874:26:22;;;;;;;;;12619:36;;-1:-1:-1;12775:19:22;;-1:-1:-1;12874:26:22;;;;;;;;-1:-1:-1;;;;;13024:7:22;13011:21;;13004:58;-1:-1:-1;13011:21:22;12363:717;;-1:-1:-1;12363:717:22;:::o;2941:8691:3:-;3056:4;3546:31;3533:45;3805:1;3801:22;;;;3707:1;3687:22;3963:1;3953:12;;4404:11;4397:19;4321:114;;;4618:95;;4671:26;;-1:-1:-1;;;4671:26:3;;4687:9;4671:26;;;13363:25:39;13336:18;;4671:26:3;;;;;;;;4618:95;3988:736;4817:33;4861:24;4896:40;5039:25;5320:1;5313:5;5310:12;5271:51;;5679:29;5613:35;5579:156;5517:35;5487:271;5452:325;5423:354;;6069:1;6062:5;6059:12;6033:1;6026:5;6023:12;6019:1;6012:5;6008:13;6004:32;5978:112;5958:132;;6508:1;6490:16;6486:24;6424:35;6394:139;6368:1;6337:28;6330:36;6326:44;6319:5;6315:56;6289:263;6270:282;;6665:268;6720:10;6749:9;6777:16;6812:28;6859:25;6903:15;6665:36;:268::i;:::-;-1:-1:-1;7309:31:3;7404:7;7363:49;;7283:148;7252:194;7025:18;7521:28;:47;;;;;;;;:::i;:::-;;7517:4008;;7750:34;;;;;;7696:29;;7750:10;7696:29;:::i;:::-;-1:-1:-1;;;;;7688:96:3;;7687:103;7665:205;;7832:22;;-1:-1:-1;;;7832:22:3;;;;;;;;;;;7665:205;7966:302;8017:15;8051:21;;;;;;;;:::i;:::-;8091:18;;;;;;;;:::i;:::-;8128:10;8157;:26;;;8202:10;:22;;;8243:10;7966:32;:302::i;:::-;8367:174;8409:30;;;;8458:18;;;;;;;;:::i;:::-;8495:31;;;;:10;:31;:::i;:::-;8367:23;:174::i;:::-;7517:4008;;;8976:30;;;14743:4:10;8976:30:3;;;;;;;;;8949:24;;8976:30;;;;;;;;;;-1:-1:-1;;8949:57:3;-1:-1:-1;9118:35:3;9109:5;:44;;;;;;;;:::i;:::-;;9105:2007;;9256:313;9294:21;;;;;;;;:::i;:::-;9338:18;;;;;;;;:::i;:::-;9379:10;9412;:26;;;9461:10;:22;;;9506:10;9539:11;9256:15;:313::i;:::-;9105:2007;;;9604:36;9595:5;:45;;;;;;;;:::i;:::-;;9591:1521;;9743:314;9782:21;;;;;;;;:::i;:::-;9826:18;;;;;;;;:::i;:::-;9867:10;9900;:26;;;9949:10;:22;;;9994:10;10027:11;9743:16;:314::i;9591:1521::-;10092:35;10083:5;:44;;;;;;;;:::i;:::-;;10079:1033;;10230:337;10268:29;;;;:10;:29;:::i;:::-;10320:10;10353:18;;;;;;;;:::i;:::-;10394:10;:34;;;10451:10;:30;;;10504:10;10537:11;10230:15;:337::i;10079:1033::-;10758:338;10797:29;;;;:10;:29;:::i;:::-;10849:10;10882:18;;;;;;;;:::i;:::-;10923:10;:34;;;10980:10;:30;;;11033:10;11066:11;10758:16;:338::i;:::-;11197:190;11241:18;;;;;;;;:::i;:::-;11278:10;11307:35;11361:11;11197:25;:190::i;:::-;11485:28;11501:11;11485:15;:28::i;:::-;8559:2966;7517:4008;11577:23;2393:1:10;1355:16:28;:31;1262:132;11577:23:3;-1:-1:-1;11620:4:3;;2941:8691;-1:-1:-1;;;;;;;;2941:8691:3:o;12704:2468:26:-;12792:14;12891:21;:19;:21::i;:::-;12976:31;;;13269:6;12976:31;13340:1704;13364:11;13360:1;:15;13340:1704;;;13438:30;13471:6;;13478:1;13471:9;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;13438:42;-1:-1:-1;13511:13:26;;;;13438:42;13511:13;:::i;:::-;13501:23;-1:-1:-1;13550:10:26;;;;;;;;:::i;:::-;13543:17;-1:-1:-1;13659:10:26;-1:-1:-1;;;;;13659:21:26;;;;;;:43;;-1:-1:-1;13684:10:26;-1:-1:-1;;;;;13684:18:26;;;;13659:43;13655:117;;;13734:18;;-1:-1:-1;;;13734:18:26;;;;;;;;;;;13655:117;13874:17;13894:579;13933:485;;;;;;;;13975:7;-1:-1:-1;;;;;13933:485:26;;;;;14009:4;-1:-1:-1;;;;;13933:485:26;;;;;14040:5;:11;;;;;;;;:::i;:::-;13933:485;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;13933:485:26;;;-1:-1:-1;;13933:485:26;;14078:19;;;;:5;:19;:::i;:::-;13933:485;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;13894:579;14584:23;;;;:12;:23;;;;;;;14700:31;;-1:-1:-1;;14750:30:26;14700:31;14750:30;;;14886:40;;14584:23;;-1:-1:-1;13874:599:26;;-1:-1:-1;;;;;;14886:40:26;;;;;;;;;;;;13874:599;13363:25:39;;13351:2;13336:18;;13217:177;14886:40:26;;;;;;;;-1:-1:-1;;15025:3:26;;13340:1704;;8547:11933:24;8892:21;:19;:21::i;:::-;9012;;8990:19;9012:21;-1:-1:-1;;;;;9142:26:24;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;9142:26:24;-1:-1:-1;9306:1:24;9286:22;;;9111:57;;-1:-1:-1;10558:31:24;10327:29;10284:15;;10262:20;10258:42;10228:151;10122:486;10102:1;10080:543;;10792:8052;10816:11;10812:1;:15;10792:8052;;;10901:34;10938:14;10953:1;10938:17;;;;;;;;:::i;:::-;;;;;;;10901:54;;11060:16;11080:1;11060:21;11056:466;;11214:1;11188:23;;;;:27;11371:1;11364:9;;11344:30;;11494:8;;11056:466;11645:17;11685;11725:19;11766:216;11822:13;11862:17;11906:15;11948:11;11766:29;:216::i;:::-;11622:360;;;;;;12126:1;12123;12119:9;12106:11;12099:30;12254:9;12267:1;12254:14;12250:278;;-1:-1:-1;;12401:1:24;12375:23;;;;:27;;;;-1:-1:-1;12500:8:24;;12250:278;12630:9;12613:11;12625:1;12613:14;;;;;;;;:::i;:::-;;;;;;;;;;:26;12970:24;;:34;;;;13110:32;;;;13267:30;;;;;13415:12;;-1:-1:-1;;12842:18:24;;;;12970:34;;13110:32;12950:17;13511:2033;13535:15;13531:1;:19;13511:2033;;;13629:26;13658:5;13664:1;13658:8;;;;;;;;:::i;:::-;;;;;;;13629:37;;14020:9;14014:16;14007:24;13943:33;13910:148;13873:185;;14181:17;14201:155;14240:9;14276:11;14314:9;:19;;;14201:12;:155::i;:::-;14181:175;;14490:9;:19;;;14465:9;:21;;;:44;14461:549;;14617:21;;;:33;;;14461:549;;;14813:173;14856:9;14896:11;14938:9;:21;;;14813:12;:173::i;:::-;14789:21;;;:197;14461:549;15115:19;;;:31;;;15318:21;;;;15271:253;;15137:9;15412;15448:7;15482:5;15271:20;:253::i;:::-;15247:21;;;;:277;;;;-1:-1:-1;13552:3:24;;13511:2033;;;-1:-1:-1;15711:24:24;;:38;;;15902:20;;15645:40;16014:2815;16038:23;16034:1;:27;16014:2815;;;16148:42;16220:13;16234:1;16220:16;;;;;;;;:::i;:::-;;;;;;;16148:111;;16357:17;16377:163;16416:9;16452:11;16490:17;:27;;;16377:12;:163::i;:::-;16357:183;;16733:17;:27;;;16675:17;:29;;;:85;16645:659;;16890:29;;;:41;;;16645:659;;;17099:181;17142:9;17182:11;17224:17;:29;;;17099:12;:181::i;:::-;17067:29;;;:213;16645:659;17409:27;;;:39;;;17665:29;;;;17614:290;;17439:9;17783;17823:7;17861:4;17614:20;:290::i;:::-;17555:29;;;:372;-1:-1:-1;18660:34:24;18562:167;;18522:238;18414:29;18324:167;;;18287:500;16063:3;;16014:2815;;;;10834:8010;;;;;;;;;;10792:8052;10829:3;;10792:8052;;;;19191:33;19228:1;19191:38;19187:102;;19253:24;;-1:-1:-1;;;19253:24:24;;;;;;;;;;;19187:102;19367:58;19391:14;19407:17;19367:23;:58::i;:::-;19669:9;19664:798;19688:11;19684:1;:15;19664:798;;;19825:1;19817:10;;19799:11;19811:1;19799:14;;;;;;;;:::i;:::-;;;;;;;:28;19795:85;19852:8;19795:85;19967:38;20031:14;20046:1;20031:17;;;;;;;;:::i;:::-;;;;;;;:28;;;19967:111;;20149:297;20196:11;20208:1;20196:14;;;;;;;;:::i;:::-;;;;;;;20233:15;:23;;;20279:15;:20;;;20322:9;20354:15;:21;;;20398:15;:29;;;20149:24;:297::i;:::-;19706:756;19664:798;19701:3;;19664:798;;;;8803:11677;;;8547:11933;;;;;:::o;37953:2312::-;38104:29;38245:12;;-1:-1:-1;;;;;38371:34:24;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;38358:47;;38576:31;38680:9;38675:959;38699:17;38695:1;:21;38675:959;;;38801:32;38836:12;;38849:1;38836:15;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;38801:50;-1:-1:-1;38949:26:24;38978:181;39018:14;39055:27;38801:50;;39055:27;:::i;:::-;39105:35;;;;:11;:35;:::i;:::-;38978:17;:181::i;:::-;38949:210;;39290:9;:17;;;-1:-1:-1;;;;;39262:45:24;:9;:14;;;:24;;;-1:-1:-1;;;;;39262:45:24;;39258:361;;39393:25;;;;;39258:361;;;39590:9;39548:10;39563:23;39559:1;:27;39548:39;;;;;;;;:::i;:::-;;;;;;:51;;;;39258:361;-1:-1:-1;;38718:3:24;;38675:959;;;-1:-1:-1;39721:28:24;;39717:328;;39964:23;39951:10;39945:17;39941:47;39904:10;39871:140;39717:328;38498:1558;40121:63;40157:14;40173:10;40121:35;:63::i;:::-;;40238:19;37953:2312;;;;;:::o;1550:220:28:-;2393:1:10;1677:16:28;;:32;1673:90;;1733:18;;-1:-1:-1;;;1733:18:28;;;;;;;;;;;1673:90;1550:220::o;24017:4349:24:-;24532:24;;24707:32;;24341:29;;;;24886:55;24707:32;24532:24;24886:55;:::i;:::-;-1:-1:-1;;;;;24856:96:24;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;24843:109;;25123:31;25233:9;25228:1073;25252:22;25248:1;:26;25228:1073;;;25376:40;25442:17;25460:1;25442:20;;;;;;;;:::i;:::-;;;;;;;25376:105;;25582:26;25611:215;25653:14;25690:10;25723;25756:19;25798:9;25611:19;:215::i;:::-;25582:244;;25957:9;:17;;;-1:-1:-1;;;;;25929:45:24;:9;:14;;;:24;;;-1:-1:-1;;;;;25929:45:24;;25925:361;;26060:25;;;;;25925:361;;;26257:9;26215:10;26230:23;26226:1;:27;26215:39;;;;;;;;:::i;:::-;;;;;;:51;;;;25925:361;-1:-1:-1;;25276:3:24;;25228:1073;;;;26383:9;26378:1185;26402:30;26398:1;:34;26378:1185;;;26538:40;26604:25;26630:1;26604:28;;;;;;;;:::i;:::-;;;;;;;26538:113;;26752:26;26781:234;26823:14;26860:18;26901:10;26934:19;26984:1;26781:19;:234::i;:::-;26752:263;;27146:9;:17;;;-1:-1:-1;;;;;27118:45:24;:9;:14;;;:24;;;-1:-1:-1;;;;;27118:45:24;;27114:434;;27249:25;;;;;27114:434;;;27519:9;27404:10;27470:23;27445:22;27441:1;:26;:52;27404:112;;;;;;;;:::i;:::-;;;;;;:124;;;;27114:434;-1:-1:-1;;26434:3:24;;26378:1185;;;-1:-1:-1;27650:28:24;;27646:328;;27893:23;27880:10;27874:17;27870:47;27833:10;27800:140;27646:328;25045:2940;28048:10;:17;28069:1;28048:22;28044:90;;28094:28;;-1:-1:-1;;;28094:28:24;;;;;;;;;;;28044:90;28209:100;28259:14;28288:10;28209:35;:100::i;:::-;28191:118;;28322:36;;24017:4349;;;;;;;;:::o;1635:663:2:-;1765:7;1867:190;1948:15;:29;;;:36;1999:15;:47;;;1867:66;:190::i;:::-;2251:23;;-1:-1:-1;;;;;1885:18:15;2251:23:2;1885:18:15;;;:9;:18;;;;;;2170:120:2;;2205:15;;2170:16;:120::i;4095:1637:35:-;4370:23;;4285:10;;4370:23;;;;;4366:309;;;4488:15;4484:90;;;4531:27;;-1:-1:-1;;;4531:27:35;;;;;13363:25:39;;;13336:18;;4531:27:35;13217:177:39;4484:90:35;-1:-1:-1;4658:5:35;4651:12;;4366:309;4791:21;;;;;-1:-1:-1;;;;;4791:21:35;4880:25;;4876:770;;5007:15;5003:632;;;5131:31;;-1:-1:-1;;;5131:31:35;;;;;13363:25:39;;;13336:18;;5131:31:35;13217:177:39;5003:632:35;5300:23;;-1:-1:-1;;;5300:23:35;;-1:-1:-1;;;;;5300:23:35;5276:47;;5272:363;;5426:15;5422:100;;;5473:29;;-1:-1:-1;;;5473:29:35;;;;;13363:25:39;;;13336:18;;5473:29:35;13217:177:39;5422:100:35;5614:5;5607:12;;;;;5272:363;-1:-1:-1;5720:4:35;;4095:1637;-1:-1:-1;;;;;4095:1637:35:o;2710:584::-;2940:10;-1:-1:-1;;;;;2929:21:35;;;2925:60;;2710:584;;;:::o;2925:60::-;3078:14;3095:50;3115:18;:16;:18::i;:::-;-1:-1:-1;;;13507:13:22;13699:25;;;13827:29;13820:54;;;;14185:23;14178:42;;;14311:25;14298:39;;14419:34;;;14298:39;13384:1087;3095:50:35;3078:67;;3237:49;3259:7;3268:6;3276:9;3237:21;:49::i;:::-;2844:450;2710:584;;;:::o;936:223:28:-;1052:21;:19;:21::i;:::-;2425:1:10;1124:16:28;:27;936:223::o;4449:7719:26:-;4719:17;4751:20;4786:22;4887:38;4928:13;:24;;;4887:65;;5066:146;5096:15;:25;;;5140:15;:23;;;5182:15;5066:11;:146::i;:::-;5047:311;;-1:-1:-1;5337:1:26;;-1:-1:-1;5337:1:26;;-1:-1:-1;5337:1:26;;-1:-1:-1;5321:25:26;;5047:311;5477:23;;;;5542:25;;;;-1:-1:-1;;;;;5469:32:26;;;;5534:34;5659:23;;;;:41;;-1:-1:-1;5686:14:26;;5659:41;5655:94;;;5724:13;;-1:-1:-1;;;5724:13:26;;;;;;;;;;;5655:94;5873:11;5861:9;:23;:94;;;;-1:-1:-1;5929:25:26;;;;21022:1;21007:17;21000:25;5901:54;5843:268;;;6067:32;;-1:-1:-1;;;6067:32:26;;;;;;;;;;;5843:268;6217:58;6259:15;6217:41;:58::i;:::-;6205:70;;6370:316;6423:13;6451:17;6483:16;6514:9;6538:15;:24;;;6577:15;:25;;;6617:15;:23;;;6655:15;:20;;;6370:38;:316::i;:::-;6767:31;6801:23;;;:12;:23;;;;;;6915:194;;6814:9;;6801:23;;7079:15;6915:18;:194::i;:::-;6896:358;;-1:-1:-1;7237:1:26;;-1:-1:-1;7237:1:26;;-1:-1:-1;7218:24:26;;-1:-1:-1;;;7218:24:26;6896:358;7353:23;;;;7348:200;;7393:143;7428:15;:23;;;7470:9;7498:13;:23;;;7393:16;:143::i;:::-;7668:21;;-1:-1:-1;;;;;7668:21:26;;;;;;-1:-1:-1;;;7728:23:26;;;7876:22;;7872:4153;;8001:11;8016:1;8001:16;7997:681;;8130:17;8118:29;;8180:17;8166:31;;7997:681;;;8336:11;8315:17;:32;8311:367;;8449:30;8468:11;8449:30;;:::i;:::-;;-1:-1:-1;8581:30:26;8594:17;8581:30;;:::i;:::-;;-1:-1:-1;8630:32:26;8645:17;8630:32;;:::i;:::-;;;8311:367;8810:11;8780:27;8798:9;8780:15;:27;:::i;:::-;:41;8776:335;;;9061:15;9047:11;:29;9035:41;;8776:335;9196:28;9215:9;9196:28;;:::i;:::-;;;-1:-1:-1;;;;;9515:11:26;9512:27;-1:-1:-1;;;;;9461:15:26;9458:31;9433:125;9430:1835;;;9664:337;;;9688:3;9719:224;9754:2;9719:224;;;9867:11;;;;;9829:2;9719:224;;;-1:-1:-1;9976:2:26;9664:337;-1:-1:-1;9664:337:26:o;:::-;10040:122;10106:33;10127:11;10110:15;10106:33;:::i;:::-;10070:9;10040:122;:::i;:::-;10287:17;;10272:33;10407:29;;;;;10549:31;;;;;10477:35;;;;-1:-1:-1;;;;;10702:31:26;;;10760:27;;;10673:137;10670:576;;;-1:-1:-1;;;10906:1:26;10899:32;11068:16;11048:18;11041:44;11204:18;11201:1;11194:29;10670:576;11483:30;;-1:-1:-1;;;;;11649:46:26;;;-1:-1:-1;;;11649:46:26;-1:-1:-1;;;;;11582:48:26;;;;;-1:-1:-1;;;;;;11582:48:26;;;;;;;11509:4;11582:48;11649:46;;;;7872:4153;;;11819:30;;-1:-1:-1;;;;;11967:46:26;;;-1:-1:-1;;;11967:46:26;-1:-1:-1;;;;;11910:42:26;;;;;-1:-1:-1;;;;;;11910:42:26;;;;;;;11845:4;11910:42;11967:46;;;;7872:4153;-1:-1:-1;12137:9:26;;-1:-1:-1;12148:11:26;;-1:-1:-1;;;;4449:7719:26;;;;;;;;;:::o;1566:7616:16:-;1951:24;;2090:21;;1918:30;2181:5128;2205:22;2201:1;:26;2181:5128;;;2305:40;2371:17;2389:1;2371:20;;;;;;;;:::i;:::-;;;;;;;2305:105;;2511:18;2532:16;:27;;;2511:48;;2659:19;2645:10;:33;2641:122;;2710:33;;-1:-1:-1;;;2710:33:16;;;;;;;;;;;2641:122;2860:14;2875:10;2860:26;;;;;;;;:::i;:::-;;;;;;;:36;;;-1:-1:-1;;;;;2860:41:16;2900:1;2860:41;2856:98;;2926:8;;;;2856:98;3033:38;3097:14;3112:10;3097:26;;;;;;;;:::i;:::-;;;;;;;;;;;:37;3279:22;;;;3097:37;;-1:-1:-1;3097:37:16;;;3548:16;:21;;;:35;;;;;;;;:::i;:::-;;3544:3087;;3679:21;;;;3816:12;;3798:30;;3794:127;;3864:33;;-1:-1:-1;;;3864:33:16;;;;;;;;;;;3794:127;4019:26;4048:5;4054:14;4048:21;;;;;;;;:::i;:::-;;;;;;;;;;;4187:18;;4251:30;;;;4187:18;;-1:-1:-1;4251:30:16;-1:-1:-1;4048:21:16;-1:-1:-1;4657:1:16;4644:15;;4641:1;4637:23;4048:21;4637:23;4705:32;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;4876:53:16;;;;4843:30;;;;:86;-1:-1:-1;3544:3087:16;;;5128:29;;;;5296:20;;5278:38;;5274:143;;5352:41;;-1:-1:-1;;;5352:41:16;;;;;;;;;;;5274:143;5521:42;5593:13;5607:14;5593:29;;;;;;;;:::i;:::-;;;;;;;;;;;5763:26;;5862:38;;;;5763:26;;-1:-1:-1;5862:38:16;-1:-1:-1;5593:29:16;-1:-1:-1;6299:1:16;6286:15;;6283:1;6279:23;5593:29;6279:23;6347:40;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;6561:27:16;;;;6493:38;;;;:118;-1:-1:-1;3544:3087:16;6733:29;6753:8;9961:1;-1:-1:-1;9948:15:16;9694:287;6733:29;6728:113;;6794:27;;-1:-1:-1;;;6794:27:16;;;;;;;;;;;6728:113;6940:34;;6936:358;;7081:193;7120:16;:27;;;7174:20;7221:16;:30;;;7081:12;:193::i;:::-;2234:5075;;;;;;2181:5128;2229:3;;2181:5128;;;;7380:9;7375:1789;7399:19;7395:1;:23;7375:1789;;;7493:34;7530:14;7545:1;7530:17;;;;;;;;:::i;:::-;;;;;;;7493:54;;7645:13;:23;;;-1:-1:-1;;;;;7645:28:16;7672:1;7645:28;7641:85;;7698:8;;;7641:85;7869:24;;8032:29;;;;:36;7805:38;8160:423;8184:10;8180:1;:14;8160:423;;;8331:118;8381:15;:29;;;8411:1;8381:32;;;;;;;;:::i;:::-;;;;;;;:41;;;9961:1;-1:-1:-1;9948:15:16;9694:287;8331:118;8301:263;;;8507:33;;-1:-1:-1;;;;;;8507:33:16;;;;;;;;;;;8301:263;8196:3;;8160:423;;;-1:-1:-1;;8686:21:16;;;;:28;8803:9;8798:351;8822:10;8818:1;:14;8798:351;;;8969:54;8989:15;:21;;;9011:1;8989:24;;;;;;;;:::i;8969:54::-;8939:191;;;9081:25;;-1:-1:-1;;;9081:25:16;;;;;;;;;;;8939:191;8834:3;;8798:351;;;;7425:1739;;;7375:1789;7420:3;;7375:1789;;;;1813:7362;;1566:7616;;:::o;6186:9859:25:-;6527:25;;;;6581:23;;;;6999:30;;;14743:4:10;6999:30:25;;;;;;;;;6507:17;;6999:30;;;;;;;;-1:-1:-1;;;9170:21:25;;;;:28;6972:57;;-1:-1:-1;8761:9:25;;9144:23;9346:1908;9370:15;9366:1;:19;9346:1908;;;9456:26;9485:15;:21;;;9507:1;9485:24;;;;;;;;:::i;:::-;;;;;;;9456:53;;9684:15;9662:37;;;;;;;;:::i;:::-;:18;;:37;;;;;;;;:::i;:::-;;9658:117;;9731:24;;-1:-1:-1;;;9731:24:25;;;;;;;;;;;9658:117;9980:14;9997:307;10038:9;:21;;;10086:9;:19;;;10132:9;10168:11;10206:9;10242:7;10276:5;9997:14;:307::i;:::-;10579:26;10564:42;;10527:143;-1:-1:-1;10808:29:25;10793:45;;10756:149;;;11113:23;;11159:26;;;;11040:198;;10568:9;;11208:11;11040:198;;;:::i;:::-;-1:-1:-1;9387:3:25;;9346:1908;;;-1:-1:-1;;;13149:47:25;;;;:72;11367:9;;12719;;11342:22;13382:2314;13406:23;13402:1;:27;13382:2314;;;13508:42;13576:15;:29;;;13606:1;13576:32;;;;;;;;:::i;:::-;;;;;;;13508:119;;13730:14;13747:290;13784:17;:29;;;13836:17;:27;;;13886:9;13918:11;13952:9;13984:7;14014:4;13747:14;:290::i;:::-;14308:26;14285:50;;14252:139;;;14730:34;14640:155;;14604:218;14547:29;14524:53;;14491:354;13730:307;-1:-1:-1;;14969:26:25;;:45;;;;;;;;:::i;:::-;;14965:419;;15134:14;15125:6;:23;15121:114;;;15184:27;;-1:-1:-1;;;15184:27:25;;;;;;;;;;;15121:114;15358:6;15340:24;;;;14965:419;15486:194;15535:17;15575:10;15608:19;15650:11;15486:26;:194;;:::i;:::-;-1:-1:-1;;13431:3:25;;13382:2314;;;;12198:3509;;15800:28;15816:11;15800:15;:28::i;:::-;15900:19;;15896:142;;15977:49;15998:10;16011:14;15977:12;:49::i;16704:884::-;17026:29;17104:5;17090:19;;17213:35;17300:13;17283:30;;17488:4;-1:-1:-1;;;;;17413:167:25;17466:7;-1:-1:-1;;;;;17413:167:25;;17442:9;17507;17531:10;17556:13;17413:167;;;;;;;;;:::i;:::-;;;;;;;;16945:643;;16704:884;;;;;;:::o;11800:213:22:-;11851:7;11923:9;11906:13;:26;:99;;11981:24;2816:193:9;;;2845:24;2816:193;;;43935:25:39;2888:10:9;43976:18:39;;;43969:34;;;;2917:13:9;44019:18:39;;;44012:34;2949:13:9;44062:18:39;;;44055:34;2989:4:9;44105:19:39;;;44098:61;2737:7:9;;43907:19:39;;2816:193:9;;;;;;;;;;;;2792:228;;;;;;2785:235;;2680:348;;11906:99:22;-1:-1:-1;11948:17:22;;11800:213::o;13520:25582:3:-;13915:21;:19;:21::i;:::-;14031:59;14043:10;:20;;;14065:10;:18;;;14085:4;14031:11;:59::i;:::-;;14448:34;:32;:34::i;:::-;14577:189;14658:31;;;;:10;:31;:::i;:::-;:38;;14711:10;:44;;;14577:66;:189::i;:::-;14833:17;15989:16;16008:28;15989:47;;16519:8;16476:41;16469:59;16639:16;16575:41;16546:128;17139:10;17081:35;17020:38;16985:183;17540:8;17481:36;17416:42;17381:186;17920:29;17852:41;17816:156;17754:39;17725:266;18345:44;18310:98;18693:7;18666:25;18662:39;18593:46;18567:153;19174:1;19076:44;19033:114;19003:195;18956:24;18927:290;19466:7;19419:24;19393:99;19365:127;;19622:16;19596:24;19589:50;19976:9;19918:35;19875:19;19849:24;19845:50;19810:194;20830:39;21207:28;21143:41;21114:140;21362:25;21301:38;21272:134;21476:1;21431:43;21424:54;21675:50;21640:104;21611:133;;21771:1;21826:3444;21839:25;21836:1;21833:32;21826:3444;;;22314:1;22287:25;22283:33;22214:42;22184:155;22636:7;22585:24;22514:44;22475:191;22973:25;22922:24;22853:42;22814:207;23309:7;23260:22;23230:109;23204:135;;23696:29;23624:41;23584:168;23535:22;23502:273;24339:17;24288:24;24258:121;24230:149;;24554:28;24503:24;24470:135;24808:25;24773:7;24747:24;24743:38;24710:146;25220:8;25169:24;25089:26;25034:24;25000:142;24961:290;-1:-1:-1;21901:1:3;21894:9;21826:3444;;;25936:7;25932:1;25905:25;25901:33;25897:47;25831:39;25795:172;25751:21;25722:264;26479:44;26444:98;26415:127;;26596:1760;26609:25;26606:1;26603:32;26596:1760;;;26954:1;26927:25;26923:33;26854:42;26824:155;26792:187;;27425:17;27374:24;27344:121;27316:149;;27640:28;27589:24;27556:135;27894:25;27859:7;27833:24;27829:38;27796:146;28306:8;28255:24;28175:26;28120:24;28086:142;28047:290;26671:1;26664:9;26596:1760;;;26600:2;;;;16186:12185;28881:16;28900:20;28881:39;;29247:8;29212:33;29205:51;29379:15;29344:33;29337:58;29901:10;29851:27;29798:30;29763:167;30198:7;30147:28;30090:34;30055:169;30534:21;30474:33;30438:140;30414:1;30385:212;30925:7;30922:1;30912:21;30878:32;30871:63;31364:7;31266:44;31223:114;31193:201;31132:38;31106:307;31525:1;31499:24;31492:35;31654:15;31644:7;31618:24;31614:38;31607:63;32056:10;32006:27;31957:25;31931:24;31927:56;31892:193;-1:-1:-1;;33241:24:3;33228:38;-1:-1:-1;;;;;1885:18:15;;33159:15:3;1885:18:15;;;:9;:18;;;;;;33525:15:3;33650:29;33643:47;;;33377:38;;-1:-1:-1;33959:8:3;33912:24;33861:28;33826:160;34183:21;34177:28;34114:40;34085:139;34353:9;34321:30;34314:49;34645:9;34596:26;34543:30;34508:165;34810:7;34780:28;34773:45;34986:17;34934:29;34902:120;34889:133;;33566:1471;;;36495:7;36427:44;36414:58;36388:133;36344:25;36322:214;36650:9;36636:12;36629:31;36817:8;36783:31;36769:12;36765:50;36758:68;37060:32;37008;36994:12;36990:51;36922:185;37270:40;37210;37196:12;37192:59;37121:204;37753:17;37685:44;37672:58;37646:143;37604:23;37582:222;38476:21;38463:35;38363:24;38350:38;38250:23;38160:8;38068:12;37980:533;;;38585:1;38575:8;38568:19;38690:191;38740:9;38764:10;:19;;;38798:9;38822:10;:18;;;;;;;;;;:::i;:::-;38855:15;;;;;;;;:::i;:::-;38690:35;:191::i;:::-;38957:137;39006:9;39030:18;;;;;;;;:::i;:::-;39063:20;;;;:10;:20;:::i;:::-;38957:137;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;38957:34:3;;-1:-1:-1;;;38957:137:3:i;:::-;13826:25276;13520:25582;;;;;;:::o;4890:3612:19:-;5214:24;;5210:3285;;5336:22;5578:21;5572:28;5554:46;;-1:-1:-1;;;5698:14:19;5691:49;6025:35;5937:42;5896:14;5866:136;5837:242;6364:38;6276:42;6235:14;6205:136;6176:245;6601:8;6541:36;6525:14;6521:57;6492:136;6801:5;6744:33;6728:14;6724:54;6695:130;7007:4;6951:32;6935:14;6931:53;6902:128;7170:2;7137:30;7121:14;7117:51;7110:63;7362:10;7300:38;7284:14;7280:59;7251:140;7575:6;7517:34;7501:14;7497:55;7468:132;7680:142;7723:10;7752:14;14620:5:10;7680:24:19;:142::i;:::-;5240:2594;5210:3285;;;7949:15;7937:8;:27;;;;;;;;:::i;:::-;;7933:551;;8064:6;8074:1;8064:11;8060:96;;8107:29;;-1:-1:-1;;;8107:29:19;;;;;;;;;;;8060:96;8246:51;8269:5;8276:4;8282:2;8286:10;8246:22;:51::i;:::-;7933:551;;;8408:60;8432:5;8439:4;8445:2;8449:10;8461:6;8408:23;:60::i;39633:2296:3:-;39899:9;40036:20;39874:22;40230:1068;40254:25;40250:1;:29;40230:1068;;;40360:48;40434:20;;40455:1;40434:23;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;;40614:26:3;;40728:42;;;40724:125;;;40802:27;;-1:-1:-1;;;40802:27:3;;;;;;;;;;;40724:125;40933:131;40968:29;;;;;;;;:::i;:::-;41020:25;40933:12;:131::i;:::-;41239:43;;;;-1:-1:-1;40281:3:3;;40230:1068;;;;41395:14;41386:6;:23;41382:90;;;41433:27;;-1:-1:-1;;;41433:27:3;;;;;;;;;;;41382:90;41527:24;41540:2;41544:6;41527:12;:24::i;:::-;41660:6;41643:14;:23;41639:283;;;41837:58;41858:10;41888:6;41871:14;:23;41837:12;:58::i;:::-;39798:2131;;39633:2296;;;;:::o;12478:1126:19:-;12782:59;12817:11;12830:10;12782:34;:59::i;:::-;12906:10;12902:695;;13022:6;13032:1;13022:11;13018:88;;13061:29;;-1:-1:-1;;;13061:29:19;;;;;;;;;;;13018:88;13188:51;13211:5;13218:4;13224:2;13228:10;13188:22;:51::i;12902:695::-;13341:244;13367:10;13396:11;13426:22;13467:5;13491:4;13514:2;13535:10;13564:6;13341:7;:244::i;14590:1060::-;14886:28;14907:6;14886:20;:28::i;:::-;14993:59;15028:11;15041:10;14993:34;:59::i;:::-;15117:10;15113:530;;15224:60;15248:5;15255:4;15261:2;15265:10;15277:6;15224:23;:60::i;15113:530::-;15386:245;15412:10;15441:11;15471:23;15513:5;15537:4;15560:2;15581:10;15610:6;15386:7;:245::i;42486:3610:3:-;42762:12;42785:10;42888:13;42912:14;43107:18;43227:11;43223:833;;;43340:7;;-1:-1:-1;43371:10:3;;-1:-1:-1;43491:21:3;;;;;;;;:::i;:::-;43483:29;-1:-1:-1;;;43598:22:3;;;;43544:26;;;;43223:833;;;43742:10;;-1:-1:-1;43776:7:3;;-1:-1:-1;43887:29:3;;;;:10;:29;:::i;:::-;43879:37;-1:-1:-1;;;44010:30:3;;;;43948:34;;;;43223:833;44131:15;;44127:85;;44174:22;;-1:-1:-1;;;44174:22:3;;;;;;;;;;;44127:85;-1:-1:-1;44650:7:3;44633:25;;44577:33;44551:126;44520:172;44293:18;44845:31;;;;:10;:31;:::i;:::-;:38;;44794:100;;44964:9;44959:971;44983:25;44979:1;:29;44959:971;;;45078:48;45148:31;;;;:10;:31;:::i;:::-;45180:1;45148:34;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;;45250:26:3;;45369:87;;;;45405:35;45415:25;45405:35;;:::i;:::-;;;45369:87;45550:227;45583:5;45607:4;45630:29;;;;;;;;:::i;:::-;45678:25;45722:10;45751:11;45550:14;:227::i;:::-;-1:-1:-1;;45900:3:3;;44959:971;;;;46024:64;46039:5;46046:4;46052:2;46056:6;46064:10;46076:11;46024:14;:64::i;:::-;42676:3420;;;;;;42486:3610;;;;:::o;17259:448:19:-;14786:4:10;17386:11:19;:18;:38;17382:77;;17259:448;:::o;17382:77::-;17538:29;17570:38;17596:11;22395:26;22378:44;22354:83;;22080:375;17570:38;17538:70;;17655:44;17664:21;17687:11;17655:8;:44::i;:::-;17319:388;17259:448;:::o;4789:1187:1:-;4923:16;5043:11;5030:9;:24;5026:69;;-1:-1:-1;5078:5:1;5071:12;;5026:69;5445:11;5434:9;5427:5;5420:37;5417:171;;;-1:-1:-1;;;5484:1:1;5477:42;5547:25;5544:1;5537:36;5417:171;5690:27;5720:17;5728:9;5720:5;:17;:::i;:::-;5921:37;;;;;4789:1187;-1:-1:-1;;;;4789:1187:1:o;1638:2326::-;1833:14;1956:9;1941:11;:24;1937:1923;;2358:19;;;2490:15;:27;;;2632:18;;;2061:16;2836:19;2490:27;2836:9;:19;:::i;:::-;2791:23;2805:9;2791:11;:23;:::i;:::-;2790:66;;;;:::i;:::-;2759:98;;3712:7;3676:8;3666:7;3645:19;3641:33;3637:48;3607:135;3256:19;3249:27;3242:35;3216:545;3206:555;;3835:13;;;;;;1937:1923;-1:-1:-1;3947:9:1;;1638:2326;-1:-1:-1;;;;1638:2326:1:o;1726:3902:21:-;1955:26;;:::i;:::-;2091:27;;;:66;;-1:-1:-1;2122:35:21;;2091:66;2073:174;;;2191:44;;-1:-1:-1;;;2191:44:21;;;;;;;;;;;2073:174;2303:39;;:::i;:::-;2433:159;2492:14;2521:23;;2433:159;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;2559:22;2433:44;:159::i;:::-;2716:27;;2946:130;;;;;;;;;;;;;;;;;;;2997:14;;2946:130;3026:15;;;;;;2676:37;;2946:130;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;3056:9;2946:36;:130::i;:::-;3214:26;;3187:53;;;;;;;;:::i;:::-;:14;;:23;:53;;;;;;;;:::i;:::-;;;:117;;;;3281:17;:23;;;-1:-1:-1;;;;;3257:47:21;:9;:14;;;:20;;;-1:-1:-1;;;;;3257:47:21;;;3187:117;:191;;;;3350:17;:28;;;3321:9;:14;;;:25;;;:57;;3187:191;3169:309;;;3412:54;;-1:-1:-1;;;3412:54:21;;;;;;;;;;;3169:309;3591:9;:14;;;:21;;;3564:17;:24;;;:48;3560:1786;;;3710:43;3775:23;;3799:1;3775:26;;;;;;;:::i;:::-;;;;;;3710:106;;;;;;;;;;:::i;:::-;;;4314:9;:14;;;:21;;;4266:17;:24;;;:69;4090:14;4105:15;:26;;;4090:42;;;;;;;;:::i;:::-;;;;;;;:75;;;:111;;;4202:15;:25;;;4090:138;;;;;;;;:::i;:::-;;;;;;;;;;;:172;;;;:246;;;;4472:14;;:21;;;4445:24;;;:48;-1:-1:-1;3560:1786:21;;;4599:43;4645:15;;4661:1;4645:18;;;;;;;:::i;:::-;;;;;;4599:64;;;;;;;;;;:::i;:::-;;;5152:17;:24;;;5107:9;:14;;;:21;;;:69;4939:14;4954:15;:26;;;4939:42;;;;;;;;:::i;:::-;;;;;;;:75;;;:103;;;5043:15;:25;;;4939:130;;;;;;;;:::i;:::-;;;;;;;:164;;:238;;;;;5310:17;:24;;;5286:9;:14;;;:21;;:48;;;;;4511:835;3560:1786;5428:27;;;;;5401:14;;-1:-1:-1;;;;;5401:54:21;;;:24;;:54;-1:-1:-1;1726:3902:21;;;;;;;:::o;29167:4619:24:-;29470:21;;29325:29;;29470:21;-1:-1:-1;;;;;29582:23:24;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;29582:23:24;;29564:41;;29802:9;29797:1614;29821:11;29817:1;:15;29797:1614;;;29910:34;29947:14;29962:1;29947:17;;;;;;;;:::i;:::-;;;;;;;29910:54;;30068:13;:23;;;-1:-1:-1;;;;;30068:28:24;30095:1;30068:28;30064:328;;30364:8;;;30064:328;30482:4;30461:15;30477:1;30461:18;;;;;;;;:::i;:::-;:25;;;:18;;;;;;;;;;;:25;30652:24;;:38;;;30843:20;;30586:40;30962:434;30986:23;30982:1;:27;30962:434;;;31116:19;31138:13;31152:1;31138:16;;;;;;;;:::i;:::-;;;;;;;:28;;;31116:50;;31263:11;31278:1;31263:16;31259:118;;31315:38;;-1:-1:-1;;;31315:38:24;;;;;36440:25:39;;;36481:18;;;36474:34;;;36524:18;;;36517:34;;;36413:18;;31315:38:24;36238:319:39;31259:118:24;-1:-1:-1;31011:3:24;;30962:434;;;;29839:1572;;;29797:1614;29834:3;;29797:1614;;;-1:-1:-1;31928:30:24;;;14743:4:10;31928:30:24;;;;;;;;;31524:9;;31499:22;;31928:30;;;;;;;;;;;-1:-1:-1;;32073:17:24;;31901:57;;-1:-1:-1;32047:23:24;32144:1151;32168:15;32164:1;:19;32144:1151;;;32275:26;32304:10;32315:1;32304:13;;;;;;;;:::i;:::-;;;;;;;;;;;32359:14;;32304:13;;-1:-1:-1;32332:24:24;32472:13;;:32;;;;;;;;:::i;:::-;;32468:444;;32621:14;32607:4;:11;;;:28;32603:111;;;32667:27;;-1:-1:-1;;;32667:27:24;;;;;;;;;;;32603:111;32866:4;:11;;;32848:29;;;;32468:444;32990:152;33018:4;33041:9;:17;;;33077:9;:20;;;33116:11;32990:9;:152::i;:::-;-1:-1:-1;;33265:3:24;;32144:1151;;;;33388:28;33404:11;33388:15;:28::i;:::-;33511:19;;33507:101;;33547:49;33568:10;33581:14;33547:12;:49::i;:::-;33660:23;2393:1:10;1355:16:28;:31;1262:132;33660:23:24;33754:24;;;;29167:4619;;;;:::o;6854:2224:21:-;7109:26;;:::i;:::-;7416:21;:28;7448:1;7416:33;7412:127;;7518:4;7477:46;;-1:-1:-1;;;7477:46:21;;;;;;;;:::i;7412:127::-;7637:10;7629:4;:18;;;;;;;;:::i;:::-;;7625:1109;;7738:14;;-1:-1:-1;;;;;7738:45:21;;:24;;;;:45;7883:168;7942:14;7979:21;7738:9;7883:36;:168::i;:::-;7625:1109;;;8281:176;8348:14;8385:21;8429:9;8281:44;:176::i;:::-;8566:10;8546:17;;;:30;8676:20;;;:42;;;7625:1109;8911:14;;:21;;;:14;:26;8907:153;;8986:1;8958:17;;;:30;;;9007:14;;:24;;:37;6854:2224;;;;;;;:::o;2875:433:2:-;3200:30;3167;:63;3163:138;;;3254:35;;-1:-1:-1;;;3254:35:2;;;;;;;;;;;1093:10140:30;1317:12;1522:1;1519;1512:12;1597:5;1696:9;1690:16;2003:7;1992:9;1988:23;2148:22;2142:29;2623:15;2606;2602:37;2718:19;2891:1;2882:7;2879:14;2869:3454;;3045:24;3034:9;3030:40;2998:95;3486:24;3475:9;3471:40;3465:47;3437:1;3406:129;3401:134;;3637:7;3634:838;;;3891:17;3841:18;3831:8;3827:33;3793:142;3788:147;;-1:-1:-1;;;;;4310:18:30;4272:150;4216:24;4205:9;4201:40;4164:285;3634:838;4660:1;4649:9;4642:20;4876:6;4852:22;4845:38;5550:7;5484:1;5402:19;5320:22;5239:20;5203:5;5162:458;-1:-1:-1;5729:57:30;;;5867:34;;;6033:24;6018:40;;5985:141;-1:-1:-1;;6296:8:30;2869:3454;6597:27;;6626:13;;;6593:47;;-1:-1:-1;6593:47:30;;-1:-1:-1;6750:4030:30;;7075:46;7030:22;7001:139;7316:48;7284:9;7258:125;7526:11;7520:18;7714:46;7682:9;7656:123;7918:9;7912:16;-1:-1:-1;;;8031:11:30;8024:54;8160:6;8149:9;8142:25;8587:7;8563:1;8473:44;8431:15;8401:139;8367:11;8338:6;8310:5;8277:336;8266:347;;8713:7;8710:1724;;;-1:-1:-1;;;8896:1:30;8890:8;8887:47;8877:1538;;9057:6;9045:19;9042:258;;;-1:-1:-1;;;9159:1:30;9152:47;9239:33;9236:1;9229:44;9042:258;9440:1;9422:15;9405;9401:37;9398:44;9395:296;;;-1:-1:-1;;;9558:1:30;9551:43;9634:29;9631:1;9624:40;9395:296;9819:42;9816:1;9811:51;9771:412;;-1:-1:-1;;;9989:1:30;9982:40;10087:1;10059:26;10052:37;10129:26;10126:1;10119:37;9771:412;-1:-1:-1;;;10296:1:30;10289:40;10365:26;10362:1;10355:37;8877:1538;10572:57;;;10647:52;;;;10717:48;;6750:4030;;;;;10842:7;10837:389;;10932:34;:32;:34::i;:::-;-1:-1:-1;;;11098:1:30;11091:47;11166:33;11163:1;11156:44;1375:645:35;1511:10;1630:15;1618:9;:27;:57;;;;1660:15;1649:7;:26;;1618:57;1614:322;;;1770:15;1766:76;;;1813:13;;-1:-1:-1;;;1813:13:35;;;;;;;;;;;1766:76;-1:-1:-1;1919:5:35;1912:12;;1614:322;-1:-1:-1;2008:4:35;1375:645;;;;;:::o;4238:1717:36:-;4715:1;4702:9;4694:18;;;;;;;;:::i;:::-;:22;:57;;;;-1:-1:-1;4733:10:36;-1:-1:-1;;;;;4733:18:36;;;;4694:57;:95;;;;-1:-1:-1;4768:10:36;-1:-1:-1;;;;;4768:21:36;;;;4694:95;4676:1272;;;4908:23;;;;:30;:35;:85;;;;-1:-1:-1;4964:24:36;;:29;4908:85;4886:1051;;;5088:53;5106:4;5112:9;5123:7;5132:8;5088:17;:53::i;:::-;4886:1051;;;5343:12;5358:405;5392:4;5468:53;;;5548:9;5584:10;5621:13;5661:16;5704:17;5419:325;;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;5419:325:36;;;;;;;;;;;;;;-1:-1:-1;;;;;5419:325:36;-1:-1:-1;;;;;;5419:325:36;;;;;;;;;;5358:11;:405::i;:::-;5343:420;;5865:56;5902:7;5911:9;5865:36;:56::i;4886:1051::-;4238:1717;;;;;;;;:::o;10325:2180:16:-;10536:12;10740:4;10737:1;10730:15;10875:7;10872:1;10862:21;11101:7;11094:5;11090:19;11330:5;11324:12;11321:1;11317:20;11311:4;11307:31;11199:1038;11363:3;11357:4;11354:13;11199:1038;;;11562:11;;11818:28;;;11815:1;11811:36;12031:29;;;12098:7;12085:21;;;12078:41;12213:8;12210:1;12200:22;;11448:18;;;;11199:1038;;;-1:-1:-1;;12325:22:16;;;-1:-1:-1;12325:22:16;12436:62;;12472:14;;-1:-1:-1;;;12472:14:16;;;;;;;;;;;1908:1850:19;2163:15;2146:13;;:32;;;;;;;;:::i;:::-;;2142:1609;;2302:15;;;;2288:10;;;;-1:-1:-1;;;;;2280:37:19;;2279:44;2275:114;;2351:22;;-1:-1:-1;;;2351:22:19;;;;;;;;;;;2275:114;2466:41;2479:4;:14;;;2495:4;:11;;;2466:12;:41::i;:::-;2142:1609;;;2546:14;2529:13;;:31;;;;;;;;:::i;:::-;;2525:1226;;2636:15;;;;:20;2632:90;;2684:22;;-1:-1:-1;;;2684:22:19;;;;;;;;;;;2632:90;2810:203;2843:4;:10;;;2872:4;2895;:14;;;2928:4;:11;;;2958:10;2987:11;2810:14;:203::i;2525:1226::-;3052:15;3035:13;;:32;;;;;;;;:::i;:::-;;3031:720;;3156:238;3190:4;:10;;;3219:4;3242;:14;;;3275:4;:15;;;3309:4;:11;;;3339:10;3368:11;3156:15;:238::i;3031:720::-;3500:239;3535:4;:10;;;3564:4;3587;:14;;;3620:4;:15;;;3654:4;:11;;;3684:10;3713:11;3500:16;:239::i;6789:889:1:-;7036:14;7159:9;7144:11;:24;7140:531;;7240:47;7253:9;7264:11;7277:9;7240:12;:47::i;:::-;7231:56;;7140:531;;;7410:249;7449:49;7462:9;7473:11;7486;7449:12;:49::i;:::-;7517:47;7530:9;7541:11;7554:9;7517:12;:47::i;:::-;7583:9;7611:7;7637;7410:20;:249::i;:::-;7401:258;;7140:531;6789:889;;;;;;;;;:::o;8742:762:19:-;8877:28;8898:6;8877:20;:28::i;:::-;9000:12;9160:1;9157;9154;9151;9143:6;9139:2;9132:5;9127:35;9116:46;;9223:7;9218:279;;9324:34;:32;:34::i;:::-;9446:39;;-1:-1:-1;;;9446:39:19;;-1:-1:-1;;;;;43589:32:39;;9446:39:19;;;43571:51:39;43638:18;;;43631:34;;;43544:18;;9446:39:19;43389:282:39;9218:279:19;8809:695;8742:762;;:::o;4209:2557:2:-;6503:31;6394;6381:45;6281:272;5527:26;5514:40;5689:24;5901:44;5854:122;6087:25;5740:399;5659:503;5422:759;4964:27;4951:41;5015:25;4926:133;5197:42;5184:56;5263:40;5159:163;4824:513;5369:827;6228:340;;6670:89;;6711:36;;-1:-1:-1;;;6711:36:2;;;;;;;;;;;6670:89;4267:2499;4209:2557::o;1292:560:36:-;1623:1;1610:9;1602:18;;;;;;;;:::i;:::-;:22;:57;;;;-1:-1:-1;1641:10:36;-1:-1:-1;;;;;1641:18:36;;;;1602:57;:95;;;;-1:-1:-1;1676:10:36;-1:-1:-1;;;;;1676:21:36;;;;1602:95;1584:261;;;1780:53;1798:4;1804:9;1815:7;1824:8;1780:17;:53::i;1593:1011:26:-;1815:31;1849:23;;;:12;:23;;;;;1944:223;1862:9;1849:23;2027:4;;1944:18;:223::i;:::-;-1:-1:-1;2267:23:26;;;;2262:104;;2307:47;2324:7;2333:9;2344;2307:16;:47::i;:::-;2569:27;;;-1:-1:-1;;;1593:1011:26:o;20251:1399:19:-;10255:21:22;10249:28;;9865:19;-1:-1:-1;;;10465:41:22;20474:15:19;10455:52:22;;;10605:7;10598:27;;;10013;10723:41;;11160:31;11037:28;10941:269;11406:48;;;;-1:-1:-1;;;;;10873:468:22;20474:44:19;;20531:12;20554:13;20705:1;20702;20695:12;20993:7;20973:1;20942:12;20909:14;20889:1;20863:7;20839:5;20816:199;20805:210;;21120:1;21114:8;21104:18;;21184:7;21179:260;;21284:34;:32;:34::i;:::-;21398:29;;-1:-1:-1;;;21398:29:19;;-1:-1:-1;;;;;44334:32:39;;21398:29:19;;;44316:51:39;44289:18;;21398:29:19;44170:203:39;21179:260:19;-1:-1:-1;;;;;;21529:43:19;;-1:-1:-1;;;21529:43:19;21525:118;;21596:35;;-1:-1:-1;;;21596:35:19;;;;;44552:25:39;;;-1:-1:-1;;;;;44613:32:39;;44593:18;;;44586:60;44525:18;;21596:35:19;44378:274:39;11779:5026:32;12107:5;12095:18;12085:258;;-1:-1:-1;;;12141:24:32;12134:60;12247:5;12219:26;12212:41;12304:23;12278:24;12271:57;12085:258;12545:21;12539:28;-1:-1:-1;;;12665:27:32;12658:66;12775:4;12745:28;12738:42;12829:2;12801:26;12794:38;12881:10;12853:26;12846:46;13181:1;13161;13116:26;13070:27;13050:1;13026:5;13002;12979:218;13265:7;13255:3335;;13419:16;13416:2376;;;13868:7;13827:13;13809:16;13805:36;13775:123;14185:7;14173:10;14169:24;14316:15;14303:11;14299:33;14448:10;14431:15;14428:31;14425:786;;;14644:32;;;14715:11;14602:159;15069:26;14964:27;;;14884:37;;;14838:192;14796:334;14564:597;14495:693;14425:786;15460:5;15443:14;15437:4;15433:25;15430:36;15427:346;;;15597:16;15594:1;15591;15576:38;15733:16;15730:1;15723:27;15427:346;;;;13416:2376;-1:-1:-1;;;15908:41:32;15879:155;16104:5;16059:43;16052:58;16179:4;16135:42;16128:56;16251:2;16209:40;16202:52;16321:10;16279:40;16272:60;16403:1;16357:44;16350:55;16516:40;16452:41;16423:152;13255:3335;-1:-1:-1;16671:21:32;16664:41;-1:-1:-1;;16785:1:32;16775:8;16768:19;-1:-1:-1;;11779:5026:32:o;17468:5749::-;17823:5;17811:18;17801:258;;-1:-1:-1;;;17857:24:32;17850:60;17963:5;17935:26;17928:41;18020:23;17994:24;17987:57;17801:258;18255:21;18249:28;18313:8;18307:15;18358:8;18352:15;18403:8;18397:15;-1:-1:-1;;;18532:32:32;18507:125;18688:4;18653:33;18646:47;18747:2;18714:31;18707:43;18804:10;18771:31;18764:51;18873:6;18836:35;18829:51;18978:43;18919:40;18894:142;19099:1;19057:40;19050:51;19400:1;19380;19330:31;19279:32;19259:1;19235:5;19211;19188:228;19484:7;19474:3340;;19638:16;19635:2376;;;20087:7;20046:13;20028:16;20024:36;19994:123;20404:7;20392:10;20388:24;20535:15;20522:11;20518:33;20667:10;20650:15;20647:31;20644:786;;;20863:32;;;20934:11;20821:159;21288:26;21183:27;;;21103:37;;;21057:192;21015:334;20783:597;20714:693;20644:786;21679:5;21662:14;21656:4;21652:25;21649:36;21646:346;;;21816:16;21813:1;21810;21795:38;21952:16;21949:1;21942:27;21646:346;;;;19635:2376;-1:-1:-1;;;22127:41:32;22098:155;22323:5;22278:43;22271:58;22398:4;22354:42;22347:56;22470:2;22428:40;22421:52;22540:10;22498:40;22491:60;22622:6;22576:44;22569:60;22740:40;22676:41;22647:152;19474:3340;-1:-1:-1;22837:8:32;22830:26;;;;22899:8;22892:26;22961:8;22954:26;23083:21;23076:41;-1:-1:-1;;23197:1:32;-1:-1:-1;23180:19:32;-1:-1:-1;;;17468:5749:32:o;16416:469:19:-;16618:29;16650:38;16676:11;22395:26;22378:44;22354:83;;22080:375;16650:38;16618:70;;16811:10;16786:21;:35;16782:96;;16838:28;16854:11;16838:15;:28::i;23471:2207::-;23741:16;14743:4:10;23918:11:19;:18;:41;23914:1031;;-1:-1:-1;24117:16:19;24097:37;;;24202:26;24185:44;;;24178:64;;;-1:-1:-1;;;24267:42:19;;;24260:60;;;;24384:28;24367:46;;24338:141;23987:1;24521:28;24504:46;;24497:64;;;23914:1031;;;-1:-1:-1;24764:28:19;24747:46;;24741:53;;24817:1;24715:122;24855:64;;;;23914:1031;25128:36;25082:25;25072:8;25068:40;25055:11;25051:58;25029:150;25213:8;25200:11;25193:29;25293:5;25260:30;25247:11;25243:48;25236:63;25369:4;25337:29;25324:11;25320:47;25313:61;25442:2;25412:27;25399:11;25395:45;25388:57;25556:10;25501:35;25488:11;25484:53;25459:122;25653:6;25619:31;25606:11;25602:49;25595:65;;24995:676;23471:2207;;;;;;;;:::o;3482:208:2:-;3617:6;3627:1;3617:11;3613:70;;3652:19;;-1:-1:-1;;;3652:19:2;;;;;;;;;;;10458:1000:19;10723:28;10744:6;10723:20;:28::i;:::-;10830:59;10865:11;10878:10;10830:34;:59::i;:::-;10954:10;10950:501;;11048:46;11070:5;11077:4;11083:2;11087:6;11048:21;:46::i;:::-;10950:501;;;11196:243;11222:10;11251:11;11281:21;11321:5;11345:4;11368:2;11397:1;11418:6;11196:7;:243::i;18426:1141::-;19115:28;19098:46;;19092:53;18923:8;18906:26;;;19168:25;19066:146;19019:28;18997:230;19332:66;19357:10;18906:26;18997:230;19332:24;:66::i;:::-;-1:-1:-1;;19529:19:19;19509:40;;-1:-1:-1;18426:1141:19:o;21592:10887:21:-;21999:372;;;-1:-1:-1;;;22152:1:21;22145:58;22314:41;22311:1;22304:52;22461:412;-1:-1:-1;;;22565:1:21;22558:32;22717:16;22697:18;22690:44;22839:18;22836:1;22829:29;22461:412;23006:7;22981:23;22977:37;23132:18;23126:25;23120:32;23264:14;23258:21;23246:10;23243:37;23233:121;;23301:38;;:::i;:::-;23612:7;23600:10;23596:24;23586:7;23570:14;23566:28;23562:59;23463:173;23897:41;23865:8;23859:15;23753:204;23729:243;24140:28;24119:18;24113:25;24109:60;24085:99;24295:19;24289:26;24278:9;24275:41;24265:125;;24337:38;;:::i;:::-;24766:7;24755:9;24751:23;24649:7;24628:19;24624:33;24532:261;24508:300;24911:1;25020;25177:30;25167:8;25163:45;25157:52;25154:528;;;-1:-1:-1;;25350:20:21;25324:47;;25437:16;;25665:1;25647:20;;;25541:14;;25154:528;25786:9;25780:16;25895:20;25889:27;25875:12;25868:49;26099:19;26077:20;26073:46;26067:53;26028:19;26014:12;26010:38;25985:150;26327:24;26305:20;26301:51;26295:58;26251:24;26237:12;26233:43;26208:160;26637:34;26590:20;26560:134;26532:181;26483:29;26469:12;26465:48;26440:288;26888:30;26857:12;26829:104;27137:7;27111:23;27105:30;27101:44;27059:23;27037:123;27265:4417;27296:6;27275:18;27272:31;27265:4417;;;27444:7;27424:18;27420:32;27398:54;;27569:18;27563:25;27557:32;27543:46;;27696:14;27690:21;27678:10;27675:37;27665:127;;27735:38;;:::i;:::-;28011:7;27999:10;27995:24;27960:7;27944:14;27940:28;27910:132;27882:179;27870:191;;28193:30;28183:8;28179:45;28173:52;28141:152;27265:4417;28141:152;28590:41;28554:8;28548:15;28439:215;28411:262;28388:285;;28813:7;28792:18;28786:25;28782:39;28776:46;28763:59;;28941:19;28935:26;28924:9;28921:41;28911:133;;28987:38;;:::i;:::-;29429:7;29418:9;29414:23;29310:7;29289:19;29285:33;29185:275;29157:322;29133:346;;29667:20;29622;29594:112;29819:9;29813:16;29805:6;29801:29;30092:9;30086:16;30079:24;30048:6;30037:9;30034:21;30031:1;30027:29;30002:122;29970:11;29947:196;29932:211;;30238:9;30228:19;;;30366:1;30355:9;30348:20;;31388:30;31337:20;31297:150;31260:8;31229:245;31008:29;30957:12;30915:157;30875:228;30749:29;30690:20;30648:165;30608:236;30575:555;30489:1008;30457:1210;;31610:38;;:::i;:::-;27265:4417;;;-1:-1:-1;;31770:20:21;31752:39;31745:55;;;31898:563;;;;32023:1;32010:11;32007:18;32004:310;;-1:-1:-1;;;32125:1:21;32118:44;32267:27;32264:1;32257:38;32004:310;32431:15;;:::i;:::-;31898:563;;;;;;;;21592:10887;;;:::o;9711:11114::-;11019:7;11002:15;10998:29;11145:18;11139:25;11133:32;11277:14;11271:21;11259:10;11256:37;11246:121;;11314:38;;:::i;:::-;11625:7;11613:10;11609:24;11599:7;11583:14;11579:28;11575:59;11476:173;11764:8;11758:15;11893:33;11882:9;11878:49;11854:88;12110:28;12089:18;12083:25;12079:60;12055:99;12265:11;12259:18;12248:9;12245:33;12235:117;;12299:38;;:::i;:::-;12712:7;12701:9;12697:23;12595:7;12582:11;12578:25;12486:253;12462:292;12857:1;12966;13088:30;13078:8;13074:45;13068:52;13065:532;;;-1:-1:-1;;13253:20:21;13235:39;;13340:16;;13466:1;13448:20;;;13568:14;;13065:532;13694:9;13688:16;13806:12;13800:19;13783:15;13776:44;13997:19;13983:12;13979:38;13973:45;13934:19;13917:15;13913:41;13888:145;14220:24;14206:12;14202:43;14196:50;14152:24;14135:15;14131:46;14106:155;14407:9;14401:16;14374:24;14363:9;14359:40;14352:66;14621:30;14610:9;14606:46;14600:53;14556:24;14545:9;14541:40;14516:152;14831:30;14797:15;14769:107;14753:123;;15064:7;15046:15;15040:22;15036:36;15002:15;14980:107;15192:4832;15223:6;15202:18;15199:31;15192:4832;;;15378:7;15358:18;15354:32;15332:54;;15503:18;15497:25;15491:32;15477:46;;15630:14;15624:21;15612:10;15609:37;15599:127;;15669:38;;:::i;:::-;15945:7;15933:10;15929:24;15894:7;15878:14;15874:28;15844:132;15816:179;15804:191;;16127:30;16117:8;16113:45;16085:92;16075:152;15192:4832;16075:152;16346:8;16340:15;16327:28;;16530:33;16494:9;16464:122;16436:169;16421:184;;16745:7;16724:18;16718:25;16714:39;16708:46;16695:59;;16895:11;16889:18;16878:9;16875:33;16843:165;;16951:38;;:::i;:::-;17369:7;17358:9;17354:23;17250:7;17237:11;17233:25;17133:267;17105:314;17089:330;;17591:20;17554:12;17526:104;17743:9;17737:16;17729:6;17725:29;18016:9;18010:16;18003:24;17972:6;17961:9;17958:21;17955:1;17951:29;17926:122;17894:11;17871:196;17856:211;;18162:9;18152:19;;;18290:1;18279:9;18272:20;;19728:30;19681:12;19637:152;19598:8;19565:251;19312:24;19262:9;19218:155;19176:230;19043:30;18993:9;18949:161;18907:236;18872:563;18684:24;18673:9;18669:40;18627:115;18584:9;18578:16;18543:228;18443:1019;18413:1426;18381:1628;;19952:38;;:::i;:::-;15192:4832;;;15196:2;;20139:6;20116:20;20104:9;20098:16;20094:43;20087:59;20247:11;20244:563;;;20369:1;20356:11;20353:18;20350:310;;-1:-1:-1;;;20471:1:21;20464:44;20613:27;20610:1;20603:38;20350:310;20777:15;;:::i;:::-;20244:563;;;;;;;;;9711:11114;;;:::o;1393:2286:23:-;1604:16;1601:2060;;;1976:7;1939:13;1921:16;1917:36;1891:111;2291:7;2267:21;2261:28;2257:42;2414:15;2401:11;2397:33;2538:10;2521:15;2518:31;2515:621;;;2680:32;;;2714:11;2676:50;3010:26;2913:27;;;2837:37;;;2795:180;2757:310;2642:452;2581:536;2515:621;3349:5;3332:14;3326:4;3322:25;3319:36;3316:330;;;3478:16;3475:1;3472;3457:38;3610:16;3607:1;3600:27;1860:641:36;2135:201;;;;;44888:25:39;;;2258:10:36;44967:18:39;;;44960:43;-1:-1:-1;;;;;45039:15:39;;45019:18;;;45012:43;45071:18;;;45064:34;;;2075:12:36;;2090:257;;2116:4;;-1:-1:-1;;;2176:35:36;44860:19:39;;2135:201:36;44657:447:39;2090:257:36;2075:272;;2437:56;2474:7;2483:9;2437:36;:56::i;718:422:23:-;828:12;1106:1;1086;1058:8;1052:15;1025:7;1015:8;1011:22;986:6;962:5;933:189;922:200;718:422;-1:-1:-1;;;718:422:23:o;6435:650:36:-;6603:7;6598:262;;6693:34;:32;:34::i;:::-;6815:33;;-1:-1:-1;;;6815:33:36;;;;;13363:25:39;;;13336:18;;6815:33:36;13217:177:39;6598:262:36;6954:55;-1:-1:-1;;;6954:18:36;:55::i;:::-;6950:128;;;7033:33;;-1:-1:-1;;;7033:33:36;;;;;13363:25:39;;;13336:18;;7033:33:36;13217:177:39;1355:9806:32;1791:21;1785:28;-1:-1:-1;;;1914:26:32;1907:64;2021:4;1992:27;1985:41;2074:2;2047:25;2040:37;2129:6;2098:29;2091:45;2838:7;2818:1;2774:25;2729:26;2709:1;2685:5;2661;2638:222;3348:10;3293:16;3286:24;3259:2;3241:16;3238:24;3234:1;3230;3224:8;3221:15;3217:46;3192:137;2972:401;3740:16;3733:24;3726:32;3717:7;3713:46;3703:7243;;4065:7;4055:5;4043:18;4036:26;4029:34;4025:48;4015:6706;;4156:7;4146:6248;;4257:10;4247:4845;;4450:16;4447:3380;;;5025:7;4972:13;4954:16;4950:36;4908:159;5438:7;5426:10;5422:24;5593:15;5580:11;5576:33;5749:10;5732:15;5729:31;5726:1316;;;6005:189;;;6245:11;5951:352;6852:26;6723:27;;;6462:206;;;6404:397;6350:575;5901:1067;5808:1199;5726:1316;7339:5;7322:14;7316:4;7312:25;7309:36;7306:490;;;7540:16;7537:1;7534;7519:38;7744:16;7741:1;7734:27;7306:490;;;;4447:3380;-1:-1:-1;;;7979:41:32;7938:191;8278:5;8200:43;8159:155;8462:4;8385:42;8344:153;8576:2;8534:40;8527:52;8658:1;8616:40;8609:51;8810:6;8731:44;8690:157;8994:40;8918:41;8877:188;4247:4845;-1:-1:-1;;;9309:47:32;9272:191;9606:5;9526:49;9489:149;9780:4;9701:48;9664:147;9951:2;9874:46;9837:143;10124:6;10043:50;10006:151;10298:46;10220:47;10183:188;4146:6248;-1:-1:-1;;;10507:24:32;10500:60;10617:5;10589:26;10582:41;10678:23;10652:24;10645:57;4015:6706;-1:-1:-1;;11027:21:32;11020:41;-1:-1:-1;;11141:1:32;11131:8;11124:19;-1:-1:-1;;1355:9806:32:o;4035:797:23:-;4103:4;4197:13;4427:7;4409:16;4406:29;4403:291;;4556:7;4553:1;4550;4535:29;-1:-1:-1;4677:1:23;4671:8;4403:291;-1:-1:-1;;;;;;4806:18:23;;;;;;;;;;;4035:797;-1:-1:-1;4035:797:23:o;-1:-1:-1:-;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;14:472:39:-;56:3;94:5;88:12;121:6;116:3;109:19;146:1;156:162;170:6;167:1;164:13;156:162;;;232:4;288:13;;;284:22;;278:29;260:11;;;256:20;;249:59;185:12;156:162;;;336:6;333:1;330:13;327:87;;;402:1;395:4;386:6;381:3;377:16;373:27;366:38;327:87;-1:-1:-1;468:2:39;447:15;-1:-1:-1;;443:29:39;434:39;;;;475:4;430:50;;14:472;-1:-1:-1;;14:472:39:o;491:220::-;640:2;629:9;622:21;603:4;660:45;701:2;690:9;686:18;678:6;660:45;:::i;716:180::-;775:6;828:2;816:9;807:7;803:23;799:32;796:52;;;844:1;841;834:12;796:52;-1:-1:-1;867:23:39;;716:180;-1:-1:-1;716:180:39:o;1317:127::-;1378:10;1373:3;1369:20;1366:1;1359:31;1409:4;1406:1;1399:15;1433:4;1430:1;1423:15;1449:253;1521:2;1515:9;1563:4;1551:17;;-1:-1:-1;;;;;1583:34:39;;1619:22;;;1580:62;1577:88;;;1645:18;;:::i;:::-;1681:2;1674:22;1449:253;:::o;1707:255::-;1779:2;1773:9;1821:6;1809:19;;-1:-1:-1;;;;;1843:34:39;;1879:22;;;1840:62;1837:88;;;1905:18;;:::i;1967:275::-;2038:2;2032:9;2103:2;2084:13;;-1:-1:-1;;2080:27:39;2068:40;;-1:-1:-1;;;;;2123:34:39;;2159:22;;;2120:62;2117:88;;;2185:18;;:::i;:::-;2221:2;2214:22;1967:275;;-1:-1:-1;1967:275:39:o;2247:196::-;2320:4;-1:-1:-1;;;;;2345:6:39;2342:30;2339:56;;;2375:18;;:::i;:::-;-1:-1:-1;2420:1:39;2416:14;2432:4;2412:25;;2247:196::o;2448:131::-;-1:-1:-1;;;;;2523:31:39;;2513:42;;2503:70;;2569:1;2566;2559:12;2584:134;2652:20;;2681:31;2652:20;2681:31;:::i;:::-;2584:134;;;:::o;2723:149::-;2797:20;;2846:1;2836:12;;2826:40;;2862:1;2859;2852:12;2877:566;2933:5;2981:4;2969:9;2964:3;2960:19;2956:30;2953:50;;;2999:1;2996;2989:12;2953:50;3021:22;;:::i;:::-;3012:31;;3066:35;3091:9;3066:35;:::i;:::-;3059:5;3052:50;3154:2;3143:9;3139:18;3126:32;3167:33;3192:7;3167:33;:::i;:::-;3232:7;3227:2;3220:5;3216:14;3209:31;;3300:2;3289:9;3285:18;3272:32;3267:2;3260:5;3256:14;3249:56;3365:2;3354:9;3350:18;3337:32;3332:2;3325:5;3321:14;3314:56;3431:3;3420:9;3416:19;3403:33;3397:3;3390:5;3386:15;3379:58;2877:566;;;;:::o;3448:728::-;3511:5;3564:3;3557:4;3549:6;3545:17;3541:27;3531:55;;3582:1;3579;3572:12;3531:55;3618:6;3605:20;3644:4;3668:73;3684:56;3737:2;3684:56;:::i;:::-;3668:73;:::i;:::-;3775:15;;;3837:4;3880:11;;;3868:24;;3864:33;;;3806:12;;;;3763:3;3909:15;;;3906:35;;;3937:1;3934;3927:12;3906:35;3973:2;3965:6;3961:15;3985:162;4001:6;3996:3;3993:15;3985:162;;;4067:37;4100:3;4095;4067:37;:::i;:::-;4055:50;;4125:12;;;;4018;;3985:162;;;-1:-1:-1;4165:5:39;;3448:728;-1:-1:-1;;;;;;;3448:728:39:o;4181:908::-;4245:5;4293:4;4281:9;4276:3;4272:19;4268:30;4265:50;;;4311:1;4308;4301:12;4265:50;4344:2;4338:9;4386:4;4378:6;4374:17;4457:6;4445:10;4442:22;-1:-1:-1;;;;;4409:10:39;4406:34;4403:62;4400:88;;;4468:18;;:::i;:::-;4504:2;4497:22;4537:6;-1:-1:-1;4537:6:39;4567:35;4592:9;4567:35;:::i;:::-;4559:6;4552:51;4655:2;4644:9;4640:18;4627:32;4668:33;4693:7;4668:33;:::i;:::-;4734:7;4729:2;4721:6;4717:15;4710:32;;4803:2;4792:9;4788:18;4775:32;4770:2;4762:6;4758:15;4751:57;4869:2;4858:9;4854:18;4841:32;4836:2;4828:6;4824:15;4817:57;4936:3;4925:9;4921:19;4908:33;4902:3;4894:6;4890:16;4883:59;4994:3;4983:9;4979:19;4966:33;5008;5033:7;5008:33;:::i;:::-;5069:3;5057:16;;;;5050:33;4181:908;;-1:-1:-1;;4181:908:39:o;5094:744::-;5165:5;5218:3;5211:4;5203:6;5199:17;5195:27;5185:55;;5236:1;5233;5226:12;5185:55;5272:6;5259:20;5298:4;5322:73;5338:56;5391:2;5338:56;:::i;5322:73::-;5429:15;;;5491:4;5534:11;;;5522:24;;5518:33;;;5460:12;;;;5417:3;5563:15;;;5560:35;;;5591:1;5588;5581:12;5560:35;5627:2;5619:6;5615:15;5639:170;5655:6;5650:3;5647:15;5639:170;;;5721:45;5762:3;5757;5721:45;:::i;:::-;5709:58;;5787:12;;;;5672;;5639:170;;5843:150;5918:20;;5967:1;5957:12;;5947:40;;5983:1;5980;5973:12;5998:1291;6060:5;6108:6;6096:9;6091:3;6087:19;6083:32;6080:52;;;6128:1;6125;6118:12;6080:52;6150:22;;:::i;:::-;6141:31;;6195:29;6214:9;6195:29;:::i;:::-;6188:5;6181:44;6257:38;6291:2;6280:9;6276:18;6257:38;:::i;:::-;6252:2;6245:5;6241:14;6234:62;6347:2;6336:9;6332:18;6319:32;-1:-1:-1;;;;;6411:2:39;6403:6;6400:14;6397:34;;;6427:1;6424;6417:12;6397:34;6463:66;6525:3;6516:6;6505:9;6501:22;6463:66;:::i;:::-;6458:2;6451:5;6447:14;6440:90;6583:2;6572:9;6568:18;6555:32;6539:48;;6612:2;6602:8;6599:16;6596:36;;;6628:1;6625;6618:12;6596:36;;6664:76;6736:3;6725:8;6714:9;6710:24;6664:76;:::i;:::-;6659:2;6652:5;6648:14;6641:100;;6774:46;6815:3;6804:9;6800:19;6774:46;:::i;:::-;6768:3;6761:5;6757:15;6750:71;6882:3;6871:9;6867:19;6854:33;6848:3;6841:5;6837:15;6830:58;6949:3;6938:9;6934:19;6921:33;6915:3;6908:5;6904:15;6897:58;7016:3;7005:9;7001:19;6988:33;6982:3;6975:5;6971:15;6964:58;7041:3;7104:2;7093:9;7089:18;7076:32;7071:2;7064:5;7060:14;7053:56;;7128:3;7191:2;7180:9;7176:18;7163:32;7158:2;7151:5;7147:14;7140:56;;7215:3;7278:2;7267:9;7263:18;7250:32;7245:2;7238:5;7234:14;7227:56;;5998:1291;;;;:::o;7294:186::-;7362:20;;-1:-1:-1;;;;;7411:44:39;;7401:55;;7391:83;;7470:1;7467;7460:12;7485:530;7527:5;7580:3;7573:4;7565:6;7561:17;7557:27;7547:55;;7598:1;7595;7588:12;7547:55;7634:6;7621:20;-1:-1:-1;;;;;7656:2:39;7653:26;7650:52;;;7682:18;;:::i;:::-;7726:55;7769:2;7750:13;;-1:-1:-1;;7746:27:39;7775:4;7742:38;7726:55;:::i;:::-;7806:2;7797:7;7790:19;7852:3;7845:4;7840:2;7832:6;7828:15;7824:26;7821:35;7818:55;;;7869:1;7866;7859:12;7818:55;7934:2;7927:4;7919:6;7915:17;7908:4;7899:7;7895:18;7882:55;7982:1;7957:16;;;7975:4;7953:27;7946:38;;;;7961:7;7485:530;-1:-1:-1;;;7485:530:39:o;8020:896::-;8080:5;8128:4;8116:9;8111:3;8107:19;8103:30;8100:50;;;8146:1;8143;8136:12;8100:50;8168:22;;:::i;:::-;8159:31;;8226:9;8213:23;-1:-1:-1;;;;;8296:2:39;8288:6;8285:14;8282:34;;;8312:1;8309;8302:12;8282:34;8339:62;8397:3;8388:6;8377:9;8373:22;8339:62;:::i;:::-;8332:5;8325:77;8434:38;8468:2;8457:9;8453:18;8434:38;:::i;:::-;8429:2;8422:5;8418:14;8411:62;8505:38;8539:2;8528:9;8524:18;8505:38;:::i;:::-;8500:2;8493:5;8489:14;8482:62;8597:2;8586:9;8582:18;8569:32;8553:48;;8626:2;8616:8;8613:16;8610:36;;;8642:1;8639;8632:12;8610:36;8678:47;8721:3;8710:8;8699:9;8695:24;8678:47;:::i;:::-;8673:2;8666:5;8662:14;8655:71;8779:3;8768:9;8764:19;8751:33;8735:49;;8809:2;8799:8;8796:16;8793:36;;;8825:1;8822;8815:12;8793:36;;8862:47;8905:3;8894:8;8883:9;8879:24;8862:47;:::i;:::-;8856:3;8849:5;8845:15;8838:72;;8020:896;;;;:::o;8921:929::-;8988:5;9041:3;9034:4;9026:6;9022:17;9018:27;9008:55;;9059:1;9056;9049:12;9008:55;9095:6;9082:20;9121:4;9145:73;9161:56;9214:2;9161:56;:::i;9145:73::-;9252:15;;;9338:1;9334:10;;;;9322:23;;9318:32;;;9283:12;;;;9362:15;;;9359:35;;;9390:1;9387;9380:12;9359:35;9426:2;9418:6;9414:15;9438:383;9454:6;9449:3;9446:15;9438:383;;;9540:3;9527:17;-1:-1:-1;;;;;9563:11:39;9560:35;9557:125;;;9636:1;9665:2;9661;9654:14;9557:125;9707:71;9774:3;9769:2;9755:11;9747:6;9743:24;9739:33;9707:71;:::i;:::-;9695:84;;-1:-1:-1;9799:12:39;;;;9471;;9438:383;;;-1:-1:-1;9839:5:39;8921:929;-1:-1:-1;;;;;;8921:929:39:o;9855:392::-;9943:8;9953:6;10007:3;10000:4;9992:6;9988:17;9984:27;9974:55;;10025:1;10022;10015:12;9974:55;-1:-1:-1;10048:20:39;;-1:-1:-1;;;;;10080:30:39;;10077:50;;;10123:1;10120;10113:12;10077:50;10160:4;10152:6;10148:17;10136:29;;10220:3;10213:4;10203:6;10200:1;10196:14;10188:6;10184:27;10180:38;10177:47;10174:67;;;10237:1;10234;10227:12;10174:67;9855:392;;;;;:::o;10252:1160::-;10506:6;10514;10522;10530;10538;10591:2;10579:9;10570:7;10566:23;10562:32;10559:52;;;10607:1;10604;10597:12;10559:52;10647:9;10634:23;-1:-1:-1;;;;;10717:2:39;10709:6;10706:14;10703:34;;;10733:1;10730;10723:12;10703:34;10756:74;10822:7;10813:6;10802:9;10798:22;10756:74;:::i;:::-;10746:84;;10883:2;10872:9;10868:18;10855:32;10839:48;;10912:2;10902:8;10899:16;10896:36;;;10928:1;10925;10918:12;10896:36;10967:97;11056:7;11045:8;11034:9;11030:24;10967:97;:::i;:::-;11083:8;;-1:-1:-1;10941:123:39;-1:-1:-1;11171:2:39;11156:18;;11143:32;;-1:-1:-1;11187:16:39;;;11184:36;;;11216:1;11213;11206:12;11184:36;;11255:97;11344:7;11333:8;11322:9;11318:24;11255:97;:::i;:::-;10252:1160;;;;-1:-1:-1;10252:1160:39;;-1:-1:-1;11371:8:39;;11229:123;10252:1160;-1:-1:-1;;;10252:1160:39:o;11417:127::-;11478:10;11473:3;11469:20;11466:1;11459:31;11509:4;11506:1;11499:15;11533:4;11530:1;11523:15;11549:139;11629:1;11622:5;11619:12;11609:46;;11635:18;;:::i;:::-;11664;;11549:139::o;11802:436::-;11868:43;11907:3;11899:5;11893:12;11868:43;:::i;:::-;11957:4;11946:16;;;11940:23;-1:-1:-1;;;;;12033:21:39;;;12017:14;;;12010:45;;;;12104:4;12093:16;;;12087:23;12071:14;;;12064:47;12160:4;12149:16;;;12143:23;12127:14;;;12120:47;12220:4;12209:16;;;12203:23;12199:32;12183:14;;12176:56;11802:436::o;12243:640::-;12305:3;12343:5;12337:12;12370:6;12365:3;12358:19;12396:4;12425:2;12420:3;12416:12;12409:19;;12462:2;12455:5;12451:14;12483:1;12493:365;12507:6;12504:1;12501:13;12493:365;;;12572:6;12566:13;12592:46;12634:3;12629:2;12623:9;12592:46;:::i;:::-;12684:11;;;12678:18;-1:-1:-1;;;;;12674:44:39;12706:3;12658:14;;12651:68;12769:4;12761:13;12755:20;12748:4;12739:14;;12732:44;12805:4;12796:14;;;;12833:15;;;;12715:1;12522:9;12493:365;;;-1:-1:-1;12874:3:39;;12243:640;-1:-1:-1;;;;;12243:640:39:o;12888:324::-;13121:2;13110:9;13103:21;13084:4;13141:65;13202:2;13191:9;13187:18;13179:6;13141:65;:::i;13399:395::-;13493:6;13546:2;13534:9;13525:7;13521:23;13517:32;13514:52;;;13562:1;13559;13552:12;13514:52;13602:9;13589:23;-1:-1:-1;;;;;13627:6:39;13624:30;13621:50;;;13667:1;13664;13657:12;13621:50;13690:22;;13746:3;13728:16;;;13724:26;13721:46;;;13763:1;13760;13753:12;13981:1817;14401:6;14409;14417;14425;14433;14441;14449;14457;14465;14473;14526:3;14514:9;14505:7;14501:23;14497:33;14494:53;;;14543:1;14540;14533:12;14494:53;14583:9;14570:23;-1:-1:-1;;;;;14653:2:39;14645:6;14642:14;14639:34;;;14669:1;14666;14659:12;14639:34;14692:74;14758:7;14749:6;14738:9;14734:22;14692:74;:::i;:::-;14682:84;;14819:2;14808:9;14804:18;14791:32;14775:48;;14848:2;14838:8;14835:16;14832:36;;;14864:1;14861;14854:12;14832:36;14903:97;14992:7;14981:8;14970:9;14966:24;14903:97;:::i;:::-;15019:8;;-1:-1:-1;14877:123:39;-1:-1:-1;15107:2:39;15092:18;;15079:32;;-1:-1:-1;15123:16:39;;;15120:36;;;15152:1;15149;15142:12;15120:36;15191:97;15280:7;15269:8;15258:9;15254:24;15191:97;:::i;:::-;15307:8;;-1:-1:-1;15165:123:39;-1:-1:-1;15395:2:39;15380:18;;15367:32;;-1:-1:-1;15411:16:39;;;15408:36;;;15440:1;15437;15430:12;15408:36;;15479:97;15568:7;15557:8;15546:9;15542:24;15479:97;:::i;:::-;15595:8;;-1:-1:-1;15453:123:39;-1:-1:-1;;15677:3:39;15662:19;;15649:33;;-1:-1:-1;15701:39:39;15735:3;15720:19;;15701:39;:::i;:::-;15691:49;;15787:3;15776:9;15772:19;15759:33;15749:43;;13981:1817;;;;;;;;;;;;;:::o;15803:879::-;16119:2;16131:21;;;16201:13;;16104:18;;;16223:22;;;16071:4;;16298;;16276:2;16261:18;;;16325:15;;;16071:4;16368:185;16382:6;16379:1;16376:13;16368:185;;;16457:13;;16450:21;16443:29;16431:42;;16493:12;;;;16528:15;;;;16404:1;16397:9;16368:185;;;16372:3;;;16598:9;16593:3;16589:19;16584:2;16573:9;16569:18;16562:47;16626:50;16672:3;16664:6;16626:50;:::i;:::-;16618:58;15803:879;-1:-1:-1;;;;;;15803:879:39:o;16687:487::-;16798:6;16806;16859:2;16847:9;16838:7;16834:23;16830:32;16827:52;;;16875:1;16872;16865:12;16827:52;16915:9;16902:23;-1:-1:-1;;;;;16940:6:39;16937:30;16934:50;;;16980:1;16977;16970:12;16934:50;17019:95;17106:7;17097:6;17086:9;17082:22;17019:95;:::i;:::-;17133:8;;16993:121;;-1:-1:-1;16687:487:39;-1:-1:-1;;;;16687:487:39:o;17371:879::-;17549:6;17557;17565;17573;17626:2;17614:9;17605:7;17601:23;17597:32;17594:52;;;17642:1;17639;17632:12;17594:52;17682:9;17669:23;-1:-1:-1;;;;;17752:2:39;17744:6;17741:14;17738:34;;;17768:1;17765;17758:12;17738:34;17807:95;17894:7;17885:6;17874:9;17870:22;17807:95;:::i;:::-;17921:8;;-1:-1:-1;17781:121:39;-1:-1:-1;18009:2:39;17994:18;;17981:32;;-1:-1:-1;18025:16:39;;;18022:36;;;18054:1;18051;18044:12;18022:36;;18093:97;18182:7;18171:8;18160:9;18156:24;18093:97;:::i;:::-;17371:879;;;;-1:-1:-1;18209:8:39;-1:-1:-1;;;;17371:879:39:o;18255:452::-;18348:6;18356;18409:2;18397:9;18388:7;18384:23;18380:32;18377:52;;;18425:1;18422;18415:12;18377:52;18465:9;18452:23;-1:-1:-1;;;;;18490:6:39;18487:30;18484:50;;;18530:1;18527;18520:12;18484:50;18553:22;;18609:2;18591:16;;;18587:25;18584:45;;;18625:1;18622;18615:12;18584:45;18648:2;18697;18682:18;;;;18669:32;;-1:-1:-1;;;18255:452:39:o;18712:994::-;18894:6;18902;18910;18918;18926;18979:3;18967:9;18958:7;18954:23;18950:33;18947:53;;;18996:1;18993;18986:12;18947:53;19036:9;19023:23;-1:-1:-1;;;;;19106:2:39;19098:6;19095:14;19092:34;;;19122:1;19119;19112:12;19092:34;19145:22;;;;19201:3;19183:16;;;19179:26;19176:46;;;19218:1;19215;19208:12;19176:46;19241:2;;-1:-1:-1;19296:2:39;19281:18;;19268:32;;19312:16;;;19309:36;;;19341:1;19338;19331:12;19309:36;;19380:97;19469:7;19458:8;19447:9;19443:24;19380:97;:::i;:::-;19496:8;;-1:-1:-1;19354:123:39;-1:-1:-1;;19578:2:39;19563:18;;19550:32;;-1:-1:-1;19632:2:39;19617:18;;19604:32;19645:31;19604:32;19645:31;:::i;:::-;19695:5;19685:15;;;18712:994;;;;;;;;:::o;19711:1460::-;20046:6;20054;20062;20070;20078;20086;20094;20102;20155:3;20143:9;20134:7;20130:23;20126:33;20123:53;;;20172:1;20169;20162:12;20123:53;20212:9;20199:23;-1:-1:-1;;;;;20282:2:39;20274:6;20271:14;20268:34;;;20298:1;20295;20288:12;20268:34;20337:95;20424:7;20415:6;20404:9;20400:22;20337:95;:::i;:::-;20451:8;;-1:-1:-1;20311:121:39;-1:-1:-1;20539:2:39;20524:18;;20511:32;;-1:-1:-1;20555:16:39;;;20552:36;;;20584:1;20581;20574:12;20552:36;20623:97;20712:7;20701:8;20690:9;20686:24;20623:97;:::i;:::-;20739:8;;-1:-1:-1;20597:123:39;-1:-1:-1;20827:2:39;20812:18;;20799:32;;-1:-1:-1;20843:16:39;;;20840:36;;;20872:1;20869;20862:12;20840:36;;20911:97;21000:7;20989:8;20978:9;20974:24;20911:97;:::i;:::-;19711:1460;;;;-1:-1:-1;19711:1460:39;;;;21027:8;;21109:2;21094:18;;21081:32;;21160:3;21145:19;21132:33;;-1:-1:-1;19711:1460:39;-1:-1:-1;;;;19711:1460:39:o;21176:247::-;21235:6;21288:2;21276:9;21267:7;21263:23;21259:32;21256:52;;;21304:1;21301;21294:12;21256:52;21343:9;21330:23;21362:31;21387:5;21362:31;:::i;21428:388::-;21633:2;21622:9;21615:21;21596:4;21653:45;21694:2;21683:9;21679:18;21671:6;21653:45;:::i;:::-;21729:2;21714:18;;21707:34;;;;-1:-1:-1;;;;;;21777:32:39;;;;21772:2;21757:18;;;21750:60;21645:53;21428:388;-1:-1:-1;21428:388:39:o;21821:400::-;21920:6;21973:2;21961:9;21952:7;21948:23;21944:32;21941:52;;;21989:1;21986;21979:12;21941:52;22029:9;22016:23;-1:-1:-1;;;;;22054:6:39;22051:30;22048:50;;;22094:1;22091;22084:12;22048:50;22117:22;;22173:3;22155:16;;;22151:26;22148:46;;;22190:1;22187;22180:12;22728:2710;22914:9;22949:77;22965:60;23018:6;22965:60;:::i;22949:77::-;23060:19;;;23098:4;23118:12;;;;23048:3;23149:1;23184:15;;;23173:27;;23223:14;23212:26;;23209:46;;;23251:1;23248;23241:12;23209:46;23275:5;23289:2116;23305:6;23300:3;23297:15;23289:2116;;;23391:3;23378:17;-1:-1:-1;;;;;23468:2:39;23455:11;23452:19;23449:109;;;23512:1;23541:2;23537;23530:14;23449:109;23592:11;23585:5;23581:23;23571:33;;23649:4;23644:2;23628:14;23624:23;23620:34;23617:124;;;23695:1;23724:2;23720;23713:14;23617:124;23769:22;;:::i;:::-;23833:2;23820:16;23811:7;23804:33;23886:2;23882;23878:11;23865:25;23925:1;23916:7;23913:14;23903:112;;23969:1;23998:2;23994;23987:14;23903:112;24035:16;;;24028:33;24084:2;24137:11;;;24124:25;24106:16;;;24099:51;24173:2;24226:11;;;24213:25;24195:16;;;24188:51;24263:3;24306:12;;;24293:26;24335:14;;;24332:107;;;24391:1;24421:3;24416;24409:16;24332:107;24463:15;;;;;24521:14;24514:4;24505:14;;24501:35;24491:136;;24579:1;24568:12;;24609:3;24604;24597:16;24491:136;24664:3;24651:17;24640:28;;24694:74;24710:57;24763:3;24710:57;:::i;24694:74::-;24812:18;;;24908:12;;;24899:22;;24895:31;;;24852:14;;;;24955;24942:28;;24939:121;;;25012:1;25042:3;25037;25030:16;24939:121;25086:12;;;;25111:174;25129:8;25122:5;25119:19;25111:174;;;25211:19;;25197:34;;25150:14;;;;25257;;;;25111:174;;;25305:17;;;25298:32;;;;-1:-1:-1;25343:20:39;;-1:-1:-1;;25383:12:39;;;;23322;;23289:2116;;;-1:-1:-1;25427:5:39;;22728:2710;-1:-1:-1;;;;;;;22728:2710:39:o;25443:577::-;25565:4;25571:6;25631:11;25618:25;25725:2;25721:7;25710:8;25694:14;25690:29;25686:43;25666:18;25662:68;25652:96;;25744:1;25741;25734:12;25652:96;25771:33;;25823:20;;;-1:-1:-1;;;;;;25855:30:39;;25852:50;;;25898:1;25895;25888:12;25852:50;25931:4;25919:17;;-1:-1:-1;25990:4:39;25978:17;;25962:14;25958:38;25948:49;;25945:69;;;26010:1;26007;26000:12;26025:232;26111:6;26164:3;26152:9;26143:7;26139:23;26135:33;26132:53;;;26181:1;26178;26171:12;26132:53;26204:47;26243:7;26232:9;26204:47;:::i;26262:585::-;26392:4;26398:6;26458:11;26445:25;26552:2;26548:7;26537:8;26521:14;26517:29;26513:43;26493:18;26489:68;26479:96;;26571:1;26568;26561:12;26479:96;26598:33;;26650:20;;;-1:-1:-1;;;;;;26682:30:39;;26679:50;;;26725:1;26722;26715:12;26679:50;26758:4;26746:17;;-1:-1:-1;26817:4:39;26805:17;;26789:14;26785:38;26775:49;;26772:69;;;26837:1;26834;26827:12;26852:248;26946:6;26999:3;26987:9;26978:7;26974:23;26970:33;26967:53;;;27016:1;27013;27006:12;26967:53;27039:55;27086:7;27075:9;27039:55;:::i;27105:207::-;27178:6;27231:2;27219:9;27210:7;27206:23;27202:32;27199:52;;;27247:1;27244;27237:12;27199:52;27270:36;27296:9;27270:36;:::i;27317:211::-;27431:9;27468:54;27507:14;27500:5;27468:54;:::i;27533:489::-;27600:5;27648:4;27636:9;27631:3;27627:19;27623:30;27620:50;;;27666:1;27663;27656:12;27620:50;27699:4;27693:11;27743:4;27735:6;27731:17;27814:6;27802:10;27799:22;-1:-1:-1;;;;;27766:10:39;27763:34;27760:62;27757:88;;;27825:18;;:::i;:::-;27861:4;27854:24;27926:23;;27911:39;;28011:2;27996:18;;;27983:32;27966:15;;;27959:57;;;;-1:-1:-1;27896:6:39;27533:489;-1:-1:-1;27533:489:39:o;28027:1832::-;28273:9;28308:77;28324:60;28377:6;28324:60;:::i;28308:77::-;28407:3;28431:6;28426:3;28419:19;28457:4;28486:2;28481:3;28477:12;28470:19;;28530:6;28527:1;28523:14;28516:5;28512:26;28561:14;28553:6;28550:26;28547:46;;;28589:1;28586;28579:12;28547:46;28613:5;28627:1199;28643:6;28638:3;28635:15;28627:1199;;;28729:3;28716:17;-1:-1:-1;;;;;28752:11:39;28749:35;28746:125;;;28825:1;28854:2;28850;28843:14;28746:125;28894:23;;28959:14;28952:4;28944:13;;28940:34;28930:132;;29016:1;29045:2;29041;29034:14;28930:132;29098:2;29085:16;29127:73;29143:56;29196:2;29143:56;:::i;29127:73::-;29244:17;;;29342:1;29338:10;;;;29330:19;;29326:28;;;29283:14;;;;29383;29370:28;;29367:118;;;29439:1;29468:2;29464;29457:14;29367:118;29511:11;;;;29535:218;29553:8;29546:5;29543:19;29535:218;;;29637:61;29683:14;29676:5;29637:61;:::i;:::-;29630:5;29623:76;29736:2;29729:5;29725:14;29716:23;;29585:4;29578:5;29574:16;29565:25;;29535:218;;;29766:18;;-1:-1:-1;;;29804:12:39;;;;28660;;28627:1199;;;-1:-1:-1;29848:5:39;;28027:1832;-1:-1:-1;;;;;;28027:1832:39:o;29864:127::-;29925:10;29920:3;29916:20;29913:1;29906:31;29956:4;29953:1;29946:15;29980:4;29977:1;29970:15;29996:322;30087:4;30145:11;30132:25;30239:2;30235:7;30224:8;30208:14;30204:29;30200:43;30180:18;30176:68;30166:96;;30258:1;30255;30248:12;30166:96;30279:33;;;;;29996:322;-1:-1:-1;;29996:322:39:o;30323:333::-;30424:4;30482:11;30469:25;30576:3;30572:8;30561;30545:14;30541:29;30537:44;30517:18;30513:69;30503:97;;30596:1;30593;30586:12;30661:217;30779:9;30816:56;30857:14;30850:5;30816:56;:::i;30883:521::-;30960:4;30966:6;31026:11;31013:25;31120:2;31116:7;31105:8;31089:14;31085:29;31081:43;31061:18;31057:68;31047:96;;31139:1;31136;31129:12;31047:96;31166:33;;31218:20;;;-1:-1:-1;;;;;;31250:30:39;;31247:50;;;31293:1;31290;31283:12;31247:50;31326:4;31314:17;;-1:-1:-1;31357:14:39;31353:27;;;31343:38;;31340:58;;;31394:1;31391;31384:12;31669:584;31801:4;31807:6;31867:11;31854:25;31961:2;31957:7;31946:8;31930:14;31926:29;31922:43;31902:18;31898:68;31888:96;;31980:1;31977;31970:12;31888:96;32007:33;;32059:20;;;-1:-1:-1;;;;;;32091:30:39;;32088:50;;;32134:1;32131;32124:12;32088:50;32167:4;32155:17;;-1:-1:-1;32218:1:39;32214:14;;;32198;32194:35;32184:46;;32181:66;;;32243:1;32240;32233:12;33519:127;33580:10;33575:3;33571:20;33568:1;33561:31;33611:4;33608:1;33601:15;33635:4;33632:1;33625:15;33651:128;33691:3;33722:1;33718:6;33715:1;33712:13;33709:39;;;33728:18;;:::i;:::-;-1:-1:-1;33764:9:39;;33651:128::o;33784:168::-;33824:7;33890:1;33886;33882:6;33878:14;33875:1;33872:21;33867:1;33860:9;33853:17;33849:45;33846:71;;;33897:18;;:::i;:::-;-1:-1:-1;33937:9:39;;33784:168::o;33957:473::-;34022:3;34060:5;34054:12;34087:6;34082:3;34075:19;34113:4;34142:2;34137:3;34133:12;34126:19;;34179:2;34172:5;34168:14;34200:1;34210:195;34224:6;34221:1;34218:13;34210:195;;;34273:50;34319:3;34310:6;34304:13;34273:50;:::i;:::-;34352:4;34343:14;;;;;34380:15;;;;34246:1;34239:9;34210:195;;34435:1410;34825:4;34854:3;34895:2;34884:9;34880:18;34925:6;34914:9;34907:25;34951:2;34989:1;34985;34980:3;34976:11;34972:19;35039:2;35031:6;35027:15;35022:2;35011:9;35007:18;35000:43;35062:2;35100;35095;35084:9;35080:18;35073:30;35123:6;35158;35152:13;35189:6;35181;35174:22;35227:3;35216:9;35212:19;35205:26;;35266:2;35258:6;35254:15;35240:29;;35287:1;35297:414;35311:6;35308:1;35305:13;35297:414;;;35376:6;35370:13;35396:40;35432:3;35427:2;35421:9;35396:40;:::i;:::-;35480:11;;;35474:18;35470:27;;35456:12;;;35449:49;35538:11;;;35532:18;35518:12;;;35511:40;35574:4;35618:11;;;35612:18;35598:12;;;35591:40;35686:15;;;;35651:12;;;;35333:1;35326:9;35297:414;;;35301:3;;35758:9;35753:3;35749:19;35742:4;35731:9;35727:20;35720:49;35786:53;35835:3;35827:6;35786:53;:::i;:::-;35778:61;34435:1410;-1:-1:-1;;;;;;;;;;;;34435:1410:39:o;35850:125::-;35890:4;35918:1;35915;35912:8;35909:34;;;35923:18;;:::i;:::-;-1:-1:-1;35960:9:39;;35850:125::o;35980:253::-;36077:6;36130:2;36118:9;36109:7;36105:23;36101:32;36098:52;;;36146:1;36143;36136:12;36098:52;36169:58;36219:7;36208:9;36169:58;:::i;36562:135::-;36638:1;36631:5;36628:12;36618:46;;36644:18;;:::i;36702:198::-;36843:2;36828:18;;36855:39;36832:9;36876:6;36855:39;:::i;36905:815::-;36967:3;37005:5;36999:12;37032:6;37027:3;37020:19;37058:4;37087:2;37082:3;37078:12;37071:19;;37124:2;37117:5;37113:14;37145:1;37155:540;37169:6;37166:1;37163:13;37155:540;;;37234:6;37228:13;37254:40;37290:3;37285:2;37279:9;37254:40;:::i;:::-;37338:11;;;37332:18;-1:-1:-1;;;;;37328:44:39;37314:12;;;37307:66;37396:4;37440:11;;;37434:18;37420:12;;;37413:40;37476:4;37520:11;;;37514:18;37500:12;;;37493:40;37556:4;37600:11;;;37594:18;37580:12;;;37573:40;37360:3;37633:14;;;;37670:15;;;;37369:1;37184:9;37155:540;;37725:982;37795:3;37833:5;37827:12;37860:6;37855:3;37848:19;37886:4;37915:2;37910:3;37906:12;37899:19;;37952:2;37945:5;37941:14;37973:1;37983:699;37997:6;37994:1;37991:13;37983:699;;;38062:6;38056:13;38082:40;38118:3;38113:2;38107:9;38082:40;:::i;:::-;38161:11;;;38155:18;-1:-1:-1;;;;;38249:21:39;;;38235:12;;;38228:43;38294:4;38338:11;;;38332:18;38318:12;;;38311:40;38374:4;38418:11;;;38412:18;38398:12;;;38391:40;38454:4;38498:11;;;38492:18;38478:12;;;38471:40;38204:3;38582:11;;;38576:18;38572:27;38558:12;;;38551:49;38629:4;38620:14;;;;38657:15;;;;38213:1;38012:9;37983:699;;38712:140;38793:1;38786:5;38783:12;38773:46;;38799:18;;:::i;38979:435::-;39032:3;39070:5;39064:12;39097:6;39092:3;39085:19;39123:4;39152:2;39147:3;39143:12;39136:19;;39189:2;39182:5;39178:14;39210:1;39220:169;39234:6;39231:1;39228:13;39220:169;;;39295:13;;39283:26;;39329:12;;;;39364:15;;;;39256:1;39249:9;39220:169;;39419:1146;39488:3;39526:5;39520:12;39553:6;39548:3;39541:19;39579:4;39620:2;39615:3;39611:12;39645:11;39672;39665:18;;39722:6;39719:1;39715:14;39708:5;39704:26;39692:38;;39764:2;39757:5;39753:14;39785:1;39795:744;39809:6;39806:1;39803:13;39795:744;;;39880:5;39874:4;39870:16;39865:3;39858:29;39916:6;39910:13;39946:4;39982:2;39976:9;39970:4;39963:23;40033:2;40029;40025:11;40019:18;40050:49;40095:2;40089:4;40085:13;40071:12;40050:49;:::i;:::-;-1:-1:-1;40122:4:39;40167:11;;;40161:18;40146:13;;;40139:41;40203:4;40248:11;;;40242:18;40227:13;;;40220:41;40284:4;40329:11;;;40323:18;40361:13;;;40354:25;;;40400:59;40445:13;;;40323:18;40400:59;:::i;:::-;40517:12;;;;40392:67;-1:-1:-1;;;40482:15:39;;;;39831:1;39824:9;39795:744;;;-1:-1:-1;40555:4:39;;39419:1146;-1:-1:-1;;;;;;;39419:1146:39:o;40570:2814::-;41041:6;41030:9;41023:25;41113:1;41109;41104:3;41100:11;41096:19;41088:6;41084:32;41079:2;41068:9;41064:18;41057:60;41153:3;41148:2;41137:9;41133:18;41126:31;41004:4;41176:3;41214:6;41208:13;41258:3;41252;41241:9;41237:19;41230:32;41271:59;41326:2;41315:9;41311:18;41296:12;41290:19;-1:-1:-1;;;;;11759:31:39;11747:44;;11693:104;41271:59;41385:2;41371:12;41367:21;41361:28;41408:6;41423:54;41473:2;41462:9;41458:18;41442:14;-1:-1:-1;;;;;11759:31:39;11747:44;;11693:104;41423:54;41532:2;41518:12;41514:21;41508:28;41486:50;;41573:2;41567:3;41556:9;41552:19;41545:31;;41599:74;41668:3;41657:9;41653:19;41637:14;41599:74;:::i;:::-;41585:88;;41728:4;41714:12;41710:23;41704:30;41803:3;41799:8;41787:9;41779:6;41775:22;41771:37;41765:3;41754:9;41750:19;41743:66;41832:69;41894:6;41878:14;41832:69;:::i;:::-;41818:83;;;41956:4;41942:12;41938:23;41932:30;41971:62;42028:3;42017:9;42013:19;41997:14;41971:62;:::i;:::-;;42094:3;42080:12;42076:22;42070:29;42064:3;42053:9;42049:19;42042:58;42161:4;42147:12;42143:23;42137:30;42131:3;42120:9;42116:19;42109:59;42229:4;42215:12;42211:23;42205:30;42199:3;42188:9;42184:19;42177:59;42255:6;42322:2;42308:12;42304:21;42298:28;42292:3;42281:9;42277:19;42270:57;42346:6;42413:2;42399:12;42395:21;42389:28;42383:3;42372:9;42368:19;42361:57;42479:2;42465:12;42461:21;42455:28;42449:3;42438:9;42434:19;42427:57;42533:2;42525:6;42521:15;42515:22;42493:44;;42546:56;42596:4;42585:9;42581:20;42565:14;-1:-1:-1;;;;;38923:44:39;38911:57;;38857:117;42546:56;42651:2;42639:15;;42633:22;-1:-1:-1;;;;;38923:44:39;42714:4;42699:20;;38911:57;42769:4;42757:17;;42751:24;42842:22;;;-1:-1:-1;;42838:31:39;;;42818:18;;;42811:59;42751:24;;-1:-1:-1;;;42893:41:39;42846:6;42751:24;42893:41;:::i;:::-;42879:55;;42983:4;42975:6;42971:17;42965:24;42943:46;;43053:2;43041:9;43033:6;43029:22;43025:31;43020:2;43009:9;43005:18;42998:59;;;43077:41;43111:6;43095:14;43077:41;:::i;:::-;43066:52;;;;43165:9;43160:3;43156:19;43149:4;43138:9;43134:20;43127:49;43199:41;43236:3;43228:6;43199:41;:::i;:::-;43185:55;;43290:9;43282:6;43278:22;43271:4;43260:9;43256:20;43249:52;43318:60;43371:6;43363;43318:60;:::i;:::-;43310:68;40570:2814;-1:-1:-1;;;;;;;;40570:2814:39:o
Swarm Source
ipfs://d9ec6bf53c7c4dd207e9b7af873aae1b86f9ebf0a16709b20f4f94de35603786
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.