Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
OrderBook
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 1000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; import {ReentrancyGuardTransientUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardTransientUpgradeable.sol"; import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {IERC2981} from "@openzeppelin/contracts/interfaces/IERC2981.sol"; import {BokkyPooBahsRedBlackTreeLibrary} from "./BokkyPooBahsRedBlackTreeLibrary.sol"; import {IBrushToken} from "../interfaces/external/IBrushToken.sol"; import {IOrderBook} from "./interfaces/IOrderBook.sol"; import {IActivityPoints, IActivityPointsCaller, ActivityType} from "../ActivityPoints/interfaces/IActivityPoints.sol"; /// @notice This efficient ERC1155 order book is an upgradeable UUPS proxy contract. It has functions for bulk placing /// limit orders, cancelling limit orders, and claiming NFTs and tokens from filled or partially filled orders. /// It suppports ERC2981 royalties, and optional dev & burn fees on successful trades. contract OrderBook is UUPSUpgradeable, OwnableUpgradeable, ERC1155Holder, IOrderBook, IActivityPointsCaller, ReentrancyGuardTransientUpgradeable { using BokkyPooBahsRedBlackTreeLibrary for BokkyPooBahsRedBlackTreeLibrary.Tree; using BokkyPooBahsRedBlackTreeLibrary for BokkyPooBahsRedBlackTreeLibrary.Node; using SafeERC20 for IBrushToken; // constants uint16 private constant MAX_ORDERS_HIT = 500; uint8 private constant NUM_ORDERS_PER_SEGMENT = 4; uint256 private constant MAX_ORDER_ID = 1_099_511_627_776; uint256 private constant MAX_CLAIMABLE_ORDERS = 200; // slot_0 IERC1155 private _nft; // slot_1 IBrushToken private _coin; // slot_2 address private _devAddr; uint16 private _devFee; uint8 private _burntFee; uint16 private _royaltyFee; uint16 private _maxOrdersPerPrice; uint40 private _nextOrderId; // slot_3 address private _royaltyRecipient; // mappings mapping(uint256 tokenId => TokenIdInfo tokenIdInfo) private _tokenIdInfos; mapping(uint256 tokenId => BokkyPooBahsRedBlackTreeLibrary.Tree) private _asks; mapping(uint256 tokenId => BokkyPooBahsRedBlackTreeLibrary.Tree) private _bids; // token id => price => ask(quantity (uint24), id (uint40)) x 4 mapping(uint256 tokenId => mapping(uint256 price => bytes32[] segments)) private _asksAtPrice; // token id => price => bid(quantity (uint24), id (uint40)) x 4 mapping(uint256 tokenId => mapping(uint256 price => bytes32[] segments)) private _bidsAtPrice; ClaimableTokenInfo[MAX_ORDER_ID] private _tokenClaimables; IActivityPoints private _activityPoints; /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /// @notice Initialize the contract as part of the proxy contract deployment /// @param nft Address of the nft /// @param token The quote token /// @param devAddr The address to receive trade fees /// @param devFee The fee to send to the dev address (max 10%) /// @param burntFee The fee to burn (max 2.55%) /// @param maxOrdersPerPrice The maximum number of orders allowed at each price level function initialize( IERC1155 nft, address token, address devAddr, uint16 devFee, uint8 burntFee, uint16 maxOrdersPerPrice, IActivityPoints activityPoints ) external initializer { __Ownable_init(_msgSender()); __UUPSUpgradeable_init(); setFees(devAddr, devFee, burntFee); // nft must be an ERC1155 via ERC165 require(nft.supportsInterface(type(IERC1155).interfaceId), NotERC1155()); _activityPoints = activityPoints; _nft = nft; _coin = IBrushToken(token); updateRoyaltyFee(); // The max orders spans segments, so num segments = maxOrdersPrice / NUM_ORDERS_PER_SEGMENT setMaxOrdersPerPrice(maxOrdersPerPrice); _nextOrderId = 1; } // TODO: remove in prod function setActivityPoints(address activityPoints) external override onlyOwner { _activityPoints = IActivityPoints(activityPoints); } /// @notice Place market order /// @param order market order to be placed function marketOrder(MarketOrder calldata order) external override nonReentrant { // Must fufill the order and be below the total cost (or above depending on the side) uint256 coinsToUs; uint256 coinsFromUs; address sender = _msgSender(); uint256[] memory orderIdsPool = new uint256[](MAX_ORDERS_HIT); uint256[] memory quantitiesPool = new uint256[](MAX_ORDERS_HIT); uint256 cost = _makeMarketOrder(order, orderIdsPool, quantitiesPool); bool isBuy = order.side == OrderSide.Buy; (uint256 royalty, uint256 dev, uint256 burn) = _calcFees(cost); if (isBuy) { require(cost <= order.totalCost, TotalCostConditionNotMet()); coinsToUs = cost; } else { require(cost >= order.totalCost, TotalCostConditionNotMet()); // Transfer tokens to the seller if any have sold uint256 fees = royalty + dev + burn; coinsFromUs = cost - fees; } if (coinsToUs != 0) { _coin.safeTransferFrom(sender, address(this), coinsToUs); } if (coinsFromUs != 0) { _coin.safeTransfer(sender, coinsFromUs); } if (!isBuy) { // Selling, transfer all NFTs to us _safeTransferNFTsToUs(sender, order.tokenId, order.quantity); } else { // Buying transfer the NFTs to the taker _safeTransferNFTsFromUs(sender, order.tokenId, order.quantity); } _sendFees(royalty, dev, burn); } /// @notice Place multiple limit orders in the order book /// @param orders Array of limit orders to be placed function limitOrders(LimitOrder[] calldata orders) external override nonReentrant { _limitOrders(orders); } /// @notice Cancel multiple orders in the order book /// @param orderIds Array of order IDs to be cancelled /// @param orders Information about the orders so that they can be found in the order book function cancelOrders(uint256[] calldata orderIds, CancelOrder[] calldata orders) external override nonReentrant { _cancelOrders(orderIds, orders); } /// @notice Cancel multiple orders and place multiple limit orders in the order book. Can be used to replace orders /// @param orderIds Array of order IDs to be cancelled /// @param orders Information about the orders so that they can be found in the order book /// @param newOrders Array of limit orders to be placed function cancelAndMakeLimitOrders( uint256[] calldata orderIds, CancelOrder[] calldata orders, LimitOrder[] calldata newOrders ) external override nonReentrant { _cancelOrders(orderIds, orders); _limitOrders(newOrders); } /// @notice Claim tokens associated with filled or partially filled orders. /// Must be the maker of these orders. /// @param orderIds Array of order IDs from which to claim NFTs function claimTokens(uint256[] calldata orderIds) external override nonReentrant { _claimTokens(orderIds); } /// @notice Claim NFTs associated with filled or partially filled orders /// Must be the maker of these orders. /// @param orderIds Array of order IDs from which to claim NFTs function claimNFTs(uint256[] calldata orderIds) external override nonReentrant { _claimNFTs(orderIds); } /// @notice Convience function to claim both tokens and nfts in filled or partially filled orders. /// Must be the maker of these orders. /// @param coinOrderIds Array of order IDs from which to claim tokens /// @param nftOrderIds Array of order IDs from which to claim NFTs function claimAll(uint256[] calldata coinOrderIds, uint256[] calldata nftOrderIds) external override nonReentrant { require(coinOrderIds.length != 0 || nftOrderIds.length != 0, NothingToClaim()); require(coinOrderIds.length + nftOrderIds.length <= MAX_CLAIMABLE_ORDERS, ClaimingTooManyOrders()); if (coinOrderIds.length != 0) { _claimTokens(coinOrderIds); } if (nftOrderIds.length != 0) { _claimNFTs(nftOrderIds); } } /// @notice When the _nft royalty changes this updates the fee and recipient. Assumes all token ids have the same royalty function updateRoyaltyFee() public { if (_nft.supportsInterface(type(IERC2981).interfaceId)) { (address royaltyRecipient, uint256 royaltyFee) = IERC2981(address(_nft)).royaltyInfo(1, 10000); _royaltyRecipient = royaltyRecipient; _royaltyFee = uint16(royaltyFee); } else { _royaltyRecipient = address(0); _royaltyFee = 0; } } /// @notice Get the amount of tokens claimable for these orders /// @param orderIds The order IDs of which to find the claimable tokens for function tokensClaimable(uint40[] calldata orderIds) external view override returns (uint256 amount) { for (uint256 i = 0; i < orderIds.length; ++i) { ClaimableTokenInfo storage claimableTokenInfo = _tokenClaimables[orderIds[i]]; if (claimableTokenInfo.tokenId == 0) { amount += claimableTokenInfo.amount; } } } /// @notice Get the amount of NFTs claimable for these orders /// @param orderIds The order IDs to get the claimable NFTs for function nftsClaimable(uint40[] calldata orderIds) external view override returns (uint256[] memory amounts) { amounts = new uint256[](orderIds.length); for (uint256 i = 0; i < orderIds.length; ++i) { ClaimableTokenInfo storage claimableTokenInfo = _tokenClaimables[orderIds[i]]; if (claimableTokenInfo.tokenId != 0) { amounts[i] = claimableTokenInfo.amount; } } } /// @notice Get the token ID info for a specific token ID /// @param tokenId The token ID to get the info for function getTokenIdInfo(uint256 tokenId) external view override returns (TokenIdInfo memory) { return _tokenIdInfos[tokenId]; } function getClaimableTokenInfo(uint40 orderId) external view override returns (ClaimableTokenInfo memory) { return _tokenClaimables[orderId]; } /// @notice Get the highest bid for a specific token ID /// @param tokenId The token ID to get the highest bid for function getHighestBid(uint256 tokenId) public view override returns (uint72) { return _bids[tokenId].last(); } /// @notice Get the lowest ask for a specific token ID /// @param tokenId The token ID to get the lowest ask for function getLowestAsk(uint256 tokenId) public view override returns (uint72) { return _asks[tokenId].first(); } /// @notice Get the order book entry for a specific order ID /// @param side The side of the order book to get the order from /// @param tokenId The token ID to get the order for /// @param price The price level to get the order for function getNode( OrderSide side, uint256 tokenId, uint72 price ) external view override returns (BokkyPooBahsRedBlackTreeLibrary.Node memory) { if (side == OrderSide.Buy) { return _bids[tokenId].getNode(price); } else { return _asks[tokenId].getNode(price); } } /// @notice Check if the node exists /// @param side The side of the order book to get the order from /// @param tokenId The token ID to get the order for /// @param price The price level to get the order for function nodeExists(OrderSide side, uint256 tokenId, uint72 price) external view override returns (bool) { if (side == OrderSide.Buy) { return _bids[tokenId].exists(price); } else { return _asks[tokenId].exists(price); } } /// @notice Get all orders at a specific price level /// @param side The side of the order book to get orders from /// @param tokenId The token ID to get orders for /// @param price The price level to get orders for function allOrdersAtPrice( OrderSide side, uint256 tokenId, uint72 price ) external view override returns (Order[] memory) { if (side == OrderSide.Buy) { return _allOrdersAtPriceSide(_bidsAtPrice[tokenId][price], _bids[tokenId], price); } else { return _allOrdersAtPriceSide(_asksAtPrice[tokenId][price], _asks[tokenId], price); } } function _limitOrders(LimitOrder[] calldata orders) private { uint256 royalty; uint256 dev; uint256 burn; uint256 coinsToUs; uint256 coinsFromUs; uint256 nftsToUs; uint256[] memory nftIdsToUs = new uint256[](orders.length); uint256[] memory nftAmountsToUs = new uint256[](orders.length); uint256 lengthFromUs; uint256[] memory nftIdsFromUs = new uint256[](orders.length); uint256[] memory nftAmountsFromUs = new uint256[](orders.length); address sender = _msgSender(); // Reuse this array in all the orders uint256[] memory orderIdsPool = new uint256[](MAX_ORDERS_HIT); uint256[] memory quantitiesPool = new uint256[](MAX_ORDERS_HIT); // read the next order ID so we can increment in memory uint40 currentOrderId = _nextOrderId; for (uint256 i = 0; i < orders.length; ++i) { LimitOrder calldata limitOrder = orders[i]; (uint24 quantityAddedToBook, uint24 failedQuantity, uint256 cost) = _makeLimitOrder( currentOrderId, limitOrder, orderIdsPool, quantitiesPool ); if (quantityAddedToBook != 0) { ++currentOrderId; } uint256 feesOrder; if (cost != 0) { (uint256 royaltyOrder, uint256 devOrder, uint256 burnOrder) = _calcFees(cost); royalty += royaltyOrder; dev += devOrder; burn += burnOrder; feesOrder = royaltyOrder + devOrder + burnOrder; } if (limitOrder.side == OrderSide.Buy) { coinsToUs += cost + uint256(limitOrder.price) * quantityAddedToBook; if (cost != 0) { // Transfer the NFTs taken from the order book straight to the taker nftIdsFromUs[lengthFromUs] = limitOrder.tokenId; nftAmountsFromUs[lengthFromUs] = uint256(limitOrder.quantity) - quantityAddedToBook; ++lengthFromUs; } } else { // Selling, transfer all NFTs to us uint256 amount = limitOrder.quantity - failedQuantity; if (amount != 0) { nftIdsToUs[nftsToUs] = limitOrder.tokenId; nftAmountsToUs[nftsToUs] = amount; ++nftsToUs; } // Transfer tokens to the seller if any have sold coinsFromUs += cost - feesOrder; } } // update the state if any orders were added to the book if (currentOrderId != _nextOrderId) { _nextOrderId = currentOrderId; } if (coinsToUs != 0) { _coin.safeTransferFrom(sender, address(this), coinsToUs); } if (coinsFromUs != 0) { _coin.safeTransfer(sender, coinsFromUs); } if (nftsToUs != 0) { assembly ("memory-safe") { mstore(nftIdsToUs, nftsToUs) mstore(nftAmountsToUs, nftsToUs) } _safeBatchTransferNFTsToUs(sender, nftIdsToUs, nftAmountsToUs); } if (lengthFromUs != 0) { assembly ("memory-safe") { mstore(nftIdsFromUs, lengthFromUs) mstore(nftAmountsFromUs, lengthFromUs) } _safeBatchTransferNFTsFromUs(sender, nftIdsFromUs, nftAmountsFromUs); } _sendFees(royalty, dev, burn); } function _cancelOrders(uint256[] calldata orderIds, CancelOrder[] calldata orders) private { require(orderIds.length == orders.length, LengthMismatch()); address sender = _msgSender(); uint256 coinsFromUs = 0; uint256 nftsFromUs = 0; uint256 numberOfOrders = orderIds.length; uint256[] memory nftIdsFromUs = new uint256[](numberOfOrders); uint256[] memory nftAmountsFromUs = new uint256[](numberOfOrders); for (uint256 i = 0; i < numberOfOrders; ++i) { CancelOrder calldata cancelOrder = orders[i]; (OrderSide side, uint256 tokenId, uint72 price) = (cancelOrder.side, cancelOrder.tokenId, cancelOrder.price); if (side == OrderSide.Buy) { uint256 quantity = _cancelOrdersSide(orderIds[i], price, _bidsAtPrice[tokenId][price], _bids[tokenId]); // Send the remaining token back to them coinsFromUs += quantity * price; } else { uint256 quantity = _cancelOrdersSide(orderIds[i], price, _asksAtPrice[tokenId][price], _asks[tokenId]); // Send the remaining NFTs back to them nftIdsFromUs[nftsFromUs] = tokenId; nftAmountsFromUs[nftsFromUs] = quantity; ++nftsFromUs; } } emit OrdersCancelled(sender, orderIds); // Transfer tokens if there are any to send if (coinsFromUs != 0) { _coin.safeTransfer(sender, coinsFromUs); } // Send the NFTs if (nftsFromUs != 0) { // shrink the size assembly ("memory-safe") { mstore(nftIdsFromUs, nftsFromUs) mstore(nftAmountsFromUs, nftsFromUs) } _safeBatchTransferNFTsFromUs(sender, nftIdsFromUs, nftAmountsFromUs); } } function _claimTokens(uint256[] calldata orderIds) private { require(orderIds.length <= MAX_CLAIMABLE_ORDERS, ClaimingTooManyOrders()); uint256 amount; for (uint256 i = 0; i < orderIds.length; ++i) { uint40 orderId = SafeCast.toUint40(orderIds[i]); ClaimableTokenInfo storage claimableTokenInfo = _tokenClaimables[orderId]; uint256 claimableAmount = claimableTokenInfo.amount; require(claimableAmount != 0, NothingToClaim()); require(claimableTokenInfo.maker == _msgSender(), NotMaker()); claimableTokenInfo.amount = 0; amount += claimableAmount; } require(amount != 0, NothingToClaim()); _coin.safeTransfer(_msgSender(), amount); emit ClaimedTokens(_msgSender(), orderIds, amount); } function _claimNFTs(uint256[] calldata orderIds) private { require(orderIds.length <= MAX_CLAIMABLE_ORDERS, ClaimingTooManyOrders()); require(orderIds.length != 0, NothingToClaim()); uint256[] memory nftAmountsFromUs = new uint256[](orderIds.length); uint256[] memory tokenIds = new uint256[](orderIds.length); for (uint256 i = 0; i < tokenIds.length; ++i) { uint40 orderId = SafeCast.toUint40(orderIds[i]); ClaimableTokenInfo storage claimableTokenInfo = _tokenClaimables[orderId]; uint256 tokenId = claimableTokenInfo.tokenId; tokenIds[i] = tokenId; uint256 claimableAmount = claimableTokenInfo.amount; require(claimableAmount != 0, NothingToClaim()); require(_tokenClaimables[orderId].maker == _msgSender(), NotMaker()); nftAmountsFromUs[i] = claimableAmount; _tokenClaimables[orderId].amount = 0; } _safeBatchTransferNFTsFromUs(_msgSender(), tokenIds, nftAmountsFromUs); emit ClaimedNFTs(_msgSender(), orderIds, tokenIds, nftAmountsFromUs); } function _takeFromOrderBookSide( uint256 tokenId, uint72 price, uint24 quantity, uint256[] memory orderIdsPool, uint256[] memory quantitiesPool, OrderSide side, // which side are you taking from mapping(uint256 tokenId => mapping(uint256 price => bytes32[] segments)) storage segmentsAtPrice, mapping(uint256 tokenId => BokkyPooBahsRedBlackTreeLibrary.Tree) storage tree ) private returns (uint24 quantityRemaining, uint256 cost) { quantityRemaining = quantity; // reset the size assembly ("memory-safe") { mstore(orderIdsPool, MAX_ORDERS_HIT) mstore(quantitiesPool, MAX_ORDERS_HIT) } bool isTakingFromBuy = side == OrderSide.Buy; uint256 numberOfOrders; while (quantityRemaining != 0) { uint72 bestPrice = isTakingFromBuy ? getHighestBid(tokenId) : getLowestAsk(tokenId); if (bestPrice == 0 || (isTakingFromBuy ? bestPrice < price : bestPrice > price)) { // No more orders left break; } // Loop through all at this order uint256 numSegmentsFullyConsumed = 0; bytes32[] storage segments = segmentsAtPrice[tokenId][bestPrice]; BokkyPooBahsRedBlackTreeLibrary.Node storage node = tree[tokenId].getNode(bestPrice); bool eatIntoLastOrder; uint256 numOrdersWithinLastSegmentFullyConsumed; bytes32 segment; uint256 lastSegment; for (uint256 i = node.tombstoneOffset; i < segments.length && quantityRemaining != 0; ++i) { lastSegment = i; segment = segments[i]; uint256 numOrdersWithinSegmentConsumed; bool wholeSegmentConsumed; for (uint256 offset; offset < NUM_ORDERS_PER_SEGMENT && quantityRemaining != 0; ++offset) { uint256 remainingSegment = uint256(segment >> (offset * 64)); uint40 orderId = uint40(remainingSegment); if (orderId == 0) { // Check if there are any order left in this segment if (remainingSegment != 0) { // Skip this order in the segment as it's been deleted ++numOrdersWithinLastSegmentFullyConsumed; continue; } else { break; } } uint24 quantityL3 = uint24(uint256(segment >> (offset * 64 + 40))); uint256 quantityNFTClaimable = 0; if (quantityRemaining >= quantityL3) { // Consume this whole order quantityRemaining -= quantityL3; // Is the last one in the segment being fully consumed? wholeSegmentConsumed = offset == NUM_ORDERS_PER_SEGMENT - 1; ++numOrdersWithinSegmentConsumed; quantityNFTClaimable = quantityL3; } else { // Eat into the order segment = bytes32( (uint256(segment) & ~(uint256(0xffffff) << (offset * 64 + 40))) | (uint256(quantityL3 - quantityRemaining) << (offset * 64 + 40)) ); quantityNFTClaimable = quantityRemaining; quantityRemaining = 0; eatIntoLastOrder = true; } uint256 tradeCost = quantityNFTClaimable * bestPrice; cost += tradeCost; ClaimableTokenInfo storage claimableTokenInfo = _tokenClaimables[orderId]; if (isTakingFromBuy) { claimableTokenInfo.amount += uint80(quantityNFTClaimable); } else { uint256 fees = _calcFee(tradeCost); claimableTokenInfo.amount += uint80(tradeCost - fees); } orderIdsPool[numberOfOrders] = orderId; quantitiesPool[numberOfOrders] = quantityNFTClaimable; ++numberOfOrders; require(numberOfOrders < MAX_ORDERS_HIT, TooManyOrdersHit()); } if (wholeSegmentConsumed) { ++numSegmentsFullyConsumed; numOrdersWithinLastSegmentFullyConsumed = 0; } else { numOrdersWithinLastSegmentFullyConsumed += numOrdersWithinSegmentConsumed; if (eatIntoLastOrder) { break; } } } if (numSegmentsFullyConsumed != 0) { uint256 tombstoneOffset = node.tombstoneOffset; tree[tokenId].edit(bestPrice, uint32(numSegmentsFullyConsumed)); // Consumed all orders at this price level, so remove it from the tree if (numSegmentsFullyConsumed == segments.length - tombstoneOffset) { tree[tokenId].remove(bestPrice); // TODO: A ranged delete would be nice } } if (eatIntoLastOrder || numOrdersWithinLastSegmentFullyConsumed != 0) { // This segment wasn't completely filled before if (numOrdersWithinLastSegmentFullyConsumed != 0) { for (uint256 i; i < numOrdersWithinLastSegmentFullyConsumed; ++i) { segment &= _clearOrderMask(i); } } if (uint256(segment) == 0) { // All orders in the segment are consumed, delete from tree tree[tokenId].remove(bestPrice); } segments[lastSegment] = segment; if (eatIntoLastOrder) { break; } } } if (numberOfOrders != 0) { assembly ("memory-safe") { mstore(orderIdsPool, numberOfOrders) mstore(quantitiesPool, numberOfOrders) } address msgSender = _msgSender(); _activityPoints.rewardBlueTickets(ActivityType.orderbook_evt_ordersmatched, msgSender, true, cost / 1 ether); emit OrdersMatched(msgSender, orderIdsPool, quantitiesPool); } } function _takeFromOrderBook( OrderSide side, uint256 tokenId, uint72 price, uint24 quantity, uint256[] memory orderIdsPool, uint256[] memory quantitiesPool ) private returns (uint24 quantityRemaining, uint256 cost) { // Take as much as possible from the order book if (side == OrderSide.Buy) { (quantityRemaining, cost) = _takeFromOrderBookSide( tokenId, price, quantity, orderIdsPool, quantitiesPool, OrderSide.Sell, _asksAtPrice, _asks ); } else { (quantityRemaining, cost) = _takeFromOrderBookSide( tokenId, price, quantity, orderIdsPool, quantitiesPool, OrderSide.Buy, _bidsAtPrice, _bids ); } } function _allOrdersAtPriceSide( bytes32[] storage segments, BokkyPooBahsRedBlackTreeLibrary.Tree storage tree, uint72 price ) private view returns (Order[] memory orders) { if (!tree.exists(price)) { return orders; } BokkyPooBahsRedBlackTreeLibrary.Node storage node = tree.getNode(price); uint256 tombstoneOffset = node.tombstoneOffset; uint256 numInSegmentDeleted; { uint256 segment = uint256(segments[tombstoneOffset]); for (uint256 offset; offset < NUM_ORDERS_PER_SEGMENT; ++offset) { uint256 remainingSegment = uint64(segment >> (offset * 64)); uint64 order = uint64(remainingSegment); if (order == 0) { ++numInSegmentDeleted; } else { break; } } } orders = new Order[]((segments.length - tombstoneOffset) * NUM_ORDERS_PER_SEGMENT - numInSegmentDeleted); uint256 numberOfEntries; for (uint256 i = numInSegmentDeleted; i < orders.length + numInSegmentDeleted; ++i) { uint256 segment = uint256(segments[i / NUM_ORDERS_PER_SEGMENT + tombstoneOffset]); uint256 offset = i % NUM_ORDERS_PER_SEGMENT; uint40 id = uint40(segment >> (offset * 64)); if (id != 0) { uint24 quantity = uint24(segment >> (offset * 64 + 40)); orders[numberOfEntries] = Order(_tokenClaimables[id].maker, quantity, id); ++numberOfEntries; } } assembly ("memory-safe") { mstore(orders, numberOfEntries) } } function _cancelOrdersSide( uint256 orderId, uint72 price, bytes32[] storage segments, BokkyPooBahsRedBlackTreeLibrary.Tree storage tree ) private returns (uint24 quantity) { // Loop through all of them until we hit ours. if (!tree.exists(price)) { revert OrderNotFoundInTree(orderId, price); } BokkyPooBahsRedBlackTreeLibrary.Node storage node = tree.getNode(price); uint256 tombstoneOffset = node.tombstoneOffset; (uint256 index, uint256 offset) = _find(segments, tombstoneOffset, segments.length, orderId); if (index == type(uint).max) { revert OrderNotFound(orderId, price); } quantity = uint24(uint256(segments[index]) >> (offset * 64 + 40)); _cancelOrder(segments, price, index, offset, tombstoneOffset, tree); } function _makeMarketOrder( MarketOrder calldata order, uint256[] memory orderIdsPool, uint256[] memory quantitiesPool ) private returns (uint256 cost) { require(order.quantity != 0, NoQuantity()); uint128 tick = _tokenIdInfos[order.tokenId].tick; require(tick != 0, TokenDoesntExist(order.tokenId)); uint24 quantityRemaining; uint72 price = order.side == OrderSide.Buy ? type(uint72).max : 0; (quantityRemaining, cost) = _takeFromOrderBook( order.side, order.tokenId, price, order.quantity, orderIdsPool, quantitiesPool ); require(quantityRemaining == 0, FailedToTakeFromBook(_msgSender(), order.side, order.tokenId, quantityRemaining)); } function _makeLimitOrder( uint40 newOrderId, LimitOrder calldata limitOrder, uint256[] memory orderIdsPool, uint256[] memory quantitiesPool ) private returns (uint24 quantityAddedToBook, uint24 failedQuantity, uint256 cost) { require(limitOrder.quantity != 0, NoQuantity()); require(limitOrder.price != 0, PriceZero()); uint128 tick = _tokenIdInfos[limitOrder.tokenId].tick; require(tick != 0, TokenDoesntExist(limitOrder.tokenId)); require(limitOrder.price % tick == 0, PriceNotMultipleOfTick(tick)); uint24 quantityRemaining; (quantityRemaining, cost) = _takeFromOrderBook( limitOrder.side, limitOrder.tokenId, limitOrder.price, limitOrder.quantity, orderIdsPool, quantitiesPool ); // Add the rest to the order book if has the minimum required, in order to keep order books healthy if (quantityRemaining >= _tokenIdInfos[limitOrder.tokenId].minQuantity) { quantityAddedToBook = quantityRemaining; _addToBook(newOrderId, tick, limitOrder.side, limitOrder.tokenId, limitOrder.price, quantityAddedToBook); } else if (quantityRemaining != 0) { failedQuantity = quantityRemaining; emit FailedToAddToBook(_msgSender(), limitOrder.side, limitOrder.tokenId, limitOrder.price, failedQuantity); } } function _addToBookSide( mapping(uint256 price => bytes32[]) storage segmentsPriceMap, BokkyPooBahsRedBlackTreeLibrary.Tree storage tree, uint72 price, uint256 orderId, uint256 quantity, int128 tick // -1 for buy, +1 for sell ) private returns (uint72) { // Add to the bids section if (!tree.exists(price)) { tree.insert(price); } else { uint256 tombstoneOffset = tree.getNode(price).tombstoneOffset; // Check if this would go over the max number of orders allowed at this price level bool lastSegmentFilled = uint256( segmentsPriceMap[price][segmentsPriceMap[price].length - 1] >> ((NUM_ORDERS_PER_SEGMENT - 1) * 64) ) != 0; // Check if last segment is full if ( (segmentsPriceMap[price].length - tombstoneOffset) * NUM_ORDERS_PER_SEGMENT >= _maxOrdersPerPrice && lastSegmentFilled ) { // Loop until we find a suitable place to put this while (true) { price = SafeCast.toUint72(uint128(int128(uint128(price)) + tick)); if (!tree.exists(price)) { tree.insert(price); break; } else if ( (segmentsPriceMap[price].length - tombstoneOffset) * NUM_ORDERS_PER_SEGMENT < _maxOrdersPerPrice || uint256( segmentsPriceMap[price][segmentsPriceMap[price].length - 1] >> ((NUM_ORDERS_PER_SEGMENT - 1) * 64) ) == 0 ) { // There are segments available at this price level or the last segment is not filled yet break; } } } } // Read last one. Decide if we can add to the existing segment or if we need to add a new segment bytes32[] storage segments = segmentsPriceMap[price]; bool pushToEnd = true; if (segments.length != 0) { bytes32 lastSegment = segments[segments.length - 1]; // Are there are free entries in this segment for (uint256 offset = 0; offset < NUM_ORDERS_PER_SEGMENT; ++offset) { uint256 remainingSegment = uint256(lastSegment >> (offset * 64)); if (remainingSegment == 0) { // Found free entry one, so add to an existing segment bytes32 newSegment = lastSegment | (bytes32(orderId) << (offset * 64)) | (bytes32(quantity) << (offset * 64 + 40)); segments[segments.length - 1] = newSegment; pushToEnd = false; break; } } } if (pushToEnd) { bytes32 segment = bytes32(orderId) | (bytes32(quantity) << 40); segments.push(segment); } return price; } function _addToBook( uint40 newOrderId, uint128 tick, OrderSide side, uint256 tokenId, uint72 price, uint24 quantity ) private { _tokenClaimables[newOrderId] = ClaimableTokenInfo({ maker: _msgSender(), tokenId: uint16(OrderSide.Buy == side ? tokenId : 0), amount: 0 }); // Price can update if the price level is at capacity if (side == OrderSide.Buy) { price = _addToBookSide(_bidsAtPrice[tokenId], _bids[tokenId], price, newOrderId, quantity, -int128(tick)); } else { price = _addToBookSide(_asksAtPrice[tokenId], _asks[tokenId], price, newOrderId, quantity, int128(tick)); } emit AddedToBook(_msgSender(), side, newOrderId, tokenId, price, quantity); } function _calcFee(uint256 cost) private view returns (uint256 fees) { (uint256 royalty, uint256 dev, uint256 burn) = _calcFees(cost); fees = royalty + dev + burn; } function _calcFees(uint256 cost) private view returns (uint256 royalty, uint256 dev, uint256 burn) { royalty = (cost * _royaltyFee) / 10000; dev = (cost * _devFee) / 10000; burn = (cost * _burntFee) / 10000; } function _sendFees(uint256 royalty, uint256 dev, uint256 burn) private { if (royalty != 0) { _coin.safeTransfer(_royaltyRecipient, royalty); } if (dev != 0) { _coin.safeTransfer(_devAddr, dev); } if (burn != 0) { _coin.burn(burn); } } function _find( bytes32[] storage segments, uint256 begin, uint256 end, uint256 value ) private view returns (uint256 mid, uint256 offset) { while (begin < end) { mid = begin + (end - begin) / 2; uint256 segment = uint256(segments[mid]); offset = 0; for (uint256 i = 0; i < NUM_ORDERS_PER_SEGMENT; ++i) { uint40 id = uint40(segment >> (offset * 8)); if (id == value) { return (mid, i); // Return the index where the ID is found } else if (id < value) { offset = offset + 8; // Move to the next segment } else { break; // Break if the searched value is smaller, as it's a binary search } } if (offset == NUM_ORDERS_PER_SEGMENT * 8) { begin = mid + 1; } else { end = mid; } } return (type(uint).max, type(uint).max); // ID not found in any segment of the segment data } function _cancelOrder( bytes32[] storage segments, uint72 price, uint256 index, uint256 offset, uint256 tombstoneOffset, BokkyPooBahsRedBlackTreeLibrary.Tree storage tree ) private { bytes32 segment = segments[index]; uint40 orderId = uint40(uint256(segment) >> (offset * 64)); require(_tokenClaimables[orderId].maker == _msgSender(), NotMaker()); bool isFinalSegment = index == segments.length - 1; bool isOnlyOrderInSegment = (segment & ~(bytes32(uint(0xffffffffffffffff)) << (offset * 64))) == 0; if (isFinalSegment && isOnlyOrderInSegment) { // If there is only one order in this final segment then remove the segment segments.pop(); // There are no other segments so remove the price level if (segments.length == tombstoneOffset) { tree.remove(price); } } else { uint256 flattenedIndexToRemove = index * NUM_ORDERS_PER_SEGMENT + offset; // Although this is called next, it also acts as the "last" used later uint256 nextSegmentIndex = flattenedIndexToRemove / NUM_ORDERS_PER_SEGMENT; uint256 nextOffsetIndex = flattenedIndexToRemove % NUM_ORDERS_PER_SEGMENT; // Shift orders cross-segments. // This does all except the last order // TODO: For offset 0, 1, 2 we can shift the whole elements of the segment in 1 go. uint256 totalOrders = segments.length * NUM_ORDERS_PER_SEGMENT - 1; for (uint256 i = flattenedIndexToRemove; i < totalOrders; ++i) { nextSegmentIndex = (i + 1) / NUM_ORDERS_PER_SEGMENT; nextOffsetIndex = (i + 1) % NUM_ORDERS_PER_SEGMENT; bytes32 currentOrNextSegment = segments[nextSegmentIndex]; uint256 currentSegmentIndex = i / NUM_ORDERS_PER_SEGMENT; uint256 currentOffsetIndex = i % NUM_ORDERS_PER_SEGMENT; bytes32 currentSegment = segments[currentSegmentIndex]; uint256 nextOrder = uint64(uint256(currentOrNextSegment >> (nextOffsetIndex * 64))); if (nextOrder == 0) { // There are no more orders left, reset back to the currently iterated order as the last nextSegmentIndex = currentSegmentIndex; nextOffsetIndex = currentOffsetIndex; break; } // Clear the current order and set it with the shifted order currentSegment &= _clearOrderMask(currentOffsetIndex); currentSegment |= bytes32(nextOrder) << (currentOffsetIndex * 64); segments[currentSegmentIndex] = currentSegment; } // Only pop if the next offset is 0 which means there is only 1 order left in that segment (at the start) if (nextOffsetIndex == 0) { segments.pop(); } else { // Clear the last element bytes32 lastElement = segments[nextSegmentIndex]; lastElement &= _clearOrderMask(nextOffsetIndex); segments[nextSegmentIndex] = lastElement; } } } function _clearOrderMask(uint256 offsetIndex) private pure returns (bytes32) { return ~(bytes32(uint256(0xffffffffffffffff)) << (offsetIndex * 64)); } function _safeBatchTransferNFTsToUs(address from, uint256[] memory tokenIds, uint256[] memory amounts) private { _nft.safeBatchTransferFrom(from, address(this), tokenIds, amounts, ""); } function _safeBatchTransferNFTsFromUs(address to, uint256[] memory tokenIds, uint256[] memory amounts) private { _nft.safeBatchTransferFrom(address(this), to, tokenIds, amounts, ""); } function _safeTransferNFTsToUs(address from, uint256 tokenId, uint256 amount) private { _nft.safeTransferFrom(from, address(this), tokenId, amount, ""); } function _safeTransferNFTsFromUs(address to, uint256 tokenId, uint256 amount) private { _nft.safeTransferFrom(address(this), to, tokenId, amount, ""); } /// @notice Set the maximum amount of orders allowed at a specific price level /// @param maxOrdersPerPrice The new maximum amount of orders allowed at a specific price level function setMaxOrdersPerPrice(uint16 maxOrdersPerPrice) public payable onlyOwner { require(maxOrdersPerPrice % NUM_ORDERS_PER_SEGMENT == 0, MaxOrdersNotMultipleOfOrdersInSegment()); _maxOrdersPerPrice = maxOrdersPerPrice; emit SetMaxOrdersPerPriceLevel(maxOrdersPerPrice); } /// @notice Set constraints like minimum quantity of an order that is allowed to be /// placed and the minimum of specific tokenIds in this nft collection. /// @param tokenIds Array of token IDs for which to set TokenInfo /// @param tokenIdInfos Array of TokenInfo to be set function setTokenIdInfos( uint256[] calldata tokenIds, TokenIdInfo[] calldata tokenIdInfos ) external payable onlyOwner { require(tokenIds.length == tokenIdInfos.length, LengthMismatch()); for (uint256 i = 0; i < tokenIds.length; ++i) { // Cannot change tick once set uint256 existingTick = _tokenIdInfos[tokenIds[i]].tick; uint256 newTick = tokenIdInfos[i].tick; require(!(existingTick != 0 && newTick != 0 && existingTick != newTick), TickCannotBeChanged()); _tokenIdInfos[tokenIds[i]] = tokenIdInfos[i]; } emit SetTokenIdInfos(tokenIds, tokenIdInfos); } /// @notice Set the fees for the contract /// @param devAddr The address to receive trade fees /// @param devFee The fee to send to the dev address (max 10%) /// @param burntFee The fee to burn (max 2%) function setFees(address devAddr, uint16 devFee, uint8 burntFee) public onlyOwner { if (devFee != 0) { require(devAddr != address(0), ZeroAddress()); require(devFee <= 1000, DevFeeTooHigh()); } else { require(devAddr == address(0), DevFeeNotSet()); } _devFee = devFee; // 30 = 0.3% fee _devAddr = devAddr; _burntFee = burntFee; emit SetFees(devAddr, devFee, burntFee); } // solhint-disable-next-line no-empty-blocks function _authorizeUpgrade(address newImplementation) internal override onlyOwner {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable struct OwnableStorage { address _owner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; function _getOwnableStorage() private pure returns (OwnableStorage storage $) { assembly ("memory-safe") { $.slot := OwnableStorageLocation } } /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ function __Ownable_init(address initialOwner) internal onlyInitializing { __Ownable_init_unchained(initialOwner); } function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { OwnableStorage storage $ = _getOwnableStorage(); return $._owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { OwnableStorage storage $ = _getOwnableStorage(); address oldOwner = $._owner; $._owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly ("memory-safe") { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.20; import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol"; import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; import {Initializable} from "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. */ abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable __self = address(this); /** * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function * during an upgrade. */ string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; /** * @dev The call is from an unauthorized context. */ error UUPSUnauthorizedCallContext(); /** * @dev The storage `slot` is unsupported as a UUID. */ error UUPSUnsupportedProxiableUUID(bytes32 slot); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { _checkProxy(); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { _checkNotDelegated(); _; } function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /** * @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual notDelegated returns (bytes32) { return ERC1967Utils.IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data); } /** * @dev Reverts if the execution is not performed via delegatecall or the execution * context is not of a proxy with an ERC-1967 compliant implementation pointing to self. * See {_onlyProxy}. */ function _checkProxy() internal view virtual { if ( address(this) == __self || // Must be called through delegatecall ERC1967Utils.getImplementation() != __self // Must be called through an active proxy ) { revert UUPSUnauthorizedCallContext(); } } /** * @dev Reverts if the execution is performed via delegatecall. * See {notDelegated}. */ function _checkNotDelegated() internal view virtual { if (address(this) != __self) { // Must not be called through delegatecall revert UUPSUnauthorizedCallContext(); } } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call. * * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value * is expected to be the implementation slot in ERC-1967. * * Emits an {IERC1967-Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) { revert UUPSUnsupportedProxiableUUID(slot); } ERC1967Utils.upgradeToAndCall(newImplementation, data); } catch { // The implementation is not UUPS revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuardTransient.sol) pragma solidity ^0.8.24; import {TransientSlot} from "@openzeppelin/contracts/utils/TransientSlot.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Variant of {ReentrancyGuard} that uses transient storage. * * NOTE: This variant only works on networks where EIP-1153 is available. * * _Available since v5.1._ */ abstract contract ReentrancyGuardTransientUpgradeable is Initializable { using TransientSlot for *; // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant REENTRANCY_GUARD_STORAGE = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function __ReentrancyGuardTransient_init() internal onlyInitializing { } function __ReentrancyGuardTransient_init_unchained() internal onlyInitializing { } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be NOT_ENTERED if (_reentrancyGuardEntered()) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail REENTRANCY_GUARD_STORAGE.asBoolean().tstore(true); } function _nonReentrantAfter() private { REENTRANCY_GUARD_STORAGE.asBoolean().tstore(false); } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return REENTRANCY_GUARD_STORAGE.asBoolean().tload(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.20; /** * @dev ERC-1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol) pragma solidity ^0.8.20; import {IERC20} from "./IERC20.sol"; import {IERC165} from "./IERC165.sol"; /** * @title IERC1363 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363]. * * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction. */ interface IERC1363 is IERC20, IERC165 { /* * Note: the ERC-165 identifier for this interface is 0xb0202a11. * 0xb0202a11 === * bytes4(keccak256('transferAndCall(address,uint256)')) ^ * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^ * bytes4(keccak256('approveAndCall(address,uint256)')) ^ * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) */ /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @param data Additional data with no specified format, sent in call to `spender`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol) pragma solidity ^0.8.20; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. */ interface IERC1967 { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC2981.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol"; /** * @dev Interface for the NFT Royalty Standard. * * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal * support for royalty payments across all NFT marketplaces and ecosystem participants. */ interface IERC2981 is IERC165 { /** * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. * * NOTE: ERC-2981 allows setting the royalty to 100% of the price. In that case all the price would be sent to the * royalty receiver and 0 tokens to the seller. Contracts dealing with royalty should consider empty transfers. */ function royaltyInfo( uint256 tokenId, uint256 salePrice ) external view returns (address receiver, uint256 royaltyAmount); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.20; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {UpgradeableBeacon} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (proxy/ERC1967/ERC1967Utils.sol) pragma solidity ^0.8.21; import {IBeacon} from "../beacon/IBeacon.sol"; import {IERC1967} from "../../interfaces/IERC1967.sol"; import {Address} from "../../utils/Address.sol"; import {StorageSlot} from "../../utils/StorageSlot.sol"; /** * @dev This library provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots. */ library ERC1967Utils { /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev The `implementation` of the proxy is invalid. */ error ERC1967InvalidImplementation(address implementation); /** * @dev The `admin` of the proxy is invalid. */ error ERC1967InvalidAdmin(address admin); /** * @dev The `beacon` of the proxy is invalid. */ error ERC1967InvalidBeacon(address beacon); /** * @dev An upgrade function sees `msg.value > 0` that may be lost. */ error ERC1967NonPayable(); /** * @dev Returns the current implementation address. */ function getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the ERC-1967 implementation slot. */ function _setImplementation(address newImplementation) private { if (newImplementation.code.length == 0) { revert ERC1967InvalidImplementation(newImplementation); } StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Performs implementation upgrade with additional setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) internal { _setImplementation(newImplementation); emit IERC1967.Upgraded(newImplementation); if (data.length > 0) { Address.functionDelegateCall(newImplementation, data); } else { _checkNonPayable(); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(ADMIN_SLOT).value; } /** * @dev Stores a new address in the ERC-1967 admin slot. */ function _setAdmin(address newAdmin) private { if (newAdmin == address(0)) { revert ERC1967InvalidAdmin(address(0)); } StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {IERC1967-AdminChanged} event. */ function changeAdmin(address newAdmin) internal { emit IERC1967.AdminChanged(getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(BEACON_SLOT).value; } /** * @dev Stores a new beacon in the ERC-1967 beacon slot. */ function _setBeacon(address newBeacon) private { if (newBeacon.code.length == 0) { revert ERC1967InvalidBeacon(newBeacon); } StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon; address beaconImplementation = IBeacon(newBeacon).implementation(); if (beaconImplementation.code.length == 0) { revert ERC1967InvalidImplementation(beaconImplementation); } } /** * @dev Change the beacon and trigger a setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-BeaconUpgraded} event. * * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for * efficiency. */ function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal { _setBeacon(newBeacon); emit IERC1967.BeaconUpgraded(newBeacon); if (data.length > 0) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } else { _checkNonPayable(); } } /** * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract * if an upgrade doesn't perform an initialization call. */ function _checkNonPayable() private { if (msg.value > 0) { revert ERC1967NonPayable(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/IERC1155.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC-1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[ERC]. */ interface IERC1155 is IERC165 { /** * @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the value of tokens of token type `id` owned by `account`. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch( address[] calldata accounts, uint256[] calldata ids ) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the zero address. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. * * WARNING: This function can potentially allow a reentrancy attack when transferring tokens * to an untrusted contract, when invoking {onERC1155Received} on the receiver. * Ensure to follow the checks-effects-interactions pattern and consider employing * reentrancy guards when interacting with untrusted contracts. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `value` amount. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * WARNING: This function can potentially allow a reentrancy attack when transferring tokens * to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver. * Ensure to follow the checks-effects-interactions pattern and consider employing * reentrancy guards when interacting with untrusted contracts. * * Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments. * * Requirements: * * - `ids` and `values` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/IERC1155Receiver.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Interface that must be implemented by smart contracts in order to receive * ERC-1155 token transfers. */ interface IERC1155Receiver is IERC165 { /** * @dev Handles the receipt of a single ERC-1155 token type. This function is * called at the end of a `safeTransferFrom` after the balance has been updated. * * NOTE: To accept the transfer, this must return * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` * (i.e. 0xf23a6e61, or its own function selector). * * @param operator The address which initiated the transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param id The ID of the token being transferred * @param value The amount of tokens being transferred * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns (bytes4); /** * @dev Handles the receipt of a multiple ERC-1155 token types. This function * is called at the end of a `safeBatchTransferFrom` after the balances have * been updated. * * NOTE: To accept the transfer(s), this must return * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` * (i.e. 0xbc197c81, or its own function selector). * * @param operator The address which initiated the batch transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param ids An array containing ids of each token being transferred (order and length must match values array) * @param values An array containing amounts of each token being transferred (order and length must match ids array) * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/utils/ERC1155Holder.sol) pragma solidity ^0.8.20; import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol"; import {IERC1155Receiver} from "../IERC1155Receiver.sol"; /** * @dev Simple implementation of `IERC1155Receiver` that will allow a contract to hold ERC-1155 tokens. * * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be * stuck. */ abstract contract ERC1155Holder is ERC165, IERC1155Receiver { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); } function onERC1155Received( address, address, uint256, uint256, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155Received.selector; } function onERC1155BatchReceived( address, address, uint256[] memory, uint256[] memory, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155BatchReceived.selector; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 standard as defined in the ERC. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC1363} from "../../../interfaces/IERC1363.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC-20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { /** * @dev An operation with an ERC-20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. * * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. * * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. * * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being * set here. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { safeTransfer(token, to, value); } else if (!token.transferAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferFromAndCallRelaxed( IERC1363 token, address from, address to, uint256 value, bytes memory data ) internal { if (to.code.length == 0) { safeTransferFrom(token, from, to, value); } else if (!token.transferFromAndCall(from, to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}. * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall} * once without retrying, and relies on the returned value to be true. * * Reverts if the returned value is other than `true`. */ function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { forceApprove(token, to, value); } else if (!token.approveAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements. */ function _callOptionalReturn(IERC20 token, bytes memory data) private { uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) // bubble errors if iszero(success) { let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } returnSize := returndatasize() returnValue := mload(0) } if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { bool success; uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) returnSize := returndatasize() returnValue := mload(0) } return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Address.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert Errors.InsufficientBalance(address(this).balance, amount); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert Errors.FailedCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {Errors.FailedCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert Errors.InsufficientBalance(address(this).balance, value); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case * of an unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {Errors.FailedCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly ("memory-safe") { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert Errors.FailedCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol) pragma solidity ^0.8.20; /** * @dev Collection of common custom errors used in multiple contracts * * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. * It is recommended to avoid relying on the error API for critical functionality. * * _Available since v5.1._ */ library Errors { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error InsufficientBalance(uint256 balance, uint256 needed); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedCall(); /** * @dev The deployment failed. */ error FailedDeployment(); /** * @dev A necessary precompile is missing. */ error MissingPrecompile(address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.20; /** * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeCast { /** * @dev Value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); /** * @dev An int value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedIntToUint(int256 value); /** * @dev Value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); /** * @dev An uint value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedUintToInt(uint256 value); /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits */ function toUint248(uint256 value) internal pure returns (uint248) { if (value > type(uint248).max) { revert SafeCastOverflowedUintDowncast(248, value); } return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits */ function toUint240(uint256 value) internal pure returns (uint240) { if (value > type(uint240).max) { revert SafeCastOverflowedUintDowncast(240, value); } return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits */ function toUint232(uint256 value) internal pure returns (uint232) { if (value > type(uint232).max) { revert SafeCastOverflowedUintDowncast(232, value); } return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits */ function toUint224(uint256 value) internal pure returns (uint224) { if (value > type(uint224).max) { revert SafeCastOverflowedUintDowncast(224, value); } return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits */ function toUint216(uint256 value) internal pure returns (uint216) { if (value > type(uint216).max) { revert SafeCastOverflowedUintDowncast(216, value); } return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits */ function toUint208(uint256 value) internal pure returns (uint208) { if (value > type(uint208).max) { revert SafeCastOverflowedUintDowncast(208, value); } return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits */ function toUint200(uint256 value) internal pure returns (uint200) { if (value > type(uint200).max) { revert SafeCastOverflowedUintDowncast(200, value); } return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits */ function toUint192(uint256 value) internal pure returns (uint192) { if (value > type(uint192).max) { revert SafeCastOverflowedUintDowncast(192, value); } return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits */ function toUint184(uint256 value) internal pure returns (uint184) { if (value > type(uint184).max) { revert SafeCastOverflowedUintDowncast(184, value); } return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits */ function toUint176(uint256 value) internal pure returns (uint176) { if (value > type(uint176).max) { revert SafeCastOverflowedUintDowncast(176, value); } return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits */ function toUint168(uint256 value) internal pure returns (uint168) { if (value > type(uint168).max) { revert SafeCastOverflowedUintDowncast(168, value); } return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits */ function toUint160(uint256 value) internal pure returns (uint160) { if (value > type(uint160).max) { revert SafeCastOverflowedUintDowncast(160, value); } return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits */ function toUint152(uint256 value) internal pure returns (uint152) { if (value > type(uint152).max) { revert SafeCastOverflowedUintDowncast(152, value); } return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits */ function toUint144(uint256 value) internal pure returns (uint144) { if (value > type(uint144).max) { revert SafeCastOverflowedUintDowncast(144, value); } return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits */ function toUint136(uint256 value) internal pure returns (uint136) { if (value > type(uint136).max) { revert SafeCastOverflowedUintDowncast(136, value); } return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { if (value > type(uint128).max) { revert SafeCastOverflowedUintDowncast(128, value); } return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits */ function toUint120(uint256 value) internal pure returns (uint120) { if (value > type(uint120).max) { revert SafeCastOverflowedUintDowncast(120, value); } return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits */ function toUint112(uint256 value) internal pure returns (uint112) { if (value > type(uint112).max) { revert SafeCastOverflowedUintDowncast(112, value); } return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits */ function toUint104(uint256 value) internal pure returns (uint104) { if (value > type(uint104).max) { revert SafeCastOverflowedUintDowncast(104, value); } return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits */ function toUint96(uint256 value) internal pure returns (uint96) { if (value > type(uint96).max) { revert SafeCastOverflowedUintDowncast(96, value); } return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits */ function toUint88(uint256 value) internal pure returns (uint88) { if (value > type(uint88).max) { revert SafeCastOverflowedUintDowncast(88, value); } return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits */ function toUint80(uint256 value) internal pure returns (uint80) { if (value > type(uint80).max) { revert SafeCastOverflowedUintDowncast(80, value); } return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits */ function toUint72(uint256 value) internal pure returns (uint72) { if (value > type(uint72).max) { revert SafeCastOverflowedUintDowncast(72, value); } return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { if (value > type(uint64).max) { revert SafeCastOverflowedUintDowncast(64, value); } return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits */ function toUint56(uint256 value) internal pure returns (uint56) { if (value > type(uint56).max) { revert SafeCastOverflowedUintDowncast(56, value); } return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits */ function toUint48(uint256 value) internal pure returns (uint48) { if (value > type(uint48).max) { revert SafeCastOverflowedUintDowncast(48, value); } return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits */ function toUint40(uint256 value) internal pure returns (uint40) { if (value > type(uint40).max) { revert SafeCastOverflowedUintDowncast(40, value); } return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { if (value > type(uint32).max) { revert SafeCastOverflowedUintDowncast(32, value); } return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits */ function toUint24(uint256 value) internal pure returns (uint24) { if (value > type(uint24).max) { revert SafeCastOverflowedUintDowncast(24, value); } return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { if (value > type(uint16).max) { revert SafeCastOverflowedUintDowncast(16, value); } return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits */ function toUint8(uint256 value) internal pure returns (uint8) { if (value > type(uint8).max) { revert SafeCastOverflowedUintDowncast(8, value); } return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { if (value < 0) { revert SafeCastOverflowedIntToUint(value); } return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(248, value); } } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(240, value); } } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(232, value); } } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(224, value); } } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(216, value); } } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(208, value); } } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(200, value); } } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(192, value); } } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(184, value); } } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(176, value); } } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(168, value); } } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(160, value); } } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(152, value); } } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(144, value); } } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(136, value); } } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(128, value); } } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(120, value); } } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(112, value); } } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(104, value); } } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(96, value); } } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(88, value); } } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(80, value); } } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(72, value); } } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(64, value); } } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(56, value); } } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(48, value); } } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(40, value); } } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(32, value); } } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(24, value); } } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(16, value); } } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(8, value); } } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive if (value > uint256(type(int256).max)) { revert SafeCastOverflowedUintToInt(value); } return int256(value); } /** * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump. */ function toUint(bool b) internal pure returns (uint256 u) { assembly ("memory-safe") { u := iszero(iszero(b)) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.20; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC-1967 implementation slot: * ```solidity * contract ERC1967 { * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * TIP: Consider using this library along with {SlotDerivation}. */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct Int256Slot { int256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Int256Slot` with member `value` located at `slot`. */ function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } /** * @dev Returns a `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/TransientSlot.sol) // This file was procedurally generated from scripts/generate/templates/TransientSlot.js. pragma solidity ^0.8.24; /** * @dev Library for reading and writing value-types to specific transient storage slots. * * Transient slots are often used to store temporary values that are removed after the current transaction. * This library helps with reading and writing to such slots without the need for inline assembly. * * * Example reading and writing values using transient storage: * ```solidity * contract Lock { * using TransientSlot for *; * * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542; * * modifier locked() { * require(!_LOCK_SLOT.asBoolean().tload()); * * _LOCK_SLOT.asBoolean().tstore(true); * _; * _LOCK_SLOT.asBoolean().tstore(false); * } * } * ``` * * TIP: Consider using this library along with {SlotDerivation}. */ library TransientSlot { /** * @dev UDVT that represent a slot holding a address. */ type AddressSlot is bytes32; /** * @dev Cast an arbitrary slot to a AddressSlot. */ function asAddress(bytes32 slot) internal pure returns (AddressSlot) { return AddressSlot.wrap(slot); } /** * @dev UDVT that represent a slot holding a bool. */ type BooleanSlot is bytes32; /** * @dev Cast an arbitrary slot to a BooleanSlot. */ function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) { return BooleanSlot.wrap(slot); } /** * @dev UDVT that represent a slot holding a bytes32. */ type Bytes32Slot is bytes32; /** * @dev Cast an arbitrary slot to a Bytes32Slot. */ function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) { return Bytes32Slot.wrap(slot); } /** * @dev UDVT that represent a slot holding a uint256. */ type Uint256Slot is bytes32; /** * @dev Cast an arbitrary slot to a Uint256Slot. */ function asUint256(bytes32 slot) internal pure returns (Uint256Slot) { return Uint256Slot.wrap(slot); } /** * @dev UDVT that represent a slot holding a int256. */ type Int256Slot is bytes32; /** * @dev Cast an arbitrary slot to a Int256Slot. */ function asInt256(bytes32 slot) internal pure returns (Int256Slot) { return Int256Slot.wrap(slot); } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(AddressSlot slot) internal view returns (address value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(AddressSlot slot, address value) internal { assembly ("memory-safe") { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(BooleanSlot slot) internal view returns (bool value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(BooleanSlot slot, bool value) internal { assembly ("memory-safe") { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Bytes32Slot slot) internal view returns (bytes32 value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Bytes32Slot slot, bytes32 value) internal { assembly ("memory-safe") { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Uint256Slot slot) internal view returns (uint256 value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Uint256Slot slot, uint256 value) internal { assembly ("memory-safe") { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Int256Slot slot) internal view returns (int256 value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Int256Slot slot, int256 value) internal { assembly ("memory-safe") { tstore(slot, value) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; enum ActivityType { NONE, // // BLUE TICKETS // instantactions_evt_doinstantactions, instantvrfactions_evt_doinstantvrfactions, passiveactions_evt_claimpassiveaction, quests_evt_questcompleted, shop_evt_buy, // + shop_evt_buybatch, shop_evt_sell, // + shop_evt_sellbatch, wishingwell_evt_donate, wishingwell_evt_donatetoclan, orderbook_evt_ordersmatched, orderbook_evt_claimedtokens, orderbook_evt_claimednfts, // players players_evt_actionfinished, players_evt_addxp, players_evt_levelup, players_evt_boostfinished, players_evt_dailyreward, players_evt_weeklyreward, players_evt_claimedxpthresholdrewards, // clans clans_evt_clancreated, // _isClanActivityType lockedbankvaults_evt_attackvaults, // _isClanActivityType territories_evt_attackterritory, // _isClanActivityType territories_evt_claimunoccupiedterritory, // _isClanActivityType // // GREEN TICKETS // players_dailyreward, // = 8 wishingwell_luckofthedraw, // = 3 wishingwell_luckypotion // = 50 } interface IActivityPointsCaller { function setActivityPoints(address activityPoints) external; } interface IActivityPoints { event ActivityPointsEarned( ActivityType indexed activityType, uint256 value, address indexed from, uint16 indexed tokenId, uint256 points ); function rewardGreenTickets( ActivityType activityType, address recipient, bool isEvolved ) external returns (uint256 tickets); function rewardBlueTickets( ActivityType activityType, address from, bool isEvolvedOrNA, uint256 value ) external returns (uint256 points); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; // ---------------------------------------------------------------------------- // BokkyPooBah's Red-Black Tree Library v1.0-pre-release-a // // A Solidity Red-Black Tree binary search library to store and access a sorted // list of unsigned integer data. The Red-Black algorithm rebalances the binary // search tree, resulting in O(log n) insert, remove and search time (and ~gas) // // https://github.com/bokkypoobah/BokkyPooBahsRedBlackTreeLibrary // // // Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2020. The MIT Licence. // ---------------------------------------------------------------------------- library BokkyPooBahsRedBlackTreeLibrary { error KeyCannotBeZero(); error KeyDoesntExist(); struct Node { uint72 parent; uint72 left; uint72 right; uint32 tombstoneOffset; // Number of deleted segments, for gas efficiency bool red; } struct Tree { uint72 root; mapping(uint72 => Node) nodes; } uint72 private constant EMPTY = 0; function first(Tree storage self) internal view returns (uint72 key) { key = self.root; if (key != EMPTY) { while (self.nodes[key].left != EMPTY) { key = self.nodes[key].left; } } } function last(Tree storage self) internal view returns (uint72 key) { key = self.root; if (key != EMPTY) { while (self.nodes[key].right != EMPTY) { key = self.nodes[key].right; } } } function next(Tree storage self, uint72 target) internal view returns (uint72 cursor) { require(target != EMPTY, KeyCannotBeZero()); if (self.nodes[target].right != EMPTY) { cursor = treeMinimum(self, self.nodes[target].right); } else { cursor = self.nodes[target].parent; while (cursor != EMPTY && target == self.nodes[cursor].right) { target = cursor; cursor = self.nodes[cursor].parent; } } } function prev(Tree storage self, uint72 target) internal view returns (uint72 cursor) { require(target != EMPTY, KeyCannotBeZero()); if (self.nodes[target].left != EMPTY) { cursor = treeMaximum(self, self.nodes[target].left); } else { cursor = self.nodes[target].parent; while (cursor != EMPTY && target == self.nodes[cursor].left) { target = cursor; cursor = self.nodes[cursor].parent; } } } function exists(Tree storage self, uint72 key) internal view returns (bool) { return (key != EMPTY) && ((key == self.root) || (self.nodes[key].parent != EMPTY)); } function isEmpty(uint72 key) internal pure returns (bool) { return key == EMPTY; } function getEmpty() internal pure returns (uint) { return EMPTY; } function getNode(Tree storage self, uint72 key) internal view returns (Node storage node) { require(exists(self, key), KeyDoesntExist()); return self.nodes[key]; } function edit(Tree storage self, uint72 key, uint32 extraTombstoneOffset) internal { require(exists(self, key), KeyDoesntExist()); self.nodes[key].tombstoneOffset += extraTombstoneOffset; } function insert(Tree storage self, uint72 key) internal { require(key != EMPTY, KeyCannotBeZero()); uint72 cursor = EMPTY; uint72 probe = self.root; while (probe != EMPTY) { cursor = probe; if (key < probe) { probe = self.nodes[probe].left; } else { probe = self.nodes[probe].right; } } self.nodes[key] = Node({ parent: cursor, left: EMPTY, right: EMPTY, red: true, tombstoneOffset: self.nodes[key].tombstoneOffset }); if (cursor == EMPTY) { self.root = key; } else if (key < cursor) { self.nodes[cursor].left = key; } else { self.nodes[cursor].right = key; } insertFixup(self, key); } function remove(Tree storage self, uint72 key) internal { require(key != EMPTY, KeyCannotBeZero()); require(exists(self, key), KeyDoesntExist()); uint72 probe; uint72 cursor; if (self.nodes[key].left == EMPTY || self.nodes[key].right == EMPTY) { cursor = key; } else { cursor = self.nodes[key].right; while (self.nodes[cursor].left != EMPTY) { cursor = self.nodes[cursor].left; } } if (self.nodes[cursor].left != EMPTY) { probe = self.nodes[cursor].left; } else { probe = self.nodes[cursor].right; } uint72 yParent = self.nodes[cursor].parent; self.nodes[probe].parent = yParent; if (yParent != EMPTY) { if (cursor == self.nodes[yParent].left) { self.nodes[yParent].left = probe; } else { self.nodes[yParent].right = probe; } } else { self.root = probe; } bool doFixup = !self.nodes[cursor].red; if (cursor != key) { replaceParent(self, cursor, key); self.nodes[cursor].left = self.nodes[key].left; self.nodes[self.nodes[cursor].left].parent = cursor; self.nodes[cursor].right = self.nodes[key].right; self.nodes[self.nodes[cursor].right].parent = cursor; self.nodes[cursor].red = self.nodes[key].red; (cursor, key) = (key, cursor); } if (doFixup) { removeFixup(self, probe); } // Don't delete the node, so that we can re-use the tombstone offset if re-adding this price self.nodes[cursor].parent = EMPTY; } function treeMinimum(Tree storage self, uint72 key) private view returns (uint72) { while (self.nodes[key].left != EMPTY) { key = self.nodes[key].left; } return key; } function treeMaximum(Tree storage self, uint72 key) private view returns (uint72) { while (self.nodes[key].right != EMPTY) { key = self.nodes[key].right; } return key; } function rotateLeft(Tree storage self, uint72 key) private { uint72 cursor = self.nodes[key].right; uint72 keyParent = self.nodes[key].parent; uint72 cursorLeft = self.nodes[cursor].left; self.nodes[key].right = cursorLeft; if (cursorLeft != EMPTY) { self.nodes[cursorLeft].parent = key; } self.nodes[cursor].parent = keyParent; if (keyParent == EMPTY) { self.root = cursor; } else if (key == self.nodes[keyParent].left) { self.nodes[keyParent].left = cursor; } else { self.nodes[keyParent].right = cursor; } self.nodes[cursor].left = key; self.nodes[key].parent = cursor; } function rotateRight(Tree storage self, uint72 key) private { uint72 cursor = self.nodes[key].left; uint72 keyParent = self.nodes[key].parent; uint72 cursorRight = self.nodes[cursor].right; self.nodes[key].left = cursorRight; if (cursorRight != EMPTY) { self.nodes[cursorRight].parent = key; } self.nodes[cursor].parent = keyParent; if (keyParent == EMPTY) { self.root = cursor; } else if (key == self.nodes[keyParent].right) { self.nodes[keyParent].right = cursor; } else { self.nodes[keyParent].left = cursor; } self.nodes[cursor].right = key; self.nodes[key].parent = cursor; } function insertFixup(Tree storage self, uint72 key) private { uint72 cursor; while (key != self.root && self.nodes[self.nodes[key].parent].red) { uint72 keyParent = self.nodes[key].parent; if (keyParent == self.nodes[self.nodes[keyParent].parent].left) { cursor = self.nodes[self.nodes[keyParent].parent].right; if (self.nodes[cursor].red) { self.nodes[keyParent].red = false; self.nodes[cursor].red = false; self.nodes[self.nodes[keyParent].parent].red = true; key = self.nodes[keyParent].parent; } else { if (key == self.nodes[keyParent].right) { key = keyParent; rotateLeft(self, key); } keyParent = self.nodes[key].parent; self.nodes[keyParent].red = false; self.nodes[self.nodes[keyParent].parent].red = true; rotateRight(self, self.nodes[keyParent].parent); } } else { cursor = self.nodes[self.nodes[keyParent].parent].left; if (self.nodes[cursor].red) { self.nodes[keyParent].red = false; self.nodes[cursor].red = false; self.nodes[self.nodes[keyParent].parent].red = true; key = self.nodes[keyParent].parent; } else { if (key == self.nodes[keyParent].left) { key = keyParent; rotateRight(self, key); } keyParent = self.nodes[key].parent; self.nodes[keyParent].red = false; self.nodes[self.nodes[keyParent].parent].red = true; rotateLeft(self, self.nodes[keyParent].parent); } } } self.nodes[self.root].red = false; } function replaceParent(Tree storage self, uint72 a, uint72 b) private { uint72 bParent = self.nodes[b].parent; self.nodes[a].parent = bParent; if (bParent == EMPTY) { self.root = a; } else { if (b == self.nodes[bParent].left) { self.nodes[bParent].left = a; } else { self.nodes[bParent].right = a; } } } function removeFixup(Tree storage self, uint72 key) private { uint72 cursor; while (key != self.root && !self.nodes[key].red) { uint72 keyParent = self.nodes[key].parent; if (key == self.nodes[keyParent].left) { cursor = self.nodes[keyParent].right; if (self.nodes[cursor].red) { self.nodes[cursor].red = false; self.nodes[keyParent].red = true; rotateLeft(self, keyParent); cursor = self.nodes[keyParent].right; } if (!self.nodes[self.nodes[cursor].left].red && !self.nodes[self.nodes[cursor].right].red) { self.nodes[cursor].red = true; key = keyParent; } else { if (!self.nodes[self.nodes[cursor].right].red) { self.nodes[self.nodes[cursor].left].red = false; self.nodes[cursor].red = true; rotateRight(self, cursor); cursor = self.nodes[keyParent].right; } self.nodes[cursor].red = self.nodes[keyParent].red; self.nodes[keyParent].red = false; self.nodes[self.nodes[cursor].right].red = false; rotateLeft(self, keyParent); key = self.root; } } else { cursor = self.nodes[keyParent].left; if (self.nodes[cursor].red) { self.nodes[cursor].red = false; self.nodes[keyParent].red = true; rotateRight(self, keyParent); cursor = self.nodes[keyParent].left; } if (!self.nodes[self.nodes[cursor].right].red && !self.nodes[self.nodes[cursor].left].red) { self.nodes[cursor].red = true; key = keyParent; } else { if (!self.nodes[self.nodes[cursor].left].red) { self.nodes[self.nodes[cursor].right].red = false; self.nodes[cursor].red = true; rotateLeft(self, cursor); cursor = self.nodes[keyParent].left; } self.nodes[cursor].red = self.nodes[keyParent].red; self.nodes[keyParent].red = false; self.nodes[self.nodes[cursor].left].red = false; rotateRight(self, keyParent); key = self.root; } } } self.nodes[key].red = false; } } // ---------------------------------------------------------------------------- // End - BokkyPooBah's Red-Black Tree Library // ----------------------------------------------------------------------------
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol"; import {BokkyPooBahsRedBlackTreeLibrary} from "../BokkyPooBahsRedBlackTreeLibrary.sol"; interface IOrderBook is IERC1155Receiver { enum OrderSide { Buy, Sell } struct TokenIdInfo { uint128 tick; uint128 minQuantity; } struct LimitOrder { OrderSide side; uint256 tokenId; uint72 price; uint24 quantity; } struct MarketOrder { OrderSide side; uint256 tokenId; uint24 quantity; uint256 totalCost; } struct CancelOrder { OrderSide side; uint256 tokenId; uint72 price; } struct ClaimableTokenInfo { address maker; uint80 amount; uint16 tokenId; } // A helper type for a view function to return orders struct Order { address maker; uint24 quantity; uint40 id; } event AddedToBook(address maker, OrderSide side, uint256 orderId, uint256 tokenId, uint256 price, uint256 quantity); event OrdersMatched(address taker, uint256[] orderIds, uint256[] quantities); event OrdersCancelled(address maker, uint256[] orderIds); event FailedToAddToBook(address maker, OrderSide side, uint256 tokenId, uint256 price, uint256 quantity); event ClaimedTokens(address user, uint256[] orderIds, uint256 amount); event ClaimedNFTs(address user, uint256[] orderIds, uint256[] tokenIds, uint256[] amounts); event SetTokenIdInfos(uint256[] tokenIds, TokenIdInfo[] tokenInfos); event SetMaxOrdersPerPriceLevel(uint256 maxOrdesrsPerPrice); event SetFees(address devAddr, uint256 devFee, uint256 burntFee); error ZeroAddress(); error DevFeeNotSet(); error DevFeeTooHigh(); error NotERC1155(); error NoQuantity(); error OrderNotFound(uint256 orderId, uint256 price); error OrderNotFoundInTree(uint256 orderId, uint256 price); error PriceNotMultipleOfTick(uint256 tick); error TokenDoesntExist(uint256 tokenId); error PriceZero(); error LengthMismatch(); error NotMaker(); error NothingToClaim(); error TooManyOrdersHit(); error MaxOrdersNotMultipleOfOrdersInSegment(); error TickCannotBeChanged(); error ClaimingTooManyOrders(); error FailedToTakeFromBook(address taker, OrderSide side, uint256 tokenId, uint256 quantityRemaining); error TotalCostConditionNotMet(); function marketOrder(MarketOrder calldata order) external; function limitOrders(LimitOrder[] calldata orders) external; function cancelOrders(uint256[] calldata orderIds, CancelOrder[] calldata cancelClaimableTokenInfos) external; function cancelAndMakeLimitOrders( uint256[] calldata orderIds, CancelOrder[] calldata orders, LimitOrder[] calldata newOrders ) external; function claimTokens(uint256[] calldata _orderIds) external; function claimNFTs(uint256[] calldata orderIds) external; function claimAll(uint256[] calldata coinOrderIds, uint256[] calldata nftOrderIds) external; function tokensClaimable(uint40[] calldata orderIds) external view returns (uint256 amount); function nftsClaimable(uint40[] calldata orderIds) external view returns (uint256[] memory amounts); function getHighestBid(uint256 tokenId) external view returns (uint72); function getLowestAsk(uint256 tokenId) external view returns (uint72); function getNode( OrderSide side, uint256 tokenId, uint72 price ) external view returns (BokkyPooBahsRedBlackTreeLibrary.Node memory); function nodeExists(OrderSide side, uint256 tokenId, uint72 price) external view returns (bool); function getTokenIdInfo(uint256 tokenId) external view returns (TokenIdInfo memory); function getClaimableTokenInfo(uint40 _orderId) external view returns (ClaimableTokenInfo memory); function allOrdersAtPrice( OrderSide side, uint256 tokenId, uint72 price ) external view returns (Order[] memory orderBookEntries); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IBrushToken is IERC20 { function burn(uint256 amount) external; function burnFrom(address account, uint256 amount) external; function transferFromBulk(address from, address[] calldata tos, uint256[] calldata amounts) external; function transferOwnership(address newOwner) external; }
{ "evmVersion": "cancun", "optimizer": { "enabled": true, "runs": 1000, "details": { "yul": true } }, "viaIR": true, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[],"name":"ClaimingTooManyOrders","type":"error"},{"inputs":[],"name":"DevFeeNotSet","type":"error"},{"inputs":[],"name":"DevFeeTooHigh","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[{"internalType":"address","name":"taker","type":"address"},{"internalType":"enum IOrderBook.OrderSide","name":"side","type":"uint8"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"quantityRemaining","type":"uint256"}],"name":"FailedToTakeFromBook","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"KeyCannotBeZero","type":"error"},{"inputs":[],"name":"KeyDoesntExist","type":"error"},{"inputs":[],"name":"LengthMismatch","type":"error"},{"inputs":[],"name":"MaxOrdersNotMultipleOfOrdersInSegment","type":"error"},{"inputs":[],"name":"NoQuantity","type":"error"},{"inputs":[],"name":"NotERC1155","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"NotMaker","type":"error"},{"inputs":[],"name":"NothingToClaim","type":"error"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"name":"OrderNotFound","type":"error"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"name":"OrderNotFoundInTree","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"uint256","name":"tick","type":"uint256"}],"name":"PriceNotMultipleOfTick","type":"error"},{"inputs":[],"name":"PriceZero","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"TickCannotBeChanged","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TokenDoesntExist","type":"error"},{"inputs":[],"name":"TooManyOrdersHit","type":"error"},{"inputs":[],"name":"TotalCostConditionNotMet","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"enum IOrderBook.OrderSide","name":"side","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"AddedToBook","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"orderIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"ClaimedNFTs","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"orderIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimedTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"enum IOrderBook.OrderSide","name":"side","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"FailedToAddToBook","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"orderIds","type":"uint256[]"}],"name":"OrdersCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"taker","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"orderIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"quantities","type":"uint256[]"}],"name":"OrdersMatched","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"devAddr","type":"address"},{"indexed":false,"internalType":"uint256","name":"devFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"burntFee","type":"uint256"}],"name":"SetFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxOrdesrsPerPrice","type":"uint256"}],"name":"SetMaxOrdersPerPriceLevel","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"components":[{"internalType":"uint128","name":"tick","type":"uint128"},{"internalType":"uint128","name":"minQuantity","type":"uint128"}],"indexed":false,"internalType":"struct IOrderBook.TokenIdInfo[]","name":"tokenInfos","type":"tuple[]"}],"name":"SetTokenIdInfos","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IOrderBook.OrderSide","name":"side","type":"uint8"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint72","name":"price","type":"uint72"}],"name":"allOrdersAtPrice","outputs":[{"components":[{"internalType":"address","name":"maker","type":"address"},{"internalType":"uint24","name":"quantity","type":"uint24"},{"internalType":"uint40","name":"id","type":"uint40"}],"internalType":"struct IOrderBook.Order[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"orderIds","type":"uint256[]"},{"components":[{"internalType":"enum IOrderBook.OrderSide","name":"side","type":"uint8"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint72","name":"price","type":"uint72"}],"internalType":"struct IOrderBook.CancelOrder[]","name":"orders","type":"tuple[]"},{"components":[{"internalType":"enum IOrderBook.OrderSide","name":"side","type":"uint8"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint72","name":"price","type":"uint72"},{"internalType":"uint24","name":"quantity","type":"uint24"}],"internalType":"struct IOrderBook.LimitOrder[]","name":"newOrders","type":"tuple[]"}],"name":"cancelAndMakeLimitOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"orderIds","type":"uint256[]"},{"components":[{"internalType":"enum IOrderBook.OrderSide","name":"side","type":"uint8"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint72","name":"price","type":"uint72"}],"internalType":"struct IOrderBook.CancelOrder[]","name":"orders","type":"tuple[]"}],"name":"cancelOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"coinOrderIds","type":"uint256[]"},{"internalType":"uint256[]","name":"nftOrderIds","type":"uint256[]"}],"name":"claimAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"orderIds","type":"uint256[]"}],"name":"claimNFTs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"orderIds","type":"uint256[]"}],"name":"claimTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint40","name":"orderId","type":"uint40"}],"name":"getClaimableTokenInfo","outputs":[{"components":[{"internalType":"address","name":"maker","type":"address"},{"internalType":"uint80","name":"amount","type":"uint80"},{"internalType":"uint16","name":"tokenId","type":"uint16"}],"internalType":"struct IOrderBook.ClaimableTokenInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getHighestBid","outputs":[{"internalType":"uint72","name":"","type":"uint72"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getLowestAsk","outputs":[{"internalType":"uint72","name":"","type":"uint72"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IOrderBook.OrderSide","name":"side","type":"uint8"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint72","name":"price","type":"uint72"}],"name":"getNode","outputs":[{"components":[{"internalType":"uint72","name":"parent","type":"uint72"},{"internalType":"uint72","name":"left","type":"uint72"},{"internalType":"uint72","name":"right","type":"uint72"},{"internalType":"uint32","name":"tombstoneOffset","type":"uint32"},{"internalType":"bool","name":"red","type":"bool"}],"internalType":"struct BokkyPooBahsRedBlackTreeLibrary.Node","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getTokenIdInfo","outputs":[{"components":[{"internalType":"uint128","name":"tick","type":"uint128"},{"internalType":"uint128","name":"minQuantity","type":"uint128"}],"internalType":"struct IOrderBook.TokenIdInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC1155","name":"nft","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"devAddr","type":"address"},{"internalType":"uint16","name":"devFee","type":"uint16"},{"internalType":"uint8","name":"burntFee","type":"uint8"},{"internalType":"uint16","name":"maxOrdersPerPrice","type":"uint16"},{"internalType":"contract IActivityPoints","name":"activityPoints","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"enum IOrderBook.OrderSide","name":"side","type":"uint8"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint72","name":"price","type":"uint72"},{"internalType":"uint24","name":"quantity","type":"uint24"}],"internalType":"struct IOrderBook.LimitOrder[]","name":"orders","type":"tuple[]"}],"name":"limitOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"enum IOrderBook.OrderSide","name":"side","type":"uint8"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint24","name":"quantity","type":"uint24"},{"internalType":"uint256","name":"totalCost","type":"uint256"}],"internalType":"struct IOrderBook.MarketOrder","name":"order","type":"tuple"}],"name":"marketOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint40[]","name":"orderIds","type":"uint40[]"}],"name":"nftsClaimable","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IOrderBook.OrderSide","name":"side","type":"uint8"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint72","name":"price","type":"uint72"}],"name":"nodeExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"activityPoints","type":"address"}],"name":"setActivityPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"devAddr","type":"address"},{"internalType":"uint16","name":"devFee","type":"uint16"},{"internalType":"uint8","name":"burntFee","type":"uint8"}],"name":"setFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"maxOrdersPerPrice","type":"uint16"}],"name":"setMaxOrdersPerPrice","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"components":[{"internalType":"uint128","name":"tick","type":"uint128"},{"internalType":"uint128","name":"minQuantity","type":"uint128"}],"internalType":"struct IOrderBook.TokenIdInfo[]","name":"tokenIdInfos","type":"tuple[]"}],"name":"setTokenIdInfos","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint40[]","name":"orderIds","type":"uint40[]"}],"name":"tokensClaimable","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateRoyaltyFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"}]
Contract Creation Code
60a080604052346100c257306080525f5160206160355f395f51905f525460ff8160401c166100b3576002600160401b03196001600160401b03821601610060575b604051615f6e90816100c782396080518181816111ca01526112d00152f35b6001600160401b0319166001600160401b039081175f5160206160355f395f51905f525581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80610041565b63f92ee8a960e01b5f5260045ffd5b5f80fdfe610460806040526004361015610013575f80fd5b5f905f3560e01c90816301ffc9a714611ad0575080632d08265a14611a695780633546326c146119c057806335569842146119a65780633fd3a6a5146119085780634628b1fd146118e55780634dca93471461185e5780634f0eb731146115425780634f1ef2861461129057806352aa5e8f1461122957806352d1902d146111af5780636faf6d1914611066578063715018a614610fcd57806374aacfab14610af85780637783743714610a6c578063793052b814610a4357806379800e87146109dd57806385dd961f146107875780638da5cb5b146107415780638f28864414610707578063acfda69e146106be578063ad3cb1cc1461064a578063b110c27c14610596578063b3f4c59f14610528578063bc197c8114610477578063c385bddf14610434578063f23a6e61146103c5578063f2fde38b14610398578063f3a0934e1461032f578063f9e13eb1146102765763fb2ac52e14610174575f80fd5b346102735760403660031901126102735760043567ffffffffffffffff8111610271576101a5903690600401611b55565b9060243567ffffffffffffffff811161026d576101c6903690600401611b55565b9190926101d1612310565b801580158091610264575b156102555760c86101ed85846120a0565b1161024657610236575b505080610226575b82807f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d80f35b61022f91613590565b5f806101ff565b61023f91612384565b5f806101f7565b600486637c6b720960e11b8152fd5b6004866312d37ee560e31b8152fd5b508315156101dc565b8380fd5b505b80fd5b50346102735760203660031901126102735760043567ffffffffffffffff8111610271576102a8903690600401611b55565b908291835b8181106102bf57602084604051908152f35b6102d26102cd8284866120f0565b612175565b6501000000000081101561031b57600901548060f01c156102f7575b506001016102ad565b6001919469ffffffffffffffffffff6103149260a01c16906120a0565b93906102ee565b602486634e487b7160e01b81526032600452fd5b50346102735760203660031901126102735760043567ffffffffffffffff811161027157610364610372913690600401611d02565b9061036d612310565b612ba6565b807f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d80f35b5034610273576020366003190112610273576103c26103b5611bb9565b6103bd6124ba565b612255565b80f35b50346102735760a0366003190112610273576103df611bb9565b506103e8611bcf565b5060843567ffffffffffffffff811161027157610409903690600401611c8b565b5060206040517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b50346102735760203660031901126102735760043567ffffffffffffffff811161027157610469610372913690600401611b55565b90610472612310565b613590565b50346102735760a036600319011261027357610491611bb9565b5061049a611bcf565b5060443567ffffffffffffffff8111610271576104bb903690600401611d7e565b5060643567ffffffffffffffff8111610271576104dc903690600401611d7e565b5060843567ffffffffffffffff8111610271576104fd903690600401611c8b565b5060206040517fbc197c81000000000000000000000000000000000000000000000000000000008152f35b50346102735760a061054261053c36611b86565b9161219b565b6080604051916001600160481b0381511683526001600160481b0360208201511660208401526001600160481b03604082015116604084015263ffffffff6060820151166060840152015115156080820152f35b50346102735760203660031901126102735760043567ffffffffffffffff8111610271576105c8903690600401611b55565b906105d28261206e565b91835b8181106105f657604051602080825281906105f290820187611d33565b0390f35b6106046102cd8284866120f0565b6501000000000081101561031b5790600191600901548060f01c61062a575b50016105d5565b60a01c69ffffffffffffffffffff166106438287612187565b525f610623565b5034610273578060031936011261027357604080516106698282611c4d565b60058152602081017f352e302e3000000000000000000000000000000000000000000000000000000081528251938492602084525180928160208601528585015e828201840152601f01601f19168101030190f35b5034610273576020366003190112610273576001600160a01b036106e0611bb9565b6106e86124ba565b166001600160a01b031965010000000009541617650100000000095580f35b5034610273576020366003190112610273576107306040602092600435815260068452206134d6565b6001600160481b0360405191168152f35b503461027357806003193601126102735760206001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416604051908152f35b5060403660031901126102735760043567ffffffffffffffff8111610271576107b4903690600401611b55565b906024359067ffffffffffffffff821161026d573660238301121561026d5781600401359067ffffffffffffffff82116109d9576024830192602436918460061b0101116109d9576108046124ba565b8184036109b157845b8481106108af575061082d60209160405195604087526040870191612124565b84810382860152828152019190845b81811061086d57857fea94abb1b74fb43f057870ba68e52c15f36c6ed98b98bda185955ef4842b97aa86860387a180f35b9091926040806001926001600160801b0361088788612161565b1681526001600160801b0361089e60208901612161565b16602082015201940192910161083c565b6108ba8186846120f0565b35865260046020526001600160801b036040872054166001600160801b036108eb6108e6848789612100565b612110565b1681151591826109a7575b8261099c575b505061097457806109106001928587612100565b61091b8288866120f0565b358852600460205260408820907fffffffffffffffffffffffffffffffff0000000000000000000000000000000061096760206001600160801b0361095f85612110565b169301612110565b60801b161790550161080d565b6004867f1a20b67e000000000000000000000000000000000000000000000000000000008152fd5b141590505f806108fc565b81151592506108f6565b6004857fff633a38000000000000000000000000000000000000000000000000000000008152fd5b8480fd5b50346102735760403660031901126102735760043567ffffffffffffffff811161027157610a0f903690600401611b55565b6024359167ffffffffffffffff831161026d57610a33610372933690600401611cd1565b929091610a3e612310565b6129a6565b503461027357602036600319011261027357610730604060209260043581526005845220613466565b50346102735760603660031901126102735760043567ffffffffffffffff811161027157610a9e903690600401611b55565b60243567ffffffffffffffff811161026d57610abe903690600401611cd1565b6044939193359067ffffffffffffffff8211610af45761037294610ae961036d933690600401611d02565b959094610a3e612310565b8580fd5b50346102735760e0366003190112610273576004356001600160a01b03811680910361027157610b26611bcf565b906044356001600160a01b03811680910361026d576064359261ffff841692838503610af4576084359460ff861693848703610fc95760a4359461ffff861696878703610fc55760c435936001600160a01b038516809503610fc1577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00549960ff8b60401c16159a67ffffffffffffffff811680159081610fb9575b6001149081610faf575b159081610fa6575b50610f7e5767ffffffffffffffff1981166001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00558b610f3f575b50610c19614372565b610c21614372565b610c2a33612255565b610c32614372565b610c3a6124ba565b8215610efe578415610eef576103e88311610ee05791606093917fd2578cc27cd56b02e72d064ed9d68d965ec91300be9f269da17f0686716110b895935b76ffffffffffffffffffffffffffffffffffffffffffffff1961ffff60a01b60ff60b01b6002549360b01b169360a01b1691161784171760025560405192835260208301526040820152a16040516301ffc9a760e01b81527fd9b67a26000000000000000000000000000000000000000000000000000000006004820152602081602481865afa908115610ed5578891610ea6575b5015610e7e57906001600160a01b0392916001600160a01b03196501000000000954161765010000000009556001600160a01b0319875416178655166001600160a01b03196001541617600155610d62611e11565b610d6a6124ba565b60038116610e6f579078ffffffffffffffffffffffffffffffffffffffffffffffffff61ffff60c81b7b01000000000000000000000000000000000000000000000000000000937f7d17ca2c1939a5351692336344e18b51ee4c6038f1c4f45b9cb928daad54119f602060025495604051908152a160c81b1691161717600255610df15780f35b68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b6004846317ea5f1160e21b8152fd5b6004877f34d28112000000000000000000000000000000000000000000000000000000008152fd5b610ec8915060203d602011610ece575b610ec08183611c4d565b810190611df9565b5f610d0d565b503d610eb6565b6040513d8a823e3d90fd5b60048c6324a5279560e21b8152fd5b60048c63d92e233d60e01b8152fd5b84610f305791606093917fd2578cc27cd56b02e72d064ed9d68d965ec91300be9f269da17f0686716110b89593610c78565b60048c63825a7cf160e01b8152fd5b68ffffffffffffffffff191668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00555f610c10565b60048d7ff92ee8a9000000000000000000000000000000000000000000000000000000008152fd5b9050155f610bd4565b303b159150610bcc565b8d9150610bc2565b8a80fd5b8980fd5b8780fd5b5034610273578060031936011261027357610fe66124ba565b806001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031981167f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461027357606036600319011261027357611080611bb9565b6024359061ffff821680830361026d576044359260ff841692838503610af4576110a86124ba565b8215611165576001600160a01b03811615611156576103e883116111475791606093917fd2578cc27cd56b02e72d064ed9d68d965ec91300be9f269da17f0686716110b895935b76ffffffffffffffffffffffffffffffffffffffffffffff1961ffff60a01b60ff60b01b6001600160a01b0360025494169760b01b169360a01b1691161784171760025560405192835260208301526040820152a180f35b6004866324a5279560e21b8152fd5b60048663d92e233d60e01b8152fd5b6001600160a01b0381166111a05791606093917fd2578cc27cd56b02e72d064ed9d68d965ec91300be9f269da17f0686716110b895936110ef565b60048663825a7cf160e01b8152fd5b50346102735780600319360112610273576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361121a5760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b8063703e46dd60e11b60049252fd5b50346102735760203660031901126102735760408181926020835161124d81611c15565b828152015260043581526004602052206001600160801b0382519161127183611c15565b54602082821693848152019060801c8152835192835251166020820152f35b506040366003190112610273576112a5611bb9565b9060243567ffffffffffffffff8111610271576112c6903690600401611c8b565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001680301490811561150d575b506114fe576113086124ba565b6001600160a01b03831690604051937f52d1902d000000000000000000000000000000000000000000000000000000008552602085600481865afa809585966114ca575b506113645760248484634c9c8ce360e01b8252600452fd5b9091847f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc810361149f5750813b1561148d57806001600160a01b03197f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416177f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8480a2815183901561145a578083602061144e95519101845af43d15611452573d9161143283611c6f565b926114406040519485611c4d565b83523d85602085013e61531c565b5080f35b60609161531c565b505050346114655780f35b807fb398979f0000000000000000000000000000000000000000000000000000000060049252fd5b634c9c8ce360e01b8452600452602483fd5b7faa1d49a4000000000000000000000000000000000000000000000000000000008552600452602484fd5b9095506020813d6020116114f6575b816114e660209383611c4d565b810103126109d95751945f61134c565b3d91506114d9565b60048263703e46dd60e11b8152fd5b90506001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541614155f6112fb565b50346117505760803660031901126117505761155c612310565b5f905f611567612039565b92611570612039565b9362ffffff61157d6120ce565b16156118365760243590815f5260046020526115a8826001600160801b0360405f2054161515612795565b6004356002811015611750576115df62ffffff97821593845f14611830576001600160481b035b6115d76120ce565b9087866136e3565b9716806117e55750506115f1866127d5565b9591979094835f146117b75750606435811161178f575b80611770575b5080611754575b506116b6579280949362ffffff61162a6120ce565b16906001600160a01b0383541691823b1561026d57604051637921219560e11b81523360048201523060248201526044810192909252606482015260a060848201525f60a4820152908290829060c490829084905af180156116ab57611696575b5050610372926128c9565b816116a091611c4d565b61026d57835f61168b565b6040513d84823e3d90fd5b62ffffff6116c26120ce565b16906001600160a01b035f541691823b1561175057604051637921219560e11b81523060048201523360248201526044810192909252606482015260a060848201525f60a482018190529091829060c490829084905af180156117455761172f575b5061037292936128c9565b61037293505f61173e91611c4d565b5f92611724565b6040513d5f823e3d90fd5b5f80fd5b61176a90336001600160a01b0360015416612879565b5f611615565b611789906001600160a01b036001541630903390612818565b5f61160e565b7fb83cca50000000000000000000000000000000000000000000000000000000005f5260045ffd5b9150606435811061178f576117df906117d9876117d4888c6120a0565b6120a0565b906120c1565b90611608565b6084925083611824604051937f3e2a8e7400000000000000000000000000000000000000000000000000000000855233600486015260248501906127c8565b60448301526064820152fd5b5f6115cf565b7f94640235000000000000000000000000000000000000000000000000000000005f5260045ffd5b346117505761187561186f36611b86565b91611fbf565b6040518091602082016020835281518091526020604084019201905f5b8181106118a0575050500390f35b919350916020606060019264ffffffffff604088516001600160a01b03815116845262ffffff8682015116868501520151166040820152019401910191849392611892565b346117505760206118fe6118f836611b86565b91611f70565b6040519015158152f35b60203660031901126117505760043561ffff8116908181036117505761192c6124ba565b60038116611997577f7d17ca2c1939a5351692336344e18b51ee4c6038f1c4f45b9cb928daad54119f916020917fffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffff61ffff60c81b6002549260c81b16911617600255604051908152a1005b6317ea5f1160e21b5f5260045ffd5b34611750575f366003190112611750576119be611e11565b005b346117505760203660031901126117505760043564ffffffffff81168103611750576119ea611ddb565b5065010000000000811015611a555760609061ffff60405191611a0c83611be5565b6009015469ffffffffffffffffffff6001600160a01b0382169384815260406020820191838560a01c168352019260f01c83526040519485525116602084015251166040820152f35b634e487b7160e01b5f52603260045260245ffd5b346117505760203660031901126117505760043567ffffffffffffffff811161175057611a9d611aab913690600401611b55565b90611aa6612310565b612384565b5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d005b3461175057602036600319011261175057600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361175057817f4e2312e00000000000000000000000000000000000000000000000000000000060209314908115611b44575b5015158152f35b6301ffc9a760e01b91501483611b3d565b9181601f840112156117505782359167ffffffffffffffff8311611750576020808501948460051b01011161175057565b60609060031901126117505760043560028110156117505790602435906044356001600160481b03811681036117505790565b600435906001600160a01b038216820361175057565b602435906001600160a01b038216820361175057565b6060810190811067ffffffffffffffff821117611c0157604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff821117611c0157604052565b60a0810190811067ffffffffffffffff821117611c0157604052565b90601f8019910116810190811067ffffffffffffffff821117611c0157604052565b67ffffffffffffffff8111611c0157601f01601f191660200190565b81601f8201121561175057803590611ca282611c6f565b92611cb06040519485611c4d565b8284526020838301011161175057815f926020809301838601378301015290565b9181601f840112156117505782359167ffffffffffffffff8311611750576020808501946060850201011161175057565b9181601f840112156117505782359167ffffffffffffffff8311611750576020808501948460071b01011161175057565b90602080835192838152019201905f5b818110611d505750505090565b8251845260209384019390920191600101611d43565b67ffffffffffffffff8111611c015760051b60200190565b9080601f83011215611750578135611d9581611d66565b92611da36040519485611c4d565b81845260208085019260051b82010192831161175057602001905b828210611dcb5750505090565b8135815260209182019101611dbe565b60405190611de882611be5565b5f6040838281528260208201520152565b90816020910312611750575180151581036117505790565b602460206001600160a01b035f5416604051928380926301ffc9a760e01b825263152a902d60e11b60048301525afa908115611745575f91611f51575b5015611f3157604460406001600160a01b035f541681519283809263152a902d60e11b82526001600483015261271060248301525afa908115611745575f905f92611ee0575b506001600160a01b03166001600160a01b0319600354161760035561ffff60b81b1978ffff00000000000000000000000000000000000000000000006002549260b81b16911617600255565b9150506040813d604011611f29575b81611efc60409383611c4d565b81010312611750578051906001600160a01b03821682036117505760200151906001600160a01b03611e94565b3d9150611eef565b6001600160a01b03196003541660035561ffff60b81b1960025416600255565b611f6a915060203d602011610ece57610ec08183611c4d565b5f611e4e565b9190916002811015611fab57611f9757611f94915f52600660205260405f20612519565b90565b611f94915f52600560205260405f20612519565b634e487b7160e01b5f52602160045260245ffd5b9190916002811015611fab576120045781611f94925f52600860205260405f206001600160481b0383165f5260205260405f20905f52600660205260405f20906125b5565b81611f94925f52600760205260405f206001600160481b0383165f5260205260405f20905f52600560205260405f20906125b5565b6040516101f49190613ea061204e8183611c4d565b83825267ffffffffffffffff829411611c0157601f190190369060200137565b9061207882611d66565b6120856040519182611c4d565b8281528092612096601f1991611d66565b0190602036910137565b919082018092116120ad57565b634e487b7160e01b5f52601160045260245ffd5b919082039182116120ad57565b60443562ffffff811681036117505790565b3562ffffff811681036117505790565b9190811015611a555760051b0190565b9190811015611a555760061b0190565b356001600160801b03811681036117505790565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116117505760209260051b809284830137010190565b35906001600160801b038216820361175057565b3564ffffffffff811681036117505790565b8051821015611a555760209160051b010190565b9190916040516121aa81611c31565b5f81525f60208201525f60408201525f60608201525f6080820152506002811015611fab57612241576121e7915f52600660205260405f20613540565b604051906121f482611c31565b546001600160481b03811682526001600160481b038160481c1660208301526001600160481b038160901c16604083015263ffffffff8160d81c16606083015260f81c1515608082015290565b6121e7915f52600560205260405f20613540565b6001600160a01b031680156122e4576001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054826001600160a01b03198216177f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b7f1e4fbdf7000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c61235c5760017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b60c882116124ab575f915f5b81811061240d575082156123fe57826123d67f730ad7566a8a34d6ceb6a935a03fce683d09bd3d47fc52e557fa87069cea2e9a94336001600160a01b0360015416612879565b6123f3604051938493338552606060208601526060850191612124565b9060408301520390a1565b6312d37ee560e31b5f5260045ffd5b9261242261241c8584866120f0565b356136b6565b65010000000000811015611a5557600901805469ffffffffffffffffffff8160a01c169081156123fe576001600160a01b0333911603612483576001928269ffffffffffffffffffff60a01b1961247c94541690556120a0565b9301612390565b7fb331e421000000000000000000000000000000000000000000000000000000005f5260045ffd5b637c6b720960e11b5f5260045ffd5b6001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300541633036124ed57565b7f118cdaa7000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b906001600160481b0316801515918261253157505090565b80546001600160481b03168214925090821561254c57505090565b600192505f52016020526001600160481b0360405f205416151590565b8054821015611a55575f5260205f2001905f90565b908160021b91808304600414901517156120ad57565b818102929181159184041417156120ad57565b5f1981146120ad5760010190565b91906125c18282612519565b1561278d5763ffffffff916125d591613540565b5460d81c16915f916125e78482612569565b90545f9160031b1c5b6004821061274f575b50506126178361261261260d8785546120c1565b61257e565b6120c1565b9361262185611d66565b9461262f6040519687611c4d565b80865261263e601f1991611d66565b015f5b818110612738575050845f93855b61265a8789516120a0565b81101561272e57612677612671858360021c6120a0565b86612569565b90549060031b1c600382169060c08360061b1691808304604014901517156120ad5764ffffffffff81831c1690816126b5575b50505060010161264f565b90919297602884018094116120ad5765010000000000831015611a555761265a938362ffffff612726946001600160a01b03600197600901541693604051946126fd86611be5565b85521c1660208301526040820152612715828d612187565b52612720818c612187565b506125a7565b96915f6126aa565b5094509491505052565b602090612743611ddb565b82828a01015201612641565b90938460061b858104604014861517156120ad5782901c67ffffffffffffffff166127875761277f6001916125a7565b9401906125f0565b936125f9565b505050606090565b1561279d5750565b7f03399b24000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b906002821015611fab5752565b9060025490612710612814816127f261ffff8660b81c1687612594565b049460ff8361280861ffff8860a01c1684612594565b049560b01c1690612594565b0490565b9091926001600160a01b036128779481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252612872608483611c4d565b614305565b565b612877926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252612872606483611c4d565b8061296a575b5080612942575b50806128df5750565b6001600160a01b036001541690813b15611750575f916024839260405194859384927f42966c6800000000000000000000000000000000000000000000000000000000845260048401525af18015611745576129385750565b5f61287791611c4d565b612964906001600160a01b03600154166001600160a01b036002541690612879565b5f6128d6565b61298c906001600160a01b03600154166001600160a01b036003541690612879565b5f6128cf565b356001600160481b03811681036117505790565b929092818403612b66575f929192905f946129c08161206e565b936129ca8261206e565b955f915b838310612a5757505050907f518405fd4d1da4785cc552188e579f0508054f396deba0bec66f5caca9070bb491612a18604051928392338452604060208501526040840191612124565b0390a180612a3b575b5082612a2c57505050565b826128779382528252336146e4565b612a5190336001600160a01b0360015416612879565b5f612a21565b90919482861015611a5557606086028201803590600282101561175057612a85604060208301359201612992565b91612af35791612ae3612ae99262ffffff612add600196612aa78d8c8e6120f0565b3590805f52600860205260405f20946001600160481b03811695865f5260205260405f20915f52600660205260405f20926143c9565b16612594565b906120a0565b955b0191906129ce565b99879a62ffffff612b43612b6094612b0f6001979c8b8d6120f0565b3590845f52600760205260405f206001600160481b0382165f5260205260405f2090855f52600560205260405f20926143c9565b1690612b4f838c612187565b52612b5a828c612187565b526125a7565b98612aeb565b7fff633a38000000000000000000000000000000000000000000000000000000005f5260045ffd5b9062ffffff8091169116039062ffffff82116120ad57565b610220526101608190525f61014081905261012081905260e0819052919082908190612bd19061206e565b608052612be06101605161206e565b610180525f6102005261016051612bf69061206e565b61010052612c066101605161206e565b6101a052612c12612039565b91612c1b612039565b6101e05260025460d81c945f5b610160518110156132f4575f935f9462ffffff612c4f60608560071b6102205101016120e0565b1615611836576001600160481b03612c7160408560071b610220510101612992565b16156132cc5760208360071b610220510101355f5260046020526001600160801b0360405f205416958615612cb360208660071b610220510101358215612795565b6001600160481b03612ccf60408760071b610220510101612992565b16906132b857876001600160801b0391061661328c5760028460071b6102205101351015968761175057612d43612d1060408760071b610220510101612992565b8a6101e05191612d2a60608a60071b6102205101016120e0565b6102205190919060078b901b01602081013590356136e3565b6101c0529260208660071b610220510101355f52600460205260405f205460801c62ffffff851610155f146131eb5750829761175057612d8d60408660071b610220510101612992565b928560071b610220510135155f146131e55760208660071b610220510101355b60405190612dba82611be5565b3382528d6501000000000060208401915f835261ffff60408601941684521015611a555769ffffffffffffffffffff8f916001600160a01b03612e3b936009019551166001600160a01b03198654161785555116839069ffffffffffffffffffff60a01b1969ffffffffffffffffffff60a01b83549260a01b169116179055565b517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffff00000000000000000000000000000000000000000000000000000000000083549260f01b1691161790555f938c8760071b610220510135155f14613162575061022051600788901b016020908101355f908152600882526040808220600690935290209093600f0b926f7fffffffffffffffffffffffffffffff1984146120ad576001600160481b038f93612f2c9062ffffff947ff4ed6e99fd267f4e8f8273058850e0ded9794213643d112a2a58802f8b461e0c9860c0985f03928787169264ffffffffff8a16926153a8565b64ffffffffff60405195338752612f508d602089019060071b6102205101356127c8565b16604086015260208b60071b6102205101013560608601521660808401521660a0820152a15b62ffffff8716613145575b5f916101c0516130e7575b611750578360071b610220510135155f1461305957505090612fdb600192612ae3612fd262ffffff89166001600160481b03612add60408860071b610220510101612992565b6101c0516120a0565b946101c051612fed575b505b01612c28565b62ffffff6130329160208460071b610220510101356130126102005161010051612187565b521662ffffff61302c60608560071b6102205101016120e0565b166120c1565b613042610200516101a051612187565b5261304f610200516125a7565b610200525f612fe5565b839296506130809061307b606062ffffff94979660071b6102205101016120e0565b612b8e565b16806130ab575b506130a361309b600193946101c0516120c1565b60e0516120a0565b60e052612fe7565b61309b6130df6001946130a39360208660071b610220510101356130d183608051612187565b52612b5a8261018051612187565b935050613087565b915061313f6131086130fb6101c0516127d5565b60c05260a05280986120a0565b9661311860a051610140516120a0565b6101405261312b60c051610120516120a0565b610120526117d460c0519160a051906120a0565b91612f8c565b9864ffffffffff1664ffffffffff81146120ad5760010198612f81565b9060c0926001600160481b036131e062ffffff937ff4ed6e99fd267f4e8f8273058850e0ded9794213643d112a2a58802f8b461e0c9760208d60071b610220510101355f5260076020528c602060405f209160071b610220510101355f52600560205260405f2091600f0b928787169264ffffffffff8a16926153a8565b612f2c565b5f612dad565b9792905062ffffff8116613200575b50612f76565b915050807f12f572861d108ac2c546b0b80770afe6fe8b3921acb39b6a2fe9f91c4cd6d14d60a05f9362ffffff61324160408960071b610220510101612992565b916001600160481b0360405193338552613267602086018c60071b6102205101356127c8565b60208b60071b610220510101356040860152166060840152166080820152a15f6131fa565b867f766de9a4000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b634e487b7160e01b5f52601260045260245ffd5b7fe528e11e000000000000000000000000000000000000000000000000000000005f5260045ffd5b5092509293600254908160d81c64ffffffffff821603613417575b5050806133f8575b5060e0516133db575b8061336b575b506128779061020051613343575b610120519061014051906128c9565b610200516101005152610200516101a051526133666101a05161010051336146e4565b613334565b806080515261018051526001600160a01b035f541690813b15611750575f6040518093631759616b60e11b82528183816133b0610180516080513033600486016146a5565b03925af191821561174557612877926133cb575b5090613326565b5f6133d591611c4d565b5f6133c4565b6133f360e051336001600160a01b0360015416612879565b613320565b613411906001600160a01b036001541630903390612818565b5f613317565b7fffffffffff0000000000000000000000000000000000000000000000000000007affffffffffffffffffffffffffffffffffffffffffffffffffffff9160d81b169116176002555f8061330f565b6001600160481b03815416908161347b575090565b905b60018201906001600160481b0381165f52816020526001600160481b0360405f205460481c16156134d0576001600160481b03165f5260205260016001600160481b0360405f205460481c16905061347d565b92915050565b6001600160481b0381541690816134eb575090565b905b60018201906001600160481b0381165f52816020526001600160481b0360405f205460901c16156134d0576001600160481b03165f5260205260016001600160481b0360405f205460901c1690506134ed565b61354a8282612519565b15613568576001600160481b03600192165f520160205260405f2090565b7f2a8020fe000000000000000000000000000000000000000000000000000000005f5260045ffd5b91909160c883116124ab5782156123fe576135aa8361206e565b926135b48161206e565b915f5b8351811015613641576135ce61241c8285856120f0565b65010000000000811015611a5557600901908154918260f01c6135f18388612187565b5269ffffffffffffffffffff8360a01c169283156123fe576001600160a01b033391160361248357600192613626838a612187565b5269ffffffffffffffffffff60a01b198154169055016135b7565b50917fde3c2f9295fefa02a7867bf4445e614a43531448e07a5753940c0696b46e263293946136a36136b1926136788382336146e4565b613695604051968796338852608060208901526080880191612124565b908582036040870152611d33565b908382036060850152611d33565b0390a1565b64ffffffffff81116136cc5764ffffffffff1690565b6306dfcc6560e41b5f52602860045260245260445ffd5b9293909491610260526103a0526103c0526002811015611fab57613d5b575f610440525f610380525f61038052610440526101f46103a051526101f46103c051525f905b62ffffff610440511661383a575b5080613748575b50610380516104405191565b806103a051526103c051525f60206001600160a01b0365010000000009541660846040518094819363ec01f01960e01b83526009600484015233602484015260016044840152670de0b6b3a7640000610380510460648401525af180156117455761380b575b507f29c45e48d0fdd73dc977da9c0ed6c48240b873a5c373a3df49364e879b51203360405133815260606020820152806138026137f1606083016103a051611d33565b82810360408401526103c051611d33565b0390a15f61373c565b6020813d602011613832575b8161382460209383611c4d565b8101031261175057516137ae565b3d9150613817565b91905f61036052825f52600560205261385560405f20613466565b610360526001600160481b036103605116158015613d3a575b613d33575f91835f52600760205260405f206001600160481b0361036051165f5260205260405f2092845f5260056020526138af6103605160405f20613540565b935f925f935f610280525f610280525f9263ffffffff885460d81c16935b8154851080613d22575b15613d13575083906138e98582612569565b905460039190911b1c610280525f610320819052610400819052975b6004891080613d02575b15613cf757888060061b04604014891517156120ad576102805160068a901b1c64ffffffffff16908115613afe5760288a60061b018a60061b116120ad5762ffffff6102805160288c60061b011c16610340526103405162ffffff610440511610155f14613ab1576139876103405161044051612b8e565b6104405260038a1461040052610320516139a0906125a7565b61032052610340515b6139bf6001600160481b03610360511682612594565b926139cd84610380516120a0565b6103805265010000000000811015611a5557613a54613a6f94613a2969ffffffffffffffffffff613a1285600901936117d96117d4613a0b836127d5565b92916120a0565b1669ffffffffffffffffffff835460a01c1661472e565b69ffffffffffffffffffff60a01b1969ffffffffffffffffffff60a01b83549260a01b169116179055565b613a61836103a051612187565b52612b5a826103c051612187565b976101f4891015613a8957613a83906125a7565b97613905565b7fc8690679000000000000000000000000000000000000000000000000000000005f5260045ffd5b935062ffffff613ac76104405161034051612b8e565b1660288a60061b011b62ffffff60288b60061b011b196102805116176102805262ffffff6104405116935f610440526001946139a9565b610280519099989150600689901b1c15613b2457613b1e613a83916125a7565b976125a7565b9095919496505b6104005115613b4f5750613b3e906125a7565b93613b495f966125a7565b936138cd565b95613b62839761032097939751906120a0565b96613b7057613b49906125a7565b5092939094919795965b81613c3b575b5050838415613c32575b613b98575b50505050613727565b80613bfe575b50613bcf91613bb5916102805115613be157612569565b6102805182545f1960039390931b92831b1916911b179055565b613bdc575f808080613b8f565b613735565b855f526005602052613bf96103605160405f20614877565b612569565b5f5b818110613c0d5750613b9e565b80613c1e60019297949596976152fa565b610280511661028052019493929194613c00565b50801515613b8a565b63ffffffff905460d81c16865f52600560205260405f20613c5f6103605182612519565b15613568576001906001600160481b0361036051165f520160205260405f209063ffffffff831663ffffffff835460d81c16019163ffffffff83116120ad57613ccd92613cc6919063ffffffff60d81b1963ffffffff60d81b83549260d81b169116179055565b84546120c1565b14613cda575b5f80613b80565b845f526005602052613cf26103605160405f20614877565b613cd3565b975094909395613b2b565b5062ffffff6104405116151561390f565b94919592989697909350613b7a565b5062ffffff610440511615156138d7565b9091613735565b506001600160481b0361026051166001600160481b0361036051161161386e565b5f610240525f610420525f61042052610240526101f46103a051526101f46103c051525f905b62ffffff6102405116613e83575b5080613da2575b50610420516102405191565b806103a051526103c051525f60206001600160a01b0365010000000009541660846040518094819363ec01f01960e01b83526009600484015233602484015260016044840152670de0b6b3a7640000610420510460648401525af1801561174557613e54575b507f29c45e48d0fdd73dc977da9c0ed6c48240b873a5c373a3df49364e879b5120336040513381526060602082015280613e4b6137f1606083016103a051611d33565b0390a15f613d96565b6020813d602011613e7b575b81613e6d60209383611c4d565b810103126117505751613e08565b3d9150613e60565b915f61030052825f526006602052613e9d60405f206134d6565b610300526001600160481b0361030051161580156142e4575b6142de575f90835f52600860205260405f206001600160481b0361030051165f5260205260405f2091845f526006602052613ef76103005160405f20613540565b925f925f935f6102c0525f6102c0525f9263ffffffff875460d81c16935b81548510806142cd575b156142bf57508390613f318582612569565b905460039190911b1c6102c0525f6102a08190526103e0819052985b60048a10806142ae575b156142a357898060061b046040148a1517156120ad576102c05160068b901b1c64ffffffffff169081156140bd5760288b60061b018b60061b116120ad5762ffffff6102c05160288d60061b011c166102e0526102e05162ffffff610240511610155f1461407057613fcf6102e05161024051612b8e565b6102405260038b146103e0526102a051613fe8906125a7565b6102a0526102e0515b61401361400a6001600160481b03610300511683612594565b610420516120a0565b6104205265010000000000831015611a555782613a5461405694600901613a2969ffffffffffffffffffff851669ffffffffffffffffffff835460a01c1661472e565b986101f48a1015613a895761406a906125a7565b98613f4d565b935062ffffff614086610240516102e051612b8e565b1660288b60061b011b62ffffff60288c60061b011b196102c05116176102c05262ffffff6102405116935f61024052600194613ff1565b6102c051909a989150600689901b1c156140dd57613b1e61406a916125a7565b9095919496505b6103e0511561410857506140f7906125a7565b936141025f966125a7565b93613f15565b9561411b83976102a097939751906120a0565b9661412957614102906125a7565b50929390949197955b816141ee575b50508384156141e5575b614150575b50505050613d81565b806141b1575b506141879161416d916102c0511561419957612569565b6102c05182545f1960039390931b92831b1916911b179055565b614194575f808080614147565b613d8f565b855f526006602052613bf96103005160405f20614877565b5f5b8181106141c05750614156565b806141d160019297949596976152fa565b6102c051166102c0520194939291946141b3565b50801515614142565b63ffffffff905460d81c16865f52600660205260405f206142126103005182612519565b15613568576001906001600160481b0361030051165f520160205260405f209063ffffffff831663ffffffff835460d81c16019163ffffffff83116120ad5761427992613cc6919063ffffffff60d81b1963ffffffff60d81b83549260d81b169116179055565b14614286575b5f80614138565b845f52600660205261429e6103005160405f20614877565b61427f565b9850949093956140e4565b5062ffffff61024051161515613f57565b949195929896909350614132565b5062ffffff61024051161515613f1f565b91613d8f565b506001600160481b0361026051166001600160481b03610300511610613eb6565b905f602091828151910182855af115611745575f513d61436957506001600160a01b0381163b155b6143345750565b6001600160a01b03907f5274afe7000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b6001141561432d565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156143a157565b7fd7e6bcf8000000000000000000000000000000000000000000000000000000005f5260045ffd5b9392916143d68284612519565b1561466c5763ffffffff6143ea8385613540565b5460d81c169080546143fe87828585614769565b90975f19891461463357506144138884612569565b90549060031b1c978160061b98828a04604014831517156120ad5760288a0190818b116120ad5762ffffff911c169861444c8286612569565b90549060031b1c64ffffffffff81831c1665010000000000811015611a5557600901546001600160a01b03163303612483575f1985018581116120ad578314918261461c575b5050156144b8575050506144a58161483c565b54146144af575050565b61287791614877565b909294506117d49195506144cc935061257e565b918260021c926144df600382169261257e565b5f198101919082116120ad57905b808210614548575b5050806145075750612877915061483c565b826145309161452961451c6128779686612569565b90549060031b1c916152fa565b1692612569565b90919082549060031b91821b915f19901b1916179055565b9150925060018301908184116120ad578160021c9182946003821661456e819587612569565b90549060031b1c8260021c91600384169160c061458b858b612569565b90549060031b1c9660061b1691808304604014901517156120ad5767ffffffffffffffff911c1693841561460c576145c2826152fa565b169360c08460061b1691808304604014901517156120ad576001946145ea614605948a612569565b9290931b179082549060031b91821b915f19901b1916179055565b01906144ed565b5096509350505050915f806144f5565b67ffffffffffffffff9192501b1916155f80614492565b856001600160481b03917fdca140df000000000000000000000000000000000000000000000000000000005f526004521660245260445ffd5b6001600160481b0382867ff965eb63000000000000000000000000000000000000000000000000000000005f526004521660245260445ffd5b926136a3906001600160a01b036146d4948160209895168752168686015260a0604086015260a0850190611d33565b9060808183039101525f81520190565b90916001600160a01b035f5416803b156117505761471d935f809460405196879586948593631759616b60e11b855230600486016146a5565b03925af18015611745576129385750565b9069ffffffffffffffffffff8091169116019069ffffffffffffffffffff82116120ad57565b60061b90613fc060c08316921682036120ad57565b9291905b81811061477f57505050505f19908190565b61479561478c82846120c1565b60011c826120a0565b906147a08286612569565b90549060031b1c5f905f905b600482106147d9575b50506020036147d25750600181018091116120ad57905b9061476d565b91506147cc565b9097969492918060039795971b818104600814821517156120ad5782901c64ffffffffff1685810361481057505050505050509190565b94809795999394969899105f1461483657600881018091116120ad5791600101906147ac565b916147b5565b80548015614863575f1901906148528282612569565b8154905f199060031b1b1916905555565b634e487b7160e01b5f52603160045260245ffd5b6001600160481b0382169081156152d2576148928382612519565b15613568576001810192825f52836020526001600160481b0360405f205460481c161580156152b3575b156152495780925b6001600160481b0384165f52846020526001600160481b0360405f205460481c1615155f14615222576001600160481b0384165f52846020526001600160481b0360405f205460481c16915b6001600160481b038581165f908152602088905260408082205486841683529120805468ffffffffffffffffff1916919092169081179091558015615201576001600160481b03908181165f52876020528160405f205460481c16828816145f146151c357165f52856020526149ae8360405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b6001600160481b0385165f528560205260405f205460f81c1591806001600160481b03871603614fe7575b5050614a04575b50506001600160481b03165f5260205260405f206001600160481b03198154169055565b939091935b6001600160481b03835416906001600160481b0381169182141580614fd1575b15614fa25750805f52836020526001600160481b0360405f205416906001600160481b0382165f52846020526001600160481b0360405f205460481c16145f14614d11576001600160481b0381165f52836020526001600160481b0360405f205460901c166001600160481b0381165f528460205260405f205460f81c614c9a575b6001600160481b038181165f908152602087905260408082205460481c9092168152205460f81c1580614c6c575b15614b0c576001600160481b03165f528360205260405f20600160f81b6001600160f81b03825416179055935b93614a09565b90614be5916001600160481b0381165f52856020526001600160481b038060405f205460901c16165f528560205260405f205460f81c15614bf6575b6001600160481b03908183165f5286602052614b9460405f205460f81c8383165f528860205260405f20906001600160f81b036001600160f81b0319835492151560f81b169116179055565b8183165f528660205260405f206001600160f81b038154169055165f52846020526001600160481b038060405f205460901c16165f528460205260405f206001600160f81b03815416905583615dab565b6001600160481b0382541693614b06565b6001600160481b038082165f81815260208990526040808220805460481c9094168252812080546001600160f81b03908116909155919052815416600160f81b179055614c439085615bfb565b6001600160481b0381165f52846020526001600160481b038060405f205460901c169050614b48565b506001600160481b038181165f908152602087905260408082205460901c9092168152205460f81c15614ad9565b6001600160481b03165f528360205260405f206001600160f81b0381541690556001600160481b0381165f528360205260405f20600160f81b6001600160f81b03825416179055614ceb8184615dab565b6001600160481b0381165f52836020526001600160481b0360405f205460901c16614aab565b6001600160481b0381165f52836020526001600160481b0360405f205460481c166001600160481b0381165f528460205260405f205460f81c614f2b575b6001600160481b038181165f908152602087905260408082205460901c9092168152205460f81c1580614efd575b15614dae576001600160481b03165f528360205260405f20600160f81b6001600160f81b0382541617905593614b06565b90614be5916001600160481b0381165f52856020526001600160481b038060405f205460481c16165f528560205260405f205460f81c15614e87575b6001600160481b03908183165f5286602052614e3660405f205460f81c8383165f528860205260405f20906001600160f81b036001600160f81b0319835492151560f81b169116179055565b8183165f528660205260405f206001600160f81b038154169055165f52846020526001600160481b038060405f205460481c16165f528460205260405f206001600160f81b03815416905583615bfb565b6001600160481b038082165f81815260208990526040808220805460901c9094168252812080546001600160f81b03908116909155919052815416600160f81b179055614ed49085615dab565b6001600160481b0381165f52846020526001600160481b038060405f205460481c169050614dea565b506001600160481b038181165f908152602087905260408082205460481c9092168152205460f81c15614d7d565b6001600160481b03165f528360205260405f206001600160f81b0381541690556001600160481b0381165f528360205260405f20600160f81b6001600160f81b03825416179055614f7c8184615bfb565b6001600160481b0381165f52836020526001600160481b0360405f205460481c16614d4f565b6001600160481b039350839150949194165f528260205260405f206001600160f81b038154169055905f6149e0565b50815f528460205260405f205460f81c15614a29565b94615120919295805f52876020526001600160481b0360405f2054166001600160481b0383165f528860205260405f206001600160481b0382166001600160481b031982541617905580155f146151285750855468ffffffffffffffffff19166001600160481b0383161786555b5f9081526020889052604080822080546001600160481b03948516808552838520805468ffffffffffffffffff60481b191668ffffffffffffffffff60481b9093169290921780835560481c86168552838520805468ffffffffffffffffff1990811683179091558354835468ffffffffffffffffff60901b191668ffffffffffffffffff60901b9091161780845560901c90961685529284208054909516831790945554915281546001600160f81b031660f891821c151590911b6001600160f81b031916179055565b925f806149d9565b6001600160481b03908181165f52896020528160405f205460481c1683145f1461518a57165f52876020526151858260405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b615055565b165f52876020526151858260405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b165f52856020526151fc8360405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b6149ae565b50835468ffffffffffffffffff19166001600160481b0384161784556149ae565b6001600160481b0384165f52846020526001600160481b0360405f205460901c1691614910565b825f52836020526001600160481b0360405f205460901c165b6001600160481b0381165f52846020526001600160481b0360405f205460481c16156152ad576001600160481b03165f52836020526001600160481b0360405f205460481c16615262565b926148c4565b50825f52836020526001600160481b0360405f205460901c16156148bc565b7fd77534c7000000000000000000000000000000000000000000000000000000005f5260045ffd5b8060061b90808204604014901517156120ad5767ffffffffffffffff901b1990565b90615359575080511561533157805190602001fd5b7fd6bda275000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061539f575b61536a575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15615362565b9180959493946153b88284612519565b6154e057506153c6916156a6565b6001600160481b0384165f5260205260405f2091600183548061543c575b506153f0575b50505090565b82549268010000000000000000841015611c01578361541791600161543496018155612569565b91909260281b179082549060031b91821b915f19901b1916179055565b5f80806153ea565b5f1981019081116120ad576154519085612569565b90549060031b1c5f5b60048110615469575b506153e4565b8060061b818104604014821517156120ad5782811c1561548c575060010161545a565b9192505060288101908181116120ad5785545f198101919082116120ad576154d893856154ba88948a612569565b9490951b921b17179082549060031b91821b915f19901b1916179055565b5f5f80615463565b906154f063ffffffff9184613540565b5460d81c166001600160481b03871691825f528460205260405f20835f528560205260405f20545f1981019081116120ad5761552b91612569565b905460039491851b1c60ff61553f86614754565b161c1515905f528560205261555b61260d8460405f20546120c1565b61ffff60025460c81c161115908161569e575b5061557d575b505050506153c6565b965b6001600160481b0388600f0b9116600f0b016f7fffffffffffffffffffffffffffffff1981126f7fffffffffffffffffffffffffffffff8213176120ad576001600160801b0381166001600160481b03811161568757506001600160481b0316966155ea8885612519565b61560457505050846155fb916156a6565b5f808080615574565b875f9892939498528460205261562161260d8460405f20546120c1565b61ffff60025460c81c1611801561564a575b615640579692919061557f565b50955050506155fb565b505f82815260208690526040902080545f1981019081116120ad5761566e91612569565b905490851b1c60ff61567f86614754565b161c15615633565b6306dfcc6560e41b5f52604860045260245260445ffd5b90505f61556e565b906001600160481b0381169283156152d25782546001600160481b03165f5b6001600160481b03821690811561572f5750818187101561570e576001600160481b039150165f52600184016020526001600160481b0360405f205460481c16915b91906156c5565b505f52600184016020526001600160481b0360405f205460901c1691615707565b95915050929190926001830194815f528560205261585663ffffffff60405f205460d81c16918361583563ffffffff6001600160481b036040519461577386611c31565b16958685526158156001600160481b038d6157eb8260208a015f815260408b01935f855260608c0197885260808c019a60018c525f52602052818060405f209c51161682198c5416178b555116899068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b51875468ffffffffffffffffff60901b1916911660901b68ffffffffffffffffff60901b16178655565b51845463ffffffff60d81b1916911660d81b63ffffffff60d81b16178355565b5181546001600160f81b031690151560f81b6001600160f81b031916179055565b80615b7d5750825468ffffffffffffffffff19161782555b905b6001600160481b038154166001600160481b0383169081141580615b57575b15615b2d575f81815260208690526040808220546001600160481b039081168084528284205482168452919092205490929160489190911c168203615a0457506001600160481b038181165f9081526020879052604080822054831682528082205460901c9092168082529190205490939060f81c1561596357506001600160481b039081165f8181526020879052604080822080546001600160f81b03908116825596851683528183208054881690558054851683529082208054909616600160f81b1790955552915490911690615870565b92506001600160481b0381165f52846020526001600160481b0360405f205460901c166001600160481b038416146159f2575b506001600160481b038281165f9081526020869052604080822054831680835281832080546001600160f81b03818116835590861685529284208054909316600160f81b17909255909152546159ed911682615bfb565b615870565b91506159fe8282615dab565b5f615996565b6001600160481b038281165f9081526020889052604080822054831682528082205460481c909216808252919020549094919060f81c15615a9a5750506001600160481b039081165f8181526020879052604080822080546001600160f81b03908116825596851683528183208054881690558054851683529082208054909616600160f81b1790955552915490911690615870565b9093506001600160481b0382165f52856020526001600160481b0360405f205460481c1614615b1b575b506001600160481b038281165f9081526020869052604080822054831680835281832080546001600160f81b03818116835590861685529284208054909316600160f81b17909255909152546159ed911682615dab565b9150615b278282615bfb565b5f615ac4565b50546001600160481b03165f90815260209390935250604090912080546001600160f81b03169055565b505f81815260208690526040808220546001600160481b0316825290205460f81c61588f565b8091105f14615bc3575f5283602052615bbe8160405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b61586e565b5f5283602052615bbe8160405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b6001600160481b038083165f81815260018401602081905260408083208054604881811c8816808752938620549690955268ffffffffffffffffff60481b1981169486901c68ffffffffffffffffff60481b169490941790559590949092909184169060901c841680615d8e575b508386165f528460205260405f20848216851982541617905580155f14615cf7575082851683198254161790555b8184165f5282602052615cd28160405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b165f526020526001600160481b0360405f2091166001600160481b0319825416179055565b8391508181165f52846020528160405f205460901c16828416145f14615d5557165f5282602052615d508460405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b615c97565b165f5282602052615d508460405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b84165f528460205260405f2084841685198254161790555f615c69565b6001600160481b038083165f81815260018401602081905260408083208054609081901c8716808652928520549590945268ffffffffffffffffff60901b198416604886811b68ffffffffffffffffff60901b16919091179091559096919591939192851691901c841680615f1b575b508386165f528460205260405f20848216851982541617905580155f14615e84575082851683198254161790555b8184165f5282602052615cd28160405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b8391508181165f52846020528160405f205460481c16828416145f14615ee257165f5282602052615edd8460405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b615e49565b165f5282602052615edd8460405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b84165f528460205260405f2084841685198254161790555f615e1b56fea2646970667358221220453cff37bef3d1a1e094719830493c33742aeb2f8c0ffc0bf850f6d9618a298664736f6c634300081c0033f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00
Deployed Bytecode
0x610460806040526004361015610013575f80fd5b5f905f3560e01c90816301ffc9a714611ad0575080632d08265a14611a695780633546326c146119c057806335569842146119a65780633fd3a6a5146119085780634628b1fd146118e55780634dca93471461185e5780634f0eb731146115425780634f1ef2861461129057806352aa5e8f1461122957806352d1902d146111af5780636faf6d1914611066578063715018a614610fcd57806374aacfab14610af85780637783743714610a6c578063793052b814610a4357806379800e87146109dd57806385dd961f146107875780638da5cb5b146107415780638f28864414610707578063acfda69e146106be578063ad3cb1cc1461064a578063b110c27c14610596578063b3f4c59f14610528578063bc197c8114610477578063c385bddf14610434578063f23a6e61146103c5578063f2fde38b14610398578063f3a0934e1461032f578063f9e13eb1146102765763fb2ac52e14610174575f80fd5b346102735760403660031901126102735760043567ffffffffffffffff8111610271576101a5903690600401611b55565b9060243567ffffffffffffffff811161026d576101c6903690600401611b55565b9190926101d1612310565b801580158091610264575b156102555760c86101ed85846120a0565b1161024657610236575b505080610226575b82807f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d80f35b61022f91613590565b5f806101ff565b61023f91612384565b5f806101f7565b600486637c6b720960e11b8152fd5b6004866312d37ee560e31b8152fd5b508315156101dc565b8380fd5b505b80fd5b50346102735760203660031901126102735760043567ffffffffffffffff8111610271576102a8903690600401611b55565b908291835b8181106102bf57602084604051908152f35b6102d26102cd8284866120f0565b612175565b6501000000000081101561031b57600901548060f01c156102f7575b506001016102ad565b6001919469ffffffffffffffffffff6103149260a01c16906120a0565b93906102ee565b602486634e487b7160e01b81526032600452fd5b50346102735760203660031901126102735760043567ffffffffffffffff811161027157610364610372913690600401611d02565b9061036d612310565b612ba6565b807f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d80f35b5034610273576020366003190112610273576103c26103b5611bb9565b6103bd6124ba565b612255565b80f35b50346102735760a0366003190112610273576103df611bb9565b506103e8611bcf565b5060843567ffffffffffffffff811161027157610409903690600401611c8b565b5060206040517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b50346102735760203660031901126102735760043567ffffffffffffffff811161027157610469610372913690600401611b55565b90610472612310565b613590565b50346102735760a036600319011261027357610491611bb9565b5061049a611bcf565b5060443567ffffffffffffffff8111610271576104bb903690600401611d7e565b5060643567ffffffffffffffff8111610271576104dc903690600401611d7e565b5060843567ffffffffffffffff8111610271576104fd903690600401611c8b565b5060206040517fbc197c81000000000000000000000000000000000000000000000000000000008152f35b50346102735760a061054261053c36611b86565b9161219b565b6080604051916001600160481b0381511683526001600160481b0360208201511660208401526001600160481b03604082015116604084015263ffffffff6060820151166060840152015115156080820152f35b50346102735760203660031901126102735760043567ffffffffffffffff8111610271576105c8903690600401611b55565b906105d28261206e565b91835b8181106105f657604051602080825281906105f290820187611d33565b0390f35b6106046102cd8284866120f0565b6501000000000081101561031b5790600191600901548060f01c61062a575b50016105d5565b60a01c69ffffffffffffffffffff166106438287612187565b525f610623565b5034610273578060031936011261027357604080516106698282611c4d565b60058152602081017f352e302e3000000000000000000000000000000000000000000000000000000081528251938492602084525180928160208601528585015e828201840152601f01601f19168101030190f35b5034610273576020366003190112610273576001600160a01b036106e0611bb9565b6106e86124ba565b166001600160a01b031965010000000009541617650100000000095580f35b5034610273576020366003190112610273576107306040602092600435815260068452206134d6565b6001600160481b0360405191168152f35b503461027357806003193601126102735760206001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416604051908152f35b5060403660031901126102735760043567ffffffffffffffff8111610271576107b4903690600401611b55565b906024359067ffffffffffffffff821161026d573660238301121561026d5781600401359067ffffffffffffffff82116109d9576024830192602436918460061b0101116109d9576108046124ba565b8184036109b157845b8481106108af575061082d60209160405195604087526040870191612124565b84810382860152828152019190845b81811061086d57857fea94abb1b74fb43f057870ba68e52c15f36c6ed98b98bda185955ef4842b97aa86860387a180f35b9091926040806001926001600160801b0361088788612161565b1681526001600160801b0361089e60208901612161565b16602082015201940192910161083c565b6108ba8186846120f0565b35865260046020526001600160801b036040872054166001600160801b036108eb6108e6848789612100565b612110565b1681151591826109a7575b8261099c575b505061097457806109106001928587612100565b61091b8288866120f0565b358852600460205260408820907fffffffffffffffffffffffffffffffff0000000000000000000000000000000061096760206001600160801b0361095f85612110565b169301612110565b60801b161790550161080d565b6004867f1a20b67e000000000000000000000000000000000000000000000000000000008152fd5b141590505f806108fc565b81151592506108f6565b6004857fff633a38000000000000000000000000000000000000000000000000000000008152fd5b8480fd5b50346102735760403660031901126102735760043567ffffffffffffffff811161027157610a0f903690600401611b55565b6024359167ffffffffffffffff831161026d57610a33610372933690600401611cd1565b929091610a3e612310565b6129a6565b503461027357602036600319011261027357610730604060209260043581526005845220613466565b50346102735760603660031901126102735760043567ffffffffffffffff811161027157610a9e903690600401611b55565b60243567ffffffffffffffff811161026d57610abe903690600401611cd1565b6044939193359067ffffffffffffffff8211610af45761037294610ae961036d933690600401611d02565b959094610a3e612310565b8580fd5b50346102735760e0366003190112610273576004356001600160a01b03811680910361027157610b26611bcf565b906044356001600160a01b03811680910361026d576064359261ffff841692838503610af4576084359460ff861693848703610fc95760a4359461ffff861696878703610fc55760c435936001600160a01b038516809503610fc1577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00549960ff8b60401c16159a67ffffffffffffffff811680159081610fb9575b6001149081610faf575b159081610fa6575b50610f7e5767ffffffffffffffff1981166001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00558b610f3f575b50610c19614372565b610c21614372565b610c2a33612255565b610c32614372565b610c3a6124ba565b8215610efe578415610eef576103e88311610ee05791606093917fd2578cc27cd56b02e72d064ed9d68d965ec91300be9f269da17f0686716110b895935b76ffffffffffffffffffffffffffffffffffffffffffffff1961ffff60a01b60ff60b01b6002549360b01b169360a01b1691161784171760025560405192835260208301526040820152a16040516301ffc9a760e01b81527fd9b67a26000000000000000000000000000000000000000000000000000000006004820152602081602481865afa908115610ed5578891610ea6575b5015610e7e57906001600160a01b0392916001600160a01b03196501000000000954161765010000000009556001600160a01b0319875416178655166001600160a01b03196001541617600155610d62611e11565b610d6a6124ba565b60038116610e6f579078ffffffffffffffffffffffffffffffffffffffffffffffffff61ffff60c81b7b01000000000000000000000000000000000000000000000000000000937f7d17ca2c1939a5351692336344e18b51ee4c6038f1c4f45b9cb928daad54119f602060025495604051908152a160c81b1691161717600255610df15780f35b68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b6004846317ea5f1160e21b8152fd5b6004877f34d28112000000000000000000000000000000000000000000000000000000008152fd5b610ec8915060203d602011610ece575b610ec08183611c4d565b810190611df9565b5f610d0d565b503d610eb6565b6040513d8a823e3d90fd5b60048c6324a5279560e21b8152fd5b60048c63d92e233d60e01b8152fd5b84610f305791606093917fd2578cc27cd56b02e72d064ed9d68d965ec91300be9f269da17f0686716110b89593610c78565b60048c63825a7cf160e01b8152fd5b68ffffffffffffffffff191668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00555f610c10565b60048d7ff92ee8a9000000000000000000000000000000000000000000000000000000008152fd5b9050155f610bd4565b303b159150610bcc565b8d9150610bc2565b8a80fd5b8980fd5b8780fd5b5034610273578060031936011261027357610fe66124ba565b806001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031981167f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461027357606036600319011261027357611080611bb9565b6024359061ffff821680830361026d576044359260ff841692838503610af4576110a86124ba565b8215611165576001600160a01b03811615611156576103e883116111475791606093917fd2578cc27cd56b02e72d064ed9d68d965ec91300be9f269da17f0686716110b895935b76ffffffffffffffffffffffffffffffffffffffffffffff1961ffff60a01b60ff60b01b6001600160a01b0360025494169760b01b169360a01b1691161784171760025560405192835260208301526040820152a180f35b6004866324a5279560e21b8152fd5b60048663d92e233d60e01b8152fd5b6001600160a01b0381166111a05791606093917fd2578cc27cd56b02e72d064ed9d68d965ec91300be9f269da17f0686716110b895936110ef565b60048663825a7cf160e01b8152fd5b50346102735780600319360112610273576001600160a01b037f000000000000000000000000b16fbc5251da4c4beadc685406ed2b2c5fa5f1a816300361121a5760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b8063703e46dd60e11b60049252fd5b50346102735760203660031901126102735760408181926020835161124d81611c15565b828152015260043581526004602052206001600160801b0382519161127183611c15565b54602082821693848152019060801c8152835192835251166020820152f35b506040366003190112610273576112a5611bb9565b9060243567ffffffffffffffff8111610271576112c6903690600401611c8b565b6001600160a01b037f000000000000000000000000b16fbc5251da4c4beadc685406ed2b2c5fa5f1a81680301490811561150d575b506114fe576113086124ba565b6001600160a01b03831690604051937f52d1902d000000000000000000000000000000000000000000000000000000008552602085600481865afa809585966114ca575b506113645760248484634c9c8ce360e01b8252600452fd5b9091847f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc810361149f5750813b1561148d57806001600160a01b03197f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416177f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8480a2815183901561145a578083602061144e95519101845af43d15611452573d9161143283611c6f565b926114406040519485611c4d565b83523d85602085013e61531c565b5080f35b60609161531c565b505050346114655780f35b807fb398979f0000000000000000000000000000000000000000000000000000000060049252fd5b634c9c8ce360e01b8452600452602483fd5b7faa1d49a4000000000000000000000000000000000000000000000000000000008552600452602484fd5b9095506020813d6020116114f6575b816114e660209383611c4d565b810103126109d95751945f61134c565b3d91506114d9565b60048263703e46dd60e11b8152fd5b90506001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541614155f6112fb565b50346117505760803660031901126117505761155c612310565b5f905f611567612039565b92611570612039565b9362ffffff61157d6120ce565b16156118365760243590815f5260046020526115a8826001600160801b0360405f2054161515612795565b6004356002811015611750576115df62ffffff97821593845f14611830576001600160481b035b6115d76120ce565b9087866136e3565b9716806117e55750506115f1866127d5565b9591979094835f146117b75750606435811161178f575b80611770575b5080611754575b506116b6579280949362ffffff61162a6120ce565b16906001600160a01b0383541691823b1561026d57604051637921219560e11b81523360048201523060248201526044810192909252606482015260a060848201525f60a4820152908290829060c490829084905af180156116ab57611696575b5050610372926128c9565b816116a091611c4d565b61026d57835f61168b565b6040513d84823e3d90fd5b62ffffff6116c26120ce565b16906001600160a01b035f541691823b1561175057604051637921219560e11b81523060048201523360248201526044810192909252606482015260a060848201525f60a482018190529091829060c490829084905af180156117455761172f575b5061037292936128c9565b61037293505f61173e91611c4d565b5f92611724565b6040513d5f823e3d90fd5b5f80fd5b61176a90336001600160a01b0360015416612879565b5f611615565b611789906001600160a01b036001541630903390612818565b5f61160e565b7fb83cca50000000000000000000000000000000000000000000000000000000005f5260045ffd5b9150606435811061178f576117df906117d9876117d4888c6120a0565b6120a0565b906120c1565b90611608565b6084925083611824604051937f3e2a8e7400000000000000000000000000000000000000000000000000000000855233600486015260248501906127c8565b60448301526064820152fd5b5f6115cf565b7f94640235000000000000000000000000000000000000000000000000000000005f5260045ffd5b346117505761187561186f36611b86565b91611fbf565b6040518091602082016020835281518091526020604084019201905f5b8181106118a0575050500390f35b919350916020606060019264ffffffffff604088516001600160a01b03815116845262ffffff8682015116868501520151166040820152019401910191849392611892565b346117505760206118fe6118f836611b86565b91611f70565b6040519015158152f35b60203660031901126117505760043561ffff8116908181036117505761192c6124ba565b60038116611997577f7d17ca2c1939a5351692336344e18b51ee4c6038f1c4f45b9cb928daad54119f916020917fffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffff61ffff60c81b6002549260c81b16911617600255604051908152a1005b6317ea5f1160e21b5f5260045ffd5b34611750575f366003190112611750576119be611e11565b005b346117505760203660031901126117505760043564ffffffffff81168103611750576119ea611ddb565b5065010000000000811015611a555760609061ffff60405191611a0c83611be5565b6009015469ffffffffffffffffffff6001600160a01b0382169384815260406020820191838560a01c168352019260f01c83526040519485525116602084015251166040820152f35b634e487b7160e01b5f52603260045260245ffd5b346117505760203660031901126117505760043567ffffffffffffffff811161175057611a9d611aab913690600401611b55565b90611aa6612310565b612384565b5f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d005b3461175057602036600319011261175057600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361175057817f4e2312e00000000000000000000000000000000000000000000000000000000060209314908115611b44575b5015158152f35b6301ffc9a760e01b91501483611b3d565b9181601f840112156117505782359167ffffffffffffffff8311611750576020808501948460051b01011161175057565b60609060031901126117505760043560028110156117505790602435906044356001600160481b03811681036117505790565b600435906001600160a01b038216820361175057565b602435906001600160a01b038216820361175057565b6060810190811067ffffffffffffffff821117611c0157604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff821117611c0157604052565b60a0810190811067ffffffffffffffff821117611c0157604052565b90601f8019910116810190811067ffffffffffffffff821117611c0157604052565b67ffffffffffffffff8111611c0157601f01601f191660200190565b81601f8201121561175057803590611ca282611c6f565b92611cb06040519485611c4d565b8284526020838301011161175057815f926020809301838601378301015290565b9181601f840112156117505782359167ffffffffffffffff8311611750576020808501946060850201011161175057565b9181601f840112156117505782359167ffffffffffffffff8311611750576020808501948460071b01011161175057565b90602080835192838152019201905f5b818110611d505750505090565b8251845260209384019390920191600101611d43565b67ffffffffffffffff8111611c015760051b60200190565b9080601f83011215611750578135611d9581611d66565b92611da36040519485611c4d565b81845260208085019260051b82010192831161175057602001905b828210611dcb5750505090565b8135815260209182019101611dbe565b60405190611de882611be5565b5f6040838281528260208201520152565b90816020910312611750575180151581036117505790565b602460206001600160a01b035f5416604051928380926301ffc9a760e01b825263152a902d60e11b60048301525afa908115611745575f91611f51575b5015611f3157604460406001600160a01b035f541681519283809263152a902d60e11b82526001600483015261271060248301525afa908115611745575f905f92611ee0575b506001600160a01b03166001600160a01b0319600354161760035561ffff60b81b1978ffff00000000000000000000000000000000000000000000006002549260b81b16911617600255565b9150506040813d604011611f29575b81611efc60409383611c4d565b81010312611750578051906001600160a01b03821682036117505760200151906001600160a01b03611e94565b3d9150611eef565b6001600160a01b03196003541660035561ffff60b81b1960025416600255565b611f6a915060203d602011610ece57610ec08183611c4d565b5f611e4e565b9190916002811015611fab57611f9757611f94915f52600660205260405f20612519565b90565b611f94915f52600560205260405f20612519565b634e487b7160e01b5f52602160045260245ffd5b9190916002811015611fab576120045781611f94925f52600860205260405f206001600160481b0383165f5260205260405f20905f52600660205260405f20906125b5565b81611f94925f52600760205260405f206001600160481b0383165f5260205260405f20905f52600560205260405f20906125b5565b6040516101f49190613ea061204e8183611c4d565b83825267ffffffffffffffff829411611c0157601f190190369060200137565b9061207882611d66565b6120856040519182611c4d565b8281528092612096601f1991611d66565b0190602036910137565b919082018092116120ad57565b634e487b7160e01b5f52601160045260245ffd5b919082039182116120ad57565b60443562ffffff811681036117505790565b3562ffffff811681036117505790565b9190811015611a555760051b0190565b9190811015611a555760061b0190565b356001600160801b03811681036117505790565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116117505760209260051b809284830137010190565b35906001600160801b038216820361175057565b3564ffffffffff811681036117505790565b8051821015611a555760209160051b010190565b9190916040516121aa81611c31565b5f81525f60208201525f60408201525f60608201525f6080820152506002811015611fab57612241576121e7915f52600660205260405f20613540565b604051906121f482611c31565b546001600160481b03811682526001600160481b038160481c1660208301526001600160481b038160901c16604083015263ffffffff8160d81c16606083015260f81c1515608082015290565b6121e7915f52600560205260405f20613540565b6001600160a01b031680156122e4576001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054826001600160a01b03198216177f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b7f1e4fbdf7000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c61235c5760017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b60c882116124ab575f915f5b81811061240d575082156123fe57826123d67f730ad7566a8a34d6ceb6a935a03fce683d09bd3d47fc52e557fa87069cea2e9a94336001600160a01b0360015416612879565b6123f3604051938493338552606060208601526060850191612124565b9060408301520390a1565b6312d37ee560e31b5f5260045ffd5b9261242261241c8584866120f0565b356136b6565b65010000000000811015611a5557600901805469ffffffffffffffffffff8160a01c169081156123fe576001600160a01b0333911603612483576001928269ffffffffffffffffffff60a01b1961247c94541690556120a0565b9301612390565b7fb331e421000000000000000000000000000000000000000000000000000000005f5260045ffd5b637c6b720960e11b5f5260045ffd5b6001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300541633036124ed57565b7f118cdaa7000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b906001600160481b0316801515918261253157505090565b80546001600160481b03168214925090821561254c57505090565b600192505f52016020526001600160481b0360405f205416151590565b8054821015611a55575f5260205f2001905f90565b908160021b91808304600414901517156120ad57565b818102929181159184041417156120ad57565b5f1981146120ad5760010190565b91906125c18282612519565b1561278d5763ffffffff916125d591613540565b5460d81c16915f916125e78482612569565b90545f9160031b1c5b6004821061274f575b50506126178361261261260d8785546120c1565b61257e565b6120c1565b9361262185611d66565b9461262f6040519687611c4d565b80865261263e601f1991611d66565b015f5b818110612738575050845f93855b61265a8789516120a0565b81101561272e57612677612671858360021c6120a0565b86612569565b90549060031b1c600382169060c08360061b1691808304604014901517156120ad5764ffffffffff81831c1690816126b5575b50505060010161264f565b90919297602884018094116120ad5765010000000000831015611a555761265a938362ffffff612726946001600160a01b03600197600901541693604051946126fd86611be5565b85521c1660208301526040820152612715828d612187565b52612720818c612187565b506125a7565b96915f6126aa565b5094509491505052565b602090612743611ddb565b82828a01015201612641565b90938460061b858104604014861517156120ad5782901c67ffffffffffffffff166127875761277f6001916125a7565b9401906125f0565b936125f9565b505050606090565b1561279d5750565b7f03399b24000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b906002821015611fab5752565b9060025490612710612814816127f261ffff8660b81c1687612594565b049460ff8361280861ffff8860a01c1684612594565b049560b01c1690612594565b0490565b9091926001600160a01b036128779481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252612872608483611c4d565b614305565b565b612877926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252612872606483611c4d565b8061296a575b5080612942575b50806128df5750565b6001600160a01b036001541690813b15611750575f916024839260405194859384927f42966c6800000000000000000000000000000000000000000000000000000000845260048401525af18015611745576129385750565b5f61287791611c4d565b612964906001600160a01b03600154166001600160a01b036002541690612879565b5f6128d6565b61298c906001600160a01b03600154166001600160a01b036003541690612879565b5f6128cf565b356001600160481b03811681036117505790565b929092818403612b66575f929192905f946129c08161206e565b936129ca8261206e565b955f915b838310612a5757505050907f518405fd4d1da4785cc552188e579f0508054f396deba0bec66f5caca9070bb491612a18604051928392338452604060208501526040840191612124565b0390a180612a3b575b5082612a2c57505050565b826128779382528252336146e4565b612a5190336001600160a01b0360015416612879565b5f612a21565b90919482861015611a5557606086028201803590600282101561175057612a85604060208301359201612992565b91612af35791612ae3612ae99262ffffff612add600196612aa78d8c8e6120f0565b3590805f52600860205260405f20946001600160481b03811695865f5260205260405f20915f52600660205260405f20926143c9565b16612594565b906120a0565b955b0191906129ce565b99879a62ffffff612b43612b6094612b0f6001979c8b8d6120f0565b3590845f52600760205260405f206001600160481b0382165f5260205260405f2090855f52600560205260405f20926143c9565b1690612b4f838c612187565b52612b5a828c612187565b526125a7565b98612aeb565b7fff633a38000000000000000000000000000000000000000000000000000000005f5260045ffd5b9062ffffff8091169116039062ffffff82116120ad57565b610220526101608190525f61014081905261012081905260e0819052919082908190612bd19061206e565b608052612be06101605161206e565b610180525f6102005261016051612bf69061206e565b61010052612c066101605161206e565b6101a052612c12612039565b91612c1b612039565b6101e05260025460d81c945f5b610160518110156132f4575f935f9462ffffff612c4f60608560071b6102205101016120e0565b1615611836576001600160481b03612c7160408560071b610220510101612992565b16156132cc5760208360071b610220510101355f5260046020526001600160801b0360405f205416958615612cb360208660071b610220510101358215612795565b6001600160481b03612ccf60408760071b610220510101612992565b16906132b857876001600160801b0391061661328c5760028460071b6102205101351015968761175057612d43612d1060408760071b610220510101612992565b8a6101e05191612d2a60608a60071b6102205101016120e0565b6102205190919060078b901b01602081013590356136e3565b6101c0529260208660071b610220510101355f52600460205260405f205460801c62ffffff851610155f146131eb5750829761175057612d8d60408660071b610220510101612992565b928560071b610220510135155f146131e55760208660071b610220510101355b60405190612dba82611be5565b3382528d6501000000000060208401915f835261ffff60408601941684521015611a555769ffffffffffffffffffff8f916001600160a01b03612e3b936009019551166001600160a01b03198654161785555116839069ffffffffffffffffffff60a01b1969ffffffffffffffffffff60a01b83549260a01b169116179055565b517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffff00000000000000000000000000000000000000000000000000000000000083549260f01b1691161790555f938c8760071b610220510135155f14613162575061022051600788901b016020908101355f908152600882526040808220600690935290209093600f0b926f7fffffffffffffffffffffffffffffff1984146120ad576001600160481b038f93612f2c9062ffffff947ff4ed6e99fd267f4e8f8273058850e0ded9794213643d112a2a58802f8b461e0c9860c0985f03928787169264ffffffffff8a16926153a8565b64ffffffffff60405195338752612f508d602089019060071b6102205101356127c8565b16604086015260208b60071b6102205101013560608601521660808401521660a0820152a15b62ffffff8716613145575b5f916101c0516130e7575b611750578360071b610220510135155f1461305957505090612fdb600192612ae3612fd262ffffff89166001600160481b03612add60408860071b610220510101612992565b6101c0516120a0565b946101c051612fed575b505b01612c28565b62ffffff6130329160208460071b610220510101356130126102005161010051612187565b521662ffffff61302c60608560071b6102205101016120e0565b166120c1565b613042610200516101a051612187565b5261304f610200516125a7565b610200525f612fe5565b839296506130809061307b606062ffffff94979660071b6102205101016120e0565b612b8e565b16806130ab575b506130a361309b600193946101c0516120c1565b60e0516120a0565b60e052612fe7565b61309b6130df6001946130a39360208660071b610220510101356130d183608051612187565b52612b5a8261018051612187565b935050613087565b915061313f6131086130fb6101c0516127d5565b60c05260a05280986120a0565b9661311860a051610140516120a0565b6101405261312b60c051610120516120a0565b610120526117d460c0519160a051906120a0565b91612f8c565b9864ffffffffff1664ffffffffff81146120ad5760010198612f81565b9060c0926001600160481b036131e062ffffff937ff4ed6e99fd267f4e8f8273058850e0ded9794213643d112a2a58802f8b461e0c9760208d60071b610220510101355f5260076020528c602060405f209160071b610220510101355f52600560205260405f2091600f0b928787169264ffffffffff8a16926153a8565b612f2c565b5f612dad565b9792905062ffffff8116613200575b50612f76565b915050807f12f572861d108ac2c546b0b80770afe6fe8b3921acb39b6a2fe9f91c4cd6d14d60a05f9362ffffff61324160408960071b610220510101612992565b916001600160481b0360405193338552613267602086018c60071b6102205101356127c8565b60208b60071b610220510101356040860152166060840152166080820152a15f6131fa565b867f766de9a4000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b634e487b7160e01b5f52601260045260245ffd5b7fe528e11e000000000000000000000000000000000000000000000000000000005f5260045ffd5b5092509293600254908160d81c64ffffffffff821603613417575b5050806133f8575b5060e0516133db575b8061336b575b506128779061020051613343575b610120519061014051906128c9565b610200516101005152610200516101a051526133666101a05161010051336146e4565b613334565b806080515261018051526001600160a01b035f541690813b15611750575f6040518093631759616b60e11b82528183816133b0610180516080513033600486016146a5565b03925af191821561174557612877926133cb575b5090613326565b5f6133d591611c4d565b5f6133c4565b6133f360e051336001600160a01b0360015416612879565b613320565b613411906001600160a01b036001541630903390612818565b5f613317565b7fffffffffff0000000000000000000000000000000000000000000000000000007affffffffffffffffffffffffffffffffffffffffffffffffffffff9160d81b169116176002555f8061330f565b6001600160481b03815416908161347b575090565b905b60018201906001600160481b0381165f52816020526001600160481b0360405f205460481c16156134d0576001600160481b03165f5260205260016001600160481b0360405f205460481c16905061347d565b92915050565b6001600160481b0381541690816134eb575090565b905b60018201906001600160481b0381165f52816020526001600160481b0360405f205460901c16156134d0576001600160481b03165f5260205260016001600160481b0360405f205460901c1690506134ed565b61354a8282612519565b15613568576001600160481b03600192165f520160205260405f2090565b7f2a8020fe000000000000000000000000000000000000000000000000000000005f5260045ffd5b91909160c883116124ab5782156123fe576135aa8361206e565b926135b48161206e565b915f5b8351811015613641576135ce61241c8285856120f0565b65010000000000811015611a5557600901908154918260f01c6135f18388612187565b5269ffffffffffffffffffff8360a01c169283156123fe576001600160a01b033391160361248357600192613626838a612187565b5269ffffffffffffffffffff60a01b198154169055016135b7565b50917fde3c2f9295fefa02a7867bf4445e614a43531448e07a5753940c0696b46e263293946136a36136b1926136788382336146e4565b613695604051968796338852608060208901526080880191612124565b908582036040870152611d33565b908382036060850152611d33565b0390a1565b64ffffffffff81116136cc5764ffffffffff1690565b6306dfcc6560e41b5f52602860045260245260445ffd5b9293909491610260526103a0526103c0526002811015611fab57613d5b575f610440525f610380525f61038052610440526101f46103a051526101f46103c051525f905b62ffffff610440511661383a575b5080613748575b50610380516104405191565b806103a051526103c051525f60206001600160a01b0365010000000009541660846040518094819363ec01f01960e01b83526009600484015233602484015260016044840152670de0b6b3a7640000610380510460648401525af180156117455761380b575b507f29c45e48d0fdd73dc977da9c0ed6c48240b873a5c373a3df49364e879b51203360405133815260606020820152806138026137f1606083016103a051611d33565b82810360408401526103c051611d33565b0390a15f61373c565b6020813d602011613832575b8161382460209383611c4d565b8101031261175057516137ae565b3d9150613817565b91905f61036052825f52600560205261385560405f20613466565b610360526001600160481b036103605116158015613d3a575b613d33575f91835f52600760205260405f206001600160481b0361036051165f5260205260405f2092845f5260056020526138af6103605160405f20613540565b935f925f935f610280525f610280525f9263ffffffff885460d81c16935b8154851080613d22575b15613d13575083906138e98582612569565b905460039190911b1c610280525f610320819052610400819052975b6004891080613d02575b15613cf757888060061b04604014891517156120ad576102805160068a901b1c64ffffffffff16908115613afe5760288a60061b018a60061b116120ad5762ffffff6102805160288c60061b011c16610340526103405162ffffff610440511610155f14613ab1576139876103405161044051612b8e565b6104405260038a1461040052610320516139a0906125a7565b61032052610340515b6139bf6001600160481b03610360511682612594565b926139cd84610380516120a0565b6103805265010000000000811015611a5557613a54613a6f94613a2969ffffffffffffffffffff613a1285600901936117d96117d4613a0b836127d5565b92916120a0565b1669ffffffffffffffffffff835460a01c1661472e565b69ffffffffffffffffffff60a01b1969ffffffffffffffffffff60a01b83549260a01b169116179055565b613a61836103a051612187565b52612b5a826103c051612187565b976101f4891015613a8957613a83906125a7565b97613905565b7fc8690679000000000000000000000000000000000000000000000000000000005f5260045ffd5b935062ffffff613ac76104405161034051612b8e565b1660288a60061b011b62ffffff60288b60061b011b196102805116176102805262ffffff6104405116935f610440526001946139a9565b610280519099989150600689901b1c15613b2457613b1e613a83916125a7565b976125a7565b9095919496505b6104005115613b4f5750613b3e906125a7565b93613b495f966125a7565b936138cd565b95613b62839761032097939751906120a0565b96613b7057613b49906125a7565b5092939094919795965b81613c3b575b5050838415613c32575b613b98575b50505050613727565b80613bfe575b50613bcf91613bb5916102805115613be157612569565b6102805182545f1960039390931b92831b1916911b179055565b613bdc575f808080613b8f565b613735565b855f526005602052613bf96103605160405f20614877565b612569565b5f5b818110613c0d5750613b9e565b80613c1e60019297949596976152fa565b610280511661028052019493929194613c00565b50801515613b8a565b63ffffffff905460d81c16865f52600560205260405f20613c5f6103605182612519565b15613568576001906001600160481b0361036051165f520160205260405f209063ffffffff831663ffffffff835460d81c16019163ffffffff83116120ad57613ccd92613cc6919063ffffffff60d81b1963ffffffff60d81b83549260d81b169116179055565b84546120c1565b14613cda575b5f80613b80565b845f526005602052613cf26103605160405f20614877565b613cd3565b975094909395613b2b565b5062ffffff6104405116151561390f565b94919592989697909350613b7a565b5062ffffff610440511615156138d7565b9091613735565b506001600160481b0361026051166001600160481b0361036051161161386e565b5f610240525f610420525f61042052610240526101f46103a051526101f46103c051525f905b62ffffff6102405116613e83575b5080613da2575b50610420516102405191565b806103a051526103c051525f60206001600160a01b0365010000000009541660846040518094819363ec01f01960e01b83526009600484015233602484015260016044840152670de0b6b3a7640000610420510460648401525af1801561174557613e54575b507f29c45e48d0fdd73dc977da9c0ed6c48240b873a5c373a3df49364e879b5120336040513381526060602082015280613e4b6137f1606083016103a051611d33565b0390a15f613d96565b6020813d602011613e7b575b81613e6d60209383611c4d565b810103126117505751613e08565b3d9150613e60565b915f61030052825f526006602052613e9d60405f206134d6565b610300526001600160481b0361030051161580156142e4575b6142de575f90835f52600860205260405f206001600160481b0361030051165f5260205260405f2091845f526006602052613ef76103005160405f20613540565b925f925f935f6102c0525f6102c0525f9263ffffffff875460d81c16935b81548510806142cd575b156142bf57508390613f318582612569565b905460039190911b1c6102c0525f6102a08190526103e0819052985b60048a10806142ae575b156142a357898060061b046040148a1517156120ad576102c05160068b901b1c64ffffffffff169081156140bd5760288b60061b018b60061b116120ad5762ffffff6102c05160288d60061b011c166102e0526102e05162ffffff610240511610155f1461407057613fcf6102e05161024051612b8e565b6102405260038b146103e0526102a051613fe8906125a7565b6102a0526102e0515b61401361400a6001600160481b03610300511683612594565b610420516120a0565b6104205265010000000000831015611a555782613a5461405694600901613a2969ffffffffffffffffffff851669ffffffffffffffffffff835460a01c1661472e565b986101f48a1015613a895761406a906125a7565b98613f4d565b935062ffffff614086610240516102e051612b8e565b1660288b60061b011b62ffffff60288c60061b011b196102c05116176102c05262ffffff6102405116935f61024052600194613ff1565b6102c051909a989150600689901b1c156140dd57613b1e61406a916125a7565b9095919496505b6103e0511561410857506140f7906125a7565b936141025f966125a7565b93613f15565b9561411b83976102a097939751906120a0565b9661412957614102906125a7565b50929390949197955b816141ee575b50508384156141e5575b614150575b50505050613d81565b806141b1575b506141879161416d916102c0511561419957612569565b6102c05182545f1960039390931b92831b1916911b179055565b614194575f808080614147565b613d8f565b855f526006602052613bf96103005160405f20614877565b5f5b8181106141c05750614156565b806141d160019297949596976152fa565b6102c051166102c0520194939291946141b3565b50801515614142565b63ffffffff905460d81c16865f52600660205260405f206142126103005182612519565b15613568576001906001600160481b0361030051165f520160205260405f209063ffffffff831663ffffffff835460d81c16019163ffffffff83116120ad5761427992613cc6919063ffffffff60d81b1963ffffffff60d81b83549260d81b169116179055565b14614286575b5f80614138565b845f52600660205261429e6103005160405f20614877565b61427f565b9850949093956140e4565b5062ffffff61024051161515613f57565b949195929896909350614132565b5062ffffff61024051161515613f1f565b91613d8f565b506001600160481b0361026051166001600160481b03610300511610613eb6565b905f602091828151910182855af115611745575f513d61436957506001600160a01b0381163b155b6143345750565b6001600160a01b03907f5274afe7000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b6001141561432d565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c16156143a157565b7fd7e6bcf8000000000000000000000000000000000000000000000000000000005f5260045ffd5b9392916143d68284612519565b1561466c5763ffffffff6143ea8385613540565b5460d81c169080546143fe87828585614769565b90975f19891461463357506144138884612569565b90549060031b1c978160061b98828a04604014831517156120ad5760288a0190818b116120ad5762ffffff911c169861444c8286612569565b90549060031b1c64ffffffffff81831c1665010000000000811015611a5557600901546001600160a01b03163303612483575f1985018581116120ad578314918261461c575b5050156144b8575050506144a58161483c565b54146144af575050565b61287791614877565b909294506117d49195506144cc935061257e565b918260021c926144df600382169261257e565b5f198101919082116120ad57905b808210614548575b5050806145075750612877915061483c565b826145309161452961451c6128779686612569565b90549060031b1c916152fa565b1692612569565b90919082549060031b91821b915f19901b1916179055565b9150925060018301908184116120ad578160021c9182946003821661456e819587612569565b90549060031b1c8260021c91600384169160c061458b858b612569565b90549060031b1c9660061b1691808304604014901517156120ad5767ffffffffffffffff911c1693841561460c576145c2826152fa565b169360c08460061b1691808304604014901517156120ad576001946145ea614605948a612569565b9290931b179082549060031b91821b915f19901b1916179055565b01906144ed565b5096509350505050915f806144f5565b67ffffffffffffffff9192501b1916155f80614492565b856001600160481b03917fdca140df000000000000000000000000000000000000000000000000000000005f526004521660245260445ffd5b6001600160481b0382867ff965eb63000000000000000000000000000000000000000000000000000000005f526004521660245260445ffd5b926136a3906001600160a01b036146d4948160209895168752168686015260a0604086015260a0850190611d33565b9060808183039101525f81520190565b90916001600160a01b035f5416803b156117505761471d935f809460405196879586948593631759616b60e11b855230600486016146a5565b03925af18015611745576129385750565b9069ffffffffffffffffffff8091169116019069ffffffffffffffffffff82116120ad57565b60061b90613fc060c08316921682036120ad57565b9291905b81811061477f57505050505f19908190565b61479561478c82846120c1565b60011c826120a0565b906147a08286612569565b90549060031b1c5f905f905b600482106147d9575b50506020036147d25750600181018091116120ad57905b9061476d565b91506147cc565b9097969492918060039795971b818104600814821517156120ad5782901c64ffffffffff1685810361481057505050505050509190565b94809795999394969899105f1461483657600881018091116120ad5791600101906147ac565b916147b5565b80548015614863575f1901906148528282612569565b8154905f199060031b1b1916905555565b634e487b7160e01b5f52603160045260245ffd5b6001600160481b0382169081156152d2576148928382612519565b15613568576001810192825f52836020526001600160481b0360405f205460481c161580156152b3575b156152495780925b6001600160481b0384165f52846020526001600160481b0360405f205460481c1615155f14615222576001600160481b0384165f52846020526001600160481b0360405f205460481c16915b6001600160481b038581165f908152602088905260408082205486841683529120805468ffffffffffffffffff1916919092169081179091558015615201576001600160481b03908181165f52876020528160405f205460481c16828816145f146151c357165f52856020526149ae8360405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b6001600160481b0385165f528560205260405f205460f81c1591806001600160481b03871603614fe7575b5050614a04575b50506001600160481b03165f5260205260405f206001600160481b03198154169055565b939091935b6001600160481b03835416906001600160481b0381169182141580614fd1575b15614fa25750805f52836020526001600160481b0360405f205416906001600160481b0382165f52846020526001600160481b0360405f205460481c16145f14614d11576001600160481b0381165f52836020526001600160481b0360405f205460901c166001600160481b0381165f528460205260405f205460f81c614c9a575b6001600160481b038181165f908152602087905260408082205460481c9092168152205460f81c1580614c6c575b15614b0c576001600160481b03165f528360205260405f20600160f81b6001600160f81b03825416179055935b93614a09565b90614be5916001600160481b0381165f52856020526001600160481b038060405f205460901c16165f528560205260405f205460f81c15614bf6575b6001600160481b03908183165f5286602052614b9460405f205460f81c8383165f528860205260405f20906001600160f81b036001600160f81b0319835492151560f81b169116179055565b8183165f528660205260405f206001600160f81b038154169055165f52846020526001600160481b038060405f205460901c16165f528460205260405f206001600160f81b03815416905583615dab565b6001600160481b0382541693614b06565b6001600160481b038082165f81815260208990526040808220805460481c9094168252812080546001600160f81b03908116909155919052815416600160f81b179055614c439085615bfb565b6001600160481b0381165f52846020526001600160481b038060405f205460901c169050614b48565b506001600160481b038181165f908152602087905260408082205460901c9092168152205460f81c15614ad9565b6001600160481b03165f528360205260405f206001600160f81b0381541690556001600160481b0381165f528360205260405f20600160f81b6001600160f81b03825416179055614ceb8184615dab565b6001600160481b0381165f52836020526001600160481b0360405f205460901c16614aab565b6001600160481b0381165f52836020526001600160481b0360405f205460481c166001600160481b0381165f528460205260405f205460f81c614f2b575b6001600160481b038181165f908152602087905260408082205460901c9092168152205460f81c1580614efd575b15614dae576001600160481b03165f528360205260405f20600160f81b6001600160f81b0382541617905593614b06565b90614be5916001600160481b0381165f52856020526001600160481b038060405f205460481c16165f528560205260405f205460f81c15614e87575b6001600160481b03908183165f5286602052614e3660405f205460f81c8383165f528860205260405f20906001600160f81b036001600160f81b0319835492151560f81b169116179055565b8183165f528660205260405f206001600160f81b038154169055165f52846020526001600160481b038060405f205460481c16165f528460205260405f206001600160f81b03815416905583615bfb565b6001600160481b038082165f81815260208990526040808220805460901c9094168252812080546001600160f81b03908116909155919052815416600160f81b179055614ed49085615dab565b6001600160481b0381165f52846020526001600160481b038060405f205460481c169050614dea565b506001600160481b038181165f908152602087905260408082205460481c9092168152205460f81c15614d7d565b6001600160481b03165f528360205260405f206001600160f81b0381541690556001600160481b0381165f528360205260405f20600160f81b6001600160f81b03825416179055614f7c8184615bfb565b6001600160481b0381165f52836020526001600160481b0360405f205460481c16614d4f565b6001600160481b039350839150949194165f528260205260405f206001600160f81b038154169055905f6149e0565b50815f528460205260405f205460f81c15614a29565b94615120919295805f52876020526001600160481b0360405f2054166001600160481b0383165f528860205260405f206001600160481b0382166001600160481b031982541617905580155f146151285750855468ffffffffffffffffff19166001600160481b0383161786555b5f9081526020889052604080822080546001600160481b03948516808552838520805468ffffffffffffffffff60481b191668ffffffffffffffffff60481b9093169290921780835560481c86168552838520805468ffffffffffffffffff1990811683179091558354835468ffffffffffffffffff60901b191668ffffffffffffffffff60901b9091161780845560901c90961685529284208054909516831790945554915281546001600160f81b031660f891821c151590911b6001600160f81b031916179055565b925f806149d9565b6001600160481b03908181165f52896020528160405f205460481c1683145f1461518a57165f52876020526151858260405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b615055565b165f52876020526151858260405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b165f52856020526151fc8360405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b6149ae565b50835468ffffffffffffffffff19166001600160481b0384161784556149ae565b6001600160481b0384165f52846020526001600160481b0360405f205460901c1691614910565b825f52836020526001600160481b0360405f205460901c165b6001600160481b0381165f52846020526001600160481b0360405f205460481c16156152ad576001600160481b03165f52836020526001600160481b0360405f205460481c16615262565b926148c4565b50825f52836020526001600160481b0360405f205460901c16156148bc565b7fd77534c7000000000000000000000000000000000000000000000000000000005f5260045ffd5b8060061b90808204604014901517156120ad5767ffffffffffffffff901b1990565b90615359575080511561533157805190602001fd5b7fd6bda275000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061539f575b61536a575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15615362565b9180959493946153b88284612519565b6154e057506153c6916156a6565b6001600160481b0384165f5260205260405f2091600183548061543c575b506153f0575b50505090565b82549268010000000000000000841015611c01578361541791600161543496018155612569565b91909260281b179082549060031b91821b915f19901b1916179055565b5f80806153ea565b5f1981019081116120ad576154519085612569565b90549060031b1c5f5b60048110615469575b506153e4565b8060061b818104604014821517156120ad5782811c1561548c575060010161545a565b9192505060288101908181116120ad5785545f198101919082116120ad576154d893856154ba88948a612569565b9490951b921b17179082549060031b91821b915f19901b1916179055565b5f5f80615463565b906154f063ffffffff9184613540565b5460d81c166001600160481b03871691825f528460205260405f20835f528560205260405f20545f1981019081116120ad5761552b91612569565b905460039491851b1c60ff61553f86614754565b161c1515905f528560205261555b61260d8460405f20546120c1565b61ffff60025460c81c161115908161569e575b5061557d575b505050506153c6565b965b6001600160481b0388600f0b9116600f0b016f7fffffffffffffffffffffffffffffff1981126f7fffffffffffffffffffffffffffffff8213176120ad576001600160801b0381166001600160481b03811161568757506001600160481b0316966155ea8885612519565b61560457505050846155fb916156a6565b5f808080615574565b875f9892939498528460205261562161260d8460405f20546120c1565b61ffff60025460c81c1611801561564a575b615640579692919061557f565b50955050506155fb565b505f82815260208690526040902080545f1981019081116120ad5761566e91612569565b905490851b1c60ff61567f86614754565b161c15615633565b6306dfcc6560e41b5f52604860045260245260445ffd5b90505f61556e565b906001600160481b0381169283156152d25782546001600160481b03165f5b6001600160481b03821690811561572f5750818187101561570e576001600160481b039150165f52600184016020526001600160481b0360405f205460481c16915b91906156c5565b505f52600184016020526001600160481b0360405f205460901c1691615707565b95915050929190926001830194815f528560205261585663ffffffff60405f205460d81c16918361583563ffffffff6001600160481b036040519461577386611c31565b16958685526158156001600160481b038d6157eb8260208a015f815260408b01935f855260608c0197885260808c019a60018c525f52602052818060405f209c51161682198c5416178b555116899068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b51875468ffffffffffffffffff60901b1916911660901b68ffffffffffffffffff60901b16178655565b51845463ffffffff60d81b1916911660d81b63ffffffff60d81b16178355565b5181546001600160f81b031690151560f81b6001600160f81b031916179055565b80615b7d5750825468ffffffffffffffffff19161782555b905b6001600160481b038154166001600160481b0383169081141580615b57575b15615b2d575f81815260208690526040808220546001600160481b039081168084528284205482168452919092205490929160489190911c168203615a0457506001600160481b038181165f9081526020879052604080822054831682528082205460901c9092168082529190205490939060f81c1561596357506001600160481b039081165f8181526020879052604080822080546001600160f81b03908116825596851683528183208054881690558054851683529082208054909616600160f81b1790955552915490911690615870565b92506001600160481b0381165f52846020526001600160481b0360405f205460901c166001600160481b038416146159f2575b506001600160481b038281165f9081526020869052604080822054831680835281832080546001600160f81b03818116835590861685529284208054909316600160f81b17909255909152546159ed911682615bfb565b615870565b91506159fe8282615dab565b5f615996565b6001600160481b038281165f9081526020889052604080822054831682528082205460481c909216808252919020549094919060f81c15615a9a5750506001600160481b039081165f8181526020879052604080822080546001600160f81b03908116825596851683528183208054881690558054851683529082208054909616600160f81b1790955552915490911690615870565b9093506001600160481b0382165f52856020526001600160481b0360405f205460481c1614615b1b575b506001600160481b038281165f9081526020869052604080822054831680835281832080546001600160f81b03818116835590861685529284208054909316600160f81b17909255909152546159ed911682615dab565b9150615b278282615bfb565b5f615ac4565b50546001600160481b03165f90815260209390935250604090912080546001600160f81b03169055565b505f81815260208690526040808220546001600160481b0316825290205460f81c61588f565b8091105f14615bc3575f5283602052615bbe8160405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b61586e565b5f5283602052615bbe8160405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b6001600160481b038083165f81815260018401602081905260408083208054604881811c8816808752938620549690955268ffffffffffffffffff60481b1981169486901c68ffffffffffffffffff60481b169490941790559590949092909184169060901c841680615d8e575b508386165f528460205260405f20848216851982541617905580155f14615cf7575082851683198254161790555b8184165f5282602052615cd28160405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b165f526020526001600160481b0360405f2091166001600160481b0319825416179055565b8391508181165f52846020528160405f205460901c16828416145f14615d5557165f5282602052615d508460405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b615c97565b165f5282602052615d508460405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b84165f528460205260405f2084841685198254161790555f615c69565b6001600160481b038083165f81815260018401602081905260408083208054609081901c8716808652928520549590945268ffffffffffffffffff60901b198416604886811b68ffffffffffffffffff60901b16919091179091559096919591939192851691901c841680615f1b575b508386165f528460205260405f20848216851982541617905580155f14615e84575082851683198254161790555b8184165f5282602052615cd28160405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b8391508181165f52846020528160405f205460481c16828416145f14615ee257165f5282602052615edd8460405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b615e49565b165f5282602052615edd8460405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b84165f528460205260405f2084841685198254161790555f615e1b56fea2646970667358221220453cff37bef3d1a1e094719830493c33742aeb2f8c0ffc0bf850f6d9618a298664736f6c634300081c0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 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.