Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
Book
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
Yes with 1000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: - // License: https://license.sonic.market/LICENSE.pdf pragma solidity ^0.8.20; import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; import {IBookManager} from "../interfaces/IBookManager.sol"; import {SegmentedSegmentTree} from "./SegmentedSegmentTree.sol"; import {Tick, TickLibrary} from "./Tick.sol"; import {OrderId, OrderIdLibrary} from "./OrderId.sol"; import {TotalClaimableMap} from "./TotalClaimableMap.sol"; import {TickBitmap} from "./TickBitmap.sol"; library Book { using Book for State; using TickBitmap for mapping(uint256 => uint256); using SegmentedSegmentTree for SegmentedSegmentTree.Core; using TotalClaimableMap for mapping(uint24 => uint256); using TickLibrary for Tick; using OrderIdLibrary for OrderId; error ZeroUnit(); error BookAlreadyOpened(); error BookNotOpened(); error QueueReplaceFailed(); error CancelFailed(uint64 maxCancelableUnit); // @dev Due to the segment tree implementation, the maximum order size is 2 ** 15. uint40 internal constant MAX_ORDER = 2 ** 15; // 32768 uint256 internal constant MAX_ORDER_M = 2 ** 15 - 1; // % 32768 struct Order { address provider; uint64 pending; // @dev unfilled unit + filled(claimable) unit } struct Queue { SegmentedSegmentTree.Core tree; Order[] orders; } struct State { IBookManager.BookKey key; mapping(Tick tick => Queue) queues; mapping(uint256 => uint256) tickBitmap; // @dev Four values of totalClaimable are stored in one uint256 mapping(uint24 groupIndex => uint256) totalClaimableOf; } function open(State storage self, IBookManager.BookKey calldata key) external { if (self.isOpened()) revert BookAlreadyOpened(); self.key = key; } function isOpened(State storage self) internal view returns (bool) { return self.key.unitSize != 0; } function checkOpened(State storage self) internal view { if (!self.isOpened()) revert BookNotOpened(); } function depth(State storage self, Tick tick) internal view returns (uint64) { return self.queues[tick].tree.total() - self.totalClaimableOf.get(tick); } function highest(State storage self) internal view returns (Tick) { return self.tickBitmap.highest(); } function maxLessThan(State storage self, Tick tick) internal view returns (Tick) { return self.tickBitmap.maxLessThan(tick); } function isEmpty(State storage self) internal view returns (bool) { return self.tickBitmap.isEmpty(); } function _getOrder(State storage self, Tick tick, uint40 index) private view returns (Order storage) { return self.queues[tick].orders[index]; } function getOrder(State storage self, Tick tick, uint40 index) internal view returns (Order memory) { return _getOrder(self, tick, index); } function make(State storage self, Tick tick, uint64 unit, address provider) external returns (uint40 orderIndex) { if (unit == 0) revert ZeroUnit(); if (!self.tickBitmap.has(tick)) self.tickBitmap.set(tick); Queue storage queue = self.queues[tick]; // @dev Assume that orders.length cannot reach to type(uint40).max + 1. orderIndex = SafeCast.toUint40(queue.orders.length); if (orderIndex >= MAX_ORDER) { unchecked { uint40 staleOrderIndex = orderIndex - MAX_ORDER; uint64 stalePendingUnit = queue.orders[staleOrderIndex].pending; if (stalePendingUnit > 0) { // If the order is not settled completely, we cannot replace it uint64 claimable = calculateClaimableUnit(self, tick, staleOrderIndex); if (claimable != stalePendingUnit) revert QueueReplaceFailed(); } } // The stale order is settled completely, so remove it from the totalClaimableOf. // We can determine the stale order is claimable. uint64 staleOrderedUnit = queue.tree.get(orderIndex & MAX_ORDER_M); if (staleOrderedUnit > 0) self.totalClaimableOf.sub(tick, staleOrderedUnit); } queue.tree.update(orderIndex & MAX_ORDER_M, unit); queue.orders.push(Order({pending: unit, provider: provider})); } /** * @notice Take orders from the book * @param self The book state * @param maxTakeUnit The maximum unit to take * @return takenUnit The actual unit to take */ function take(State storage self, Tick tick, uint64 maxTakeUnit) external returns (uint64 takenUnit) { uint64 currentDepth = depth(self, tick); if (currentDepth > maxTakeUnit) { takenUnit = maxTakeUnit; } else { takenUnit = currentDepth; self.tickBitmap.clear(tick); } self.totalClaimableOf.add(tick, takenUnit); } function cancel(State storage self, OrderId orderId, uint64 to) external returns (uint64 canceled, uint64 afterPending) { (, Tick tick, uint40 orderIndex) = orderId.decode(); Queue storage queue = self.queues[tick]; uint64 pendingUnit = queue.orders[orderIndex].pending; uint64 claimableUnit = calculateClaimableUnit(self, tick, orderIndex); afterPending = to + claimableUnit; unchecked { if (pendingUnit < afterPending) revert CancelFailed(pendingUnit - claimableUnit); canceled = pendingUnit - afterPending; self.queues[tick].tree.update( orderIndex & MAX_ORDER_M, self.queues[tick].tree.get(orderIndex & MAX_ORDER_M) - canceled ); } queue.orders[orderIndex].pending = afterPending; if (depth(self, tick) == 0) { // clear() won't revert so we can cancel with to=0 even if the depth() is already zero // works even if bitmap is empty self.tickBitmap.clear(tick); } } function claim(State storage self, Tick tick, uint40 index) external returns (uint64 claimedUnit) { Order storage order = _getOrder(self, tick, index); claimedUnit = calculateClaimableUnit(self, tick, index); unchecked { order.pending -= claimedUnit; } } function calculateClaimableUnit(State storage self, Tick tick, uint40 index) public view returns (uint64) { uint64 orderUnit = self.getOrder(tick, index).pending; Queue storage queue = self.queues[tick]; // @dev Book logic always considers replaced orders as claimable. unchecked { if (uint256(index) + MAX_ORDER < queue.orders.length) return orderUnit; uint64 totalClaimableUnit = self.totalClaimableOf.get(tick); uint64 rangeRight = _getClaimRangeRight(queue, index); if (rangeRight - orderUnit >= totalClaimableUnit) return 0; // -------- totalClaimable ---------|--- // ------|---- orderUnit ----|-------- // rangeLeft rangeRight if (rangeRight <= totalClaimableUnit) return orderUnit; // -- totalClaimable --|---------------- // ------|---- orderUnit ----|-------- // rangeLeft rangeRight else return totalClaimableUnit - (rangeRight - orderUnit); } } function _getClaimRangeRight(Queue storage queue, uint256 orderIndex) private view returns (uint64 rangeRight) { uint256 l = queue.orders.length & MAX_ORDER_M; uint256 r = (orderIndex + 1) & MAX_ORDER_M; rangeRight = (l < r) ? queue.tree.query(l, r) : queue.tree.total() - queue.tree.query(r, l); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.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.0.0) (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.20; import {IERC721} from "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC-721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC-721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or * {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the address zero. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.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.0.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) { /// @solidity memory-safe-assembly assembly { u := iszero(iszero(b)) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import {BookId} from "../libraries/BookId.sol"; import {Currency} from "../libraries/Currency.sol"; import {OrderId} from "../libraries/OrderId.sol"; import {Tick} from "../libraries/Tick.sol"; import {FeePolicy} from "../libraries/FeePolicy.sol"; import {IERC721Permit} from "./IERC721Permit.sol"; import {IHooks} from "./IHooks.sol"; /** * @title IBookManager * @notice The interface for the BookManager contract */ interface IBookManager is IERC721Metadata, IERC721Permit { error InvalidUnitSize(); error InvalidFeePolicy(); error InvalidProvider(address provider); error LockedBy(address locker, address hook); error CurrencyNotSettled(); /** * @notice Event emitted when a new book is opened * @param id The book id * @param base The base currency * @param quote The quote currency * @param unitSize The unit size of the book * @param makerPolicy The maker fee policy * @param takerPolicy The taker fee policy * @param hooks The hooks contract */ event Open( BookId indexed id, Currency indexed base, Currency indexed quote, uint64 unitSize, FeePolicy makerPolicy, FeePolicy takerPolicy, IHooks hooks ); /** * @notice Event emitted when a new order is made * @param bookId The book id * @param user The user address * @param tick The order tick * @param orderIndex The order index * @param unit The order unit * @param provider The provider address */ event Make( BookId indexed bookId, address indexed user, Tick tick, uint256 orderIndex, uint64 unit, address provider ); /** * @notice Event emitted when an order is taken * @param bookId The book id * @param user The user address * @param tick The order tick * @param unit The order unit */ event Take(BookId indexed bookId, address indexed user, Tick tick, uint64 unit); /** * @notice Event emitted when an order is canceled * @param orderId The order id * @param unit The canceled unit */ event Cancel(OrderId indexed orderId, uint64 unit); /** * @notice Event emitted when an order is claimed * @param orderId The order id * @param unit The claimed unit */ event Claim(OrderId indexed orderId, uint64 unit); /** * @notice Event emitted when a provider is whitelisted * @param provider The provider address */ event Whitelist(address indexed provider); /** * @notice Event emitted when a provider is delisted * @param provider The provider address */ event Delist(address indexed provider); /** * @notice Event emitted when a provider collects fees * @param provider The provider address * @param recipient The recipient address * @param currency The currency * @param amount The collected amount */ event Collect(address indexed provider, address indexed recipient, Currency indexed currency, uint256 amount); /** * @notice Event emitted when new default provider is set * @param newDefaultProvider The new default provider address */ event SetDefaultProvider(address indexed newDefaultProvider); /** * @notice This structure represents a unique identifier for a book in the BookManager. * @param base The base currency of the book * @param unitSize The unit size of the book * @param quote The quote currency of the book * @param makerPolicy The maker fee policy of the book * @param hooks The hooks contract of the book * @param takerPolicy The taker fee policy of the book */ struct BookKey { Currency base; uint64 unitSize; Currency quote; FeePolicy makerPolicy; IHooks hooks; FeePolicy takerPolicy; } /** * @notice Returns the base URI * @return The base URI */ function baseURI() external view returns (string memory); /** * @notice Returns the contract URI * @return The contract URI */ function contractURI() external view returns (string memory); /** * @notice Returns the default provider * @return The default provider */ function defaultProvider() external view returns (address); /** * @notice Returns the total reserves of a given currency * @param currency The currency in question * @return The total reserves amount */ function reservesOf(Currency currency) external view returns (uint256); /** * @notice Checks if a provider is whitelisted * @param provider The address of the provider * @return True if the provider is whitelisted, false otherwise */ function isWhitelisted(address provider) external view returns (bool); /** * @notice Verifies if an owner has authorized a spender for a token * @param owner The address of the token owner * @param spender The address of the spender * @param tokenId The token ID */ function checkAuthorized(address owner, address spender, uint256 tokenId) external view; /** * @notice Calculates the amount owed to a provider in a given currency * @param provider The provider's address * @param currency The currency in question * @return The owed amount */ function tokenOwed(address provider, Currency currency) external view returns (uint256); /** * @notice Calculates the currency balance changes for a given locker * @param locker The address of the locker * @param currency The currency in question * @return The net change in currency balance */ function getCurrencyDelta(address locker, Currency currency) external view returns (int256); /** * @notice Retrieves the book key for a given book ID * @param id The book ID * @return The book key */ function getBookKey(BookId id) external view returns (BookKey memory); /** * @notice This structure represents a current status for an order in the BookManager. * @param provider The provider of the order * @param open The open unit of the order * @param claimable The claimable unit of the order */ struct OrderInfo { address provider; uint64 open; uint64 claimable; } /** * @notice Provides information about an order * @param id The order ID * @return Order information including provider, open status, and claimable unit */ function getOrder(OrderId id) external view returns (OrderInfo memory); /** * @notice Retrieves the locker and caller addresses for a given lock * @param i The index of the lock * @return locker The locker's address * @return lockCaller The caller's address */ function getLock(uint256 i) external view returns (address locker, address lockCaller); /** * @notice Provides the lock data * @return The lock data including necessary numeric values */ function getLockData() external view returns (uint128, uint128); /** * @notice Returns the depth of a given book ID and tick * @param id The book ID * @param tick The tick * @return The depth of the tick */ function getDepth(BookId id, Tick tick) external view returns (uint64); /** * @notice Retrieves the highest tick for a given book ID * @param id The book ID * @return tick The highest tick */ function getHighest(BookId id) external view returns (Tick tick); /** * @notice Finds the maximum tick less than a specified tick in a book * @dev Returns `Tick.wrap(type(int24).min)` if the specified tick is the lowest * @param id The book ID * @param tick The specified tick * @return The next lower tick */ function maxLessThan(BookId id, Tick tick) external view returns (Tick); /** * @notice Checks if a book is opened * @param id The book ID * @return True if the book is opened, false otherwise */ function isOpened(BookId id) external view returns (bool); /** * @notice Checks if a book is empty * @param id The book ID * @return True if the book is empty, false otherwise */ function isEmpty(BookId id) external view returns (bool); /** * @notice Encodes a BookKey into a BookId * @param key The BookKey to encode * @return The encoded BookId */ function encodeBookKey(BookKey calldata key) external pure returns (BookId); /** * @notice Loads a value from a specific storage slot * @param slot The storage slot * @return The value in the slot */ function load(bytes32 slot) external view returns (bytes32); /** * @notice Loads a sequence of values starting from a specific slot * @param startSlot The starting slot * @param nSlot The number of slots to load * @return The sequence of values */ function load(bytes32 startSlot, uint256 nSlot) external view returns (bytes memory); /** * @notice Opens a new book * @param key The book key * @param hookData The hook data */ function open(BookKey calldata key, bytes calldata hookData) external; /** * @notice Locks a book manager function * @param locker The locker address * @param data The lock data * @return The lock return data */ function lock(address locker, bytes calldata data) external returns (bytes memory); /** * @notice This structure represents the parameters for making an order. * @param key The book key for the order * @param tick The tick for the order * @param unit The unit for the order. Times key.unitSize to get actual bid amount. * @param provider The provider for the order. The limit order service provider address to collect fees. */ struct MakeParams { BookKey key; Tick tick; uint64 unit; address provider; } /** * @notice Make a limit order * @param params The order parameters * @param hookData The hook data * @return id The order id. Returns 0 if the order is not settled * @return quoteAmount The amount of quote currency to be paid */ function make(MakeParams calldata params, bytes calldata hookData) external returns (OrderId id, uint256 quoteAmount); /** * @notice This structure represents the parameters for taking orders in the specified tick. * @param key The book key for the order * @param tick The tick for the order * @param maxUnit The max unit to take */ struct TakeParams { BookKey key; Tick tick; uint64 maxUnit; } /** * @notice Take a limit order at specific tick * @param params The order parameters * @param hookData The hook data * @return quoteAmount The amount of quote currency to be received * @return baseAmount The amount of base currency to be paid */ function take(TakeParams calldata params, bytes calldata hookData) external returns (uint256 quoteAmount, uint256 baseAmount); /** * @notice This structure represents the parameters for canceling an order. * @param id The order id for the order * @param toUnit The remaining open unit for the order after cancellation. Must not exceed the current open unit. */ struct CancelParams { OrderId id; uint64 toUnit; } /** * @notice Cancel a limit order * @param params The order parameters * @param hookData The hook data * @return canceledAmount The amount of quote currency canceled */ function cancel(CancelParams calldata params, bytes calldata hookData) external returns (uint256 canceledAmount); /** * @notice Claims an order * @param id The order ID * @param hookData The hook data * @return claimedAmount The amount claimed */ function claim(OrderId id, bytes calldata hookData) external returns (uint256 claimedAmount); /** * @notice Collects fees from a provider * @param recipient The recipient address * @param currency The currency * @return The collected amount */ function collect(address recipient, Currency currency) external returns (uint256); /** * @notice Withdraws a currency * @param currency The currency * @param to The recipient address * @param amount The amount */ function withdraw(Currency currency, address to, uint256 amount) external; /** * @notice Settles a currency * @param currency The currency * @return The settled amount */ function settle(Currency currency) external payable returns (uint256); /** * @notice Whitelists a provider * @param provider The provider address */ function whitelist(address provider) external; /** * @notice Delists a provider * @param provider The provider address */ function delist(address provider) external; /** * @notice Sets the default provider * @param newDefaultProvider The new default provider address */ function setDefaultProvider(address newDefaultProvider) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; /** * @title IERC721Permit * @notice An interface for the ERC721 permit extension */ interface IERC721Permit is IERC721 { error InvalidSignature(); error PermitExpired(); /** * @notice The EIP-712 typehash for the permit struct used by the contract */ function PERMIT_TYPEHASH() external pure returns (bytes32); /** * @notice The EIP-712 domain separator for this contract */ function DOMAIN_SEPARATOR() external view returns (bytes32); /** * @notice Approve the spender to transfer the given tokenId * @param spender The address to approve * @param tokenId The tokenId to approve * @param deadline The deadline for the signature * @param v The recovery id of the signature * @param r The r value of the signature * @param s The s value of the signature */ function permit(address spender, uint256 tokenId, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; /** * @notice Get the current nonce for a token * @param tokenId The tokenId to get the nonce for * @return The current nonce */ function nonces(uint256 tokenId) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {IBookManager} from "./IBookManager.sol"; import {OrderId} from "../libraries/OrderId.sol"; /** * @title IHooks * @notice Interface for the hooks contract */ interface IHooks { /** * @notice Hook called before opening a new book * @param sender The sender of the open transaction * @param key The key of the book being opened * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function beforeOpen(address sender, IBookManager.BookKey calldata key, bytes calldata hookData) external returns (bytes4); /** * @notice Hook called after opening a new book * @param sender The sender of the open transaction * @param key The key of the book being opened * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function afterOpen(address sender, IBookManager.BookKey calldata key, bytes calldata hookData) external returns (bytes4); /** * @notice Hook called before making a new order * @param sender The sender of the make transaction * @param params The parameters of the make transaction * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function beforeMake(address sender, IBookManager.MakeParams calldata params, bytes calldata hookData) external returns (bytes4); /** * @notice Hook called after making a new order * @param sender The sender of the make transaction * @param params The parameters of the make transaction * @param orderId The id of the order that was made * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function afterMake( address sender, IBookManager.MakeParams calldata params, OrderId orderId, bytes calldata hookData ) external returns (bytes4); /** * @notice Hook called before taking an order * @param sender The sender of the take transaction * @param params The parameters of the take transaction * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function beforeTake(address sender, IBookManager.TakeParams calldata params, bytes calldata hookData) external returns (bytes4); /** * @notice Hook called after taking an order * @param sender The sender of the take transaction * @param params The parameters of the take transaction * @param takenUnit The unit that was taken * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function afterTake( address sender, IBookManager.TakeParams calldata params, uint64 takenUnit, bytes calldata hookData ) external returns (bytes4); /** * @notice Hook called before canceling an order * @param sender The sender of the cancel transaction * @param params The parameters of the cancel transaction * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function beforeCancel(address sender, IBookManager.CancelParams calldata params, bytes calldata hookData) external returns (bytes4); /** * @notice Hook called after canceling an order * @param sender The sender of the cancel transaction * @param params The parameters of the cancel transaction * @param canceledUnit The unit that was canceled * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function afterCancel( address sender, IBookManager.CancelParams calldata params, uint64 canceledUnit, bytes calldata hookData ) external returns (bytes4); /** * @notice Hook called before claiming an order * @param sender The sender of the claim transaction * @param orderId The id of the order being claimed * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function beforeClaim(address sender, OrderId orderId, bytes calldata hookData) external returns (bytes4); /** * @notice Hook called after claiming an order * @param sender The sender of the claim transaction * @param orderId The id of the order being claimed * @param claimedUnit The unit that was claimed * @param hookData The data passed to the hook * @return Returns the function selector if the hook is successful */ function afterClaim(address sender, OrderId orderId, uint64 claimedUnit, bytes calldata hookData) external returns (bytes4); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.20; import {IBookManager} from "../interfaces/IBookManager.sol"; type BookId is uint192; library BookIdLibrary { function toId(IBookManager.BookKey memory bookKey) internal pure returns (BookId id) { bytes32 hash = keccak256(abi.encode(bookKey)); assembly { id := and(hash, 0xffffffffffffffffffffffffffffffffffffffffffffffff) } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; type Currency is address; /// @title CurrencyLibrary /// @dev This library allows for transferring and holding native tokens and ERC20 tokens library CurrencyLibrary { using CurrencyLibrary for Currency; /// @notice Thrown when a native transfer fails error NativeTransferFailed(); /// @notice Thrown when an ERC20 transfer fails error ERC20TransferFailed(); Currency public constant NATIVE = Currency.wrap(address(0)); function transfer(Currency currency, address to, uint256 amount) internal { // implementation from // https://github.com/transmissions11/solmate/blob/e8f96f25d48fe702117ce76c79228ca4f20206cb/src/utils/SafeTransferLib.sol bool success; if (currency.isNative()) { assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } if (!success) revert NativeTransferFailed(); } else { assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), currency, 0, freeMemoryPointer, 68, 0, 32) ) } if (!success) revert ERC20TransferFailed(); } } function balanceOfSelf(Currency currency) internal view returns (uint256) { if (currency.isNative()) return address(this).balance; else return IERC20(Currency.unwrap(currency)).balanceOf(address(this)); } function equals(Currency currency, Currency other) internal pure returns (bool) { return Currency.unwrap(currency) == Currency.unwrap(other); } function isNative(Currency currency) internal pure returns (bool) { return Currency.unwrap(currency) == Currency.unwrap(NATIVE); } function toId(Currency currency) internal pure returns (uint256) { return uint160(Currency.unwrap(currency)); } function fromId(uint256 id) internal pure returns (Currency) { return Currency.wrap(address(uint160(id))); } }
// SPDX-License-Identifier: - // License: https://license.sonic.market/LICENSE.pdf pragma solidity ^0.8.0; library DirtyUint64 { error DirtyUint64Error(uint256 errorCode); uint256 private constant _OVERFLOW_ERROR = 0; uint256 private constant _UNDERFLOW_ERROR = 1; function toDirtyUnsafe(uint64 cleanUint) internal pure returns (uint64 dirtyUint) { assembly { dirtyUint := add(cleanUint, 1) } } function toDirty(uint64 cleanUint) internal pure returns (uint64 dirtyUint) { assembly { dirtyUint := add(cleanUint, 1) } if (dirtyUint == 0) { revert DirtyUint64Error(_OVERFLOW_ERROR); } } function toClean(uint64 dirtyUint) internal pure returns (uint64 cleanUint) { assembly { cleanUint := sub(dirtyUint, gt(dirtyUint, 0)) } } function addClean(uint64 current, uint64 cleanUint) internal pure returns (uint64) { assembly { current := add(add(current, iszero(current)), cleanUint) } if (current < cleanUint) { revert DirtyUint64Error(_OVERFLOW_ERROR); } return current; } function addDirty(uint64 current, uint64 dirtyUint) internal pure returns (uint64) { assembly { current := sub(add(add(current, iszero(current)), add(dirtyUint, iszero(dirtyUint))), 1) } if (current < dirtyUint) { revert DirtyUint64Error(_OVERFLOW_ERROR); } return current; } function subClean(uint64 current, uint64 cleanUint) internal pure returns (uint64 ret) { assembly { current := add(current, iszero(current)) ret := sub(current, cleanUint) } if (current < ret || ret == 0) { revert DirtyUint64Error(_UNDERFLOW_ERROR); } } function subDirty(uint64 current, uint64 dirtyUint) internal pure returns (uint64 ret) { assembly { current := add(current, iszero(current)) ret := sub(add(current, 1), add(dirtyUint, iszero(dirtyUint))) } if (current < ret || ret == 0) { revert DirtyUint64Error(_UNDERFLOW_ERROR); } } function sumPackedUnsafe(uint256 packed, uint256 from, uint256 to) internal pure returns (uint64 ret) { packed = packed >> (from << 6); unchecked { for (uint256 i = from; i < to; ++i) { assembly { let element := and(packed, 0xffffffffffffffff) ret := add(ret, add(element, iszero(element))) packed := shr(64, packed) } } } assembly { ret := sub(ret, sub(to, from)) } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.20; import {Math} from "./Math.sol"; type FeePolicy is uint24; library FeePolicyLibrary { uint256 internal constant RATE_PRECISION = 10 ** 6; int256 internal constant MAX_FEE_RATE = 500000; int256 internal constant MIN_FEE_RATE = -500000; uint256 internal constant RATE_MASK = 0x7fffff; // 23 bits error InvalidFeePolicy(); function encode(bool usesQuote_, int24 rate_) internal pure returns (FeePolicy feePolicy) { if (rate_ > MAX_FEE_RATE || rate_ < MIN_FEE_RATE) { revert InvalidFeePolicy(); } uint256 mask = usesQuote_ ? 1 << 23 : 0; assembly { feePolicy := or(mask, add(and(rate_, 0xffffff), MAX_FEE_RATE)) } } function isValid(FeePolicy self) internal pure returns (bool) { int24 r = rate(self); return !(r > MAX_FEE_RATE || r < MIN_FEE_RATE); } function usesQuote(FeePolicy self) internal pure returns (bool f) { assembly { f := shr(23, self) } } function rate(FeePolicy self) internal pure returns (int24 r) { assembly { r := sub(and(self, RATE_MASK), MAX_FEE_RATE) } } function calculateFee(FeePolicy self, uint256 amount, bool reverseRounding) internal pure returns (int256 fee) { int24 r = rate(self); bool positive = r > 0; uint256 absRate; unchecked { absRate = uint256(uint24(positive ? r : -r)); } // @dev absFee must be less than type(int256).max uint256 absFee = Math.divide(amount * absRate, RATE_PRECISION, reverseRounding ? !positive : positive); fee = positive ? int256(absFee) : -int256(absFee); } function calculateOriginalAmount(FeePolicy self, uint256 amount, bool reverseFee) internal pure returns (uint256 originalAmount) { int24 r = rate(self); uint256 divider; assembly { if reverseFee { r := sub(0, r) } divider := add(RATE_PRECISION, r) } originalAmount = Math.divide(amount * RATE_PRECISION, divider, reverseFee); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; library Math { function divide(uint256 a, uint256 b, bool roundingUp) internal pure returns (uint256 ret) { // In the OrderBook contract code, b is never zero. assembly { ret := add(div(a, b), and(gt(mod(a, b), 0), roundingUp)) } } /// @dev Returns `ln(x)`, denominated in `WAD`. /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln function lnWad(int256 x) internal pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // We want to convert `x` from `10**18` fixed point to `2**96` fixed point. // We do this by multiplying by `2**96 / 10**18`. But since // `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here // and add `ln(2**96 / 10**18)` at the end. // Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`. r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // We place the check here for more optimal stack operations. if iszero(sgt(x, 0)) { mstore(0x00, 0x1615e638) // `LnWadUndefined()`. revert(0x1c, 0x04) } // forgefmt: disable-next-item r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)) // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) x := shr(159, shl(r, x)) // Evaluate using a (8, 8)-term rational approximation. // `p` is made monic, we will multiply by a scale factor later. // forgefmt: disable-next-item let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir. sar(96, mul(add(43456485725739037958740375743393, sar(96, mul(add(24828157081833163892658089445524, sar(96, mul(add(3273285459638523848632254066296, x), x))), x))), x)), 11111509109440967052023855526967) p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857) p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526) p := sub(mul(p, x), shl(96, 795164235651350426258249787498)) // We leave `p` in `2**192` basis so we don't need to scale it back up for the division. // `q` is monic by convention. let q := add(5573035233440673466300451813936, x) q := add(71694874799317883764090561454958, sar(96, mul(x, q))) q := add(283447036172924575727196451306956, sar(96, mul(x, q))) q := add(401686690394027663651624208769553, sar(96, mul(x, q))) q := add(204048457590392012362485061816622, sar(96, mul(x, q))) q := add(31853899698501571402653359427138, sar(96, mul(x, q))) q := add(909429971244387300277376558375, sar(96, mul(x, q))) // `p / q` is in the range `(0, 0.125) * 2**96`. // Finalization, we need to: // - Multiply by the scale factor `s = 5.549…`. // - Add `ln(2**96 / 10**18)`. // - Add `k * ln(2)`. // - Multiply by `10**18 / 2**96 = 5**18 >> 78`. // The q polynomial is known not to have zeros in the domain. // No scaling required because p is already `2**96` too large. p := sdiv(p, q) // Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`. p := mul(1677202110996718588342820967067443963516166, p) // Add `ln(2) * k * 5**18 * 2**192`. // forgefmt: disable-next-item p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p) // Base conversion: mul `2**96 / (5**18 * 2**192)`. r := sdiv(p, 302231454903657293676544000000000000000000) } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import {Tick} from "./Tick.sol"; import {BookId} from "./BookId.sol"; type OrderId is uint256; library OrderIdLibrary { /** * @dev Encode the order id. * @param bookId The book id. * @param tick The tick. * @param index The index. * @return id The order id. */ function encode(BookId bookId, Tick tick, uint40 index) internal pure returns (OrderId id) { // @dev If we just use tick at the assembly code, the code will convert tick into bytes32. // e.g. When index == -2, the shifted value( shl(40, tick) ) will be // 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000000 instead of 0xfffffffe0000000000 // Therefore, we have to safely cast tick into uint256 first. uint256 _tick = uint256(uint24(Tick.unwrap(tick))); assembly { id := add(index, add(shl(40, _tick), shl(64, bookId))) } } function decode(OrderId id) internal pure returns (BookId bookId, Tick tick, uint40 index) { assembly { bookId := shr(64, id) tick := and(shr(40, id), 0xffffff) index := and(id, 0xffffffffff) } } function getBookId(OrderId id) internal pure returns (BookId bookId) { assembly { bookId := shr(64, id) } } function getTick(OrderId id) internal pure returns (Tick tick) { assembly { tick := and(shr(40, id), 0xffffff) } } function getIndex(OrderId id) internal pure returns (uint40 index) { assembly { index := and(id, 0xffffffffff) } } }
// SPDX-License-Identifier: - // License: https://license.sonic.market/LICENSE.pdf pragma solidity ^0.8.0; library PackedUint256 { error PackedUint256Error(uint256 errorCode); uint256 private constant _UINT8_INDEX_ERROR = 0; uint256 private constant _UINT16_INDEX_ERROR = 1; uint256 private constant _UINT32_INDEX_ERROR = 2; uint256 private constant _UINT64_INDEX_ERROR = 3; uint256 private constant _MAX_UINT64 = type(uint64).max; uint256 private constant _MAX_UINT32 = type(uint32).max; uint256 private constant _MAX_UINT16 = type(uint16).max; uint256 private constant _MAX_UINT8 = type(uint8).max; function get8Unsafe(uint256 packed, uint256 index) internal pure returns (uint8 ret) { assembly { ret := and(shr(shl(3, index), packed), 0xff) } } function get8(uint256 packed, uint256 index) internal pure returns (uint8 ret) { if (index > 31) { revert PackedUint256Error(_UINT8_INDEX_ERROR); } assembly { ret := and(shr(shl(3, index), packed), 0xff) } } function get16Unsafe(uint256 packed, uint256 index) internal pure returns (uint16 ret) { assembly { ret := and(shr(shl(4, index), packed), 0xffff) } } function get16(uint256 packed, uint256 index) internal pure returns (uint16 ret) { if (index > 15) { revert PackedUint256Error(_UINT16_INDEX_ERROR); } assembly { ret := and(shr(shl(4, index), packed), 0xffff) } } function get32Unsafe(uint256 packed, uint256 index) internal pure returns (uint32 ret) { assembly { ret := and(shr(shl(5, index), packed), 0xffffffff) } } function get32(uint256 packed, uint256 index) internal pure returns (uint32 ret) { if (index > 7) { revert PackedUint256Error(_UINT32_INDEX_ERROR); } assembly { ret := and(shr(shl(5, index), packed), 0xffffffff) } } function get64Unsafe(uint256 packed, uint256 index) internal pure returns (uint64 ret) { assembly { ret := and(shr(shl(6, index), packed), 0xffffffffffffffff) } } function get64(uint256 packed, uint256 index) internal pure returns (uint64 ret) { if (index > 3) { revert PackedUint256Error(_UINT64_INDEX_ERROR); } assembly { ret := and(shr(shl(6, index), packed), 0xffffffffffffffff) } } function add8Unsafe(uint256 packed, uint256 index, uint8 value) internal pure returns (uint256 ret) { assembly { ret := add(packed, shl(shl(3, index), and(value, 0xff))) } } function add8(uint256 packed, uint256 index, uint8 value) internal pure returns (uint256 ret) { if (index > 31) { revert PackedUint256Error(_UINT8_INDEX_ERROR); } uint8 current = get8Unsafe(packed, index); current += value; ret = update8Unsafe(packed, index, current); } function add16Unsafe(uint256 packed, uint256 index, uint16 value) internal pure returns (uint256 ret) { assembly { ret := add(packed, shl(shl(4, index), and(value, 0xffff))) } } function add16(uint256 packed, uint256 index, uint16 value) internal pure returns (uint256 ret) { if (index > 15) { revert PackedUint256Error(_UINT16_INDEX_ERROR); } uint16 current = get16Unsafe(packed, index); current += value; ret = update16Unsafe(packed, index, current); } function add32Unsafe(uint256 packed, uint256 index, uint32 value) internal pure returns (uint256 ret) { assembly { ret := add(packed, shl(shl(5, index), and(value, 0xffffffff))) } } function add32(uint256 packed, uint256 index, uint32 value) internal pure returns (uint256 ret) { if (index > 7) { revert PackedUint256Error(_UINT32_INDEX_ERROR); } uint32 current = get32Unsafe(packed, index); current += value; ret = update32Unsafe(packed, index, current); } function add64Unsafe(uint256 packed, uint256 index, uint64 value) internal pure returns (uint256 ret) { assembly { ret := add(packed, shl(shl(6, index), and(value, 0xffffffffffffffff))) } } function add64(uint256 packed, uint256 index, uint64 value) internal pure returns (uint256 ret) { if (index > 3) { revert PackedUint256Error(_UINT64_INDEX_ERROR); } uint64 current = get64Unsafe(packed, index); current += value; ret = update64Unsafe(packed, index, current); } function sub8Unsafe(uint256 packed, uint256 index, uint8 value) internal pure returns (uint256 ret) { assembly { ret := sub(packed, shl(shl(3, index), and(value, 0xff))) } } function sub8(uint256 packed, uint256 index, uint8 value) internal pure returns (uint256 ret) { if (index > 31) { revert PackedUint256Error(_UINT8_INDEX_ERROR); } uint8 current = get8Unsafe(packed, index); current -= value; ret = update8Unsafe(packed, index, current); } function sub16Unsafe(uint256 packed, uint256 index, uint16 value) internal pure returns (uint256 ret) { assembly { ret := sub(packed, shl(shl(4, index), and(value, 0xffff))) } } function sub16(uint256 packed, uint256 index, uint16 value) internal pure returns (uint256 ret) { if (index > 15) { revert PackedUint256Error(_UINT16_INDEX_ERROR); } uint16 current = get16Unsafe(packed, index); current -= value; ret = update16Unsafe(packed, index, current); } function sub32Unsafe(uint256 packed, uint256 index, uint32 value) internal pure returns (uint256 ret) { assembly { ret := sub(packed, shl(shl(5, index), and(value, 0xffffffff))) } } function sub32(uint256 packed, uint256 index, uint32 value) internal pure returns (uint256 ret) { if (index > 7) { revert PackedUint256Error(_UINT32_INDEX_ERROR); } uint32 current = get32Unsafe(packed, index); current -= value; ret = update32Unsafe(packed, index, current); } function sub64Unsafe(uint256 packed, uint256 index, uint64 value) internal pure returns (uint256 ret) { assembly { ret := sub(packed, shl(shl(6, index), and(value, 0xffffffffffffffff))) } } function sub64(uint256 packed, uint256 index, uint64 value) internal pure returns (uint256 ret) { if (index > 3) { revert PackedUint256Error(_UINT64_INDEX_ERROR); } uint64 current = get64Unsafe(packed, index); current -= value; ret = update64Unsafe(packed, index, current); } function update8Unsafe(uint256 packed, uint256 index, uint8 value) internal pure returns (uint256 ret) { unchecked { index = index << 3; packed = packed - (packed & (_MAX_UINT8 << index)); } assembly { ret := add(packed, shl(index, and(value, 0xff))) } } function update8(uint256 packed, uint256 index, uint8 value) internal pure returns (uint256 ret) { if (index > 31) { revert PackedUint256Error(_UINT8_INDEX_ERROR); } unchecked { index = index << 3; packed = packed - (packed & (_MAX_UINT8 << index)); } assembly { ret := add(packed, shl(index, and(value, 0xff))) } } function update16Unsafe(uint256 packed, uint256 index, uint16 value) internal pure returns (uint256 ret) { unchecked { index = index << 4; packed = packed - (packed & (_MAX_UINT16 << index)); } assembly { ret := add(packed, shl(index, and(value, 0xffff))) } } function update16(uint256 packed, uint256 index, uint16 value) internal pure returns (uint256 ret) { if (index > 15) { revert PackedUint256Error(_UINT16_INDEX_ERROR); } unchecked { index = index << 4; packed = packed - (packed & (_MAX_UINT16 << index)); } assembly { ret := add(packed, shl(index, and(value, 0xffff))) } } function update32Unsafe(uint256 packed, uint256 index, uint32 value) internal pure returns (uint256 ret) { unchecked { index = index << 5; packed = packed - (packed & (_MAX_UINT32 << index)); } assembly { ret := add(packed, shl(index, and(value, 0xffffffff))) } } function update32(uint256 packed, uint256 index, uint32 value) internal pure returns (uint256 ret) { if (index > 7) { revert PackedUint256Error(_UINT32_INDEX_ERROR); } unchecked { index = index << 5; packed = packed - (packed & (_MAX_UINT32 << index)); } assembly { ret := add(packed, shl(index, and(value, 0xffffffff))) } } function update64Unsafe(uint256 packed, uint256 index, uint64 value) internal pure returns (uint256 ret) { unchecked { index = index << 6; packed = packed - (packed & (_MAX_UINT64 << index)); } assembly { ret := add(packed, shl(index, and(value, 0xffffffffffffffff))) } } function update64(uint256 packed, uint256 index, uint64 value) internal pure returns (uint256 ret) { if (index > 3) { revert PackedUint256Error(_UINT64_INDEX_ERROR); } unchecked { index = index << 6; packed = packed - (packed & (_MAX_UINT64 << index)); } assembly { ret := add(packed, shl(index, and(value, 0xffffffffffffffff))) } } function total32(uint256 packed) internal pure returns (uint256) { unchecked { uint256 ret = _MAX_UINT32 & packed; for (uint256 i = 0; i < 7; ++i) { packed = packed >> 32; ret += _MAX_UINT32 & packed; } return ret; } } function total64(uint256 packed) internal pure returns (uint256) { unchecked { uint256 ret = _MAX_UINT64 & packed; for (uint256 i = 0; i < 3; ++i) { packed = packed >> 64; ret += _MAX_UINT64 & packed; } return ret; } } function sum32(uint256 packed, uint256 from, uint256 to) internal pure returns (uint256) { unchecked { packed = packed >> (from << 5); uint256 ret = 0; for (uint256 i = from; i < to; ++i) { ret += _MAX_UINT32 & packed; packed = packed >> 32; } return ret; } } function sum64(uint256 packed, uint256 from, uint256 to) internal pure returns (uint256) { unchecked { packed = packed >> (from << 6); uint256 ret = 0; for (uint256 i = from; i < to; ++i) { ret += _MAX_UINT64 & packed; packed = packed >> 64; } return ret; } } }
// SPDX-License-Identifier: - // License: https://license.sonic.market/LICENSE.pdf pragma solidity ^0.8.0; import "./PackedUint256.sol"; import "./DirtyUint64.sol"; /** * 🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲 * * Segmented Segment Tree * by Sonic Market * * ____________/\\\_______________/\\\\\____________/\\\____ * __________/\\\\\___________/\\\\////___________/\\\\\____ * ________/\\\/\\\________/\\\///______________/\\\/\\\____ * ______/\\\/\/\\\______/\\\\\\\\\\\_________/\\\/\/\\\____ * ____/\\\/__\/\\\_____/\\\\///////\\\_____/\\\/__\/\\\____ * __/\\\\\\\\\\\\\\\\_\/\\\______\//\\\__/\\\\\\\\\\\\\\\\_ * _\///////////\\\//__\//\\\______/\\\__\///////////\\\//__ * ___________\/\\\_____\///\\\\\\\\\/_____________\/\\\____ * ___________\///________\/////////_______________\///_____ * * 4 Layers of 64-bit nodes, hence 464 * * 🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲 */ library SegmentedSegmentTree { using PackedUint256 for uint256; using DirtyUint64 for uint64; error SegmentedSegmentTreeError(uint256 errorCode); uint256 private constant _INDEX_ERROR = 0; uint256 private constant _OVERFLOW_ERROR = 1; // uint8 private constant _R = 2; // There are `2` root node groups // uint8 private constant _C = 4; // There are `4` children (each child is a node group of its own) for each node uint8 private constant _L = 4; // There are `4` layers of node groups uint256 private constant _P = 4; // uint256 / uint64 = `4` uint256 private constant _P_M = 3; // % 4 = & `3` uint256 private constant _P_P = 2; // 2 ** `2` = 4 uint256 private constant _N_P = 4; // C * P = 2 ** `4` uint256 private constant _MAX_NODES = 2 ** 15; // (R * P) * ((C * P) ** (L - 1)) = `32768` uint256 private constant _MAX_NODES_P_MINUS_ONE = 14; // MAX_NODES / R = 2 ** `14` struct Core { mapping(uint256 => uint256)[_L] layers; } struct LayerIndex { uint256 group; uint256 node; } function get(Core storage core, uint256 index) internal view returns (uint64 ret) { if (index >= _MAX_NODES) { revert SegmentedSegmentTreeError(_INDEX_ERROR); } unchecked { ret = core.layers[_L - 1][index >> _P_P].get64(index & _P_M).toClean(); } } function total(Core storage core) internal view returns (uint64) { return DirtyUint64.sumPackedUnsafe(core.layers[0][0], 0, _P) + DirtyUint64.sumPackedUnsafe(core.layers[0][1], 0, _P); } function query(Core storage core, uint256 left, uint256 right) internal view returns (uint64 sum) { if (left == right) { return 0; } // right should be greater than left if (left >= right) { revert SegmentedSegmentTreeError(_INDEX_ERROR); } if (right > _MAX_NODES) { revert SegmentedSegmentTreeError(_INDEX_ERROR); } LayerIndex[] memory leftIndices = _getLayerIndices(left); LayerIndex[] memory rightIndices = _getLayerIndices(right); uint256 ret; uint256 deficit; unchecked { uint256 leftNodeIndex; uint256 rightNodeIndex; for (uint256 l = _L - 1;; --l) { LayerIndex memory leftIndex = leftIndices[l]; LayerIndex memory rightIndex = rightIndices[l]; leftNodeIndex += leftIndex.node; rightNodeIndex += rightIndex.node; if (rightIndex.group == leftIndex.group) { ret += DirtyUint64.sumPackedUnsafe(core.layers[l][leftIndex.group], leftNodeIndex, rightNodeIndex); break; } if (rightIndex.group - leftIndex.group < 4) { ret += DirtyUint64.sumPackedUnsafe(core.layers[l][leftIndex.group], leftNodeIndex, _P); ret += DirtyUint64.sumPackedUnsafe(core.layers[l][rightIndex.group], 0, rightNodeIndex); for (uint256 group = leftIndex.group + 1; group < rightIndex.group; group++) { ret += DirtyUint64.sumPackedUnsafe(core.layers[l][group], 0, _P); } break; } if (leftIndex.group % 4 == 0) { deficit += DirtyUint64.sumPackedUnsafe(core.layers[l][leftIndex.group], 0, leftNodeIndex); leftNodeIndex = 0; } else if (leftIndex.group % 4 == 1) { deficit += DirtyUint64.sumPackedUnsafe(core.layers[l][leftIndex.group - 1], 0, _P); deficit += DirtyUint64.sumPackedUnsafe(core.layers[l][leftIndex.group], 0, leftNodeIndex); leftNodeIndex = 0; } else if (leftIndex.group % 4 == 2) { ret += DirtyUint64.sumPackedUnsafe(core.layers[l][leftIndex.group], leftNodeIndex, _P); ret += DirtyUint64.sumPackedUnsafe(core.layers[l][leftIndex.group + 1], 0, _P); leftNodeIndex = 1; } else { ret += DirtyUint64.sumPackedUnsafe(core.layers[l][leftIndex.group], leftNodeIndex, _P); leftNodeIndex = 1; } if (rightIndex.group % 4 == 0) { ret += DirtyUint64.sumPackedUnsafe(core.layers[l][rightIndex.group], 0, rightNodeIndex); rightNodeIndex = 0; } else if (rightIndex.group % 4 == 1) { ret += DirtyUint64.sumPackedUnsafe(core.layers[l][rightIndex.group - 1], 0, _P); ret += DirtyUint64.sumPackedUnsafe(core.layers[l][rightIndex.group], 0, rightNodeIndex); rightNodeIndex = 0; } else if (rightIndex.group % 4 == 2) { deficit += DirtyUint64.sumPackedUnsafe(core.layers[l][rightIndex.group], rightNodeIndex, _P); deficit += DirtyUint64.sumPackedUnsafe(core.layers[l][rightIndex.group + 1], 0, _P); rightNodeIndex = 1; } else { deficit += DirtyUint64.sumPackedUnsafe(core.layers[l][rightIndex.group], rightNodeIndex, _P); rightNodeIndex = 1; } } ret -= deficit; } sum = uint64(ret); } function update(Core storage core, uint256 index, uint64 value) internal returns (uint64 replaced) { if (index >= _MAX_NODES) { revert SegmentedSegmentTreeError(_INDEX_ERROR); } LayerIndex[] memory indices = _getLayerIndices(index); unchecked { LayerIndex memory bottomIndex = indices[_L - 1]; replaced = core.layers[_L - 1][bottomIndex.group].get64Unsafe(bottomIndex.node).toClean(); if (replaced >= value) { uint64 diff = replaced - value; for (uint256 l = 0; l < _L; ++l) { LayerIndex memory layerIndex = indices[l]; uint256 node = core.layers[l][layerIndex.group]; core.layers[l][layerIndex.group] = node.update64(layerIndex.node, node.get64(layerIndex.node).subClean(diff)); } } else { uint64 diff = value - replaced; if (total(core) > type(uint64).max - diff) revert SegmentedSegmentTreeError(_OVERFLOW_ERROR); for (uint256 l = 0; l < _L; ++l) { LayerIndex memory layerIndex = indices[l]; uint256 node = core.layers[l][layerIndex.group]; core.layers[l][layerIndex.group] = node.update64(layerIndex.node, node.get64(layerIndex.node).addClean(diff)); } } } } function _getLayerIndices(uint256 index) private pure returns (LayerIndex[] memory) { unchecked { LayerIndex[] memory indices = new LayerIndex[](_L); uint256 shifter = _MAX_NODES_P_MINUS_ONE; for (uint256 l = 0; l < _L; ++l) { indices[l] = LayerIndex({group: index >> shifter, node: (index >> (shifter - _P_P)) & _P_M}); shifter = shifter - _N_P; } return indices; } } } /* * Segmented Segment Tree is a Segment Tree * that has been compressed so that `C` nodes * are compressed into a single uint256. * * Each node in a non-leaf node group is the sum of the * total sum of each child node group that it represents. * Each non-leaf node represents `E` node groups. * * A node group consists of `S` uint256. * * By expressing the index in `N` notation, * we can find the index in each respective layer * * S: Size of each node group * C: Compression Coefficient * E: Expansion Coefficient * L: Number of Layers * N: Notation, S * C * E * * `E` will not be considered for this version of the implementation. (E = 2) */
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; library SignificantBit { // http://supertech.csail.mit.edu/papers/debruijn.pdf uint256 internal constant DEBRUIJN_SEQ = 0x818283848586878898A8B8C8D8E8F929395969799A9B9D9E9FAAEB6BEDEEFF; bytes internal constant DEBRUIJN_INDEX = hex"0001020903110a19042112290b311a3905412245134d2a550c5d32651b6d3a7506264262237d468514804e8d2b95569d0d495ea533a966b11c886eb93bc176c9071727374353637324837e9b47af86c7155181ad4fd18ed32c9096db57d59ee30e2e4a6a5f92a6be3498aae067ddb2eb1d5989b56fd7baf33ca0c2ee77e5caf7ff0810182028303840444c545c646c7425617c847f8c949c48a4a8b087b8c0c816365272829aaec650acd0d28fdad4e22d6991bd97dfdcea58b4d6f29fede4f6fe0f1f2f3f4b5b6b607b8b93a3a7b7bf357199c5abcfd9e168bcdee9b3f1ecf5fd1e3e5a7a8aa2b670c4ced8bbe8f0f4fc3d79a1c3cde7effb78cce6facbf9f8"; /** * @notice Finds the index of the least significant bit. * @param x The value to compute the least significant bit for. Must be a non-zero value. * @return ret The index of the least significant bit. */ function leastSignificantBit(uint256 x) internal pure returns (uint8) { require(x > 0); uint256 index; assembly { index := shr(248, mul(and(x, add(not(x), 1)), DEBRUIJN_SEQ)) } return uint8(DEBRUIJN_INDEX[index]); // can optimize with CODECOPY opcode } function mostSignificantBit(uint256 x) internal pure returns (uint8 msb) { require(x > 0); assembly { let f := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) msb := or(msb, f) x := shr(f, x) f := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF)) msb := or(msb, f) x := shr(f, x) f := shl(5, gt(x, 0xFFFFFFFF)) msb := or(msb, f) x := shr(f, x) f := shl(4, gt(x, 0xFFFF)) msb := or(msb, f) x := shr(f, x) f := shl(3, gt(x, 0xFF)) msb := or(msb, f) x := shr(f, x) f := shl(2, gt(x, 0xF)) msb := or(msb, f) x := shr(f, x) f := shl(1, gt(x, 0x3)) msb := or(msb, f) x := shr(f, x) f := gt(x, 0x1) msb := or(msb, f) } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.20; import {Math} from "./Math.sol"; type Tick is int24; library TickLibrary { using Math for *; using TickLibrary for Tick; error InvalidTick(); error InvalidPrice(); error TickOverflow(); int24 internal constant MAX_TICK = 2 ** 19 - 1; int24 internal constant MIN_TICK = -MAX_TICK; uint256 internal constant MIN_PRICE = 1350587; uint256 internal constant MAX_PRICE = 4647684107270898330752324302845848816923571339324334; uint256 private constant _R0 = 0xfff97272373d413259a46990; uint256 private constant _R1 = 0xfff2e50f5f656932ef12357c; uint256 private constant _R2 = 0xffe5caca7e10e4e61c3624ea; uint256 private constant _R3 = 0xffcb9843d60f6159c9db5883; uint256 private constant _R4 = 0xff973b41fa98c081472e6896; uint256 private constant _R5 = 0xff2ea16466c96a3843ec78b3; uint256 private constant _R6 = 0xfe5dee046a99a2a811c461f1; uint256 private constant _R7 = 0xfcbe86c7900a88aedcffc83b; uint256 private constant _R8 = 0xf987a7253ac413176f2b074c; uint256 private constant _R9 = 0xf3392b0822b70005940c7a39; uint256 private constant _R10 = 0xe7159475a2c29b7443b29c7f; uint256 private constant _R11 = 0xd097f3bdfd2022b8845ad8f7; uint256 private constant _R12 = 0xa9f746462d870fdf8a65dc1f; uint256 private constant _R13 = 0x70d869a156d2a1b890bb3df6; uint256 private constant _R14 = 0x31be135f97d08fd981231505; uint256 private constant _R15 = 0x9aa508b5b7a84e1c677de54; uint256 private constant _R16 = 0x5d6af8dedb81196699c329; uint256 private constant _R17 = 0x2216e584f5fa1ea92604; uint256 private constant _R18 = 0x48a170391f7dc42; uint256 private constant _R19 = 0x149b34; function validateTick(Tick tick) internal pure { if (Tick.unwrap(tick) > MAX_TICK || Tick.unwrap(tick) < MIN_TICK) revert InvalidTick(); } modifier validatePrice(uint256 price) { if (price > MAX_PRICE || price < MIN_PRICE) revert InvalidPrice(); _; } function fromPrice(uint256 price) internal pure validatePrice(price) returns (Tick) { unchecked { int24 tick = int24((int256(price).lnWad() * 42951820407860) / 2 ** 128); if (toPrice(Tick.wrap(tick)) > price) return Tick.wrap(tick - 1); return Tick.wrap(tick); } } function toPrice(Tick tick) internal pure returns (uint256 price) { validateTick(tick); int24 tickValue = Tick.unwrap(tick); uint256 absTick = uint24(tickValue < 0 ? -tickValue : tickValue); unchecked { if (absTick & 0x1 != 0) price = _R0; else price = 1 << 96; if (absTick & 0x2 != 0) price = (price * _R1) >> 96; if (absTick & 0x4 != 0) price = (price * _R2) >> 96; if (absTick & 0x8 != 0) price = (price * _R3) >> 96; if (absTick & 0x10 != 0) price = (price * _R4) >> 96; if (absTick & 0x20 != 0) price = (price * _R5) >> 96; if (absTick & 0x40 != 0) price = (price * _R6) >> 96; if (absTick & 0x80 != 0) price = (price * _R7) >> 96; if (absTick & 0x100 != 0) price = (price * _R8) >> 96; if (absTick & 0x200 != 0) price = (price * _R9) >> 96; if (absTick & 0x400 != 0) price = (price * _R10) >> 96; if (absTick & 0x800 != 0) price = (price * _R11) >> 96; if (absTick & 0x1000 != 0) price = (price * _R12) >> 96; if (absTick & 0x2000 != 0) price = (price * _R13) >> 96; if (absTick & 0x4000 != 0) price = (price * _R14) >> 96; if (absTick & 0x8000 != 0) price = (price * _R15) >> 96; if (absTick & 0x10000 != 0) price = (price * _R16) >> 96; if (absTick & 0x20000 != 0) price = (price * _R17) >> 96; if (absTick & 0x40000 != 0) price = (price * _R18) >> 96; } if (tickValue > 0) price = 0x1000000000000000000000000000000000000000000000000 / price; } function gt(Tick a, Tick b) internal pure returns (bool) { return Tick.unwrap(a) > Tick.unwrap(b); } function baseToQuote(Tick tick, uint256 base, bool roundingUp) internal pure returns (uint256) { return Math.divide((base * tick.toPrice()), 1 << 96, roundingUp); } function quoteToBase(Tick tick, uint256 quote, bool roundingUp) internal pure returns (uint256) { // @dev quote = unit(uint64) * unitSize(uint64) < 2^96 // We don't need to check overflow here return Math.divide(quote << 96, tick.toPrice(), roundingUp); } }
// SPDX-License-Identifier: - // License: https://license.sonic.market/LICENSE.pdf pragma solidity ^0.8.0; import {SignificantBit} from "./SignificantBit.sol"; import {Tick} from "./Tick.sol"; library TickBitmap { using SignificantBit for uint256; error EmptyError(); error AlreadyExistsError(); uint256 public constant B0_BITMAP_KEY = uint256(keccak256("TickBitmap")) + 1; uint256 public constant MAX_UINT_256_MINUS_1 = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe; function has(mapping(uint256 => uint256) storage self, Tick tick) internal view returns (bool) { (uint256 b0b1, uint256 b2) = _split(tick); uint256 mask = 1 << b2; return self[b0b1] & mask == mask; } function isEmpty(mapping(uint256 => uint256) storage self) internal view returns (bool) { return self[B0_BITMAP_KEY] == 0; } function _split(Tick tick) private pure returns (uint256 b0b1, uint256 b2) { assembly { let value := add(not(tick), 0x800000) b0b1 := shr(8, and(value, 0xffff00)) b2 := and(value, 0xff) } } function highest(mapping(uint256 => uint256) storage self) internal view returns (Tick) { if (isEmpty(self)) revert EmptyError(); uint256 b0 = self[B0_BITMAP_KEY].leastSignificantBit(); uint256 b0b1 = (b0 << 8) | (self[~b0].leastSignificantBit()); uint256 b2 = self[b0b1].leastSignificantBit(); return _toTick((b0b1 << 8) | b2); } function set(mapping(uint256 => uint256) storage self, Tick tick) internal { (uint256 b0b1, uint256 b2) = _split(tick); uint256 mask = 1 << b2; uint256 b2Bitmap = self[b0b1]; if (b2Bitmap & mask > 0) revert AlreadyExistsError(); self[b0b1] = b2Bitmap | mask; if (b2Bitmap == 0) { mask = 1 << (b0b1 & 0xff); uint256 b1BitmapKey = ~(b0b1 >> 8); uint256 b1Bitmap = self[b1BitmapKey]; self[b1BitmapKey] = b1Bitmap | mask; if (b1Bitmap == 0) self[B0_BITMAP_KEY] = self[B0_BITMAP_KEY] | (1 << ~b1BitmapKey); } } function clear(mapping(uint256 => uint256) storage self, Tick tick) internal { (uint256 b0b1, uint256 b2) = _split(tick); uint256 mask = 1 << b2; uint256 b2Bitmap = self[b0b1]; self[b0b1] = b2Bitmap & (~mask); if (b2Bitmap == mask) { mask = 1 << (b0b1 & 0xff); uint256 b1BitmapKey = ~(b0b1 >> 8); uint256 b1Bitmap = self[b1BitmapKey]; self[b1BitmapKey] = b1Bitmap & (~mask); if (mask == b1Bitmap) { mask = 1 << (~b1BitmapKey); self[B0_BITMAP_KEY] = self[B0_BITMAP_KEY] & (~mask); } } } function maxLessThan(mapping(uint256 => uint256) storage self, Tick tick) internal view returns (Tick) { (uint256 b0b1, uint256 b2) = _split(tick); uint256 b2Bitmap = (MAX_UINT_256_MINUS_1 << b2) & self[b0b1]; if (b2Bitmap == 0) { uint256 b0 = b0b1 >> 8; uint256 b1Bitmap = (MAX_UINT_256_MINUS_1 << (b0b1 & 0xff)) & self[~b0]; if (b1Bitmap == 0) { uint256 b0Bitmap = (MAX_UINT_256_MINUS_1 << b0) & self[B0_BITMAP_KEY]; if (b0Bitmap == 0) return Tick.wrap(type(int24).min); b0 = b0Bitmap.leastSignificantBit(); b1Bitmap = self[~b0]; } b0b1 = (b0 << 8) | b1Bitmap.leastSignificantBit(); b2Bitmap = self[b0b1]; } b2 = b2Bitmap.leastSignificantBit(); return _toTick((b0b1 << 8) | b2); } function _toTick(uint256 raw) private pure returns (Tick t) { assembly { t := and(not(sub(raw, 0x800000)), 0xffffff) } } }
// SPDX-License-Identifier: - // License: https://license.sonic.market/LICENSE.pdf pragma solidity ^0.8.20; import {DirtyUint64} from "./DirtyUint64.sol"; import {PackedUint256} from "./PackedUint256.sol"; import {Tick} from "./Tick.sol"; library TotalClaimableMap { using DirtyUint64 for uint64; using PackedUint256 for uint256; // @dev n should be less than type(uint64).max due to the dirty storage logic. function add(mapping(uint24 => uint256) storage self, Tick tick, uint64 n) internal { (uint24 groupIndex, uint8 elementIndex) = _splitTick(tick); uint256 group = self[groupIndex]; // @notice Be aware of dirty storage add logic self[groupIndex] = group.update64Unsafe( elementIndex, // elementIndex < 4 group.get64Unsafe(elementIndex).addClean(n) ); } function sub(mapping(uint24 => uint256) storage self, Tick tick, uint64 n) internal { (uint24 groupIndex, uint8 elementIndex) = _splitTick(tick); self[groupIndex] = self[groupIndex].sub64Unsafe(elementIndex, n); } function get(mapping(uint24 => uint256) storage self, Tick tick) internal view returns (uint64) { (uint24 groupIndex, uint8 elementIndex) = _splitTick(tick); return self[groupIndex].get64Unsafe(elementIndex).toClean(); } function _splitTick(Tick tick) internal pure returns (uint24 groupIndex, uint8 elementIndex) { uint256 casted = uint24(Tick.unwrap(tick)); assembly { groupIndex := shr(2, casted) // div 4 elementIndex := and(casted, 3) // mod 4 } } }
{ "evmVersion": "cancun", "optimizer": { "enabled": true, "runs": 1000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"AlreadyExistsError","type":"error"},{"inputs":[],"name":"BookAlreadyOpened","type":"error"},{"inputs":[],"name":"BookNotOpened","type":"error"},{"inputs":[{"internalType":"uint64","name":"maxCancelableUnit","type":"uint64"}],"name":"CancelFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"DirtyUint64Error","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"PackedUint256Error","type":"error"},{"inputs":[],"name":"QueueReplaceFailed","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorCode","type":"uint256"}],"name":"SegmentedSegmentTreeError","type":"error"},{"inputs":[],"name":"ZeroUnit","type":"error"}]
Contract Creation Code
6118ef610034600b8282823980515f1a607314602857634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040526004361061007a575f3560e01c8063ab8a7e3f11610058578063ab8a7e3f1461010e578063c49d26211461012f578063ffa0afb51461014e575f80fd5b8063329b4a011461007e5780633ac502c1146100af578063a151a7e1146100ef575b5f80fd5b61009161008c366004611567565b610183565b60405167ffffffffffffffff90911681526020015b60405180910390f35b8180156100ba575f80fd5b506100ce6100c93660046115c5565b61025e565b6040805167ffffffffffffffff9384168152929091166020830152016100a6565b8180156100fa575f80fd5b506100916101093660046115f0565b61040b565b818015610119575f80fd5b5061012d610128366004611622565b610463565b005b81801561013a575f80fd5b50610091610149366004611567565b6104bf565b818015610159575f80fd5b5061016d61016836600461166b565b610525565b60405164ffffffffff90911681526020016100a6565b5f80610190858585610776565b602090810151600286900b5f90815260038801909252604090912060048101549192509064ffffffffff85166180000110156101ce57509050610257565b5f6101dc60058801876107ca565b90505f6101f0838764ffffffffff1661081f565b90508167ffffffffffffffff1684820367ffffffffffffffff161061021b575f945050505050610257565b8167ffffffffffffffff168167ffffffffffffffff16116102425783945050505050610257565b8381038203945050505050610257565b505050505b9392505050565b602882901c62ffffff16600281900b5f908152600385016020526040812060048101805492938493909264ffffffffff8816929091859190849081106102a6576102a66116b9565b5f918252602082200154600160a01b900467ffffffffffffffff1691506102ce8a8686610183565b90506102da81896116e1565b95508567ffffffffffffffff168267ffffffffffffffff16101561033d576040517fc332559a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8284031660048201526024015b60405180910390fd5b600285900b5f90815260038b0160205260409020868303975061038990617fff861690899061036c9083610872565b600289900b5f90815260038f0160205260409020929190036108be565b5085836004018564ffffffffff16815481106103a7576103a76116b9565b905f5260205f20015f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506103e18a86610b16565b67ffffffffffffffff165f036103fe576103fe60048b0186610b4b565b5050505050935093915050565b5f806104178585610b16565b90508267ffffffffffffffff168167ffffffffffffffff16111561043d5782915061044d565b90508061044d6004860185610b4b565b61045b600586018584610c49565b509392505050565b8154600160a01b900467ffffffffffffffff16156104ad576040517fc15ba32200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80826104b9828261171c565b50505050565b5f806104cc858585610cc7565b90506104d9858585610183565b815467ffffffffffffffff600160a01b8083048216849003909116027fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff90911617909155949350505050565b5f8267ffffffffffffffff165f03610569576040517ff21c16aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62800000841901600881901c61ffff165f908152600487016020526040902054600160ff9092169190911b908116146105a9576105a96004860185610d08565b600284900b5f908152600386016020526040902060048101546105cb90610e28565b915061800064ffffffffff8316106106dd575f618000830390505f826004018264ffffffffff1681548110610602576106026116b9565b5f91825260209091200154600160a01b900467ffffffffffffffff1690508015610683575f610632898985610183565b90508167ffffffffffffffff168167ffffffffffffffff1614610681576040517ff2f9ac9900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b505f905061069582617fff8516610872565b905067ffffffffffffffff8116156106db57623fffff600287901c165f9081526005880160205260409020805467ffffffffffffffff831660c060068a901b161b900390555b505b6106ec81617fff8416866108be565b50604080518082019091526001600160a01b03938416815267ffffffffffffffff9485166020808301918252600490930180546001810182555f91825293902091519190920180549251909516600160a01b027fffffffff000000000000000000000000000000000000000000000000000000009092169316929092179190911790915592915050565b604080518082019091525f8082526020820152610794848484610cc7565b6040805180820190915290546001600160a01b0381168252600160a01b900467ffffffffffffffff166020820152949350505050565b600281901c623fffff165f81815260208490526040812054909190600384169061081490600686901b60c0161c67ffffffffffffffff165b67ffffffffffffffff16801515900390565b925050505b92915050565b60048201545f90617fff90811690829061083a856001611885565b1690508082106108675761084f858284610e76565b61085886611319565b6108629190611898565b610814565b610814858383610e76565b5f61800082106108975760405163163da48960e01b81525f6004820152602401610334565b6102576108026003848116908690600287901c5f9081529101602052604090205490611358565b5f61800083106108e35760405163163da48960e01b81525f6004820152602401610334565b5f6108ed84611390565b90505f81600160040360ff1681518110610909576109096116b9565b60209081029190910181015190810151909150610949906108029088600385515f908152910160205260409020549060061b1c67ffffffffffffffff1690565b92508367ffffffffffffffff168367ffffffffffffffff1610610a20578383035f5b6004811015610a19575f848281518110610987576109876116b9565b602002602001015190505f895f0183600481106109a6576109a66116b9565b83515f90815291016020908152604090912054908301519091506109ea906109e2866109d28584611358565b67ffffffffffffffff1690611436565b839190611483565b8a84600481106109fc576109fc6116b9565b93515f90815293016020526040909220919091555060010161096b565b5050610b0d565b82840367ffffffffffffffff81810316610a3988611319565b67ffffffffffffffff161115610a655760405163163da48960e01b815260016004820152602401610334565b5f5b6004811015610252575f848281518110610a8357610a836116b9565b602002602001015190505f895f018360048110610aa257610aa26116b9565b83515f9081529101602090815260409091205490830151909150610ade906109e286610ace8584611358565b67ffffffffffffffff16906114ca565b8a8460048110610af057610af06116b9565b93515f908152930160205260409092209190915550600101610a67565b50509392505050565b5f610b2460058401836107ca565b600283900b5f9081526003850160205260409020610b4190611319565b6102579190611898565b62800000811901600881901c61ffff165f8181526020859052604090208054600160ff90941693841b80198216909255919291818103610c4157600884901c195f8181526020889052604090208054600160ff88161b80198216909255909350808403610c3e5781196001901b93508319885f7f7710c0702d438d37259561c892984b894ff622adfa3d98b5dfe5a9763f94b9545f1c6001610bed9190611885565b81526020019081526020015f205416885f7f7710c0702d438d37259561c892984b894ff622adfa3d98b5dfe5a9763f94b9545f1c6001610c2d9190611885565b815260208101919091526040015f20555b50505b505050505050565b623fffff600283901c165f818152602085905260409020546003841690610ca782610c888667ffffffffffffffff60c060068b901b1686901c16610ace565b67ffffffffffffffff90811660069290921b91821b911b831683030190565b62ffffff9093165f90815260209690965250506040909320929092555050565b600282900b5f9081526003840160205260408120600401805464ffffffffff8416908110610cf757610cf76116b9565b905f5260205f200190509392505050565b62800000811901600881901c61ffff165f81815260208590526040902054909160ff16906001821b9081811615610d6b576040517feb73dbfd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8481526020879052604081208284179055819003610c4157600884901c195f8181526020889052604081208054600160ff89161b81811790925590945090819003610c3e5781196001901b885f7f7710c0702d438d37259561c892984b894ff622adfa3d98b5dfe5a9763f94b9545f1c6001610de89190611885565b81526020019081526020015f205417885f7f7710c0702d438d37259561c892984b894ff622adfa3d98b5dfe5a9763f94b9545f1c6001610c2d9190611885565b5f64ffffffffff821115610e72576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526028600482015260248101839052604401610334565b5090565b5f818303610e8557505f610257565b818310610ea75760405163163da48960e01b81525f6004820152602401610334565b618000821115610ecc5760405163163da48960e01b81525f6004820152602401610334565b5f610ed684611390565b90505f610ee284611390565b90505f80808060035b5f878281518110610efe57610efe6116b9565b602002602001015190505f878381518110610f1b57610f1b6116b9565b60200260200101519050816020015185019450806020015184019350815f0151815f015103610f8557610f708d8460048110610f5957610f596116b9565b84515f908152910160205260409020548686611511565b67ffffffffffffffff1687019650505061130a565b815181516004919003101561106757610fc18d8460048110610fa957610fa96116b9565b84515f90815291016020526040902054866004611511565b67ffffffffffffffff169690960195610ffc8d8460048110610fe557610fe56116b9565b83515f908152910160205260408120549086611511565b825167ffffffffffffffff9190911697909701966001015b815181101561105f576110488e8560048110611032576110326116b9565b5f84815291016020526040812054906004611511565b67ffffffffffffffff169790970196600101611014565b50505061130a565b81516003165f036110b45761109e8d8460048110611087576110876116b9565b84515f908152910160205260408120549087611511565b67ffffffffffffffff16860195505f94506111b3565b8151600316600103611114576110f08d84600481106110d5576110d56116b9565b84515f19015f90815291016020526040812054906004611511565b67ffffffffffffffff16959095019461109e8d8460048110611087576110876116b9565b815160031660020361118b576111358d8460048110610fa957610fa96116b9565b67ffffffffffffffff1696909601956111748d8460048110611159576111596116b9565b84516001015f90815291016020526040812054906004611511565b67ffffffffffffffff1687019650600194506111b3565b6111a08d8460048110610fa957610fa96116b9565b67ffffffffffffffff1687019650600194505b80516003165f036111e9576111d38d8460048110610fe557610fe56116b9565b67ffffffffffffffff16870196505f9350611300565b8051600316600103611249576112258d846004811061120a5761120a6116b9565b83515f19015f90815291016020526040812054906004611511565b67ffffffffffffffff1696909601956111d38d8460048110610fe557610fe56116b9565b80516003166002036112d8576112828d846004811061126a5761126a6116b9565b83515f90815291016020526040902054856004611511565b67ffffffffffffffff1695909501946112c18d84600481106112a6576112a66116b9565b83516001015f90815291016020526040812054906004611511565b67ffffffffffffffff168601955060019350611300565b6112ed8d846004811061126a5761126a6116b9565b67ffffffffffffffff1686019550600193505b50505f1901610eeb565b50505090039695505050505050565b60015f9081526020829052604081205461133590826004611511565b5f8080526020849052604081205461134e916004611511565b61081991906116e1565b5f600382111561137e5760405163b8710e2160e01b815260036004820152602401610334565b5060061b1c67ffffffffffffffff1690565b60408051600480825260a082019092526060915f9190816020015b604080518082019091525f80825260208201528152602001906001900390816113ab579050509050600e5f5b600481101561142d5760405180604001604052808387901c815260200160036002850388901c16815250838281518110611413576114136116b9565b6020908102919091010152600319909101906001016113d7565b50909392505050565b81159091019080820367ffffffffffffffff8082169084161080611462575067ffffffffffffffff8116155b1561081957604051633e6c0de960e11b815260016004820152602401610334565b5f60038311156114a95760405163b8710e2160e01b815260036004820152602401610334565b5067ffffffffffffffff90811660069290921b91821b911b82169091030190565b5f81831584010192508167ffffffffffffffff168367ffffffffffffffff16101561150a57604051633e6c0de960e11b81525f6004820152602401610334565b5090919050565b600682901b9290921c915f825b8281101561154657604085901c9467ffffffffffffffff16801501919091019060010161151e565b509190039003919050565b8035600281900b8114611562575f80fd5b919050565b5f805f60608486031215611579575f80fd5b8335925061158960208501611551565b9150604084013564ffffffffff811681146115a2575f80fd5b809150509250925092565b67ffffffffffffffff811681146115c2575f80fd5b50565b5f805f606084860312156115d7575f80fd5b833592506020840135915060408401356115a2816115ad565b5f805f60608486031215611602575f80fd5b8335925061161260208501611551565b915060408401356115a2816115ad565b5f8082840360e0811215611634575f80fd5b8335925060c0601f1982011215611649575f80fd5b506020830190509250929050565b6001600160a01b03811681146115c2575f80fd5b5f805f806080858703121561167e575f80fd5b8435935061168e60208601611551565b9250604085013561169e816115ad565b915060608501356116ae81611657565b939692955090935050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b67ffffffffffffffff818116838216019080821115611702576117026116cd565b5092915050565b5f813562ffffff81168114610819575f80fd5b813561172781611657565b815473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03821617825550602082013561175c816115ad565b81547fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff1660a09190911b7bffffffffffffffff0000000000000000000000000000000000000000161781556001810160408301356117b981611657565b815473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038216178255506118376117ef60608501611709565b82547fffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffff1660a09190911b76ffffff000000000000000000000000000000000000000016178255565b5060028101608083013561184a81611657565b815473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038216178255506118806117ef60a08501611709565b505050565b80820180821115610819576108196116cd565b67ffffffffffffffff828116828216039080821115611702576117026116cd56fea2646970667358221220a13247593ae5c15419d78b3ece674bf54ca1bc0139bfadcff46d347c626dcd5b64736f6c63430008190033
Deployed Bytecode
0x735489922f8312c812fbb7184ebf70b9dbfaeed9d4301460806040526004361061007a575f3560e01c8063ab8a7e3f11610058578063ab8a7e3f1461010e578063c49d26211461012f578063ffa0afb51461014e575f80fd5b8063329b4a011461007e5780633ac502c1146100af578063a151a7e1146100ef575b5f80fd5b61009161008c366004611567565b610183565b60405167ffffffffffffffff90911681526020015b60405180910390f35b8180156100ba575f80fd5b506100ce6100c93660046115c5565b61025e565b6040805167ffffffffffffffff9384168152929091166020830152016100a6565b8180156100fa575f80fd5b506100916101093660046115f0565b61040b565b818015610119575f80fd5b5061012d610128366004611622565b610463565b005b81801561013a575f80fd5b50610091610149366004611567565b6104bf565b818015610159575f80fd5b5061016d61016836600461166b565b610525565b60405164ffffffffff90911681526020016100a6565b5f80610190858585610776565b602090810151600286900b5f90815260038801909252604090912060048101549192509064ffffffffff85166180000110156101ce57509050610257565b5f6101dc60058801876107ca565b90505f6101f0838764ffffffffff1661081f565b90508167ffffffffffffffff1684820367ffffffffffffffff161061021b575f945050505050610257565b8167ffffffffffffffff168167ffffffffffffffff16116102425783945050505050610257565b8381038203945050505050610257565b505050505b9392505050565b602882901c62ffffff16600281900b5f908152600385016020526040812060048101805492938493909264ffffffffff8816929091859190849081106102a6576102a66116b9565b5f918252602082200154600160a01b900467ffffffffffffffff1691506102ce8a8686610183565b90506102da81896116e1565b95508567ffffffffffffffff168267ffffffffffffffff16101561033d576040517fc332559a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8284031660048201526024015b60405180910390fd5b600285900b5f90815260038b0160205260409020868303975061038990617fff861690899061036c9083610872565b600289900b5f90815260038f0160205260409020929190036108be565b5085836004018564ffffffffff16815481106103a7576103a76116b9565b905f5260205f20015f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506103e18a86610b16565b67ffffffffffffffff165f036103fe576103fe60048b0186610b4b565b5050505050935093915050565b5f806104178585610b16565b90508267ffffffffffffffff168167ffffffffffffffff16111561043d5782915061044d565b90508061044d6004860185610b4b565b61045b600586018584610c49565b509392505050565b8154600160a01b900467ffffffffffffffff16156104ad576040517fc15ba32200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80826104b9828261171c565b50505050565b5f806104cc858585610cc7565b90506104d9858585610183565b815467ffffffffffffffff600160a01b8083048216849003909116027fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff90911617909155949350505050565b5f8267ffffffffffffffff165f03610569576040517ff21c16aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62800000841901600881901c61ffff165f908152600487016020526040902054600160ff9092169190911b908116146105a9576105a96004860185610d08565b600284900b5f908152600386016020526040902060048101546105cb90610e28565b915061800064ffffffffff8316106106dd575f618000830390505f826004018264ffffffffff1681548110610602576106026116b9565b5f91825260209091200154600160a01b900467ffffffffffffffff1690508015610683575f610632898985610183565b90508167ffffffffffffffff168167ffffffffffffffff1614610681576040517ff2f9ac9900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b505f905061069582617fff8516610872565b905067ffffffffffffffff8116156106db57623fffff600287901c165f9081526005880160205260409020805467ffffffffffffffff831660c060068a901b161b900390555b505b6106ec81617fff8416866108be565b50604080518082019091526001600160a01b03938416815267ffffffffffffffff9485166020808301918252600490930180546001810182555f91825293902091519190920180549251909516600160a01b027fffffffff000000000000000000000000000000000000000000000000000000009092169316929092179190911790915592915050565b604080518082019091525f8082526020820152610794848484610cc7565b6040805180820190915290546001600160a01b0381168252600160a01b900467ffffffffffffffff166020820152949350505050565b600281901c623fffff165f81815260208490526040812054909190600384169061081490600686901b60c0161c67ffffffffffffffff165b67ffffffffffffffff16801515900390565b925050505b92915050565b60048201545f90617fff90811690829061083a856001611885565b1690508082106108675761084f858284610e76565b61085886611319565b6108629190611898565b610814565b610814858383610e76565b5f61800082106108975760405163163da48960e01b81525f6004820152602401610334565b6102576108026003848116908690600287901c5f9081529101602052604090205490611358565b5f61800083106108e35760405163163da48960e01b81525f6004820152602401610334565b5f6108ed84611390565b90505f81600160040360ff1681518110610909576109096116b9565b60209081029190910181015190810151909150610949906108029088600385515f908152910160205260409020549060061b1c67ffffffffffffffff1690565b92508367ffffffffffffffff168367ffffffffffffffff1610610a20578383035f5b6004811015610a19575f848281518110610987576109876116b9565b602002602001015190505f895f0183600481106109a6576109a66116b9565b83515f90815291016020908152604090912054908301519091506109ea906109e2866109d28584611358565b67ffffffffffffffff1690611436565b839190611483565b8a84600481106109fc576109fc6116b9565b93515f90815293016020526040909220919091555060010161096b565b5050610b0d565b82840367ffffffffffffffff81810316610a3988611319565b67ffffffffffffffff161115610a655760405163163da48960e01b815260016004820152602401610334565b5f5b6004811015610252575f848281518110610a8357610a836116b9565b602002602001015190505f895f018360048110610aa257610aa26116b9565b83515f9081529101602090815260409091205490830151909150610ade906109e286610ace8584611358565b67ffffffffffffffff16906114ca565b8a8460048110610af057610af06116b9565b93515f908152930160205260409092209190915550600101610a67565b50509392505050565b5f610b2460058401836107ca565b600283900b5f9081526003850160205260409020610b4190611319565b6102579190611898565b62800000811901600881901c61ffff165f8181526020859052604090208054600160ff90941693841b80198216909255919291818103610c4157600884901c195f8181526020889052604090208054600160ff88161b80198216909255909350808403610c3e5781196001901b93508319885f7f7710c0702d438d37259561c892984b894ff622adfa3d98b5dfe5a9763f94b9545f1c6001610bed9190611885565b81526020019081526020015f205416885f7f7710c0702d438d37259561c892984b894ff622adfa3d98b5dfe5a9763f94b9545f1c6001610c2d9190611885565b815260208101919091526040015f20555b50505b505050505050565b623fffff600283901c165f818152602085905260409020546003841690610ca782610c888667ffffffffffffffff60c060068b901b1686901c16610ace565b67ffffffffffffffff90811660069290921b91821b911b831683030190565b62ffffff9093165f90815260209690965250506040909320929092555050565b600282900b5f9081526003840160205260408120600401805464ffffffffff8416908110610cf757610cf76116b9565b905f5260205f200190509392505050565b62800000811901600881901c61ffff165f81815260208590526040902054909160ff16906001821b9081811615610d6b576040517feb73dbfd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8481526020879052604081208284179055819003610c4157600884901c195f8181526020889052604081208054600160ff89161b81811790925590945090819003610c3e5781196001901b885f7f7710c0702d438d37259561c892984b894ff622adfa3d98b5dfe5a9763f94b9545f1c6001610de89190611885565b81526020019081526020015f205417885f7f7710c0702d438d37259561c892984b894ff622adfa3d98b5dfe5a9763f94b9545f1c6001610c2d9190611885565b5f64ffffffffff821115610e72576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526028600482015260248101839052604401610334565b5090565b5f818303610e8557505f610257565b818310610ea75760405163163da48960e01b81525f6004820152602401610334565b618000821115610ecc5760405163163da48960e01b81525f6004820152602401610334565b5f610ed684611390565b90505f610ee284611390565b90505f80808060035b5f878281518110610efe57610efe6116b9565b602002602001015190505f878381518110610f1b57610f1b6116b9565b60200260200101519050816020015185019450806020015184019350815f0151815f015103610f8557610f708d8460048110610f5957610f596116b9565b84515f908152910160205260409020548686611511565b67ffffffffffffffff1687019650505061130a565b815181516004919003101561106757610fc18d8460048110610fa957610fa96116b9565b84515f90815291016020526040902054866004611511565b67ffffffffffffffff169690960195610ffc8d8460048110610fe557610fe56116b9565b83515f908152910160205260408120549086611511565b825167ffffffffffffffff9190911697909701966001015b815181101561105f576110488e8560048110611032576110326116b9565b5f84815291016020526040812054906004611511565b67ffffffffffffffff169790970196600101611014565b50505061130a565b81516003165f036110b45761109e8d8460048110611087576110876116b9565b84515f908152910160205260408120549087611511565b67ffffffffffffffff16860195505f94506111b3565b8151600316600103611114576110f08d84600481106110d5576110d56116b9565b84515f19015f90815291016020526040812054906004611511565b67ffffffffffffffff16959095019461109e8d8460048110611087576110876116b9565b815160031660020361118b576111358d8460048110610fa957610fa96116b9565b67ffffffffffffffff1696909601956111748d8460048110611159576111596116b9565b84516001015f90815291016020526040812054906004611511565b67ffffffffffffffff1687019650600194506111b3565b6111a08d8460048110610fa957610fa96116b9565b67ffffffffffffffff1687019650600194505b80516003165f036111e9576111d38d8460048110610fe557610fe56116b9565b67ffffffffffffffff16870196505f9350611300565b8051600316600103611249576112258d846004811061120a5761120a6116b9565b83515f19015f90815291016020526040812054906004611511565b67ffffffffffffffff1696909601956111d38d8460048110610fe557610fe56116b9565b80516003166002036112d8576112828d846004811061126a5761126a6116b9565b83515f90815291016020526040902054856004611511565b67ffffffffffffffff1695909501946112c18d84600481106112a6576112a66116b9565b83516001015f90815291016020526040812054906004611511565b67ffffffffffffffff168601955060019350611300565b6112ed8d846004811061126a5761126a6116b9565b67ffffffffffffffff1686019550600193505b50505f1901610eeb565b50505090039695505050505050565b60015f9081526020829052604081205461133590826004611511565b5f8080526020849052604081205461134e916004611511565b61081991906116e1565b5f600382111561137e5760405163b8710e2160e01b815260036004820152602401610334565b5060061b1c67ffffffffffffffff1690565b60408051600480825260a082019092526060915f9190816020015b604080518082019091525f80825260208201528152602001906001900390816113ab579050509050600e5f5b600481101561142d5760405180604001604052808387901c815260200160036002850388901c16815250838281518110611413576114136116b9565b6020908102919091010152600319909101906001016113d7565b50909392505050565b81159091019080820367ffffffffffffffff8082169084161080611462575067ffffffffffffffff8116155b1561081957604051633e6c0de960e11b815260016004820152602401610334565b5f60038311156114a95760405163b8710e2160e01b815260036004820152602401610334565b5067ffffffffffffffff90811660069290921b91821b911b82169091030190565b5f81831584010192508167ffffffffffffffff168367ffffffffffffffff16101561150a57604051633e6c0de960e11b81525f6004820152602401610334565b5090919050565b600682901b9290921c915f825b8281101561154657604085901c9467ffffffffffffffff16801501919091019060010161151e565b509190039003919050565b8035600281900b8114611562575f80fd5b919050565b5f805f60608486031215611579575f80fd5b8335925061158960208501611551565b9150604084013564ffffffffff811681146115a2575f80fd5b809150509250925092565b67ffffffffffffffff811681146115c2575f80fd5b50565b5f805f606084860312156115d7575f80fd5b833592506020840135915060408401356115a2816115ad565b5f805f60608486031215611602575f80fd5b8335925061161260208501611551565b915060408401356115a2816115ad565b5f8082840360e0811215611634575f80fd5b8335925060c0601f1982011215611649575f80fd5b506020830190509250929050565b6001600160a01b03811681146115c2575f80fd5b5f805f806080858703121561167e575f80fd5b8435935061168e60208601611551565b9250604085013561169e816115ad565b915060608501356116ae81611657565b939692955090935050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b67ffffffffffffffff818116838216019080821115611702576117026116cd565b5092915050565b5f813562ffffff81168114610819575f80fd5b813561172781611657565b815473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03821617825550602082013561175c816115ad565b81547fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff1660a09190911b7bffffffffffffffff0000000000000000000000000000000000000000161781556001810160408301356117b981611657565b815473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038216178255506118376117ef60608501611709565b82547fffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffff1660a09190911b76ffffff000000000000000000000000000000000000000016178255565b5060028101608083013561184a81611657565b815473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038216178255506118806117ef60a08501611709565b505050565b80820180821115610819576108196116cd565b67ffffffffffffffff828116828216039080821115611702576117026116cd56fea2646970667358221220a13247593ae5c15419d78b3ece674bf54ca1bc0139bfadcff46d347c626dcd5b64736f6c63430008190033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.