Overview
S Balance
0 S
S Value
-More 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 {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"; /// @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 { 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; /// @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 ) 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()); _nft = nft; _coin = IBrushToken(token); updateRoyaltyFee(); // The max orders spans segments, so num segments = maxOrdersPrice / NUM_ORDERS_PER_SEGMENT setMaxOrdersPerPrice(maxOrdersPerPrice); _nextOrderId = 1; } /// @notice Place market order /// @param order market order to be placed function marketOrder(MarketOrder calldata order) external override { // 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) public override { 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); } /// @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) public override { 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); } } /// @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 { 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) public override { require(orderIds.length <= MAX_CLAIMABLE_ORDERS, ClaimingTooManyOrders()); uint256 amount; for (uint256 i = 0; i < orderIds.length; ++i) { uint40 orderId = uint40(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); } /// @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) public override { 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 = uint40(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); } /// @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 { 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 _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) } 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) (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 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":[{"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"}],"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":"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
60a080604052346100c257306080525f516020615da95f395f51905f525460ff8160401c166100b3576002600160401b03196001600160401b03821601610060575b604051615ce290816100c782396080518181816110d701526111dd0152f35b6001600160401b0319166001600160401b039081175f516020615da95f395f51905f525581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80610041565b63f92ee8a960e01b5f5260045ffd5b5f80fdfe610480806040526004361015610013575f80fd5b5f905f3560e01c90816301ffc9a7146119a8575080632d08265a1461196e5780633546326c146118c557806335569842146118ab5780633fd3a6a51461180d5780634628b1fd146117ea5780634dca9347146117635780634f0eb7311461144f5780634f1ef2861461119d57806352aa5e8f1461113657806352d1902d146110bc5780636faf6d1914610f73578063715018a614610eda5780637783743714610e50578063793052b814610e2757806379800e8714610dc957806384f160c01461092657806385dd961f146106d05780638da5cb5b1461068a5780638f28864414610650578063ad3cb1cc146105dc578063b110c27c14610528578063b3f4c59f146104ba578063bc197c8114610409578063c385bddf146103ce578063f23a6e611461035f578063f2fde38b14610335578063f3a0934e146102f7578063f9e13eb11461023e5763fb2ac52e14610169575f80fd5b3461023b57604036600319011261023b5760043567ffffffffffffffff81116102395761019a903690600401611a2d565b9060243567ffffffffffffffff8111610235576101bb903690600401611a2d565b91909280158015809161022c575b1561021d5760c86101da8584611cc3565b1161020e576101fe575b5050806101ef578280f35b6101f891612497565b5f808280f35b61020791611d21565b5f806101e4565b600486637c6b720960e11b8152fd5b6004866312d37ee560e31b8152fd5b508315156101c9565b8380fd5b505b80fd5b503461023b57602036600319011261023b5760043567ffffffffffffffff811161023957610270903690600401611a2d565b908291835b81811061028757602084604051908152f35b61029a610295828486611cb3565b6123cb565b650100000000008110156102e357600901548060f01c156102bf575b50600101610275565b6001919469ffffffffffffffffffff6102dc9260a01c1690611cc3565b93906102b6565b602486634e487b7160e01b81526032600452fd5b503461023b57602036600319011261023b5760043567ffffffffffffffff81116102395761032c610332913690600401611bda565b90612695565b80f35b503461023b57602036600319011261023b57610332610352611a91565b61035a612faa565b6125c2565b503461023b5760a036600319011261023b57610379611a91565b50610382611aa7565b5060843567ffffffffffffffff8111610239576103a3903690600401611b63565b5060206040517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b503461023b57602036600319011261023b5760043567ffffffffffffffff811161023957610403610332913690600401611a2d565b90612497565b503461023b5760a036600319011261023b57610423611a91565b5061042c611aa7565b5060443567ffffffffffffffff81116102395761044d903690600401611c56565b5060643567ffffffffffffffff81116102395761046e903690600401611c56565b5060843567ffffffffffffffff81116102395761048f903690600401611b63565b5060206040517fbc197c81000000000000000000000000000000000000000000000000000000008152f35b503461023b5760a06104d46104ce36611a5e565b916123dd565b6080604051916001600160481b0381511683526001600160481b0360208201511660208401526001600160481b03604082015116604084015263ffffffff6060820151166060840152015115156080820152f35b503461023b57602036600319011261023b5760043567ffffffffffffffff81116102395761055a903690600401611a2d565b90610564826120e9565b91835b818110610588576040516020808252819061058490820187611c0b565b0390f35b610596610295828486611cb3565b650100000000008110156102e35790600191600901548060f01c6105bc575b5001610567565b60a01c69ffffffffffffffffffff166105d5828761215e565b525f6105b5565b503461023b578060031936011261023b57604080516105fb8282611b25565b60058152602081017f352e302e3000000000000000000000000000000000000000000000000000000081528251938492602084525180928160208601528585015e828201840152601f01601f19168101030190f35b503461023b57602036600319011261023b576106796040602092600435815260068452206137c9565b6001600160481b0360405191168152f35b503461023b578060031936011261023b5760206001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416604051908152f35b50604036600319011261023b5760043567ffffffffffffffff8111610239576106fd903690600401611a2d565b906024359067ffffffffffffffff821161023557366023830112156102355781600401359067ffffffffffffffff8211610922576024830192602436918460061b0101116109225761074d612faa565b8184036108fa57845b8481106107f8575061077660209160405195604087526040870191611ce4565b84810382860152828152019190845b8181106107b657857fea94abb1b74fb43f057870ba68e52c15f36c6ed98b98bda185955ef4842b97aa86860387a180f35b9091926040806001926001600160801b036107d0886123b7565b1681526001600160801b036107e7602089016123b7565b166020820152019401929101610785565b610803818684611cb3565b35865260046020526001600160801b036040872054166001600160801b0361083461082f848789612393565b6123a3565b1681151591826108f0575b826108e5575b50506108bd57806108596001928587612393565b610864828886611cb3565b358852600460205260408820907fffffffffffffffffffffffffffffffff000000000000000000000000000000006108b060206001600160801b036108a8856123a3565b1693016123a3565b60801b1617905501610756565b6004867f1a20b67e000000000000000000000000000000000000000000000000000000008152fd5b141590505f80610845565b811515925061083f565b6004857fff633a38000000000000000000000000000000000000000000000000000000008152fd5b8480fd5b503461023b5760c036600319011261023b576004356001600160a01b03811680910361023957610954611aa7565b604435916001600160a01b038316809303610235576064359161ffff831691828403610dc5576084359460ff8616808703610dc15760a4359461ffff861696878703610dbd577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00549860ff8a60401c16159967ffffffffffffffff811680159081610db5575b6001149081610dab575b159081610da2575b50610d7a5767ffffffffffffffff1981166001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00558a610d3b575b50610a31614555565b610a39614555565b610a42336125c2565b610a4a614555565b610a52612faa565b8215610cfa578415610ceb576103e88311610cdc5791606093917fd2578cc27cd56b02e72d064ed9d68d965ec91300be9f269da17f0686716110b895935b76ffffffffffffffffffffffffffffffffffffffffffffff1961ffff60a01b60ff60b01b6002549360b01b169360a01b1691161784171760025560405192835260208301526040820152a16040516301ffc9a760e01b81527fd9b67a26000000000000000000000000000000000000000000000000000000006004820152602081602481855afa908115610cd1578791610ca2575b5015610c7a57906001600160a01b03916001600160a01b0319875416178655166001600160a01b03196001541617600155610b5e611e8c565b610b66612faa565b60038116610c6b579078ffffffffffffffffffffffffffffffffffffffffffffffffff61ffff60c81b7b01000000000000000000000000000000000000000000000000000000937f7d17ca2c1939a5351692336344e18b51ee4c6038f1c4f45b9cb928daad54119f602060025495604051908152a160c81b1691161717600255610bed5780f35b68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b6004846317ea5f1160e21b8152fd5b6004867f34d28112000000000000000000000000000000000000000000000000000000008152fd5b610cc4915060203d602011610cca575b610cbc8183611b25565b810190611e74565b5f610b25565b503d610cb2565b6040513d89823e3d90fd5b60048b6324a5279560e21b8152fd5b60048b63d92e233d60e01b8152fd5b84610d2c5791606093917fd2578cc27cd56b02e72d064ed9d68d965ec91300be9f269da17f0686716110b89593610a90565b60048b63825a7cf160e01b8152fd5b68ffffffffffffffffff191668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00555f610a28565b60048c7ff92ee8a9000000000000000000000000000000000000000000000000000000008152fd5b9050155f6109ec565b303b1591506109e4565b8c91506109da565b8980fd5b8780fd5b8580fd5b503461023b57604036600319011261023b5760043567ffffffffffffffff811161023957610dfb903690600401611a2d565b6024359167ffffffffffffffff831161023557610e1f610332933690600401611ba9565b9290916121a9565b503461023b57602036600319011261023b576106796040602092600435815260058452206133f4565b503461023b57606036600319011261023b5760043567ffffffffffffffff811161023957610e82903690600401611a2d565b60243567ffffffffffffffff811161023557610ea2903690600401611ba9565b6044939193359067ffffffffffffffff8211610dc55761033294610ecd610ed5933690600401611bda565b9590946121a9565b612695565b503461023b578060031936011261023b57610ef3612faa565b806001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031981167f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461023b57606036600319011261023b57610f8d611a91565b6024359061ffff8216808303610235576044359260ff841692838503610dc557610fb5612faa565b8215611072576001600160a01b03811615611063576103e883116110545791606093917fd2578cc27cd56b02e72d064ed9d68d965ec91300be9f269da17f0686716110b895935b76ffffffffffffffffffffffffffffffffffffffffffffff1961ffff60a01b60ff60b01b6001600160a01b0360025494169760b01b169360a01b1691161784171760025560405192835260208301526040820152a180f35b6004866324a5279560e21b8152fd5b60048663d92e233d60e01b8152fd5b6001600160a01b0381166110ad5791606093917fd2578cc27cd56b02e72d064ed9d68d965ec91300be9f269da17f0686716110b89593610ffc565b60048663825a7cf160e01b8152fd5b503461023b578060031936011261023b576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036111275760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b8063703e46dd60e11b60049252fd5b503461023b57602036600319011261023b5760408181926020835161115a81611aed565b828152015260043581526004602052206001600160801b0382519161117e83611aed565b54602082821693848152019060801c8152835192835251166020820152f35b50604036600319011261023b576111b2611a91565b9060243567ffffffffffffffff8111610239576111d3903690600401611b63565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001680301490811561141a575b5061140b57611215612faa565b6001600160a01b03831690604051937f52d1902d000000000000000000000000000000000000000000000000000000008552602085600481865afa809585966113d7575b506112715760248484634c9c8ce360e01b8252600452fd5b9091847f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81036113ac5750813b1561139a57806001600160a01b03197f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416177f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8480a28151839015611367578083602061135b95519101845af43d1561135f573d9161133f83611b47565b9261134d6040519485611b25565b83523d85602085013e61538e565b5080f35b60609161538e565b505050346113725780f35b807fb398979f0000000000000000000000000000000000000000000000000000000060049252fd5b634c9c8ce360e01b8452600452602483fd5b7faa1d49a4000000000000000000000000000000000000000000000000000000008552600452602484fd5b9095506020813d602011611403575b816113f360209383611b25565b810103126109225751945f611259565b3d91506113e6565b60048263703e46dd60e11b8152fd5b90506001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541614155f611208565b5034611655576080366003190112611655575f905f61146c6120b4565b926114756120b4565b9362ffffff611482612128565b161561173b5760243590815f5260046020526114ad826001600160801b0360405f205416151561324e565b6004356002811015611655576114e462ffffff97821593845f14611735576001600160481b035b6114dc612128565b9087866138f0565b9716806116ea5750506114f68661328e565b9591979094835f146116bc57506064358111611694575b80611675575b5080611659575b506115bb579280949362ffffff61152f612128565b16906001600160a01b0383541691823b1561023557604051637921219560e11b81523360048201523060248201526044810192909252606482015260a060848201525f60a4820152908290829060c490829084905af180156115b05761159b575b50506103329261332b565b816115a591611b25565b61023557835f611590565b6040513d84823e3d90fd5b62ffffff6115c7612128565b16906001600160a01b035f541691823b1561165557604051637921219560e11b81523060048201523360248201526044810192909252606482015260a060848201525f60a482018190529091829060c490829084905af1801561164a57611634575b50610332929361332b565b61033293505f61164391611b25565b5f92611629565b6040513d5f823e3d90fd5b5f80fd5b61166f90336001600160a01b0360015416612f55565b5f61151a565b61168e906001600160a01b0360015416309033906132d1565b5f611513565b7fb83cca50000000000000000000000000000000000000000000000000000000005f5260045ffd5b91506064358110611694576116e4906116de876116d9888c611cc3565b611cc3565b9061211b565b9061150d565b6084925083611729604051937f3e2a8e740000000000000000000000000000000000000000000000000000000085523360048601526024850190613281565b60448301526064820152fd5b5f6114d4565b7f94640235000000000000000000000000000000000000000000000000000000005f5260045ffd5b346116555761177a61177436611a5e565b9161203a565b6040518091602082016020835281518091526020604084019201905f5b8181106117a5575050500390f35b919350916020606060019264ffffffffff604088516001600160a01b03815116845262ffffff8682015116868501520151166040820152019401910191849392611797565b346116555760206118036117fd36611a5e565b91611feb565b6040519015158152f35b60203660031901126116555760043561ffff81169081810361165557611831612faa565b6003811661189c577f7d17ca2c1939a5351692336344e18b51ee4c6038f1c4f45b9cb928daad54119f916020917fffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffff61ffff60c81b6002549260c81b16911617600255604051908152a1005b6317ea5f1160e21b5f5260045ffd5b34611655575f366003190112611655576118c3611e8c565b005b346116555760203660031901126116555760043564ffffffffff81168103611655576118ef611e56565b506501000000000081101561195a5760609061ffff6040519161191183611abd565b6009015469ffffffffffffffffffff6001600160a01b0382169384815260406020820191838560a01c168352019260f01c83526040519485525116602084015251166040820152f35b634e487b7160e01b5f52603260045260245ffd5b346116555760203660031901126116555760043567ffffffffffffffff8111611655576119a26118c3913690600401611a2d565b90611d21565b3461165557602036600319011261165557600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361165557817f4e2312e00000000000000000000000000000000000000000000000000000000060209314908115611a1c575b5015158152f35b6301ffc9a760e01b91501483611a15565b9181601f840112156116555782359167ffffffffffffffff8311611655576020808501948460051b01011161165557565b60609060031901126116555760043560028110156116555790602435906044356001600160481b03811681036116555790565b600435906001600160a01b038216820361165557565b602435906001600160a01b038216820361165557565b6060810190811067ffffffffffffffff821117611ad957604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff821117611ad957604052565b60a0810190811067ffffffffffffffff821117611ad957604052565b90601f8019910116810190811067ffffffffffffffff821117611ad957604052565b67ffffffffffffffff8111611ad957601f01601f191660200190565b81601f8201121561165557803590611b7a82611b47565b92611b886040519485611b25565b8284526020838301011161165557815f926020809301838601378301015290565b9181601f840112156116555782359167ffffffffffffffff8311611655576020808501946060850201011161165557565b9181601f840112156116555782359167ffffffffffffffff8311611655576020808501948460071b01011161165557565b90602080835192838152019201905f5b818110611c285750505090565b8251845260209384019390920191600101611c1b565b67ffffffffffffffff8111611ad95760051b60200190565b9080601f83011215611655578135611c6d81611c3e565b92611c7b6040519485611b25565b81845260208085019260051b82010192831161165557602001905b828210611ca35750505090565b8135815260209182019101611c96565b919081101561195a5760051b0190565b91908201809211611cd057565b634e487b7160e01b5f52601160045260245ffd5b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116116555760209260051b809284830137010190565b60c88211611e47575f915f5b818110611daa57508215611d9b5782611d737f730ad7566a8a34d6ceb6a935a03fce683d09bd3d47fc52e557fa87069cea2e9a94336001600160a01b0360015416612f55565b611d90604051938493338552606060208601526060850191611ce4565b9060408301520390a1565b6312d37ee560e31b5f5260045ffd5b9264ffffffffff611dbc858486611cb3565b35166501000000000081101561195a57600901805469ffffffffffffffffffff8160a01c16908115611d9b576001600160a01b0333911603611e1f576001928269ffffffffffffffffffff60a01b19611e189454169055611cc3565b9301611d2d565b7fb331e421000000000000000000000000000000000000000000000000000000005f5260045ffd5b637c6b720960e11b5f5260045ffd5b60405190611e6382611abd565b5f6040838281528260208201520152565b90816020910312611655575180151581036116555790565b602460206001600160a01b035f5416604051928380926301ffc9a760e01b825263152a902d60e11b60048301525afa90811561164a575f91611fcc575b5015611fac57604460406001600160a01b035f541681519283809263152a902d60e11b82526001600483015261271060248301525afa90811561164a575f905f92611f5b575b506001600160a01b03166001600160a01b0319600354161760035561ffff60b81b1978ffff00000000000000000000000000000000000000000000006002549260b81b16911617600255565b9150506040813d604011611fa4575b81611f7760409383611b25565b81010312611655578051906001600160a01b03821682036116555760200151906001600160a01b03611f0f565b3d9150611f6a565b6001600160a01b03196003541660035561ffff60b81b1960025416600255565b611fe5915060203d602011610cca57610cbc8183611b25565b5f611ec9565b9190916002811015612026576120125761200f915f52600660205260405f20613009565b90565b61200f915f52600560205260405f20613009565b634e487b7160e01b5f52602160045260245ffd5b91909160028110156120265761207f578161200f925f52600860205260405f206001600160481b0383165f5260205260405f20905f52600660205260405f209061306e565b8161200f925f52600760205260405f206001600160481b0383165f5260205260405f20905f52600560205260405f209061306e565b6040516101f49190613ea06120c98183611b25565b83825267ffffffffffffffff829411611ad957601f190190369060200137565b906120f382611c3e565b6121006040519182611b25565b8281528092612111601f1991611c3e565b0190602036910137565b91908203918211611cd057565b60443562ffffff811681036116555790565b3562ffffff811681036116555790565b356001600160481b03811681036116555790565b805182101561195a5760209160051b010190565b5f198114611cd05760010190565b908160021b9180830460041490151715611cd057565b81810292918115918404141715611cd057565b92909281840361236b575f929192905f946121c3816120e9565b936121cd826120e9565b955f915b83831061225c57505050907f518405fd4d1da4785cc552188e579f0508054f396deba0bec66f5caca9070bb49161221b604051928392338452604060208501526040840191611ce4565b0390a180612240575b508261222f57505050565b8261223e93825282523361377f565b565b61225690336001600160a01b0360015416612f55565b5f612224565b9091948286101561195a5760608602820180359060028210156116555761228a60406020830135920161214a565b916122f857916122e86122ee9262ffffff6122e26001966122ac8d8c8e611cb3565b3590805f52600860205260405f20946001600160481b03811695865f5260205260405f20915f52600660205260405f2092613464565b16612196565b90611cc3565b955b0191906121d1565b99879a62ffffff612348612365946123146001979c8b8d611cb3565b3590845f52600760205260405f206001600160481b0382165f5260205260405f2090855f52600560205260405f2092613464565b1690612354838c61215e565b5261235f828c61215e565b52612172565b986122f0565b7fff633a38000000000000000000000000000000000000000000000000000000005f5260045ffd5b919081101561195a5760061b0190565b356001600160801b03811681036116555790565b35906001600160801b038216820361165557565b3564ffffffffff811681036116555790565b9190916040516123ec81611b09565b5f81525f60208201525f60408201525f60608201525f60808201525060028110156120265761248357612429915f52600660205260405f20613833565b6040519061243682611b09565b546001600160481b03811682526001600160481b038160481c1660208301526001600160481b038160901c16604083015263ffffffff8160d81c16606083015260f81c1515608082015290565b612429915f52600560205260405f20613833565b91909160c88311611e47578215611d9b576124b1836120e9565b926124bb816120e9565b915f5b835181101561254d5764ffffffffff6124d8828585611cb3565b35166501000000000081101561195a57600901908154918260f01c6124fd838861215e565b5269ffffffffffffffffffff8360a01c16928315611d9b576001600160a01b0333911603611e1f57600192612532838a61215e565b5269ffffffffffffffffffff60a01b198154169055016124be565b50917fde3c2f9295fefa02a7867bf4445e614a43531448e07a5753940c0696b46e263293946125af6125bd9261258483823361377f565b6125a1604051968796338852608060208901526080880191611ce4565b908582036040870152611c0b565b908382036060850152611c0b565b0390a1565b6001600160a01b03168015612651576001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054826001600160a01b03198216177f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b7f1e4fbdf7000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b9062ffffff8091169116039062ffffff8211611cd057565b610220526101608190525f61014081905261012081905260e08190529190829081906126c0906120e9565b6080526126cf610160516120e9565b610180525f61020052610160516126e5906120e9565b610100526126f5610160516120e9565b6101a0526127016120b4565b9161270a6120b4565b6101e05260025460d81c945f5b61016051811015612de3575f935f9462ffffff61273e60608560071b61022051010161213a565b161561173b576001600160481b0361276060408560071b61022051010161214a565b1615612dbb5760208360071b610220510101355f5260046020526001600160801b0360405f2054169586156127a260208660071b61022051010135821561324e565b6001600160481b036127be60408760071b61022051010161214a565b1690612da757876001600160801b03910616612d7b5760028460071b61022051013510159687611655576128326127ff60408760071b61022051010161214a565b8a6101e0519161281960608a60071b61022051010161213a565b6102205190919060078b901b01602081013590356138f0565b6101c0529260208660071b610220510101355f52600460205260405f205460801c62ffffff851610155f14612cda575082976116555761287c60408660071b61022051010161214a565b928560071b610220510135155f14612cd45760208660071b610220510101355b604051906128a982611abd565b3382528d6501000000000060208401915f835261ffff6040860194168452101561195a5769ffffffffffffffffffff8f916001600160a01b0361292a936009019551166001600160a01b03198654161785555116839069ffffffffffffffffffff60a01b1969ffffffffffffffffffff60a01b83549260a01b169116179055565b517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffff00000000000000000000000000000000000000000000000000000000000083549260f01b1691161790555f938c8760071b610220510135155f14612c51575061022051600788901b016020908101355f908152600882526040808220600690935290209093600f0b926f7fffffffffffffffffffffffffffffff198414611cd0576001600160481b038f93612a1b9062ffffff947ff4ed6e99fd267f4e8f8273058850e0ded9794213643d112a2a58802f8b461e0c9860c0985f03928787169264ffffffffff8a1692615077565b64ffffffffff60405195338752612a3f8d602089019060071b610220510135613281565b16604086015260208b60071b6102205101013560608601521660808401521660a0820152a15b62ffffff8716612c34575b5f916101c051612bd6575b611655578360071b610220510135155f14612b4857505090612aca6001926122e8612ac162ffffff89166001600160481b036122e260408860071b61022051010161214a565b6101c051611cc3565b946101c051612adc575b505b01612717565b62ffffff612b219160208460071b61022051010135612b01610200516101005161215e565b521662ffffff612b1b60608560071b61022051010161213a565b1661211b565b612b31610200516101a05161215e565b52612b3e61020051612172565b610200525f612ad4565b83929650612b6f90612b6a606062ffffff94979660071b61022051010161213a565b61267d565b1680612b9a575b50612b92612b8a600193946101c05161211b565b60e051611cc3565b60e052612ad6565b612b8a612bce600194612b929360208660071b61022051010135612bc08360805161215e565b5261235f826101805161215e565b935050612b76565b9150612c2e612bf7612bea6101c05161328e565b60c05260a0528098611cc3565b96612c0760a05161014051611cc3565b61014052612c1a60c05161012051611cc3565b610120526116d960c0519160a05190611cc3565b91612a7b565b9864ffffffffff1664ffffffffff8114611cd05760010198612a70565b9060c0926001600160481b03612ccf62ffffff937ff4ed6e99fd267f4e8f8273058850e0ded9794213643d112a2a58802f8b461e0c9760208d60071b610220510101355f5260076020528c602060405f209160071b610220510101355f52600560205260405f2091600f0b928787169264ffffffffff8a1692615077565b612a1b565b5f61289c565b9792905062ffffff8116612cef575b50612a65565b915050807f12f572861d108ac2c546b0b80770afe6fe8b3921acb39b6a2fe9f91c4cd6d14d60a05f9362ffffff612d3060408960071b61022051010161214a565b916001600160481b0360405193338552612d56602086018c60071b610220510135613281565b60208b60071b610220510101356040860152166060840152166080820152a15f612ce9565b867f766de9a4000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b634e487b7160e01b5f52601260045260245ffd5b7fe528e11e000000000000000000000000000000000000000000000000000000005f5260045ffd5b5092509293600254908160d81c64ffffffffff821603612f06575b505080612ee7575b5060e051612eca575b80612e5a575b5061223e9061020051612e32575b6101205190610140519061332b565b610200516101005152610200516101a05152612e556101a051610100513361377f565b612e23565b806080515261018051526001600160a01b035f541690813b15611655575f6040518093631759616b60e11b8252818381612e9f61018051608051303360048601613740565b03925af191821561164a5761223e92612eba575b5090612e15565b5f612ec491611b25565b5f612eb3565b612ee260e051336001600160a01b0360015416612f55565b612e0f565b612f00906001600160a01b0360015416309033906132d1565b5f612e06565b7fffffffffff0000000000000000000000000000000000000000000000000000007affffffffffffffffffffffffffffffffffffffffffffffffffffff9160d81b169116176002555f80612dfe565b61223e926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252612fa5606483611b25565b613883565b6001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054163303612fdd57565b7f118cdaa7000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b906001600160481b0316801515918261302157505090565b80546001600160481b03168214925090821561303c57505090565b600192505f52016020526001600160481b0360405f205416151590565b805482101561195a575f5260205f2001905f90565b919061307a8282613009565b156132465763ffffffff9161308e91613833565b5460d81c16915f916130a08482613059565b90545f9160031b1c5b60048210613208575b50506130d0836130cb6130c687855461211b565b612180565b61211b565b936130da85611c3e565b946130e86040519687611b25565b8086526130f7601f1991611c3e565b015f5b8181106131f1575050845f93855b613113878951611cc3565b8110156131e75761313061312a858360021c611cc3565b86613059565b90549060031b1c600382169060c08360061b169180830460401490151715611cd05764ffffffffff81831c16908161316e575b505050600101613108565b9091929760288401809411611cd0576501000000000083101561195a57613113938362ffffff6131df946001600160a01b03600197600901541693604051946131b686611abd565b85521c16602083015260408201526131ce828d61215e565b526131d9818c61215e565b50612172565b96915f613163565b5094509491505052565b6020906131fc611e56565b82828a010152016130fa565b90938460061b85810460401486151715611cd05782901c67ffffffffffffffff1661324057613238600191612172565b9401906130a9565b936130b2565b505050606090565b156132565750565b7f03399b24000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9060028210156120265752565b90600254906127106132cd816132ab61ffff8660b81c1687612196565b049460ff836132c161ffff8860a01c1684612196565b049560b01c1690612196565b0490565b9091926001600160a01b0361223e9481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252612fa5608483611b25565b806133cc575b50806133a4575b50806133415750565b6001600160a01b036001541690813b15611655575f916024839260405194859384927f42966c6800000000000000000000000000000000000000000000000000000000845260048401525af1801561164a5761339a5750565b5f61223e91611b25565b6133c6906001600160a01b03600154166001600160a01b036002541690612f55565b5f613338565b6133ee906001600160a01b03600154166001600160a01b036003541690612f55565b5f613331565b6001600160481b038154169081613409575090565b905b60018201906001600160481b0381165f52816020526001600160481b0360405f205460481c161561345e576001600160481b03165f5260205260016001600160481b0360405f205460481c16905061340b565b92915050565b9392916134718284613009565b156137075763ffffffff6134858385613833565b5460d81c1690805461349987828585614447565b90975f1989146136ce57506134ae8884613059565b90549060031b1c978160061b98828a0460401483151715611cd05760288a0190818b11611cd05762ffffff911c16986134e78286613059565b90549060031b1c64ffffffffff81831c166501000000000081101561195a57600901546001600160a01b03163303611e1f575f198501858111611cd057831491826136b7575b505015613553575050506135408161451a565b541461354a575050565b61223e916145f4565b909294506116d99195506135679350612180565b918260021c9261357a6003821692612180565b5f19810191908211611cd057905b8082106135e3575b5050806135a2575061223e915061451a565b826135cb916135c46135b761223e9686613059565b90549060031b1c916145d2565b1692613059565b90919082549060031b91821b915f19901b1916179055565b915092506001830190818411611cd0578160021c91829460038216613609819587613059565b90549060031b1c8260021c91600384169160c0613626858b613059565b90549060031b1c9660061b169180830460401490151715611cd05767ffffffffffffffff911c169384156136a75761365d826145d2565b169360c08460061b169180830460401490151715611cd0576001946136856136a0948a613059565b9290931b179082549060031b91821b915f19901b1916179055565b0190613588565b5096509350505050915f80613590565b67ffffffffffffffff9192501b1916155f8061352d565b856001600160481b03917fdca140df000000000000000000000000000000000000000000000000000000005f526004521660245260445ffd5b6001600160481b0382867ff965eb63000000000000000000000000000000000000000000000000000000005f526004521660245260445ffd5b926125af906001600160a01b0361376f948160209895168752168686015260a0604086015260a0850190611c0b565b9060808183039101525f81520190565b90916001600160a01b035f5416803b15611655576137b8935f809460405196879586948593631759616b60e11b85523060048601613740565b03925af1801561164a5761339a5750565b6001600160481b0381541690816137de575090565b905b60018201906001600160481b0381165f52816020526001600160481b0360405f205460901c161561345e576001600160481b03165f5260205260016001600160481b0360405f205460901c1690506137e0565b61383d8282613009565b1561385b576001600160481b03600192165f520160205260405f2090565b7f2a8020fe000000000000000000000000000000000000000000000000000000005f5260045ffd5b905f602091828151910182855af11561164a575f513d6138e757506001600160a01b0381163b155b6138b25750565b6001600160a01b03907f5274afe7000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b600114156138ab565b92939094916103a052610400526103c052600281101561202657613edd575f610460525f610380525f61038052610460526101f461040051526101f46103c051525f905b62ffffff61046051166139bc575b5080613955575b50610380516104605191565b8061040051526103c051527f29c45e48d0fdd73dc977da9c0ed6c48240b873a5c373a3df49364e879b51203360405133815260606020820152806139b36139a26060830161040051611c0b565b82810360408401526103c051611c0b565b0390a15f613949565b91905f61036052825f5260056020526139d760405f206133f4565b610360526001600160481b036103605116158015613ebc575b613eb5575f91835f52600760205260405f206001600160481b0361036051165f5260205260405f2092845f526005602052613a316103605160405f20613833565b935f925f935f610280525f610280525f9263ffffffff885460d81c16935b8154851080613ea4575b15613e9557508390613a6b8582613059565b905460039190911b1c610280525f610320819052610420819052975b6004891080613e84575b15613e7957888060061b0460401489151715611cd0576102805160068a901b1c64ffffffffff16908115613c805760288a60061b018a60061b11611cd05762ffffff6102805160288c60061b011c16610340526103405162ffffff610460511610155f14613c3357613b09610340516104605161267d565b6104605260038a146104205261032051613b2290612172565b61032052610340515b613b416001600160481b03610360511682612196565b92613b4f8461038051611cc3565b610380526501000000000081101561195a57613bd6613bf194613bab69ffffffffffffffffffff613b9485600901936116de6116d9613b8d8361328e565b9291611cc3565b1669ffffffffffffffffffff835460a01c166145ac565b69ffffffffffffffffffff60a01b1969ffffffffffffffffffff60a01b83549260a01b169116179055565b613be3836104005161215e565b5261235f826103c05161215e565b976101f4891015613c0b57613c0590612172565b97613a87565b7fc8690679000000000000000000000000000000000000000000000000000000005f5260045ffd5b935062ffffff613c49610460516103405161267d565b1660288a60061b011b62ffffff60288b60061b011b196102805116176102805262ffffff6104605116935f61046052600194613b2b565b610280519099989150600689901b1c15613ca657613ca0613c0591612172565b97612172565b9095919496505b6104205115613cd15750613cc090612172565b93613ccb5f96612172565b93613a4f565b95613ce483976103209793975190611cc3565b96613cf257613ccb90612172565b5092939094919795965b81613dbd575b5050838415613db4575b613d1a575b50505050613934565b80613d80575b50613d5191613d37916102805115613d6357613059565b6102805182545f1960039390931b92831b1916911b179055565b613d5e575f808080613d11565b613942565b855f526005602052613d7b6103605160405f206145f4565b613059565b5f5b818110613d8f5750613d20565b80613da060019297949596976145d2565b610280511661028052019493929194613d82565b50801515613d0c565b63ffffffff905460d81c16865f52600560205260405f20613de16103605182613009565b1561385b576001906001600160481b0361036051165f520160205260405f209063ffffffff831663ffffffff835460d81c16019163ffffffff8311611cd057613e4f92613e48919063ffffffff60d81b1963ffffffff60d81b83549260d81b169116179055565b845461211b565b14613e5c575b5f80613d02565b845f526005602052613e746103605160405f206145f4565b613e55565b975094909395613cad565b5062ffffff61046051161515613a91565b94919592989697909350613cfc565b5062ffffff61046051161515613a59565b9091613942565b506001600160481b036103a051166001600160481b036103605116116139f0565b61024052610400516101f4908190526103c051525f610440819052905b62ffffff6102405116613f75575b5061044051613f19575b6102405191565b610440516104005152610440516103c051527f29c45e48d0fdd73dc977da9c0ed6c48240b873a5c373a3df49364e879b5120336040513381526060602082015280613f6d6139a26060830161040051611c0b565b0390a1613f12565b915f6102e052825f526006602052613f8f60405f206137c9565b6102e0526001600160481b036102e05116158015614411575b61440b575f835f52600860205260405f206001600160481b036102e051165f5260205260405f20845f526006602052613fe76102e05160405f20613833565b5f6102608190526103008190528154919460d89290921c63ffffffff1692815b81548510806143fa575b156143ed575083906140238582613059565b905460039190911b1c610300525f6102a08190526103e08190525b60048110806143dc575b156143d357808060061b0460401481151715611cd05761030051600682901b1c64ffffffffff169889156141d45760288260061b018260061b11611cd05762ffffff6103005160288460061b011c166102c0526102c05162ffffff610240511610155f14614185576140c06102c0516102405161267d565b61024052600382146103e0526102a0516140d990612172565b6102a0526140fc6102c051915b6122e86001600160481b036102e0511684612196565b996501000000000081101561195a5761413881600901613bab69ffffffffffffffffffff851669ffffffffffffffffffff835460a01c166145ac565b614148610440516104005161215e565b52614159610440516103c05161215e565b5261416661044051612172565b610440526101f4610440511015613c0b5761418090612172565b61403e565b935062ffffff61419b610240516102c05161267d565b1660288260061b011b62ffffff60288360061b011b196103005116176103005262ffffff61024051165f610240526140fc6001956140e6565b61030051909950600682901b1c156141ff57614180906141f661026051612172565b61026052612172565b509093945b6103e0511561422a5761421961422491612172565b955f61026052612172565b93614007565b948261423c6102a05161026051611cc3565b6102605261424d5761422490612172565b509196949390935b81614317575b505082831561430b575b614272575b505050613efa565b610260516142d4575b6142ab916142919161030051156142bc57613059565b6103005182545f1960039390931b92831b1916911b179055565b6142b7575f808061426a565b613f08565b855f526006602052613d7b6102e05160405f206145f4565b5f5b6102605181106142e6575061427b565b806142f760019296939495966145d2565b6103005116610300520193929190936142d6565b50610260511515614265565b63ffffffff905460d81c16855f52600660205260405f2061433b6102e05182613009565b1561385b576001906001600160481b036102e051165f520160205260405f209063ffffffff831663ffffffff835460d81c16019163ffffffff8311611cd0576143a9926143a2919063ffffffff60d81b1963ffffffff60d81b83549260d81b169116179055565b835461211b565b146143b6575b5f8061425b565b835f5260066020526143ce6102e05160405f206145f4565b6143af565b50909394614204565b5062ffffff61024051161515614048565b9350919694939093614255565b5062ffffff61024051161515614011565b91613f08565b506001600160481b036103a051166001600160481b036102e0511610613fa8565b60061b90613fc060c0831692168203611cd057565b9291905b81811061445d57505050505f19908190565b61447361446a828461211b565b60011c82611cc3565b9061447e8286613059565b90549060031b1c5f905f905b600482106144b7575b50506020036144b0575060018101809111611cd057905b9061444b565b91506144aa565b9097969492918060039795971b81810460081482151715611cd05782901c64ffffffffff168581036144ee57505050505050509190565b94809795999394969899105f146145145760088101809111611cd057916001019061448a565b91614493565b80548015614541575f1901906145308282613059565b8154905f199060031b1b1916905555565b634e487b7160e01b5f52603160045260245ffd5b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561458457565b7fd7e6bcf8000000000000000000000000000000000000000000000000000000005f5260045ffd5b9069ffffffffffffffffffff8091169116019069ffffffffffffffffffff8211611cd057565b8060061b9080820460401490151715611cd05767ffffffffffffffff901b1990565b6001600160481b03821690811561504f5761460f8382613009565b1561385b576001810192825f52836020526001600160481b0360405f205460481c16158015615030575b15614fc65780925b6001600160481b0384165f52846020526001600160481b0360405f205460481c1615155f14614f9f576001600160481b0384165f52846020526001600160481b0360405f205460481c16915b6001600160481b038581165f908152602088905260408082205486841683529120805468ffffffffffffffffff1916919092169081179091558015614f7e576001600160481b03908181165f52876020528160405f205460481c16828816145f14614f4057165f528560205261472b8360405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b6001600160481b0385165f528560205260405f205460f81c1591806001600160481b03871603614d64575b5050614781575b50506001600160481b03165f5260205260405f206001600160481b03198154169055565b939091935b6001600160481b03835416906001600160481b0381169182141580614d4e575b15614d1f5750805f52836020526001600160481b0360405f205416906001600160481b0382165f52846020526001600160481b0360405f205460481c16145f14614a8e576001600160481b0381165f52836020526001600160481b0360405f205460901c166001600160481b0381165f528460205260405f205460f81c614a17575b6001600160481b038181165f908152602087905260408082205460481c9092168152205460f81c15806149e9575b15614889576001600160481b03165f528360205260405f20600160f81b6001600160f81b03825416179055935b93614786565b90614962916001600160481b0381165f52856020526001600160481b038060405f205460901c16165f528560205260405f205460f81c15614973575b6001600160481b03908183165f528660205261491160405f205460f81c8383165f528860205260405f20906001600160f81b036001600160f81b0319835492151560f81b169116179055565b8183165f528660205260405f206001600160f81b038154169055165f52846020526001600160481b038060405f205460901c16165f528460205260405f206001600160f81b03815416905583615b1f565b6001600160481b0382541693614883565b6001600160481b038082165f81815260208990526040808220805460481c9094168252812080546001600160f81b03908116909155919052815416600160f81b1790556149c0908561596f565b6001600160481b0381165f52846020526001600160481b038060405f205460901c1690506148c5565b506001600160481b038181165f908152602087905260408082205460901c9092168152205460f81c15614856565b6001600160481b03165f528360205260405f206001600160f81b0381541690556001600160481b0381165f528360205260405f20600160f81b6001600160f81b03825416179055614a688184615b1f565b6001600160481b0381165f52836020526001600160481b0360405f205460901c16614828565b6001600160481b0381165f52836020526001600160481b0360405f205460481c166001600160481b0381165f528460205260405f205460f81c614ca8575b6001600160481b038181165f908152602087905260408082205460901c9092168152205460f81c1580614c7a575b15614b2b576001600160481b03165f528360205260405f20600160f81b6001600160f81b0382541617905593614883565b90614962916001600160481b0381165f52856020526001600160481b038060405f205460481c16165f528560205260405f205460f81c15614c04575b6001600160481b03908183165f5286602052614bb360405f205460f81c8383165f528860205260405f20906001600160f81b036001600160f81b0319835492151560f81b169116179055565b8183165f528660205260405f206001600160f81b038154169055165f52846020526001600160481b038060405f205460481c16165f528460205260405f206001600160f81b0381541690558361596f565b6001600160481b038082165f81815260208990526040808220805460901c9094168252812080546001600160f81b03908116909155919052815416600160f81b179055614c519085615b1f565b6001600160481b0381165f52846020526001600160481b038060405f205460481c169050614b67565b506001600160481b038181165f908152602087905260408082205460481c9092168152205460f81c15614afa565b6001600160481b03165f528360205260405f206001600160f81b0381541690556001600160481b0381165f528360205260405f20600160f81b6001600160f81b03825416179055614cf9818461596f565b6001600160481b0381165f52836020526001600160481b0360405f205460481c16614acc565b6001600160481b039350839150949194165f528260205260405f206001600160f81b038154169055905f61475d565b50815f528460205260405f205460f81c156147a6565b94614e9d919295805f52876020526001600160481b0360405f2054166001600160481b0383165f528860205260405f206001600160481b0382166001600160481b031982541617905580155f14614ea55750855468ffffffffffffffffff19166001600160481b0383161786555b5f9081526020889052604080822080546001600160481b03948516808552838520805468ffffffffffffffffff60481b191668ffffffffffffffffff60481b9093169290921780835560481c86168552838520805468ffffffffffffffffff1990811683179091558354835468ffffffffffffffffff60901b191668ffffffffffffffffff60901b9091161780845560901c90961685529284208054909516831790945554915281546001600160f81b031660f891821c151590911b6001600160f81b031916179055565b925f80614756565b6001600160481b03908181165f52896020528160405f205460481c1683145f14614f0757165f5287602052614f028260405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b614dd2565b165f5287602052614f028260405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b165f5285602052614f798360405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b61472b565b50835468ffffffffffffffffff19166001600160481b03841617845561472b565b6001600160481b0384165f52846020526001600160481b0360405f205460901c169161468d565b825f52836020526001600160481b0360405f205460901c165b6001600160481b0381165f52846020526001600160481b0360405f205460481c161561502a576001600160481b03165f52836020526001600160481b0360405f205460481c16614fdf565b92614641565b50825f52836020526001600160481b0360405f205460901c1615614639565b7fd77534c7000000000000000000000000000000000000000000000000000000005f5260045ffd5b9180959493946150878284613009565b6151af57506150959161541a565b6001600160481b0384165f5260205260405f2091600183548061510b575b506150bf575b50505090565b82549268010000000000000000841015611ad957836150e691600161510396018155613059565b91909260281b179082549060031b91821b915f19901b1916179055565b5f80806150b9565b5f198101908111611cd0576151209085613059565b90549060031b1c5f5b60048110615138575b506150b3565b8060061b81810460401482151715611cd05782811c1561515b5750600101615129565b919250506028810190818111611cd05785545f19810191908211611cd0576151a7938561518988948a613059565b9490951b921b17179082549060031b91821b915f19901b1916179055565b5f5f80615132565b906151bf63ffffffff9184613833565b5460d81c166001600160481b03871691825f528460205260405f20835f528560205260405f20545f198101908111611cd0576151fa91613059565b905460039491851b1c60ff61520e86614432565b161c1515905f528560205261522a6130c68460405f205461211b565b61ffff60025460c81c1611159081615386575b5061524c575b50505050615095565b965b6001600160481b0388600f0b9116600f0b016f7fffffffffffffffffffffffffffffff1981126f7fffffffffffffffffffffffffffffff821317611cd0576001600160801b0381166001600160481b03811161535657506001600160481b0316966152b98885613009565b6152d357505050846152ca9161541a565b5f808080615243565b875f989293949852846020526152f06130c68460405f205461211b565b61ffff60025460c81c16118015615319575b61530f579692919061524e565b50955050506152ca565b505f82815260208690526040902080545f198101908111611cd05761533d91613059565b905490851b1c60ff61534e86614432565b161c15615302565b7f6dfcc650000000000000000000000000000000000000000000000000000000005f52604860045260245260445ffd5b90505f61523d565b906153cb57508051156153a357805190602001fd5b7fd6bda275000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580615411575b6153dc575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156153d4565b906001600160481b03811692831561504f5782546001600160481b03165f5b6001600160481b0382169081156154a357508181871015615482576001600160481b039150165f52600184016020526001600160481b0360405f205460481c16915b9190615439565b505f52600184016020526001600160481b0360405f205460901c169161547b565b95915050929190926001830194815f52856020526155ca63ffffffff60405f205460d81c1691836155a963ffffffff6001600160481b03604051946154e786611b09565b16958685526155896001600160481b038d61555f8260208a015f815260408b01935f855260608c0197885260808c019a60018c525f52602052818060405f209c51161682198c5416178b555116899068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b51875468ffffffffffffffffff60901b1916911660901b68ffffffffffffffffff60901b16178655565b51845463ffffffff60d81b1916911660d81b63ffffffff60d81b16178355565b5181546001600160f81b031690151560f81b6001600160f81b031916179055565b806158f15750825468ffffffffffffffffff19161782555b905b6001600160481b038154166001600160481b03831690811415806158cb575b156158a1575f81815260208690526040808220546001600160481b039081168084528284205482168452919092205490929160489190911c16820361577857506001600160481b038181165f9081526020879052604080822054831682528082205460901c9092168082529190205490939060f81c156156d757506001600160481b039081165f8181526020879052604080822080546001600160f81b03908116825596851683528183208054881690558054851683529082208054909616600160f81b17909555529154909116906155e4565b92506001600160481b0381165f52846020526001600160481b0360405f205460901c166001600160481b03841614615766575b506001600160481b038281165f9081526020869052604080822054831680835281832080546001600160f81b03818116835590861685529284208054909316600160f81b179092559091525461576191168261596f565b6155e4565b91506157728282615b1f565b5f61570a565b6001600160481b038281165f9081526020889052604080822054831682528082205460481c909216808252919020549094919060f81c1561580e5750506001600160481b039081165f8181526020879052604080822080546001600160f81b03908116825596851683528183208054881690558054851683529082208054909616600160f81b17909555529154909116906155e4565b9093506001600160481b0382165f52856020526001600160481b0360405f205460481c161461588f575b506001600160481b038281165f9081526020869052604080822054831680835281832080546001600160f81b03818116835590861685529284208054909316600160f81b1790925590915254615761911682615b1f565b915061589b828261596f565b5f615838565b50546001600160481b03165f90815260209390935250604090912080546001600160f81b03169055565b505f81815260208690526040808220546001600160481b0316825290205460f81c615603565b8091105f14615937575f52836020526159328160405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b6155e2565b5f52836020526159328160405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b6001600160481b038083165f81815260018401602081905260408083208054604881811c8816808752938620549690955268ffffffffffffffffff60481b1981169486901c68ffffffffffffffffff60481b169490941790559590949092909184169060901c841680615b02575b508386165f528460205260405f20848216851982541617905580155f14615a6b575082851683198254161790555b8184165f5282602052615a468160405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b165f526020526001600160481b0360405f2091166001600160481b0319825416179055565b8391508181165f52846020528160405f205460901c16828416145f14615ac957165f5282602052615ac48460405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b615a0b565b165f5282602052615ac48460405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b84165f528460205260405f2084841685198254161790555f6159dd565b6001600160481b038083165f81815260018401602081905260408083208054609081901c8716808652928520549590945268ffffffffffffffffff60901b198416604886811b68ffffffffffffffffff60901b16919091179091559096919591939192851691901c841680615c8f575b508386165f528460205260405f20848216851982541617905580155f14615bf8575082851683198254161790555b8184165f5282602052615a468160405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b8391508181165f52846020528160405f205460481c16828416145f14615c5657165f5282602052615c518460405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b615bbd565b165f5282602052615c518460405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b84165f528460205260405f2084841685198254161790555f615b8f56fea2646970667358221220913b011d4ec7a1df242985a01d6d69b51907041aa923c2bace7af0ca3b38ab9b64736f6c634300081c0033f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00
Deployed Bytecode
0x610480806040526004361015610013575f80fd5b5f905f3560e01c90816301ffc9a7146119a8575080632d08265a1461196e5780633546326c146118c557806335569842146118ab5780633fd3a6a51461180d5780634628b1fd146117ea5780634dca9347146117635780634f0eb7311461144f5780634f1ef2861461119d57806352aa5e8f1461113657806352d1902d146110bc5780636faf6d1914610f73578063715018a614610eda5780637783743714610e50578063793052b814610e2757806379800e8714610dc957806384f160c01461092657806385dd961f146106d05780638da5cb5b1461068a5780638f28864414610650578063ad3cb1cc146105dc578063b110c27c14610528578063b3f4c59f146104ba578063bc197c8114610409578063c385bddf146103ce578063f23a6e611461035f578063f2fde38b14610335578063f3a0934e146102f7578063f9e13eb11461023e5763fb2ac52e14610169575f80fd5b3461023b57604036600319011261023b5760043567ffffffffffffffff81116102395761019a903690600401611a2d565b9060243567ffffffffffffffff8111610235576101bb903690600401611a2d565b91909280158015809161022c575b1561021d5760c86101da8584611cc3565b1161020e576101fe575b5050806101ef578280f35b6101f891612497565b5f808280f35b61020791611d21565b5f806101e4565b600486637c6b720960e11b8152fd5b6004866312d37ee560e31b8152fd5b508315156101c9565b8380fd5b505b80fd5b503461023b57602036600319011261023b5760043567ffffffffffffffff811161023957610270903690600401611a2d565b908291835b81811061028757602084604051908152f35b61029a610295828486611cb3565b6123cb565b650100000000008110156102e357600901548060f01c156102bf575b50600101610275565b6001919469ffffffffffffffffffff6102dc9260a01c1690611cc3565b93906102b6565b602486634e487b7160e01b81526032600452fd5b503461023b57602036600319011261023b5760043567ffffffffffffffff81116102395761032c610332913690600401611bda565b90612695565b80f35b503461023b57602036600319011261023b57610332610352611a91565b61035a612faa565b6125c2565b503461023b5760a036600319011261023b57610379611a91565b50610382611aa7565b5060843567ffffffffffffffff8111610239576103a3903690600401611b63565b5060206040517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b503461023b57602036600319011261023b5760043567ffffffffffffffff811161023957610403610332913690600401611a2d565b90612497565b503461023b5760a036600319011261023b57610423611a91565b5061042c611aa7565b5060443567ffffffffffffffff81116102395761044d903690600401611c56565b5060643567ffffffffffffffff81116102395761046e903690600401611c56565b5060843567ffffffffffffffff81116102395761048f903690600401611b63565b5060206040517fbc197c81000000000000000000000000000000000000000000000000000000008152f35b503461023b5760a06104d46104ce36611a5e565b916123dd565b6080604051916001600160481b0381511683526001600160481b0360208201511660208401526001600160481b03604082015116604084015263ffffffff6060820151166060840152015115156080820152f35b503461023b57602036600319011261023b5760043567ffffffffffffffff81116102395761055a903690600401611a2d565b90610564826120e9565b91835b818110610588576040516020808252819061058490820187611c0b565b0390f35b610596610295828486611cb3565b650100000000008110156102e35790600191600901548060f01c6105bc575b5001610567565b60a01c69ffffffffffffffffffff166105d5828761215e565b525f6105b5565b503461023b578060031936011261023b57604080516105fb8282611b25565b60058152602081017f352e302e3000000000000000000000000000000000000000000000000000000081528251938492602084525180928160208601528585015e828201840152601f01601f19168101030190f35b503461023b57602036600319011261023b576106796040602092600435815260068452206137c9565b6001600160481b0360405191168152f35b503461023b578060031936011261023b5760206001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005416604051908152f35b50604036600319011261023b5760043567ffffffffffffffff8111610239576106fd903690600401611a2d565b906024359067ffffffffffffffff821161023557366023830112156102355781600401359067ffffffffffffffff8211610922576024830192602436918460061b0101116109225761074d612faa565b8184036108fa57845b8481106107f8575061077660209160405195604087526040870191611ce4565b84810382860152828152019190845b8181106107b657857fea94abb1b74fb43f057870ba68e52c15f36c6ed98b98bda185955ef4842b97aa86860387a180f35b9091926040806001926001600160801b036107d0886123b7565b1681526001600160801b036107e7602089016123b7565b166020820152019401929101610785565b610803818684611cb3565b35865260046020526001600160801b036040872054166001600160801b0361083461082f848789612393565b6123a3565b1681151591826108f0575b826108e5575b50506108bd57806108596001928587612393565b610864828886611cb3565b358852600460205260408820907fffffffffffffffffffffffffffffffff000000000000000000000000000000006108b060206001600160801b036108a8856123a3565b1693016123a3565b60801b1617905501610756565b6004867f1a20b67e000000000000000000000000000000000000000000000000000000008152fd5b141590505f80610845565b811515925061083f565b6004857fff633a38000000000000000000000000000000000000000000000000000000008152fd5b8480fd5b503461023b5760c036600319011261023b576004356001600160a01b03811680910361023957610954611aa7565b604435916001600160a01b038316809303610235576064359161ffff831691828403610dc5576084359460ff8616808703610dc15760a4359461ffff861696878703610dbd577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00549860ff8a60401c16159967ffffffffffffffff811680159081610db5575b6001149081610dab575b159081610da2575b50610d7a5767ffffffffffffffff1981166001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00558a610d3b575b50610a31614555565b610a39614555565b610a42336125c2565b610a4a614555565b610a52612faa565b8215610cfa578415610ceb576103e88311610cdc5791606093917fd2578cc27cd56b02e72d064ed9d68d965ec91300be9f269da17f0686716110b895935b76ffffffffffffffffffffffffffffffffffffffffffffff1961ffff60a01b60ff60b01b6002549360b01b169360a01b1691161784171760025560405192835260208301526040820152a16040516301ffc9a760e01b81527fd9b67a26000000000000000000000000000000000000000000000000000000006004820152602081602481855afa908115610cd1578791610ca2575b5015610c7a57906001600160a01b03916001600160a01b0319875416178655166001600160a01b03196001541617600155610b5e611e8c565b610b66612faa565b60038116610c6b579078ffffffffffffffffffffffffffffffffffffffffffffffffff61ffff60c81b7b01000000000000000000000000000000000000000000000000000000937f7d17ca2c1939a5351692336344e18b51ee4c6038f1c4f45b9cb928daad54119f602060025495604051908152a160c81b1691161717600255610bed5780f35b68ff0000000000000000197ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054167ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b6004846317ea5f1160e21b8152fd5b6004867f34d28112000000000000000000000000000000000000000000000000000000008152fd5b610cc4915060203d602011610cca575b610cbc8183611b25565b810190611e74565b5f610b25565b503d610cb2565b6040513d89823e3d90fd5b60048b6324a5279560e21b8152fd5b60048b63d92e233d60e01b8152fd5b84610d2c5791606093917fd2578cc27cd56b02e72d064ed9d68d965ec91300be9f269da17f0686716110b89593610a90565b60048b63825a7cf160e01b8152fd5b68ffffffffffffffffff191668010000000000000001177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00555f610a28565b60048c7ff92ee8a9000000000000000000000000000000000000000000000000000000008152fd5b9050155f6109ec565b303b1591506109e4565b8c91506109da565b8980fd5b8780fd5b8580fd5b503461023b57604036600319011261023b5760043567ffffffffffffffff811161023957610dfb903690600401611a2d565b6024359167ffffffffffffffff831161023557610e1f610332933690600401611ba9565b9290916121a9565b503461023b57602036600319011261023b576106796040602092600435815260058452206133f4565b503461023b57606036600319011261023b5760043567ffffffffffffffff811161023957610e82903690600401611a2d565b60243567ffffffffffffffff811161023557610ea2903690600401611ba9565b6044939193359067ffffffffffffffff8211610dc55761033294610ecd610ed5933690600401611bda565b9590946121a9565b612695565b503461023b578060031936011261023b57610ef3612faa565b806001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031981167f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461023b57606036600319011261023b57610f8d611a91565b6024359061ffff8216808303610235576044359260ff841692838503610dc557610fb5612faa565b8215611072576001600160a01b03811615611063576103e883116110545791606093917fd2578cc27cd56b02e72d064ed9d68d965ec91300be9f269da17f0686716110b895935b76ffffffffffffffffffffffffffffffffffffffffffffff1961ffff60a01b60ff60b01b6001600160a01b0360025494169760b01b169360a01b1691161784171760025560405192835260208301526040820152a180f35b6004866324a5279560e21b8152fd5b60048663d92e233d60e01b8152fd5b6001600160a01b0381166110ad5791606093917fd2578cc27cd56b02e72d064ed9d68d965ec91300be9f269da17f0686716110b89593610ffc565b60048663825a7cf160e01b8152fd5b503461023b578060031936011261023b576001600160a01b037f0000000000000000000000002df364b1f627e18b8d259ca26c0e89b51614d0871630036111275760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b8063703e46dd60e11b60049252fd5b503461023b57602036600319011261023b5760408181926020835161115a81611aed565b828152015260043581526004602052206001600160801b0382519161117e83611aed565b54602082821693848152019060801c8152835192835251166020820152f35b50604036600319011261023b576111b2611a91565b9060243567ffffffffffffffff8111610239576111d3903690600401611b63565b6001600160a01b037f0000000000000000000000002df364b1f627e18b8d259ca26c0e89b51614d0871680301490811561141a575b5061140b57611215612faa565b6001600160a01b03831690604051937f52d1902d000000000000000000000000000000000000000000000000000000008552602085600481865afa809585966113d7575b506112715760248484634c9c8ce360e01b8252600452fd5b9091847f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81036113ac5750813b1561139a57806001600160a01b03197f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416177f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8480a28151839015611367578083602061135b95519101845af43d1561135f573d9161133f83611b47565b9261134d6040519485611b25565b83523d85602085013e61538e565b5080f35b60609161538e565b505050346113725780f35b807fb398979f0000000000000000000000000000000000000000000000000000000060049252fd5b634c9c8ce360e01b8452600452602483fd5b7faa1d49a4000000000000000000000000000000000000000000000000000000008552600452602484fd5b9095506020813d602011611403575b816113f360209383611b25565b810103126109225751945f611259565b3d91506113e6565b60048263703e46dd60e11b8152fd5b90506001600160a01b037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc541614155f611208565b5034611655576080366003190112611655575f905f61146c6120b4565b926114756120b4565b9362ffffff611482612128565b161561173b5760243590815f5260046020526114ad826001600160801b0360405f205416151561324e565b6004356002811015611655576114e462ffffff97821593845f14611735576001600160481b035b6114dc612128565b9087866138f0565b9716806116ea5750506114f68661328e565b9591979094835f146116bc57506064358111611694575b80611675575b5080611659575b506115bb579280949362ffffff61152f612128565b16906001600160a01b0383541691823b1561023557604051637921219560e11b81523360048201523060248201526044810192909252606482015260a060848201525f60a4820152908290829060c490829084905af180156115b05761159b575b50506103329261332b565b816115a591611b25565b61023557835f611590565b6040513d84823e3d90fd5b62ffffff6115c7612128565b16906001600160a01b035f541691823b1561165557604051637921219560e11b81523060048201523360248201526044810192909252606482015260a060848201525f60a482018190529091829060c490829084905af1801561164a57611634575b50610332929361332b565b61033293505f61164391611b25565b5f92611629565b6040513d5f823e3d90fd5b5f80fd5b61166f90336001600160a01b0360015416612f55565b5f61151a565b61168e906001600160a01b0360015416309033906132d1565b5f611513565b7fb83cca50000000000000000000000000000000000000000000000000000000005f5260045ffd5b91506064358110611694576116e4906116de876116d9888c611cc3565b611cc3565b9061211b565b9061150d565b6084925083611729604051937f3e2a8e740000000000000000000000000000000000000000000000000000000085523360048601526024850190613281565b60448301526064820152fd5b5f6114d4565b7f94640235000000000000000000000000000000000000000000000000000000005f5260045ffd5b346116555761177a61177436611a5e565b9161203a565b6040518091602082016020835281518091526020604084019201905f5b8181106117a5575050500390f35b919350916020606060019264ffffffffff604088516001600160a01b03815116845262ffffff8682015116868501520151166040820152019401910191849392611797565b346116555760206118036117fd36611a5e565b91611feb565b6040519015158152f35b60203660031901126116555760043561ffff81169081810361165557611831612faa565b6003811661189c577f7d17ca2c1939a5351692336344e18b51ee4c6038f1c4f45b9cb928daad54119f916020917fffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffff61ffff60c81b6002549260c81b16911617600255604051908152a1005b6317ea5f1160e21b5f5260045ffd5b34611655575f366003190112611655576118c3611e8c565b005b346116555760203660031901126116555760043564ffffffffff81168103611655576118ef611e56565b506501000000000081101561195a5760609061ffff6040519161191183611abd565b6009015469ffffffffffffffffffff6001600160a01b0382169384815260406020820191838560a01c168352019260f01c83526040519485525116602084015251166040820152f35b634e487b7160e01b5f52603260045260245ffd5b346116555760203660031901126116555760043567ffffffffffffffff8111611655576119a26118c3913690600401611a2d565b90611d21565b3461165557602036600319011261165557600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361165557817f4e2312e00000000000000000000000000000000000000000000000000000000060209314908115611a1c575b5015158152f35b6301ffc9a760e01b91501483611a15565b9181601f840112156116555782359167ffffffffffffffff8311611655576020808501948460051b01011161165557565b60609060031901126116555760043560028110156116555790602435906044356001600160481b03811681036116555790565b600435906001600160a01b038216820361165557565b602435906001600160a01b038216820361165557565b6060810190811067ffffffffffffffff821117611ad957604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff821117611ad957604052565b60a0810190811067ffffffffffffffff821117611ad957604052565b90601f8019910116810190811067ffffffffffffffff821117611ad957604052565b67ffffffffffffffff8111611ad957601f01601f191660200190565b81601f8201121561165557803590611b7a82611b47565b92611b886040519485611b25565b8284526020838301011161165557815f926020809301838601378301015290565b9181601f840112156116555782359167ffffffffffffffff8311611655576020808501946060850201011161165557565b9181601f840112156116555782359167ffffffffffffffff8311611655576020808501948460071b01011161165557565b90602080835192838152019201905f5b818110611c285750505090565b8251845260209384019390920191600101611c1b565b67ffffffffffffffff8111611ad95760051b60200190565b9080601f83011215611655578135611c6d81611c3e565b92611c7b6040519485611b25565b81845260208085019260051b82010192831161165557602001905b828210611ca35750505090565b8135815260209182019101611c96565b919081101561195a5760051b0190565b91908201809211611cd057565b634e487b7160e01b5f52601160045260245ffd5b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116116555760209260051b809284830137010190565b60c88211611e47575f915f5b818110611daa57508215611d9b5782611d737f730ad7566a8a34d6ceb6a935a03fce683d09bd3d47fc52e557fa87069cea2e9a94336001600160a01b0360015416612f55565b611d90604051938493338552606060208601526060850191611ce4565b9060408301520390a1565b6312d37ee560e31b5f5260045ffd5b9264ffffffffff611dbc858486611cb3565b35166501000000000081101561195a57600901805469ffffffffffffffffffff8160a01c16908115611d9b576001600160a01b0333911603611e1f576001928269ffffffffffffffffffff60a01b19611e189454169055611cc3565b9301611d2d565b7fb331e421000000000000000000000000000000000000000000000000000000005f5260045ffd5b637c6b720960e11b5f5260045ffd5b60405190611e6382611abd565b5f6040838281528260208201520152565b90816020910312611655575180151581036116555790565b602460206001600160a01b035f5416604051928380926301ffc9a760e01b825263152a902d60e11b60048301525afa90811561164a575f91611fcc575b5015611fac57604460406001600160a01b035f541681519283809263152a902d60e11b82526001600483015261271060248301525afa90811561164a575f905f92611f5b575b506001600160a01b03166001600160a01b0319600354161760035561ffff60b81b1978ffff00000000000000000000000000000000000000000000006002549260b81b16911617600255565b9150506040813d604011611fa4575b81611f7760409383611b25565b81010312611655578051906001600160a01b03821682036116555760200151906001600160a01b03611f0f565b3d9150611f6a565b6001600160a01b03196003541660035561ffff60b81b1960025416600255565b611fe5915060203d602011610cca57610cbc8183611b25565b5f611ec9565b9190916002811015612026576120125761200f915f52600660205260405f20613009565b90565b61200f915f52600560205260405f20613009565b634e487b7160e01b5f52602160045260245ffd5b91909160028110156120265761207f578161200f925f52600860205260405f206001600160481b0383165f5260205260405f20905f52600660205260405f209061306e565b8161200f925f52600760205260405f206001600160481b0383165f5260205260405f20905f52600560205260405f209061306e565b6040516101f49190613ea06120c98183611b25565b83825267ffffffffffffffff829411611ad957601f190190369060200137565b906120f382611c3e565b6121006040519182611b25565b8281528092612111601f1991611c3e565b0190602036910137565b91908203918211611cd057565b60443562ffffff811681036116555790565b3562ffffff811681036116555790565b356001600160481b03811681036116555790565b805182101561195a5760209160051b010190565b5f198114611cd05760010190565b908160021b9180830460041490151715611cd057565b81810292918115918404141715611cd057565b92909281840361236b575f929192905f946121c3816120e9565b936121cd826120e9565b955f915b83831061225c57505050907f518405fd4d1da4785cc552188e579f0508054f396deba0bec66f5caca9070bb49161221b604051928392338452604060208501526040840191611ce4565b0390a180612240575b508261222f57505050565b8261223e93825282523361377f565b565b61225690336001600160a01b0360015416612f55565b5f612224565b9091948286101561195a5760608602820180359060028210156116555761228a60406020830135920161214a565b916122f857916122e86122ee9262ffffff6122e26001966122ac8d8c8e611cb3565b3590805f52600860205260405f20946001600160481b03811695865f5260205260405f20915f52600660205260405f2092613464565b16612196565b90611cc3565b955b0191906121d1565b99879a62ffffff612348612365946123146001979c8b8d611cb3565b3590845f52600760205260405f206001600160481b0382165f5260205260405f2090855f52600560205260405f2092613464565b1690612354838c61215e565b5261235f828c61215e565b52612172565b986122f0565b7fff633a38000000000000000000000000000000000000000000000000000000005f5260045ffd5b919081101561195a5760061b0190565b356001600160801b03811681036116555790565b35906001600160801b038216820361165557565b3564ffffffffff811681036116555790565b9190916040516123ec81611b09565b5f81525f60208201525f60408201525f60608201525f60808201525060028110156120265761248357612429915f52600660205260405f20613833565b6040519061243682611b09565b546001600160481b03811682526001600160481b038160481c1660208301526001600160481b038160901c16604083015263ffffffff8160d81c16606083015260f81c1515608082015290565b612429915f52600560205260405f20613833565b91909160c88311611e47578215611d9b576124b1836120e9565b926124bb816120e9565b915f5b835181101561254d5764ffffffffff6124d8828585611cb3565b35166501000000000081101561195a57600901908154918260f01c6124fd838861215e565b5269ffffffffffffffffffff8360a01c16928315611d9b576001600160a01b0333911603611e1f57600192612532838a61215e565b5269ffffffffffffffffffff60a01b198154169055016124be565b50917fde3c2f9295fefa02a7867bf4445e614a43531448e07a5753940c0696b46e263293946125af6125bd9261258483823361377f565b6125a1604051968796338852608060208901526080880191611ce4565b908582036040870152611c0b565b908382036060850152611c0b565b0390a1565b6001600160a01b03168015612651576001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054826001600160a01b03198216177f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b7f1e4fbdf7000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b9062ffffff8091169116039062ffffff8211611cd057565b610220526101608190525f61014081905261012081905260e08190529190829081906126c0906120e9565b6080526126cf610160516120e9565b610180525f61020052610160516126e5906120e9565b610100526126f5610160516120e9565b6101a0526127016120b4565b9161270a6120b4565b6101e05260025460d81c945f5b61016051811015612de3575f935f9462ffffff61273e60608560071b61022051010161213a565b161561173b576001600160481b0361276060408560071b61022051010161214a565b1615612dbb5760208360071b610220510101355f5260046020526001600160801b0360405f2054169586156127a260208660071b61022051010135821561324e565b6001600160481b036127be60408760071b61022051010161214a565b1690612da757876001600160801b03910616612d7b5760028460071b61022051013510159687611655576128326127ff60408760071b61022051010161214a565b8a6101e0519161281960608a60071b61022051010161213a565b6102205190919060078b901b01602081013590356138f0565b6101c0529260208660071b610220510101355f52600460205260405f205460801c62ffffff851610155f14612cda575082976116555761287c60408660071b61022051010161214a565b928560071b610220510135155f14612cd45760208660071b610220510101355b604051906128a982611abd565b3382528d6501000000000060208401915f835261ffff6040860194168452101561195a5769ffffffffffffffffffff8f916001600160a01b0361292a936009019551166001600160a01b03198654161785555116839069ffffffffffffffffffff60a01b1969ffffffffffffffffffff60a01b83549260a01b169116179055565b517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffff00000000000000000000000000000000000000000000000000000000000083549260f01b1691161790555f938c8760071b610220510135155f14612c51575061022051600788901b016020908101355f908152600882526040808220600690935290209093600f0b926f7fffffffffffffffffffffffffffffff198414611cd0576001600160481b038f93612a1b9062ffffff947ff4ed6e99fd267f4e8f8273058850e0ded9794213643d112a2a58802f8b461e0c9860c0985f03928787169264ffffffffff8a1692615077565b64ffffffffff60405195338752612a3f8d602089019060071b610220510135613281565b16604086015260208b60071b6102205101013560608601521660808401521660a0820152a15b62ffffff8716612c34575b5f916101c051612bd6575b611655578360071b610220510135155f14612b4857505090612aca6001926122e8612ac162ffffff89166001600160481b036122e260408860071b61022051010161214a565b6101c051611cc3565b946101c051612adc575b505b01612717565b62ffffff612b219160208460071b61022051010135612b01610200516101005161215e565b521662ffffff612b1b60608560071b61022051010161213a565b1661211b565b612b31610200516101a05161215e565b52612b3e61020051612172565b610200525f612ad4565b83929650612b6f90612b6a606062ffffff94979660071b61022051010161213a565b61267d565b1680612b9a575b50612b92612b8a600193946101c05161211b565b60e051611cc3565b60e052612ad6565b612b8a612bce600194612b929360208660071b61022051010135612bc08360805161215e565b5261235f826101805161215e565b935050612b76565b9150612c2e612bf7612bea6101c05161328e565b60c05260a0528098611cc3565b96612c0760a05161014051611cc3565b61014052612c1a60c05161012051611cc3565b610120526116d960c0519160a05190611cc3565b91612a7b565b9864ffffffffff1664ffffffffff8114611cd05760010198612a70565b9060c0926001600160481b03612ccf62ffffff937ff4ed6e99fd267f4e8f8273058850e0ded9794213643d112a2a58802f8b461e0c9760208d60071b610220510101355f5260076020528c602060405f209160071b610220510101355f52600560205260405f2091600f0b928787169264ffffffffff8a1692615077565b612a1b565b5f61289c565b9792905062ffffff8116612cef575b50612a65565b915050807f12f572861d108ac2c546b0b80770afe6fe8b3921acb39b6a2fe9f91c4cd6d14d60a05f9362ffffff612d3060408960071b61022051010161214a565b916001600160481b0360405193338552612d56602086018c60071b610220510135613281565b60208b60071b610220510101356040860152166060840152166080820152a15f612ce9565b867f766de9a4000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b634e487b7160e01b5f52601260045260245ffd5b7fe528e11e000000000000000000000000000000000000000000000000000000005f5260045ffd5b5092509293600254908160d81c64ffffffffff821603612f06575b505080612ee7575b5060e051612eca575b80612e5a575b5061223e9061020051612e32575b6101205190610140519061332b565b610200516101005152610200516101a05152612e556101a051610100513361377f565b612e23565b806080515261018051526001600160a01b035f541690813b15611655575f6040518093631759616b60e11b8252818381612e9f61018051608051303360048601613740565b03925af191821561164a5761223e92612eba575b5090612e15565b5f612ec491611b25565b5f612eb3565b612ee260e051336001600160a01b0360015416612f55565b612e0f565b612f00906001600160a01b0360015416309033906132d1565b5f612e06565b7fffffffffff0000000000000000000000000000000000000000000000000000007affffffffffffffffffffffffffffffffffffffffffffffffffffff9160d81b169116176002555f80612dfe565b61223e926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252612fa5606483611b25565b613883565b6001600160a01b037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930054163303612fdd57565b7f118cdaa7000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b906001600160481b0316801515918261302157505090565b80546001600160481b03168214925090821561303c57505090565b600192505f52016020526001600160481b0360405f205416151590565b805482101561195a575f5260205f2001905f90565b919061307a8282613009565b156132465763ffffffff9161308e91613833565b5460d81c16915f916130a08482613059565b90545f9160031b1c5b60048210613208575b50506130d0836130cb6130c687855461211b565b612180565b61211b565b936130da85611c3e565b946130e86040519687611b25565b8086526130f7601f1991611c3e565b015f5b8181106131f1575050845f93855b613113878951611cc3565b8110156131e75761313061312a858360021c611cc3565b86613059565b90549060031b1c600382169060c08360061b169180830460401490151715611cd05764ffffffffff81831c16908161316e575b505050600101613108565b9091929760288401809411611cd0576501000000000083101561195a57613113938362ffffff6131df946001600160a01b03600197600901541693604051946131b686611abd565b85521c16602083015260408201526131ce828d61215e565b526131d9818c61215e565b50612172565b96915f613163565b5094509491505052565b6020906131fc611e56565b82828a010152016130fa565b90938460061b85810460401486151715611cd05782901c67ffffffffffffffff1661324057613238600191612172565b9401906130a9565b936130b2565b505050606090565b156132565750565b7f03399b24000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9060028210156120265752565b90600254906127106132cd816132ab61ffff8660b81c1687612196565b049460ff836132c161ffff8860a01c1684612196565b049560b01c1690612196565b0490565b9091926001600160a01b0361223e9481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252612fa5608483611b25565b806133cc575b50806133a4575b50806133415750565b6001600160a01b036001541690813b15611655575f916024839260405194859384927f42966c6800000000000000000000000000000000000000000000000000000000845260048401525af1801561164a5761339a5750565b5f61223e91611b25565b6133c6906001600160a01b03600154166001600160a01b036002541690612f55565b5f613338565b6133ee906001600160a01b03600154166001600160a01b036003541690612f55565b5f613331565b6001600160481b038154169081613409575090565b905b60018201906001600160481b0381165f52816020526001600160481b0360405f205460481c161561345e576001600160481b03165f5260205260016001600160481b0360405f205460481c16905061340b565b92915050565b9392916134718284613009565b156137075763ffffffff6134858385613833565b5460d81c1690805461349987828585614447565b90975f1989146136ce57506134ae8884613059565b90549060031b1c978160061b98828a0460401483151715611cd05760288a0190818b11611cd05762ffffff911c16986134e78286613059565b90549060031b1c64ffffffffff81831c166501000000000081101561195a57600901546001600160a01b03163303611e1f575f198501858111611cd057831491826136b7575b505015613553575050506135408161451a565b541461354a575050565b61223e916145f4565b909294506116d99195506135679350612180565b918260021c9261357a6003821692612180565b5f19810191908211611cd057905b8082106135e3575b5050806135a2575061223e915061451a565b826135cb916135c46135b761223e9686613059565b90549060031b1c916145d2565b1692613059565b90919082549060031b91821b915f19901b1916179055565b915092506001830190818411611cd0578160021c91829460038216613609819587613059565b90549060031b1c8260021c91600384169160c0613626858b613059565b90549060031b1c9660061b169180830460401490151715611cd05767ffffffffffffffff911c169384156136a75761365d826145d2565b169360c08460061b169180830460401490151715611cd0576001946136856136a0948a613059565b9290931b179082549060031b91821b915f19901b1916179055565b0190613588565b5096509350505050915f80613590565b67ffffffffffffffff9192501b1916155f8061352d565b856001600160481b03917fdca140df000000000000000000000000000000000000000000000000000000005f526004521660245260445ffd5b6001600160481b0382867ff965eb63000000000000000000000000000000000000000000000000000000005f526004521660245260445ffd5b926125af906001600160a01b0361376f948160209895168752168686015260a0604086015260a0850190611c0b565b9060808183039101525f81520190565b90916001600160a01b035f5416803b15611655576137b8935f809460405196879586948593631759616b60e11b85523060048601613740565b03925af1801561164a5761339a5750565b6001600160481b0381541690816137de575090565b905b60018201906001600160481b0381165f52816020526001600160481b0360405f205460901c161561345e576001600160481b03165f5260205260016001600160481b0360405f205460901c1690506137e0565b61383d8282613009565b1561385b576001600160481b03600192165f520160205260405f2090565b7f2a8020fe000000000000000000000000000000000000000000000000000000005f5260045ffd5b905f602091828151910182855af11561164a575f513d6138e757506001600160a01b0381163b155b6138b25750565b6001600160a01b03907f5274afe7000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b600114156138ab565b92939094916103a052610400526103c052600281101561202657613edd575f610460525f610380525f61038052610460526101f461040051526101f46103c051525f905b62ffffff61046051166139bc575b5080613955575b50610380516104605191565b8061040051526103c051527f29c45e48d0fdd73dc977da9c0ed6c48240b873a5c373a3df49364e879b51203360405133815260606020820152806139b36139a26060830161040051611c0b565b82810360408401526103c051611c0b565b0390a15f613949565b91905f61036052825f5260056020526139d760405f206133f4565b610360526001600160481b036103605116158015613ebc575b613eb5575f91835f52600760205260405f206001600160481b0361036051165f5260205260405f2092845f526005602052613a316103605160405f20613833565b935f925f935f610280525f610280525f9263ffffffff885460d81c16935b8154851080613ea4575b15613e9557508390613a6b8582613059565b905460039190911b1c610280525f610320819052610420819052975b6004891080613e84575b15613e7957888060061b0460401489151715611cd0576102805160068a901b1c64ffffffffff16908115613c805760288a60061b018a60061b11611cd05762ffffff6102805160288c60061b011c16610340526103405162ffffff610460511610155f14613c3357613b09610340516104605161267d565b6104605260038a146104205261032051613b2290612172565b61032052610340515b613b416001600160481b03610360511682612196565b92613b4f8461038051611cc3565b610380526501000000000081101561195a57613bd6613bf194613bab69ffffffffffffffffffff613b9485600901936116de6116d9613b8d8361328e565b9291611cc3565b1669ffffffffffffffffffff835460a01c166145ac565b69ffffffffffffffffffff60a01b1969ffffffffffffffffffff60a01b83549260a01b169116179055565b613be3836104005161215e565b5261235f826103c05161215e565b976101f4891015613c0b57613c0590612172565b97613a87565b7fc8690679000000000000000000000000000000000000000000000000000000005f5260045ffd5b935062ffffff613c49610460516103405161267d565b1660288a60061b011b62ffffff60288b60061b011b196102805116176102805262ffffff6104605116935f61046052600194613b2b565b610280519099989150600689901b1c15613ca657613ca0613c0591612172565b97612172565b9095919496505b6104205115613cd15750613cc090612172565b93613ccb5f96612172565b93613a4f565b95613ce483976103209793975190611cc3565b96613cf257613ccb90612172565b5092939094919795965b81613dbd575b5050838415613db4575b613d1a575b50505050613934565b80613d80575b50613d5191613d37916102805115613d6357613059565b6102805182545f1960039390931b92831b1916911b179055565b613d5e575f808080613d11565b613942565b855f526005602052613d7b6103605160405f206145f4565b613059565b5f5b818110613d8f5750613d20565b80613da060019297949596976145d2565b610280511661028052019493929194613d82565b50801515613d0c565b63ffffffff905460d81c16865f52600560205260405f20613de16103605182613009565b1561385b576001906001600160481b0361036051165f520160205260405f209063ffffffff831663ffffffff835460d81c16019163ffffffff8311611cd057613e4f92613e48919063ffffffff60d81b1963ffffffff60d81b83549260d81b169116179055565b845461211b565b14613e5c575b5f80613d02565b845f526005602052613e746103605160405f206145f4565b613e55565b975094909395613cad565b5062ffffff61046051161515613a91565b94919592989697909350613cfc565b5062ffffff61046051161515613a59565b9091613942565b506001600160481b036103a051166001600160481b036103605116116139f0565b61024052610400516101f4908190526103c051525f610440819052905b62ffffff6102405116613f75575b5061044051613f19575b6102405191565b610440516104005152610440516103c051527f29c45e48d0fdd73dc977da9c0ed6c48240b873a5c373a3df49364e879b5120336040513381526060602082015280613f6d6139a26060830161040051611c0b565b0390a1613f12565b915f6102e052825f526006602052613f8f60405f206137c9565b6102e0526001600160481b036102e05116158015614411575b61440b575f835f52600860205260405f206001600160481b036102e051165f5260205260405f20845f526006602052613fe76102e05160405f20613833565b5f6102608190526103008190528154919460d89290921c63ffffffff1692815b81548510806143fa575b156143ed575083906140238582613059565b905460039190911b1c610300525f6102a08190526103e08190525b60048110806143dc575b156143d357808060061b0460401481151715611cd05761030051600682901b1c64ffffffffff169889156141d45760288260061b018260061b11611cd05762ffffff6103005160288460061b011c166102c0526102c05162ffffff610240511610155f14614185576140c06102c0516102405161267d565b61024052600382146103e0526102a0516140d990612172565b6102a0526140fc6102c051915b6122e86001600160481b036102e0511684612196565b996501000000000081101561195a5761413881600901613bab69ffffffffffffffffffff851669ffffffffffffffffffff835460a01c166145ac565b614148610440516104005161215e565b52614159610440516103c05161215e565b5261416661044051612172565b610440526101f4610440511015613c0b5761418090612172565b61403e565b935062ffffff61419b610240516102c05161267d565b1660288260061b011b62ffffff60288360061b011b196103005116176103005262ffffff61024051165f610240526140fc6001956140e6565b61030051909950600682901b1c156141ff57614180906141f661026051612172565b61026052612172565b509093945b6103e0511561422a5761421961422491612172565b955f61026052612172565b93614007565b948261423c6102a05161026051611cc3565b6102605261424d5761422490612172565b509196949390935b81614317575b505082831561430b575b614272575b505050613efa565b610260516142d4575b6142ab916142919161030051156142bc57613059565b6103005182545f1960039390931b92831b1916911b179055565b6142b7575f808061426a565b613f08565b855f526006602052613d7b6102e05160405f206145f4565b5f5b6102605181106142e6575061427b565b806142f760019296939495966145d2565b6103005116610300520193929190936142d6565b50610260511515614265565b63ffffffff905460d81c16855f52600660205260405f2061433b6102e05182613009565b1561385b576001906001600160481b036102e051165f520160205260405f209063ffffffff831663ffffffff835460d81c16019163ffffffff8311611cd0576143a9926143a2919063ffffffff60d81b1963ffffffff60d81b83549260d81b169116179055565b835461211b565b146143b6575b5f8061425b565b835f5260066020526143ce6102e05160405f206145f4565b6143af565b50909394614204565b5062ffffff61024051161515614048565b9350919694939093614255565b5062ffffff61024051161515614011565b91613f08565b506001600160481b036103a051166001600160481b036102e0511610613fa8565b60061b90613fc060c0831692168203611cd057565b9291905b81811061445d57505050505f19908190565b61447361446a828461211b565b60011c82611cc3565b9061447e8286613059565b90549060031b1c5f905f905b600482106144b7575b50506020036144b0575060018101809111611cd057905b9061444b565b91506144aa565b9097969492918060039795971b81810460081482151715611cd05782901c64ffffffffff168581036144ee57505050505050509190565b94809795999394969899105f146145145760088101809111611cd057916001019061448a565b91614493565b80548015614541575f1901906145308282613059565b8154905f199060031b1b1916905555565b634e487b7160e01b5f52603160045260245ffd5b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561458457565b7fd7e6bcf8000000000000000000000000000000000000000000000000000000005f5260045ffd5b9069ffffffffffffffffffff8091169116019069ffffffffffffffffffff8211611cd057565b8060061b9080820460401490151715611cd05767ffffffffffffffff901b1990565b6001600160481b03821690811561504f5761460f8382613009565b1561385b576001810192825f52836020526001600160481b0360405f205460481c16158015615030575b15614fc65780925b6001600160481b0384165f52846020526001600160481b0360405f205460481c1615155f14614f9f576001600160481b0384165f52846020526001600160481b0360405f205460481c16915b6001600160481b038581165f908152602088905260408082205486841683529120805468ffffffffffffffffff1916919092169081179091558015614f7e576001600160481b03908181165f52876020528160405f205460481c16828816145f14614f4057165f528560205261472b8360405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b6001600160481b0385165f528560205260405f205460f81c1591806001600160481b03871603614d64575b5050614781575b50506001600160481b03165f5260205260405f206001600160481b03198154169055565b939091935b6001600160481b03835416906001600160481b0381169182141580614d4e575b15614d1f5750805f52836020526001600160481b0360405f205416906001600160481b0382165f52846020526001600160481b0360405f205460481c16145f14614a8e576001600160481b0381165f52836020526001600160481b0360405f205460901c166001600160481b0381165f528460205260405f205460f81c614a17575b6001600160481b038181165f908152602087905260408082205460481c9092168152205460f81c15806149e9575b15614889576001600160481b03165f528360205260405f20600160f81b6001600160f81b03825416179055935b93614786565b90614962916001600160481b0381165f52856020526001600160481b038060405f205460901c16165f528560205260405f205460f81c15614973575b6001600160481b03908183165f528660205261491160405f205460f81c8383165f528860205260405f20906001600160f81b036001600160f81b0319835492151560f81b169116179055565b8183165f528660205260405f206001600160f81b038154169055165f52846020526001600160481b038060405f205460901c16165f528460205260405f206001600160f81b03815416905583615b1f565b6001600160481b0382541693614883565b6001600160481b038082165f81815260208990526040808220805460481c9094168252812080546001600160f81b03908116909155919052815416600160f81b1790556149c0908561596f565b6001600160481b0381165f52846020526001600160481b038060405f205460901c1690506148c5565b506001600160481b038181165f908152602087905260408082205460901c9092168152205460f81c15614856565b6001600160481b03165f528360205260405f206001600160f81b0381541690556001600160481b0381165f528360205260405f20600160f81b6001600160f81b03825416179055614a688184615b1f565b6001600160481b0381165f52836020526001600160481b0360405f205460901c16614828565b6001600160481b0381165f52836020526001600160481b0360405f205460481c166001600160481b0381165f528460205260405f205460f81c614ca8575b6001600160481b038181165f908152602087905260408082205460901c9092168152205460f81c1580614c7a575b15614b2b576001600160481b03165f528360205260405f20600160f81b6001600160f81b0382541617905593614883565b90614962916001600160481b0381165f52856020526001600160481b038060405f205460481c16165f528560205260405f205460f81c15614c04575b6001600160481b03908183165f5286602052614bb360405f205460f81c8383165f528860205260405f20906001600160f81b036001600160f81b0319835492151560f81b169116179055565b8183165f528660205260405f206001600160f81b038154169055165f52846020526001600160481b038060405f205460481c16165f528460205260405f206001600160f81b0381541690558361596f565b6001600160481b038082165f81815260208990526040808220805460901c9094168252812080546001600160f81b03908116909155919052815416600160f81b179055614c519085615b1f565b6001600160481b0381165f52846020526001600160481b038060405f205460481c169050614b67565b506001600160481b038181165f908152602087905260408082205460481c9092168152205460f81c15614afa565b6001600160481b03165f528360205260405f206001600160f81b0381541690556001600160481b0381165f528360205260405f20600160f81b6001600160f81b03825416179055614cf9818461596f565b6001600160481b0381165f52836020526001600160481b0360405f205460481c16614acc565b6001600160481b039350839150949194165f528260205260405f206001600160f81b038154169055905f61475d565b50815f528460205260405f205460f81c156147a6565b94614e9d919295805f52876020526001600160481b0360405f2054166001600160481b0383165f528860205260405f206001600160481b0382166001600160481b031982541617905580155f14614ea55750855468ffffffffffffffffff19166001600160481b0383161786555b5f9081526020889052604080822080546001600160481b03948516808552838520805468ffffffffffffffffff60481b191668ffffffffffffffffff60481b9093169290921780835560481c86168552838520805468ffffffffffffffffff1990811683179091558354835468ffffffffffffffffff60901b191668ffffffffffffffffff60901b9091161780845560901c90961685529284208054909516831790945554915281546001600160f81b031660f891821c151590911b6001600160f81b031916179055565b925f80614756565b6001600160481b03908181165f52896020528160405f205460481c1683145f14614f0757165f5287602052614f028260405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b614dd2565b165f5287602052614f028260405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b165f5285602052614f798360405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b61472b565b50835468ffffffffffffffffff19166001600160481b03841617845561472b565b6001600160481b0384165f52846020526001600160481b0360405f205460901c169161468d565b825f52836020526001600160481b0360405f205460901c165b6001600160481b0381165f52846020526001600160481b0360405f205460481c161561502a576001600160481b03165f52836020526001600160481b0360405f205460481c16614fdf565b92614641565b50825f52836020526001600160481b0360405f205460901c1615614639565b7fd77534c7000000000000000000000000000000000000000000000000000000005f5260045ffd5b9180959493946150878284613009565b6151af57506150959161541a565b6001600160481b0384165f5260205260405f2091600183548061510b575b506150bf575b50505090565b82549268010000000000000000841015611ad957836150e691600161510396018155613059565b91909260281b179082549060031b91821b915f19901b1916179055565b5f80806150b9565b5f198101908111611cd0576151209085613059565b90549060031b1c5f5b60048110615138575b506150b3565b8060061b81810460401482151715611cd05782811c1561515b5750600101615129565b919250506028810190818111611cd05785545f19810191908211611cd0576151a7938561518988948a613059565b9490951b921b17179082549060031b91821b915f19901b1916179055565b5f5f80615132565b906151bf63ffffffff9184613833565b5460d81c166001600160481b03871691825f528460205260405f20835f528560205260405f20545f198101908111611cd0576151fa91613059565b905460039491851b1c60ff61520e86614432565b161c1515905f528560205261522a6130c68460405f205461211b565b61ffff60025460c81c1611159081615386575b5061524c575b50505050615095565b965b6001600160481b0388600f0b9116600f0b016f7fffffffffffffffffffffffffffffff1981126f7fffffffffffffffffffffffffffffff821317611cd0576001600160801b0381166001600160481b03811161535657506001600160481b0316966152b98885613009565b6152d357505050846152ca9161541a565b5f808080615243565b875f989293949852846020526152f06130c68460405f205461211b565b61ffff60025460c81c16118015615319575b61530f579692919061524e565b50955050506152ca565b505f82815260208690526040902080545f198101908111611cd05761533d91613059565b905490851b1c60ff61534e86614432565b161c15615302565b7f6dfcc650000000000000000000000000000000000000000000000000000000005f52604860045260245260445ffd5b90505f61523d565b906153cb57508051156153a357805190602001fd5b7fd6bda275000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580615411575b6153dc575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156153d4565b906001600160481b03811692831561504f5782546001600160481b03165f5b6001600160481b0382169081156154a357508181871015615482576001600160481b039150165f52600184016020526001600160481b0360405f205460481c16915b9190615439565b505f52600184016020526001600160481b0360405f205460901c169161547b565b95915050929190926001830194815f52856020526155ca63ffffffff60405f205460d81c1691836155a963ffffffff6001600160481b03604051946154e786611b09565b16958685526155896001600160481b038d61555f8260208a015f815260408b01935f855260608c0197885260808c019a60018c525f52602052818060405f209c51161682198c5416178b555116899068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b51875468ffffffffffffffffff60901b1916911660901b68ffffffffffffffffff60901b16178655565b51845463ffffffff60d81b1916911660d81b63ffffffff60d81b16178355565b5181546001600160f81b031690151560f81b6001600160f81b031916179055565b806158f15750825468ffffffffffffffffff19161782555b905b6001600160481b038154166001600160481b03831690811415806158cb575b156158a1575f81815260208690526040808220546001600160481b039081168084528284205482168452919092205490929160489190911c16820361577857506001600160481b038181165f9081526020879052604080822054831682528082205460901c9092168082529190205490939060f81c156156d757506001600160481b039081165f8181526020879052604080822080546001600160f81b03908116825596851683528183208054881690558054851683529082208054909616600160f81b17909555529154909116906155e4565b92506001600160481b0381165f52846020526001600160481b0360405f205460901c166001600160481b03841614615766575b506001600160481b038281165f9081526020869052604080822054831680835281832080546001600160f81b03818116835590861685529284208054909316600160f81b179092559091525461576191168261596f565b6155e4565b91506157728282615b1f565b5f61570a565b6001600160481b038281165f9081526020889052604080822054831682528082205460481c909216808252919020549094919060f81c1561580e5750506001600160481b039081165f8181526020879052604080822080546001600160f81b03908116825596851683528183208054881690558054851683529082208054909616600160f81b17909555529154909116906155e4565b9093506001600160481b0382165f52856020526001600160481b0360405f205460481c161461588f575b506001600160481b038281165f9081526020869052604080822054831680835281832080546001600160f81b03818116835590861685529284208054909316600160f81b1790925590915254615761911682615b1f565b915061589b828261596f565b5f615838565b50546001600160481b03165f90815260209390935250604090912080546001600160f81b03169055565b505f81815260208690526040808220546001600160481b0316825290205460f81c615603565b8091105f14615937575f52836020526159328160405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b6155e2565b5f52836020526159328160405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b6001600160481b038083165f81815260018401602081905260408083208054604881811c8816808752938620549690955268ffffffffffffffffff60481b1981169486901c68ffffffffffffffffff60481b169490941790559590949092909184169060901c841680615b02575b508386165f528460205260405f20848216851982541617905580155f14615a6b575082851683198254161790555b8184165f5282602052615a468160405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b165f526020526001600160481b0360405f2091166001600160481b0319825416179055565b8391508181165f52846020528160405f205460901c16828416145f14615ac957165f5282602052615ac48460405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b615a0b565b165f5282602052615ac48460405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b84165f528460205260405f2084841685198254161790555f6159dd565b6001600160481b038083165f81815260018401602081905260408083208054609081901c8716808652928520549590945268ffffffffffffffffff60901b198416604886811b68ffffffffffffffffff60901b16919091179091559096919591939192851691901c841680615c8f575b508386165f528460205260405f20848216851982541617905580155f14615bf8575082851683198254161790555b8184165f5282602052615a468160405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b8391508181165f52846020528160405f205460481c16828416145f14615c5657165f5282602052615c518460405f209068ffffffffffffffffff60481b1968ffffffffffffffffff60481b83549260481b169116179055565b615bbd565b165f5282602052615c518460405f209068ffffffffffffffffff60901b1968ffffffffffffffffff60901b83549260901b169116179055565b84165f528460205260405f2084841685198254161790555f615b8f56fea2646970667358221220913b011d4ec7a1df242985a01d6d69b51907041aa923c2bace7af0ca3b38ab9b64736f6c634300081c0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 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.