// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)pragmasolidity ^0.8.20;/**
* @dev Collection of functions related to the address type
*/libraryAddress{
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/errorAddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/errorAddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/errorFailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/functionsendValue(addresspayable recipient, uint256 amount) internal{
if (address(this).balance< amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/functionfunctionCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/functionfunctionCallWithValue(address target, bytesmemory data, uint256 value) internalreturns (bytesmemory) {
if (address(this).balance< value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytesmemory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/functionfunctionStaticCall(address target, bytesmemory data) internalviewreturns (bytesmemory) {
(bool success, bytesmemory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/functionfunctionDelegateCall(address target, bytesmemory data) internalreturns (bytesmemory) {
(bool success, bytesmemory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/functionverifyCallResultFromTarget(address target,
bool success,
bytesmemory returndata
) internalviewreturns (bytesmemory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty// otherwise we already know that it was a contractif (returndata.length==0&& target.code.length==0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/functionverifyCallResult(bool success, bytesmemory returndata) internalpurereturns (bytesmemory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/function_revert(bytesmemory returndata) privatepure{
// Look for revert reason and bubble it up if presentif (returndata.length>0) {
// The easiest way to bubble the revert reason is using memory via assembly/// @solidity memory-safe-assemblyassembly {
let returndata_size :=mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)pragmasolidity ^0.8.20;/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
}
Contract Source Code
File 5 of 28: ERC721Psi.sol
// SPDX-License-Identifier: MIT/**
______ _____ _____ ______ ___ __ _ _ _
| ____| __ \ / ____|____ |__ \/_ | || || |
| |__ | |__) | | / / ) || | \| |/ |
| __| | _ /| | / / / / | |\_ _/
| |____| | \ \| |____ / / / /_ | | | |
|______|_| \_\\_____|/_/ |____||_| |_|
- github: https://github.com/estarriolvetch/ERC721Psi
- npm: https://www.npmjs.com/package/erc721psi
*/pragmasolidity ^0.8.0;import"@openzeppelin/contracts/utils/Strings.sol";
import"@openzeppelin/contracts/utils/Address.sol";
import"solady/src/utils/LibBitmap.sol";
import"./interface/IERC721Psi.sol";
/**
* @dev Interface of ERC721 token receiver.
*/interfaceERC721Psi__IERC721Receiver{
functiononERC721Received(address operator,
addressfrom,
uint256 tokenId,
bytescalldata data
) externalreturns (bytes4);
}
contractERC721PsiisIERC721Psi{
usingAddressforaddress;
usingStringsforuint256;
usingLibBitmapforLibBitmap.Bitmap;
LibBitmap.Bitmap private _batchHead;
stringprivate _name;
stringprivate _symbol;
// Mapping from token ID to owner addressmapping(uint256=>address) internal _owners;
uint256internal _currentIndex;
mapping(uint256=>address) private _tokenApprovals;
mapping(address=>mapping(address=>bool)) private _operatorApprovals;
// The mask of the lower 160 bits for addresses.uint256privateconstant _BITMASK_ADDRESS = (1<<160) -1;
// The `Transfer` event signature is given by:// `keccak256(bytes("Transfer(address,address,uint256)"))`.bytes32privateconstant _TRANSFER_EVENT_SIGNATURE =0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
/**
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
*/constructor(stringmemory name_, stringmemory symbol_) {
_name = name_;
_symbol = symbol_;
_currentIndex = _startTokenId();
}
/**
* @dev Returns the starting token ID.
* To change the starting token ID, please override this function.
*/function_startTokenId() internalviewvirtualreturns (uint256) {
return0;
}
/**
* @dev Returns the next token ID to be minted.
*/function_nextTokenId() internalviewvirtualreturns (uint256) {
return _currentIndex;
}
/**
* @dev Returns the total amount of tokens minted in the contract.
*/function_totalMinted() internalviewvirtualreturns (uint256) {
return _currentIndex - _startTokenId();
}
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30000 gas.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverridereturns (bool) {
// The interface IDs are constants representing the first 4 bytes// of the XOR of all function selectors in the interface.// See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)// (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)return
interfaceId ==0x01ffc9a7||// ERC165 interface ID for ERC165.
interfaceId ==0x80ac58cd||// ERC165 interface ID for ERC721.
interfaceId ==0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
}
/**
* @dev See {IERC721-balanceOf}.
*/functionbalanceOf(address owner)
publicviewvirtualoverridereturns (uint)
{
if(owner ==address(0)) revert BalanceQueryForZeroAddress();
uint count;
for( uint i = _startTokenId(); i < _nextTokenId(); ++i ){
if(_exists(i)){
if( owner == ownerOf(i)){
++count;
}
}
}
return count;
}
/**
* @dev See {IERC721-ownerOf}.
*/functionownerOf(uint256 tokenId)
publicviewvirtualoverridereturns (address)
{
(address owner, ) = _ownerAndBatchHeadOf(tokenId);
return owner;
}
function_ownerAndBatchHeadOf(uint256 tokenId) internalviewreturns (address owner, uint256 tokenIdBatchHead){
if (!_exists(tokenId)) revert OwnerQueryForNonexistentToken();
tokenIdBatchHead = _getBatchHead(tokenId);
owner = _owners[tokenIdBatchHead];
}
/**
* @dev See {IERC721Metadata-name}.
*/functionname() publicviewvirtualoverridereturns (stringmemory) {
return _name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/functionsymbol() publicviewvirtualoverridereturns (stringmemory) {
return _symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/functiontokenURI(uint256 tokenId) publicviewvirtualoverridereturns (stringmemory) {
if( !_exists(tokenId)) revert URIQueryForNonexistentToken();
stringmemory baseURI = _baseURI();
returnbytes(baseURI).length>0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overriden in child contracts.
*/function_baseURI() internalviewvirtualreturns (stringmemory) {
return"";
}
/**
* @dev See {IERC721-approve}.
*/functionapprove(address to, uint256 tokenId) publicpayablevirtualoverride{
address owner = ownerOf(tokenId);
if (_msgSenderERC721Psi() != owner) {
if (!isApprovedForAll(owner, _msgSenderERC721Psi())) {
revert ApprovalCallerNotOwnerNorApproved();
}
}
_approve(to, tokenId);
}
/**
* @dev See {IERC721-getApproved}.
*/functiongetApproved(uint256 tokenId)
publicviewvirtualoverridereturns (address)
{
if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();
return _tokenApprovals[tokenId];
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/functionsetApprovalForAll(address operator, bool approved)
publicvirtualoverride{
_operatorApprovals[_msgSenderERC721Psi()][operator] = approved;
emit ApprovalForAll(_msgSenderERC721Psi(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/functionisApprovedForAll(address owner, address operator)
publicviewvirtualoverridereturns (bool)
{
return _operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) publicpayablevirtualoverride{
_transfer(from, to, tokenId);
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) publicpayablevirtualoverride{
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytesmemory _data
) publicpayablevirtualoverride{
_safeTransfer(from, to, tokenId, _data);
}
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* `_data` is additional data, it has no specified format and it is sent in call to `to`.
*
* This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
* implement alternative mechanisms to perform token transfer, such as signature-based.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/function_safeTransfer(addressfrom,
address to,
uint256 tokenId,
bytesmemory _data
) internalvirtual{
_transfer(from, to, tokenId);
if (!_checkOnERC721Received(from, to, tokenId, 1, _data)) {
revert TransferToNonERC721ReceiverImplementer();
}
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
*
* Tokens start existing when they are minted (`_mint`).
*/function_exists(uint256 tokenId) internalviewvirtualreturns (bool) {
return tokenId < _nextTokenId() && _startTokenId() <= tokenId;
}
errorOperatorQueryForNonexistentToken();
/**
* @dev Returns whether `spender` is allowed to manage `tokenId`.
*
* Requirements:
*
* - `tokenId` must exist.
*/function_isApprovedOrOwner(address spender, uint256 tokenId)
internalviewvirtualreturns (bool)
{
if (!_exists(tokenId)) revert OperatorQueryForNonexistentToken();
address owner = ownerOf(tokenId);
return (spender == owner ||
getApproved(tokenId) == spender ||
isApprovedForAll(owner, spender));
}
/**
* @dev Safely mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
* - `quantity` must be greater than 0.
*
* Emits a {Transfer} event.
*/function_safeMint(address to, uint256 quantity) internalvirtual{
_safeMint(to, quantity, "");
}
function_safeMint(address to,
uint256 quantity,
bytesmemory _data
) internalvirtual{
_mint(to, quantity);
uint256 end = _currentIndex;
if (!_checkOnERC721Received(address(0), to, end - quantity, quantity, _data)) {
revert TransferToNonERC721ReceiverImplementer();
}
// Reentrancy protection.if (_currentIndex != end) revert();
}
function_mint(address to,
uint256 quantity
) internalvirtual{
uint256 nextTokenId = _nextTokenId();
if (quantity ==0) revert MintZeroQuantity();
if (to ==address(0)) revert MintToZeroAddress();
_beforeTokenTransfers(address(0), to, nextTokenId, quantity);
_currentIndex += quantity;
_owners[nextTokenId] = to;
_batchHead.set(nextTokenId);
uint256 toMasked;
uint256 end = nextTokenId + quantity;
// Use assembly to loop and emit the `Transfer` event for gas savings.// The duplicated `log4` removes an extra check and reduces stack juggling.// The assembly, together with the surrounding Solidity code, have been// delicately arranged to nudge the compiler into producing optimized opcodes.assembly {
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
toMasked :=and(to, _BITMASK_ADDRESS)
// Emit the `Transfer` event.log4(
0, // Start of data (0, since no data).0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.0, // `address(0)`.
toMasked, // `to`.
nextTokenId // `tokenId`.
)
// The `iszero(eq(,))` check ensures that large values of `quantity`// that overflows uint256 will make the loop run out of gas.// The compiler will optimize the `iszero` away for performance.for {
let tokenId :=add(nextTokenId, 1)
} iszero(eq(tokenId, end)) {
tokenId :=add(tokenId, 1)
} {
// Emit the `Transfer` event. Similar to above.log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
}
}
_afterTokenTransfers(address(0), to, nextTokenId, quantity);
}
/**
* @dev Transfers `tokenId` from `from` to `to`.
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {Transfer} event.
*/function_transfer(addressfrom,
address to,
uint256 tokenId
) internalvirtual{
(address owner, uint256 tokenIdBatchHead) = _ownerAndBatchHeadOf(tokenId);
if (owner !=from) revert TransferFromIncorrectOwner();
if (!_isApprovedOrOwner(_msgSenderERC721Psi(), tokenId)) {
revert TransferCallerNotOwnerNorApproved();
}
if (to ==address(0)) revert TransferToZeroAddress();
_beforeTokenTransfers(from, to, tokenId, 1);
// Clear approvals from the previous owner
_approve(address(0), tokenId);
uint256 subsequentTokenId = tokenId +1;
if(!_batchHead.get(subsequentTokenId) &&
subsequentTokenId < _nextTokenId()
) {
_owners[subsequentTokenId] =from;
_batchHead.set(subsequentTokenId);
}
_owners[tokenId] = to;
if(tokenId != tokenIdBatchHead) {
_batchHead.set(tokenId);
}
emit Transfer(from, to, tokenId);
_afterTokenTransfers(from, to, tokenId, 1);
}
/**
* @dev Approve `to` to operate on `tokenId`
*
* Emits a {Approval} event.
*/function_approve(address to, uint256 tokenId) internalvirtual{
_tokenApprovals[tokenId] = to;
emit Approval(ownerOf(tokenId), to, tokenId);
}
/**
* @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
* The call is not executed if the target address is not a contract.
*
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param startTokenId uint256 the first ID of the tokens to be transferred
* @param quantity uint256 amount of the tokens to be transfered.
* @param _data bytes optional data to send along with the call
* @return r bool whether the call correctly returned the expected magic value
*/function_checkOnERC721Received(addressfrom,
address to,
uint256 startTokenId,
uint256 quantity,
bytesmemory _data
) privatereturns (bool r) {
/// @dev removed isContract() in v5.0 but their ERC721 uses this check:if (to.code.length>0) {
r =true;
for(uint256 tokenId = startTokenId; tokenId < startTokenId + quantity; tokenId++){
try ERC721Psi__IERC721Receiver(to).onERC721Received( _msgSenderERC721Psi(), from, tokenId, _data) returns (bytes4 retval) {
r = r && retval == ERC721Psi__IERC721Receiver.onERC721Received.selector;
} catch (bytesmemory reason) {
if (reason.length==0) {
revert TransferToNonERC721ReceiverImplementer();
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
return r;
} else {
returntrue;
}
}
function_getBatchHead(uint256 tokenId) internalviewreturns (uint256 tokenIdBatchHead) {
tokenIdBatchHead = _batchHead.findLastSet(tokenId);
}
functiontotalSupply() publicvirtualoverrideviewreturns (uint256) {
return _totalMinted();
}
/**
* @dev Returns an array of token IDs owned by `owner`.
*
* This function scans the ownership mapping and is O(`totalSupply`) in complexity.
* It is meant to be called off-chain.
*
* This function is compatiable with ERC721AQueryable.
*/functiontokensOfOwner(address owner) externalviewvirtualreturns (uint256[] memory) {
unchecked {
uint256 tokenIdsIdx;
uint256 tokenIdsLength = balanceOf(owner);
uint256[] memory tokenIds =newuint256[](tokenIdsLength);
for (uint256 i = _startTokenId(); tokenIdsIdx != tokenIdsLength; ++i) {
if (_exists(i)) {
if (ownerOf(i) == owner) {
tokenIds[tokenIdsIdx++] = i;
}
}
}
return tokenIds;
}
}
/**
* @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. This includes minting.
*
* startTokenId - the first token id to be transferred
* quantity - the amount to be transferred
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
*/function_beforeTokenTransfers(addressfrom,
address to,
uint256 startTokenId,
uint256 quantity
) internalvirtual{}
/**
* @dev Hook that is called after a set of serially-ordered token ids have been transferred. This includes
* minting.
*
* startTokenId - the first token id to be transferred
* quantity - the amount to be transferred
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero.
* - `from` and `to` are never both zero.
*/function_afterTokenTransfers(addressfrom,
address to,
uint256 startTokenId,
uint256 quantity
) internalvirtual{}
/**
* @dev Returns the message sender (defaults to `msg.sender`).
*
* If you are writing GSN compatible contracts, you need to override this function.
*/function_msgSenderERC721Psi() internalviewvirtualreturns (address) {
returnmsg.sender;
}
}
Contract Source Code
File 6 of 28: ERC721PsiBurnable.sol
// SPDX-License-Identifier: MIT/**
______ _____ _____ ______ ___ __ _ _ _
| ____| __ \ / ____|____ |__ \/_ | || || |
| |__ | |__) | | / / ) || | \| |/ |
| __| | _ /| | / / / / | |\_ _/
| |____| | \ \| |____ / / / /_ | | | |
|______|_| \_\\_____|/_/ |____||_| |_|
*/pragmasolidity ^0.8.0;import"solady/src/utils/LibBitmap.sol";
import"../ERC721Psi.sol";
abstractcontractERC721PsiBurnableisERC721Psi{
usingLibBitmapforLibBitmap.Bitmap;
LibBitmap.Bitmap private _burnedToken;
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/function_burn(uint256 tokenId) internalvirtual{
addressfrom= ownerOf(tokenId);
_beforeTokenTransfers(from, address(0), tokenId, 1);
_burnedToken.set(tokenId);
emit Transfer(from, address(0), tokenId);
_afterTokenTransfers(from, address(0), tokenId, 1);
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
*
* Tokens start existing when they are minted (`_mint`),
* and stop existing when they are burned (`_burn`).
*/function_exists(uint256 tokenId) internalviewoverridevirtualreturns (bool){
if(_burnedToken.get(tokenId)) {
returnfalse;
}
returnsuper._exists(tokenId);
}
/**
* @dev See {IERC721-ownerOf}.
*/functionownerOf(uint256 tokenId)
publicviewvirtualoverridereturns (address)
{
if (_burnedToken.get(tokenId)) {
returnaddress(0);
}
else {
returnsuper.ownerOf(tokenId);
}
}
/**
* @dev See {IERC721Enumerable-totalSupply}.
*/functiontotalSupply() publicviewvirtualoverridereturns (uint256) {
return _currentIndex - _burned() - _startTokenId();
}
/**
* @dev Returns number of token burned.
*/function_burned() internalviewreturns (uint256 burned){
return _burnedToken.popCount( _startTokenId(), _totalMinted());
}
}
Contract Source Code
File 7 of 28: EnumerableMap.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableMap.sol)// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.pragmasolidity ^0.8.20;import {EnumerableSet} from"./EnumerableSet.sol";
/**
* @dev Library for managing an enumerable variant of Solidity's
* https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
* type.
*
* Maps have the following properties:
*
* - Entries are added, removed, and checked for existence in constant time
* (O(1)).
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableMap for EnumerableMap.UintToAddressMap;
*
* // Declare a set state variable
* EnumerableMap.UintToAddressMap private myMap;
* }
* ```
*
* The following map types are supported:
*
* - `uint256 -> address` (`UintToAddressMap`) since v3.0.0
* - `address -> uint256` (`AddressToUintMap`) since v4.6.0
* - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0
* - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0
* - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableMap.
* ====
*/libraryEnumerableMap{
usingEnumerableSetforEnumerableSet.Bytes32Set;
// To implement this library for multiple types with as little code repetition as possible, we write it in// terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions,// and user-facing implementations such as `UintToAddressMap` are just wrappers around the underlying Map.// This means that we can only create new EnumerableMaps for types that fit in bytes32./**
* @dev Query for a nonexistent map key.
*/errorEnumerableMapNonexistentKey(bytes32 key);
structBytes32ToBytes32Map {
// Storage of keys
EnumerableSet.Bytes32Set _keys;
mapping(bytes32 key =>bytes32) _values;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/functionset(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internalreturns (bool) {
map._values[key] = value;
return map._keys.add(key);
}
/**
* @dev Removes a key-value pair from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/functionremove(Bytes32ToBytes32Map storage map, bytes32 key) internalreturns (bool) {
delete map._values[key];
return map._keys.remove(key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/functioncontains(Bytes32ToBytes32Map storage map, bytes32 key) internalviewreturns (bool) {
return map._keys.contains(key);
}
/**
* @dev Returns the number of key-value pairs in the map. O(1).
*/functionlength(Bytes32ToBytes32Map storage map) internalviewreturns (uint256) {
return map._keys.length();
}
/**
* @dev Returns the key-value pair stored at position `index` in the map. O(1).
*
* Note that there are no guarantees on the ordering of entries inside the
* array, and it may change when more entries are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/functionat(Bytes32ToBytes32Map storage map, uint256 index) internalviewreturns (bytes32, bytes32) {
bytes32 key = map._keys.at(index);
return (key, map._values[key]);
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/functiontryGet(Bytes32ToBytes32Map storage map, bytes32 key) internalviewreturns (bool, bytes32) {
bytes32 value = map._values[key];
if (value ==bytes32(0)) {
return (contains(map, key), bytes32(0));
} else {
return (true, value);
}
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/functionget(Bytes32ToBytes32Map storage map, bytes32 key) internalviewreturns (bytes32) {
bytes32 value = map._values[key];
if (value ==0&&!contains(map, key)) {
revert EnumerableMapNonexistentKey(key);
}
return value;
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/functionkeys(Bytes32ToBytes32Map storage map) internalviewreturns (bytes32[] memory) {
return map._keys.values();
}
// UintToUintMapstructUintToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/functionset(UintToUintMap storage map, uint256 key, uint256 value) internalreturns (bool) {
return set(map._inner, bytes32(key), bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/functionremove(UintToUintMap storage map, uint256 key) internalreturns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/functioncontains(UintToUintMap storage map, uint256 key) internalviewreturns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/functionlength(UintToUintMap storage map) internalviewreturns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/functionat(UintToUintMap storage map, uint256 index) internalviewreturns (uint256, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/functiontryGet(UintToUintMap storage map, uint256 key) internalviewreturns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/functionget(UintToUintMap storage map, uint256 key) internalviewreturns (uint256) {
returnuint256(get(map._inner, bytes32(key)));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/functionkeys(UintToUintMap storage map) internalviewreturns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
/// @solidity memory-safe-assemblyassembly {
result := store
}
return result;
}
// UintToAddressMapstructUintToAddressMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/functionset(UintToAddressMap storage map, uint256 key, address value) internalreturns (bool) {
return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/functionremove(UintToAddressMap storage map, uint256 key) internalreturns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/functioncontains(UintToAddressMap storage map, uint256 key) internalviewreturns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/functionlength(UintToAddressMap storage map) internalviewreturns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/functionat(UintToAddressMap storage map, uint256 index) internalviewreturns (uint256, address) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), address(uint160(uint256(value))));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/functiontryGet(UintToAddressMap storage map, uint256 key) internalviewreturns (bool, address) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, address(uint160(uint256(value))));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/functionget(UintToAddressMap storage map, uint256 key) internalviewreturns (address) {
returnaddress(uint160(uint256(get(map._inner, bytes32(key)))));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/functionkeys(UintToAddressMap storage map) internalviewreturns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
/// @solidity memory-safe-assemblyassembly {
result := store
}
return result;
}
// AddressToUintMapstructAddressToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/functionset(AddressToUintMap storage map, address key, uint256 value) internalreturns (bool) {
return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/functionremove(AddressToUintMap storage map, address key) internalreturns (bool) {
return remove(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/functioncontains(AddressToUintMap storage map, address key) internalviewreturns (bool) {
return contains(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/functionlength(AddressToUintMap storage map) internalviewreturns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/functionat(AddressToUintMap storage map, uint256 index) internalviewreturns (address, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (address(uint160(uint256(key))), uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/functiontryGet(AddressToUintMap storage map, address key) internalviewreturns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/functionget(AddressToUintMap storage map, address key) internalviewreturns (uint256) {
returnuint256(get(map._inner, bytes32(uint256(uint160(key)))));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/functionkeys(AddressToUintMap storage map) internalviewreturns (address[] memory) {
bytes32[] memory store = keys(map._inner);
address[] memory result;
/// @solidity memory-safe-assemblyassembly {
result := store
}
return result;
}
// Bytes32ToUintMapstructBytes32ToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/functionset(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internalreturns (bool) {
return set(map._inner, key, bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/functionremove(Bytes32ToUintMap storage map, bytes32 key) internalreturns (bool) {
return remove(map._inner, key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/functioncontains(Bytes32ToUintMap storage map, bytes32 key) internalviewreturns (bool) {
return contains(map._inner, key);
}
/**
* @dev Returns the number of elements in the map. O(1).
*/functionlength(Bytes32ToUintMap storage map) internalviewreturns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/functionat(Bytes32ToUintMap storage map, uint256 index) internalviewreturns (bytes32, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (key, uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/functiontryGet(Bytes32ToUintMap storage map, bytes32 key) internalviewreturns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, key);
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/functionget(Bytes32ToUintMap storage map, bytes32 key) internalviewreturns (uint256) {
returnuint256(get(map._inner, key));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/functionkeys(Bytes32ToUintMap storage map) internalviewreturns (bytes32[] memory) {
bytes32[] memory store = keys(map._inner);
bytes32[] memory result;
/// @solidity memory-safe-assemblyassembly {
result := store
}
return result;
}
}
Contract Source Code
File 8 of 28: EnumerableSet.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.pragmasolidity ^0.8.20;/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/libraryEnumerableSet{
// To implement this library for multiple types with as little code// repetition as possible, we write it in terms of a generic Set type with// bytes32 values.// The Set implementation uses private functions, and user-facing// implementations (such as AddressSet) are just wrappers around the// underlying Set.// This means that we can only create new EnumerableSets for types that fit// in bytes32.structSet {
// Storage of set valuesbytes32[] _values;
// Position is the index of the value in the `values` array plus 1.// Position 0 is used to mean a value is not in the set.mapping(bytes32 value =>uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/function_add(Set storage set, bytes32 value) privatereturns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes// and use 0 as a sentinel value
set._positions[value] = set._values.length;
returntrue;
} else {
returnfalse;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/function_remove(Set storage set, bytes32 value) privatereturns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slotuint256 position = set._positions[value];
if (position !=0) {
// Equivalent to contains(set, value)// To delete an element from the _values array in O(1), we swap the element to delete with the last one in// the array, and then remove the last element (sometimes called as 'swap and pop').// This modifies the order of the array, as noted in {at}.uint256 valueIndex = position -1;
uint256 lastIndex = set._values.length-1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slotdelete set._positions[value];
returntrue;
} else {
returnfalse;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/function_contains(Set storage set, bytes32 value) privateviewreturns (bool) {
return set._positions[value] !=0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/function_length(Set storage set) privateviewreturns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/function_at(Set storage set, uint256 index) privateviewreturns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/function_values(Set storage set) privateviewreturns (bytes32[] memory) {
return set._values;
}
// Bytes32SetstructBytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/functionadd(Bytes32Set storage set, bytes32 value) internalreturns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/functionremove(Bytes32Set storage set, bytes32 value) internalreturns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/functioncontains(Bytes32Set storage set, bytes32 value) internalviewreturns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/functionlength(Bytes32Set storage set) internalviewreturns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/functionat(Bytes32Set storage set, uint256 index) internalviewreturns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/functionvalues(Bytes32Set storage set) internalviewreturns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assemblyassembly {
result := store
}
return result;
}
// AddressSetstructAddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/functionadd(AddressSet storage set, address value) internalreturns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/functionremove(AddressSet storage set, address value) internalreturns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/functioncontains(AddressSet storage set, address value) internalviewreturns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/functionlength(AddressSet storage set) internalviewreturns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/functionat(AddressSet storage set, uint256 index) internalviewreturns (address) {
returnaddress(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/functionvalues(AddressSet storage set) internalviewreturns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assemblyassembly {
result := store
}
return result;
}
// UintSetstructUintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/functionadd(UintSet storage set, uint256 value) internalreturns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/functionremove(UintSet storage set, uint256 value) internalreturns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/functioncontains(UintSet storage set, uint256 value) internalviewreturns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/functionlength(UintSet storage set) internalviewreturns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/functionat(UintSet storage set, uint256 index) internalviewreturns (uint256) {
returnuint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/functionvalues(UintSet storage set) internalviewreturns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assemblyassembly {
result := store
}
return result;
}
}
Contract Source Code
File 9 of 28: Escrow.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (utils/escrow/Escrow.sol)pragmasolidity ^0.8.0;import {Ownable} from"@openzeppelin/contracts/access/Ownable.sol";
import {Address} from"@openzeppelin/contracts/utils/Address.sol";
/**
* @title Escrow
* @dev Base escrow contract, holds funds designated for a payee until they
* withdraw them.
*
* Intended usage: This contract (and derived escrow contracts) should be a
* standalone contract, that only interacts with the contract that instantiated
* it. That way, it is guaranteed that all Ether will be handled according to
* the `Escrow` rules, and there is no need to check for payable functions or
* transfers in the inheritance tree. The contract that uses the escrow as its
* payment method should be its owner, and provide public methods redirecting
* to the escrow's deposit and withdraw.
*/contractEscrowisOwnable{
usingAddressforaddresspayable;
eventDeposited(addressindexed payee, uint256 weiAmount);
eventWithdrawn(addressindexed payee, uint256 weiAmount);
mapping(address=>uint256) private _deposits;
/// @dev modify this to support Ownable v5.0constructor() Ownable(msg.sender) {}
functiondepositsOf(address payee) publicviewreturns (uint256) {
return _deposits[payee];
}
/**
* @dev Stores the sent amount as credit to be withdrawn.
* @param payee The destination address of the funds.
*
* Emits a {Deposited} event.
*/functiondeposit(address payee) publicpayablevirtualonlyOwner{
uint256 amount =msg.value;
_deposits[payee] += amount;
emit Deposited(payee, amount);
}
/**
* @dev Withdraw accumulated balance for a payee, forwarding all gas to the
* recipient.
*
* WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities.
* Make sure you trust the recipient, or are either following the
* checks-effects-interactions pattern or using {ReentrancyGuard}.
*
* @param payee The address whose funds will be withdrawn and transferred to.
*
* Emits a {Withdrawn} event.
*/functionwithdraw(addresspayable payee) publicvirtualonlyOwner{
uint256 payment = _deposits[payee];
_deposits[payee] =0;
payee.sendValue(payment);
emit Withdrawn(payee, payment);
}
}
Contract Source Code
File 10 of 28: IERC721Psi.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/**
* @dev Interface of ERC721Psi.
*/interfaceIERC721Psi{
/**
* The caller must own the token or be an approved operator.
*/errorApprovalCallerNotOwnerNorApproved();
/**
* The token does not exist.
*/errorApprovalQueryForNonexistentToken();
/**
* Cannot query the balance for the zero address.
*/errorBalanceQueryForZeroAddress();
/**
* Cannot mint to the zero address.
*/errorMintToZeroAddress();
/**
* The quantity of tokens minted must be more than zero.
*/errorMintZeroQuantity();
/**
* The token does not exist.
*/errorOwnerQueryForNonexistentToken();
/**
* The caller must own the token or be an approved operator.
*/errorTransferCallerNotOwnerNorApproved();
/**
* The token must be owned by `from`.
*/errorTransferFromIncorrectOwner();
/**
* Cannot safely transfer to a contract that does not implement the
* ERC721Receiver interface.
*/errorTransferToNonERC721ReceiverImplementer();
/**
* Cannot transfer to the zero address.
*/errorTransferToZeroAddress();
/**
* The token does not exist.
*/errorURIQueryForNonexistentToken();
// =============================================================// TOKEN COUNTERS// =============================================================/**
* @dev Returns the total number of tokens in existence.
* Burned tokens will reduce the count.
* To get the total number of tokens minted, please see {_totalMinted}.
*/functiontotalSupply() externalviewreturns (uint256);
// =============================================================// IERC165// =============================================================/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30000 gas.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
// =============================================================// IERC721// =============================================================/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/eventApproval(addressindexed owner, addressindexed approved, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables
* (`approved`) `operator` to manage all of its assets.
*/eventApprovalForAll(addressindexed owner, addressindexed operator, bool approved);
/**
* @dev Returns the number of tokens in `owner`'s account.
*/functionbalanceOf(address owner) externalviewreturns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functionownerOf(uint256 tokenId) externalviewreturns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`,
* checking first that contract recipients are aware of the ERC721 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 be 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.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytescalldata data
) externalpayable;
/**
* @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) externalpayable;
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom}
* whenever possible.
*
* 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.
*/functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) externalpayable;
/**
* @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.
*/functionapprove(address to, uint256 tokenId) externalpayable;
/**
* @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 caller.
*
* Emits an {ApprovalForAll} event.
*/functionsetApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functiongetApproved(uint256 tokenId) externalviewreturns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}.
*/functionisApprovedForAll(address owner, address operator) externalviewreturns (bool);
// =============================================================// IERC721Metadata// =============================================================/**
* @dev Returns the token collection name.
*/functionname() externalviewreturns (stringmemory);
/**
* @dev Returns the token collection symbol.
*/functionsymbol() externalviewreturns (stringmemory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/functiontokenURI(uint256 tokenId) externalviewreturns (stringmemory);
}
Contract Source Code
File 11 of 28: LibBit.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.4;/// @notice Library for bit twiddling and boolean operations./// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBit.sol)/// @author Inspired by (https://graphics.stanford.edu/~seander/bithacks.html)libraryLibBit{
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* BIT TWIDDLING OPERATIONS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev Find last set./// Returns the index of the most significant bit of `x`,/// counting from the least significant bit position./// If `x` is zero, returns 256.functionfls(uint256 x) internalpurereturns (uint256 r) {
/// @solidity memory-safe-assemblyassembly {
r :=or(shl(8, iszero(x)), 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))))
// forgefmt: disable-next-item
r :=or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000))
}
}
/// @dev Count leading zeros./// Returns the number of zeros preceding the most significant one bit./// If `x` is zero, returns 256.functionclz(uint256 x) internalpurereturns (uint256 r) {
/// @solidity memory-safe-assemblyassembly {
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))))
// forgefmt: disable-next-item
r :=add(xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)), iszero(x))
}
}
/// @dev Find first set./// Returns the index of the least significant bit of `x`,/// counting from the least significant bit position./// If `x` is zero, returns 256./// Equivalent to `ctz` (count trailing zeros), which gives/// the number of zeros following the least significant one bit.functionffs(uint256 x) internalpurereturns (uint256 r) {
/// @solidity memory-safe-assemblyassembly {
// Isolate the least significant bit.let b :=and(x, add(not(x), 1))
r :=or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, b)))
r :=or(r, shl(6, lt(0xffffffffffffffff, shr(r, b))))
r :=or(r, shl(5, lt(0xffffffff, shr(r, b))))
// For the remaining 32 bits, use a De Bruijn lookup.// forgefmt: disable-next-item
r :=or(r, byte(and(div(0xd76453e0, shr(r, b)), 0x1f),
0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405))
}
}
/// @dev Returns the number of set bits in `x`.functionpopCount(uint256 x) internalpurereturns (uint256 c) {
/// @solidity memory-safe-assemblyassembly {
let max :=not(0)
let isMax :=eq(x, max)
x :=sub(x, and(shr(1, x), div(max, 3)))
x :=add(and(x, div(max, 5)), and(shr(2, x), div(max, 5)))
x :=and(add(x, shr(4, x)), div(max, 17))
c :=or(shl(8, isMax), shr(248, mul(x, div(max, 255))))
}
}
/// @dev Returns whether `x` is a power of 2.functionisPo2(uint256 x) internalpurereturns (bool result) {
/// @solidity memory-safe-assemblyassembly {
// Equivalent to `x && !(x & (x - 1))`.
result :=iszero(add(and(x, sub(x, 1)), iszero(x)))
}
}
/// @dev Returns `x` reversed at the bit level.functionreverseBits(uint256 x) internalpurereturns (uint256 r) {
/// @solidity memory-safe-assemblyassembly {
// Computing masks on-the-fly reduces bytecode size by about 500 bytes.let m :=not(0)
r := x
for { let s :=128 } 1 {} {
m :=xor(m, shl(s, m))
r :=or(and(shr(s, r), m), and(shl(s, r), not(m)))
s :=shr(1, s)
ifiszero(s) { break }
}
}
}
/// @dev Returns `x` reversed at the byte level.functionreverseBytes(uint256 x) internalpurereturns (uint256 r) {
/// @solidity memory-safe-assemblyassembly {
// Computing masks on-the-fly reduces bytecode size by about 200 bytes.let m :=not(0)
r := x
for { let s :=128 } 1 {} {
m :=xor(m, shl(s, m))
r :=or(and(shr(s, r), m), and(shl(s, r), not(m)))
s :=shr(1, s)
ifeq(s, 4) { break }
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* BOOLEAN OPERATIONS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/// A Solidity bool on the stack or memory is represented as a 256-bit word.// Non-zero values are true, zero is false.// A clean bool is either 0 (false) or 1 (true) under the hood.// Usually, if not always, the bool result of a regular Solidity expression,// or the argument of a public/external function will be a clean bool.// You can usually use the raw variants for more performance.// If uncertain, test (best with exact compiler settings).// Or use the non-raw variants (compiler can sometimes optimize out the double `iszero`s)./// @dev Returns `x & y`. Inputs must be clean.functionrawAnd(bool x, bool y) internalpurereturns (bool z) {
/// @solidity memory-safe-assemblyassembly {
z :=and(x, y)
}
}
/// @dev Returns `x & y`.functionand(bool x, bool y) internalpurereturns (bool z) {
/// @solidity memory-safe-assemblyassembly {
z :=and(iszero(iszero(x)), iszero(iszero(y)))
}
}
/// @dev Returns `x | y`. Inputs must be clean.functionrawOr(bool x, bool y) internalpurereturns (bool z) {
/// @solidity memory-safe-assemblyassembly {
z :=or(x, y)
}
}
/// @dev Returns `x | y`.functionor(bool x, bool y) internalpurereturns (bool z) {
/// @solidity memory-safe-assemblyassembly {
z :=or(iszero(iszero(x)), iszero(iszero(y)))
}
}
/// @dev Returns 1 if `b` is true, else 0. Input must be clean.functionrawToUint(bool b) internalpurereturns (uint256 z) {
/// @solidity memory-safe-assemblyassembly {
z := b
}
}
/// @dev Returns 1 if `b` is true, else 0.functiontoUint(bool b) internalpurereturns (uint256 z) {
/// @solidity memory-safe-assemblyassembly {
z :=iszero(iszero(b))
}
}
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.4;import {LibBit} from"./LibBit.sol";
/// @notice Library for storage of packed unsigned booleans./// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBitmap.sol)/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibBitmap.sol)/// @author Modified from Solidity-Bits (https://github.com/estarriolvetch/solidity-bits/blob/main/contracts/BitMaps.sol)libraryLibBitmap{
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* CONSTANTS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev The constant returned when a bitmap scan does not find a result.uint256internalconstant NOT_FOUND =type(uint256).max;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* STRUCTS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev A bitmap in storage.structBitmap {
mapping(uint256=>uint256) map;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* OPERATIONS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev Returns the boolean value of the bit at `index` in `bitmap`.functionget(Bitmap storage bitmap, uint256 index) internalviewreturns (bool isSet) {
// It is better to set `isSet` to either 0 or 1, than zero vs non-zero.// Both cost the same amount of gas, but the former allows the returned value// to be reused without cleaning the upper bits.uint256 b = (bitmap.map[index >>8] >> (index &0xff)) &1;
/// @solidity memory-safe-assemblyassembly {
isSet := b
}
}
/// @dev Updates the bit at `index` in `bitmap` to true.functionset(Bitmap storage bitmap, uint256 index) internal{
bitmap.map[index >>8] |= (1<< (index &0xff));
}
/// @dev Updates the bit at `index` in `bitmap` to false.functionunset(Bitmap storage bitmap, uint256 index) internal{
bitmap.map[index >>8] &=~(1<< (index &0xff));
}
/// @dev Flips the bit at `index` in `bitmap`./// Returns the boolean result of the flipped bit.functiontoggle(Bitmap storage bitmap, uint256 index) internalreturns (bool newIsSet) {
/// @solidity memory-safe-assemblyassembly {
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, index))
let storageSlot :=keccak256(0x00, 0x40)
let shift :=and(index, 0xff)
let storageValue :=xor(sload(storageSlot), shl(shift, 1))
// It makes sense to return the `newIsSet`,// as it allow us to skip an additional warm `sload`,// and it costs minimal gas (about 15),// which may be optimized away if the returned value is unused.
newIsSet :=and(1, shr(shift, storageValue))
sstore(storageSlot, storageValue)
}
}
/// @dev Updates the bit at `index` in `bitmap` to `shouldSet`.functionsetTo(Bitmap storage bitmap, uint256 index, bool shouldSet) internal{
/// @solidity memory-safe-assemblyassembly {
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, index))
let storageSlot :=keccak256(0x00, 0x40)
let storageValue :=sload(storageSlot)
let shift :=and(index, 0xff)
sstore(
storageSlot,
// Unsets the bit at `shift` via `and`, then sets its new value via `or`.or(and(storageValue, not(shl(shift, 1))), shl(shift, iszero(iszero(shouldSet))))
)
}
}
/// @dev Consecutively sets `amount` of bits starting from the bit at `start`.functionsetBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal{
/// @solidity memory-safe-assemblyassembly {
let max :=not(0)
let shift :=and(start, 0xff)
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, start))
ifiszero(lt(add(shift, amount), 257)) {
let storageSlot :=keccak256(0x00, 0x40)
sstore(storageSlot, or(sload(storageSlot), shl(shift, max)))
let bucket :=add(mload(0x00), 1)
let bucketEnd :=add(mload(0x00), shr(8, add(amount, shift)))
amount :=and(add(amount, shift), 0xff)
shift :=0for {} iszero(eq(bucket, bucketEnd)) { bucket :=add(bucket, 1) } {
mstore(0x00, bucket)
sstore(keccak256(0x00, 0x40), max)
}
mstore(0x00, bucket)
}
let storageSlot :=keccak256(0x00, 0x40)
sstore(storageSlot, or(sload(storageSlot), shl(shift, shr(sub(256, amount), max))))
}
}
/// @dev Consecutively unsets `amount` of bits starting from the bit at `start`.functionunsetBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal{
/// @solidity memory-safe-assemblyassembly {
let shift :=and(start, 0xff)
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, start))
ifiszero(lt(add(shift, amount), 257)) {
let storageSlot :=keccak256(0x00, 0x40)
sstore(storageSlot, and(sload(storageSlot), not(shl(shift, not(0)))))
let bucket :=add(mload(0x00), 1)
let bucketEnd :=add(mload(0x00), shr(8, add(amount, shift)))
amount :=and(add(amount, shift), 0xff)
shift :=0for {} iszero(eq(bucket, bucketEnd)) { bucket :=add(bucket, 1) } {
mstore(0x00, bucket)
sstore(keccak256(0x00, 0x40), 0)
}
mstore(0x00, bucket)
}
let storageSlot :=keccak256(0x00, 0x40)
sstore(
storageSlot, and(sload(storageSlot), not(shl(shift, shr(sub(256, amount), not(0)))))
)
}
}
/// @dev Returns number of set bits within a range by/// scanning `amount` of bits starting from the bit at `start`.functionpopCount(Bitmap storage bitmap, uint256 start, uint256 amount)
internalviewreturns (uint256 count)
{
unchecked {
uint256 bucket = start >>8;
uint256 shift = start &0xff;
if (!(amount + shift <257)) {
count = LibBit.popCount(bitmap.map[bucket] >> shift);
uint256 bucketEnd = bucket + ((amount + shift) >>8);
amount = (amount + shift) &0xff;
shift =0;
for (++bucket; bucket != bucketEnd; ++bucket) {
count += LibBit.popCount(bitmap.map[bucket]);
}
}
count += LibBit.popCount((bitmap.map[bucket] >> shift) << (256- amount));
}
}
/// @dev Returns the index of the most significant set bit before the bit at `before`./// If no set bit is found, returns `NOT_FOUND`.functionfindLastSet(Bitmap storage bitmap, uint256 before)
internalviewreturns (uint256 setBitIndex)
{
uint256 bucket;
uint256 bucketBits;
/// @solidity memory-safe-assemblyassembly {
setBitIndex :=not(0)
bucket :=shr(8, before)
mstore(0x00, bucket)
mstore(0x20, bitmap.slot)
let offset :=and(0xff, not(before)) // `256 - (255 & before) - 1`.
bucketBits :=shr(offset, shl(offset, sload(keccak256(0x00, 0x40))))
ifiszero(or(bucketBits, iszero(bucket))) {
for {} 1 {} {
bucket :=add(bucket, setBitIndex) // `sub(bucket, 1)`.mstore(0x00, bucket)
bucketBits :=sload(keccak256(0x00, 0x40))
ifor(bucketBits, iszero(bucket)) { break }
}
}
}
if (bucketBits !=0) {
setBitIndex = (bucket <<8) | LibBit.fls(bucketBits);
/// @solidity memory-safe-assemblyassembly {
setBitIndex :=or(setBitIndex, sub(0, gt(setBitIndex, before)))
}
}
}
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.4;/// @notice Library for generating pseudorandom numbers./// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibPRNG.sol)libraryLibPRNG{
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* STRUCTS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev A pseudorandom number state in memory.structPRNG {
uint256 state;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* OPERATIONS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev Seeds the `prng` with `state`.functionseed(PRNG memory prng, uint256 state) internalpure{
/// @solidity memory-safe-assemblyassembly {
mstore(prng, state)
}
}
/// @dev Returns the next pseudorandom uint256./// All bits of the returned uint256 pass the NIST Statistical Test Suite.functionnext(PRNG memory prng) internalpurereturns (uint256 result) {
// We simply use `keccak256` for a great balance between// runtime gas costs, bytecode size, and statistical properties.//// A high-quality LCG with a 32-byte state// is only about 30% more gas efficient during runtime,// but requires a 32-byte multiplier, which can cause bytecode bloat// when this function is inlined.//// Using this method is about 2x more efficient than// `nextRandomness = uint256(keccak256(abi.encode(randomness)))`./// @solidity memory-safe-assemblyassembly {
result :=keccak256(prng, 0x20)
mstore(prng, result)
}
}
/// @dev Returns a pseudorandom uint256, uniformly distributed/// between 0 (inclusive) and `upper` (exclusive)./// If your modulus is big, this method is recommended/// for uniform sampling to avoid modulo bias./// For uniform sampling across all uint256 values,/// or for small enough moduli such that the bias is neligible,/// use {next} instead.functionuniform(PRNG memory prng, uint256 upper) internalpurereturns (uint256 result) {
/// @solidity memory-safe-assemblyassembly {
for {} 1 {} {
result :=keccak256(prng, 0x20)
mstore(prng, result)
ifiszero(lt(result, mod(sub(0, upper), upper))) { break }
}
result :=mod(result, upper)
}
}
/// @dev Shuffles the array in-place with Fisher-Yates shuffle.functionshuffle(PRNG memory prng, uint256[] memory a) internalpure{
/// @solidity memory-safe-assemblyassembly {
let n :=mload(a)
let w :=not(0)
let mask :=shr(128, w)
if n {
for { a :=add(a, 0x20) } 1 {} {
// We can just directly use `keccak256`, cuz// the other approaches don't save much.let r :=keccak256(prng, 0x20)
mstore(prng, r)
// Note that there will be a very tiny modulo bias// if the length of the array is not a power of 2.// For all practical purposes, it is negligible// and will not be a fairness or security concern.
{
let j :=add(a, shl(5, mod(shr(128, r), n)))
n :=add(n, w) // `sub(n, 1)`.ifiszero(n) { break }
let i :=add(a, shl(5, n))
let t :=mload(i)
mstore(i, mload(j))
mstore(j, t)
}
{
let j :=add(a, shl(5, mod(and(r, mask), n)))
n :=add(n, w) // `sub(n, 1)`.ifiszero(n) { break }
let i :=add(a, shl(5, n))
let t :=mload(i)
mstore(i, mload(j))
mstore(j, t)
}
}
}
}
}
/// @dev Shuffles the bytes in-place with Fisher-Yates shuffle.functionshuffle(PRNG memory prng, bytesmemory a) internalpure{
/// @solidity memory-safe-assemblyassembly {
let n :=mload(a)
let w :=not(0)
let mask :=shr(128, w)
if n {
let b :=add(a, 0x01)
for { a :=add(a, 0x20) } 1 {} {
// We can just directly use `keccak256`, cuz// the other approaches don't save much.let r :=keccak256(prng, 0x20)
mstore(prng, r)
// Note that there will be a very tiny modulo bias// if the length of the array is not a power of 2.// For all practical purposes, it is negligible// and will not be a fairness or security concern.
{
let o :=mod(shr(128, r), n)
n :=add(n, w) // `sub(n, 1)`.ifiszero(n) { break }
let t :=mload(add(b, n))
mstore8(add(a, n), mload(add(b, o)))
mstore8(add(a, o), t)
}
{
let o :=mod(and(r, mask), n)
n :=add(n, w) // `sub(n, 1)`.ifiszero(n) { break }
let t :=mload(add(b, n))
mstore8(add(a, n), mload(add(b, o)))
mstore8(add(a, o), t)
}
}
}
}
}
}
Contract Source Code
File 17 of 28: LibRefundable.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.23;/// @title LibRefundable - Library for handling cancellable mint operations.libraryLibRefundable{
/// @dev Struct to hold data for mints.structMintData {
mapping(bytes32=>uint256) _mintAmounts;
uint256[] _cancelledMints;
}
/// @dev Custom error for mints that are not cancelled.errorErrorMintNonRefundable();
/// @dev Cancels a mint./// @param self The storage reference to a MintData./// @param mintId The ID of the mint.functioncancelMint(MintData storageself, uint256 mintId, uint256 total) internal{
self._mintAmounts[_mintKey(mintId, address(0))] = total;
self._cancelledMints.push(mintId);
}
/// @dev Returns all cancelled mints./// @param self The storage reference to a MintData.functioncancelledMints(MintData storageself) internalviewreturns (uint256[] memory) {
returnself._cancelledMints;
}
/// @dev Returns the total number of cancelled mints./// @param self The storage reference to a MintData.functiontotalCancelledMints(MintData storageself) internalviewreturns (uint256) {
returnself._cancelledMints.length;
}
/// @dev Returns a cancelled mint at a specific index./// @param self The storage reference to a MintData./// @param index The index of the cancelled mint.functioncancelledMintAtIndex(MintData storageself, uint256 index) internalviewreturns (uint256) {
return index <self._cancelledMints.length ? self._cancelledMints[index] : 0;
}
/// @dev Records the amount of a mint./// @param self The storage reference to a MintData./// @param mintId The ID of the mint./// @param owner The address of the owner./// @param amount The amount to record.functionaddRefundableAmount(MintData storageself, uint256 mintId, address owner, uint256 amount) internal{
self._mintAmounts[_mintKey(mintId, owner)] += amount;
}
/// @dev Retrieves the refundable amount of a mint./// @param self The storage reference to a MintData./// @param mintId The ID of the mint./// @param owner The address of the owner./// @return The refundable amount for the mint.functiongetRefundableAmount(MintData storageself, uint256 mintId, address owner) internalviewreturns (uint256) {
returnself._mintAmounts[_mintKey(mintId, owner)];
}
/// @dev Refunds the amount of a mint./// @param self The storage reference to a MintData./// @param mintId The ID of the mint./// @param owner The address of the owner.functionremoveRefundableAmount(MintData storageself, uint256 mintId, address owner) internalreturns (uint256) {
bytes32 cancelKey = _mintKey(mintId, address(0));
bytes32 key = _mintKey(mintId, owner);
if (self._mintAmounts[cancelKey] ==0) {
revert ErrorMintNonRefundable();
}
uint256 refund =self._mintAmounts[key];
deleteself._mintAmounts[key];
self._mintAmounts[cancelKey] -= refund;
if (self._mintAmounts[cancelKey] ==0) {
deleteself._mintAmounts[cancelKey];
}
return refund;
}
/// @dev Generates a key for mint./// @param mintId The ID of the mint./// @param owner The address of the owner.function_mintKey(uint256 mintId, address owner) privatepurereturns (bytes32) {
returnkeccak256(abi.encodePacked(mintId, owner));
}
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.4;/// @notice Library for converting numbers into strings and other string operations./// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)libraryLibString{
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* CUSTOM ERRORS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev The `length` of the output is too small to contain all the hex digits.errorHexLengthInsufficient();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* CONSTANTS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev The constant returned when the `search` is not found in the string.uint256internalconstant NOT_FOUND =type(uint256).max;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* DECIMAL OPERATIONS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev Returns the base 10 decimal representation of `value`.functiontoString(uint256 value) internalpurereturns (stringmemory str) {
/// @solidity memory-safe-assemblyassembly {
// The maximum value of a uint256 contains 78 digits (1 byte per digit), but// we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.// We will need 1 word for the trailing zeros padding, 1 word for the length,// and 3 words for a maximum of 78 digits.
str :=add(mload(0x40), 0x80)
// Update the free memory pointer to allocate.mstore(0x40, add(str, 0x20))
// Zeroize the slot after the string.mstore(str, 0)
// Cache the end of the memory to calculate the length later.let end := str
let w :=not(0) // Tsk.// We write the string from rightmost digit to leftmost digit.// The following is essentially a do-while loop that also handles the zero case.for { let temp := value } 1 {} {
str :=add(str, w) // `sub(str, 1)`.// Write the character to the pointer.// The ASCII index of the '0' character is 48.mstore8(str, add(48, mod(temp, 10)))
// Keep dividing `temp` until zero.
temp :=div(temp, 10)
ifiszero(temp) { break }
}
let length :=sub(end, str)
// Move the pointer 32 bytes leftwards to make room for the length.
str :=sub(str, 0x20)
// Store the length.mstore(str, length)
}
}
/// @dev Returns the base 10 decimal representation of `value`.functiontoString(int256 value) internalpurereturns (stringmemory str) {
if (value >=0) {
return toString(uint256(value));
}
unchecked {
str = toString(uint256(-value));
}
/// @solidity memory-safe-assemblyassembly {
// We still have some spare memory space on the left,// as we have allocated 3 words (96 bytes) for up to 78 digits.let length :=mload(str) // Load the string length.mstore(str, 0x2d) // Store the '-' character.
str :=sub(str, 1) // Move back the string pointer by a byte.mstore(str, add(length, 1)) // Update the string length.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* HEXADECIMAL OPERATIONS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev Returns the hexadecimal representation of `value`,/// left-padded to an input length of `length` bytes./// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,/// giving a total length of `length * 2 + 2` bytes./// Reverts if `length` is too small for the output to contain all the digits.functiontoHexString(uint256 value, uint256 length) internalpurereturns (stringmemory str) {
str = toHexStringNoPrefix(value, length);
/// @solidity memory-safe-assemblyassembly {
let strLength :=add(mload(str), 2) // Compute the length.mstore(str, 0x3078) // Write the "0x" prefix.
str :=sub(str, 2) // Move the pointer.mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hexadecimal representation of `value`,/// left-padded to an input length of `length` bytes./// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,/// giving a total length of `length * 2` bytes./// Reverts if `length` is too small for the output to contain all the digits.functiontoHexStringNoPrefix(uint256 value, uint256 length)
internalpurereturns (stringmemory str)
{
/// @solidity memory-safe-assemblyassembly {
// We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes// for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.// We add 0x20 to the total and round down to a multiple of 0x20.// (0x20 + 0x20 + 0x02 + 0x20) = 0x62.
str :=add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))
// Allocate the memory.mstore(0x40, add(str, 0x20))
// Zeroize the slot after the string.mstore(str, 0)
// Cache the end to calculate the length later.let end := str
// Store "0123456789abcdef" in scratch space.mstore(0x0f, 0x30313233343536373839616263646566)
let start :=sub(str, add(length, length))
let w :=not(1) // Tsk.let temp := value
// We write the string from rightmost digit to leftmost digit.// The following is essentially a do-while loop that also handles the zero case.for {} 1 {} {
str :=add(str, w) // `sub(str, 2)`.mstore8(add(str, 1), mload(and(temp, 15)))
mstore8(str, mload(and(shr(4, temp), 15)))
temp :=shr(8, temp)
ifiszero(xor(str, start)) { break }
}
if temp {
// Store the function selector of `HexLengthInsufficient()`.mstore(0x00, 0x2194895a)
// Revert with (offset, size).revert(0x1c, 0x04)
}
// Compute the string's length.let strLength :=sub(end, str)
// Move the pointer and write the length.
str :=sub(str, 0x20)
mstore(str, strLength)
}
}
/// @dev Returns the hexadecimal representation of `value`./// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte./// As address are 20 bytes long, the output will left-padded to have/// a length of `20 * 2 + 2` bytes.functiontoHexString(uint256 value) internalpurereturns (stringmemory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assemblyassembly {
let strLength :=add(mload(str), 2) // Compute the length.mstore(str, 0x3078) // Write the "0x" prefix.
str :=sub(str, 2) // Move the pointer.mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hexadecimal representation of `value`./// The output is prefixed with "0x"./// The output excludes leading "0" from the `toHexString` output./// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`.functiontoMinimalHexString(uint256 value) internalpurereturns (stringmemory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assemblyassembly {
let o :=eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.let strLength :=add(mload(str), 2) // Compute the length.mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero.
str :=sub(add(str, o), 2) // Move the pointer, accounting for leading zero.mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.
}
}
/// @dev Returns the hexadecimal representation of `value`./// The output excludes leading "0" from the `toHexStringNoPrefix` output./// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`.functiontoMinimalHexStringNoPrefix(uint256 value) internalpurereturns (stringmemory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assemblyassembly {
let o :=eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.let strLength :=mload(str) // Get the length.
str :=add(str, o) // Move the pointer, accounting for leading zero.mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.
}
}
/// @dev Returns the hexadecimal representation of `value`./// The output is encoded using 2 hexadecimal digits per byte./// As address are 20 bytes long, the output will left-padded to have/// a length of `20 * 2` bytes.functiontoHexStringNoPrefix(uint256 value) internalpurereturns (stringmemory str) {
/// @solidity memory-safe-assemblyassembly {
// We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,// 0x02 bytes for the prefix, and 0x40 bytes for the digits.// The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.
str :=add(mload(0x40), 0x80)
// Allocate the memory.mstore(0x40, add(str, 0x20))
// Zeroize the slot after the string.mstore(str, 0)
// Cache the end to calculate the length later.let end := str
// Store "0123456789abcdef" in scratch space.mstore(0x0f, 0x30313233343536373839616263646566)
let w :=not(1) // Tsk.// We write the string from rightmost digit to leftmost digit.// The following is essentially a do-while loop that also handles the zero case.for { let temp := value } 1 {} {
str :=add(str, w) // `sub(str, 2)`.mstore8(add(str, 1), mload(and(temp, 15)))
mstore8(str, mload(and(shr(4, temp), 15)))
temp :=shr(8, temp)
ifiszero(temp) { break }
}
// Compute the string's length.let strLength :=sub(end, str)
// Move the pointer and write the length.
str :=sub(str, 0x20)
mstore(str, strLength)
}
}
/// @dev Returns the hexadecimal representation of `value`./// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte,/// and the alphabets are capitalized conditionally according to/// https://eips.ethereum.org/EIPS/eip-55functiontoHexStringChecksummed(address value) internalpurereturns (stringmemory str) {
str = toHexString(value);
/// @solidity memory-safe-assemblyassembly {
let mask :=shl(6, div(not(0), 255)) // `0b010000000100000000 ...`let o :=add(str, 0x22)
let hashed :=and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `let t :=shl(240, 136) // `0b10001000 << 240`for { let i :=0 } 1 {} {
mstore(add(i, i), mul(t, byte(i, hashed)))
i :=add(i, 1)
ifeq(i, 20) { break }
}
mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))
o :=add(o, 0x20)
mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))
}
}
/// @dev Returns the hexadecimal representation of `value`./// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.functiontoHexString(address value) internalpurereturns (stringmemory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assemblyassembly {
let strLength :=add(mload(str), 2) // Compute the length.mstore(str, 0x3078) // Write the "0x" prefix.
str :=sub(str, 2) // Move the pointer.mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hexadecimal representation of `value`./// The output is encoded using 2 hexadecimal digits per byte.functiontoHexStringNoPrefix(address value) internalpurereturns (stringmemory str) {
/// @solidity memory-safe-assemblyassembly {
str :=mload(0x40)
// Allocate the memory.// We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,// 0x02 bytes for the prefix, and 0x28 bytes for the digits.// The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.mstore(0x40, add(str, 0x80))
// Store "0123456789abcdef" in scratch space.mstore(0x0f, 0x30313233343536373839616263646566)
str :=add(str, 2)
mstore(str, 40)
let o :=add(str, 0x20)
mstore(add(o, 40), 0)
value :=shl(96, value)
// We write the string from rightmost digit to leftmost digit.// The following is essentially a do-while loop that also handles the zero case.for { let i :=0 } 1 {} {
let p :=add(o, add(i, i))
let temp :=byte(i, value)
mstore8(add(p, 1), mload(and(temp, 15)))
mstore8(p, mload(shr(4, temp)))
i :=add(i, 1)
ifeq(i, 20) { break }
}
}
}
/// @dev Returns the hex encoded string from the raw bytes./// The output is encoded using 2 hexadecimal digits per byte.functiontoHexString(bytesmemory raw) internalpurereturns (stringmemory str) {
str = toHexStringNoPrefix(raw);
/// @solidity memory-safe-assemblyassembly {
let strLength :=add(mload(str), 2) // Compute the length.mstore(str, 0x3078) // Write the "0x" prefix.
str :=sub(str, 2) // Move the pointer.mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hex encoded string from the raw bytes./// The output is encoded using 2 hexadecimal digits per byte.functiontoHexStringNoPrefix(bytesmemory raw) internalpurereturns (stringmemory str) {
/// @solidity memory-safe-assemblyassembly {
let length :=mload(raw)
str :=add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.mstore(str, add(length, length)) // Store the length of the output.// Store "0123456789abcdef" in scratch space.mstore(0x0f, 0x30313233343536373839616263646566)
let o :=add(str, 0x20)
let end :=add(raw, length)
for {} iszero(eq(raw, end)) {} {
raw :=add(raw, 1)
mstore8(add(o, 1), mload(and(mload(raw), 15)))
mstore8(o, mload(and(shr(4, mload(raw)), 15)))
o :=add(o, 2)
}
mstore(o, 0) // Zeroize the slot after the string.mstore(0x40, add(o, 0x20)) // Allocate the memory.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* RUNE STRING OPERATIONS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*//// @dev Returns the number of UTF characters in the string.functionruneCount(stringmemory s) internalpurereturns (uint256 result) {
/// @solidity memory-safe-assemblyassembly {
ifmload(s) {
mstore(0x00, div(not(0), 255))
mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)
let o :=add(s, 0x20)
let end :=add(o, mload(s))
for { result :=1 } 1 { result :=add(result, 1) } {
o :=add(o, byte(0, mload(shr(250, mload(o)))))
ifiszero(lt(o, end)) { break }
}
}
}
}
/// @dev Returns if this string is a 7-bit ASCII string./// (i.e. all characters codes are in [0..127])functionis7BitASCII(stringmemory s) internalpurereturns (bool result) {
/// @solidity memory-safe-assemblyassembly {
let mask :=shl(7, div(not(0), 255))
result :=1let n :=mload(s)
if n {
let o :=add(s, 0x20)
let end :=add(o, n)
let last :=mload(end)
mstore(end, 0)
for {} 1 {} {
ifand(mask, mload(o)) {
result :=0break
}
o :=add(o, 0x20)
ifiszero(lt(o, end)) { break }
}
mstore(end, last)
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*//* BYTE STRING OPERATIONS *//*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/// For performance and bytecode compactness, all indices of the following operations// are byte (ASCII) offsets, not UTF character offsets./// @dev Returns `subject` all occurrences of `search` replaced with `replacement`.functionreplace(stringmemory subject, stringmemory search, stringmemory replacement)
internalpurereturns (stringmemory result)
{
/// @solidity memory-safe-assemblyassembly {
let subjectLength :=mload(subject)
let searchLength :=mload(search)
let replacementLength :=mload(replacement)
subject :=add(subject, 0x20)
search :=add(search, 0x20)
replacement :=add(replacement, 0x20)
result :=add(mload(0x40), 0x20)
let subjectEnd :=add(subject, subjectLength)
ifiszero(gt(searchLength, subjectLength)) {
let subjectSearchEnd :=add(sub(subjectEnd, searchLength), 1)
let h :=0ifiszero(lt(searchLength, 0x20)) { h :=keccak256(search, searchLength) }
let m :=shl(3, sub(0x20, and(searchLength, 0x1f)))
let s :=mload(search)
for {} 1 {} {
let t :=mload(subject)
// Whether the first `searchLength % 32` bytes of// `subject` and `search` matches.ifiszero(shr(m, xor(t, s))) {
if h {
ifiszero(eq(keccak256(subject, searchLength), h)) {
mstore(result, t)
result :=add(result, 1)
subject :=add(subject, 1)
ifiszero(lt(subject, subjectSearchEnd)) { break }
continue
}
}
// Copy the `replacement` one word at a time.for { let o :=0 } 1 {} {
mstore(add(result, o), mload(add(replacement, o)))
o :=add(o, 0x20)
ifiszero(lt(o, replacementLength)) { break }
}
result :=add(result, replacementLength)
subject :=add(subject, searchLength)
if searchLength {
ifiszero(lt(subject, subjectSearchEnd)) { break }
continue
}
}
mstore(result, t)
result :=add(result, 1)
subject :=add(subject, 1)
ifiszero(lt(subject, subjectSearchEnd)) { break }
}
}
let resultRemainder := result
result :=add(mload(0x40), 0x20)
let k :=add(sub(resultRemainder, result), sub(subjectEnd, subject))
// Copy the rest of the string one word at a time.for {} lt(subject, subjectEnd) {} {
mstore(resultRemainder, mload(subject))
resultRemainder :=add(resultRemainder, 0x20)
subject :=add(subject, 0x20)
}
result :=sub(result, 0x20)
let last :=add(add(result, 0x20), k) // Zeroize the slot after the string.mstore(last, 0)
mstore(0x40, add(last, 0x20)) // Allocate the memory.mstore(result, k) // Store the length.
}
}
/// @dev Returns the byte index of the first location of `search` in `subject`,/// searching from left to right, starting from `from`./// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.functionindexOf(stringmemory subject, stringmemory search, uint256from)
internalpurereturns (uint256 result)
{
/// @solidity memory-safe-assemblyassembly {
for { let subjectLength :=mload(subject) } 1 {} {
ifiszero(mload(search)) {
ifiszero(gt(from, subjectLength)) {
result := from
break
}
result := subjectLength
break
}
let searchLength :=mload(search)
let subjectStart :=add(subject, 0x20)
result :=not(0) // Initialize to `NOT_FOUND`.
subject :=add(subjectStart, from)
let end :=add(sub(add(subjectStart, subjectLength), searchLength), 1)
let m :=shl(3, sub(0x20, and(searchLength, 0x1f)))
let s :=mload(add(search, 0x20))
ifiszero(and(lt(subject, end), lt(from, subjectLength))) { break }
ifiszero(lt(searchLength, 0x20)) {
for { let h :=keccak256(add(search, 0x20), searchLength) } 1 {} {
ifiszero(shr(m, xor(mload(subject), s))) {
ifeq(keccak256(subject, searchLength), h) {
result :=sub(subject, subjectStart)
break
}
}
subject :=add(subject, 1)
ifiszero(lt(subject, end)) { break }
}
break
}
for {} 1 {} {
ifiszero(shr(m, xor(mload(subject), s))) {
result :=sub(subject, subjectStart)
break
}
subject :=add(subject, 1)
ifiszero(lt(subject, end)) { break }
}
break
}
}
}
/// @dev Returns the byte index of the first location of `search` in `subject`,/// searching from left to right./// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.functionindexOf(stringmemory subject, stringmemory search)
internalpurereturns (uint256 result)
{
result = indexOf(subject, search, 0);
}
/// @dev Returns the byte index of the first location of `search` in `subject`,/// searching from right to left, starting from `from`./// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.functionlastIndexOf(stringmemory subject, stringmemory search, uint256from)
internalpurereturns (uint256 result)
{
/// @solidity memory-safe-assemblyassembly {
for {} 1 {} {
result :=not(0) // Initialize to `NOT_FOUND`.let searchLength :=mload(search)
ifgt(searchLength, mload(subject)) { break }
let w := result
let fromMax :=sub(mload(subject), searchLength)
ifiszero(gt(fromMax, from)) { from := fromMax }
let end :=add(add(subject, 0x20), w)
subject :=add(add(subject, 0x20), from)
ifiszero(gt(subject, end)) { break }
// As this function is not too often used,// we shall simply use keccak256 for smaller bytecode size.for { let h :=keccak256(add(search, 0x20), searchLength) } 1 {} {
ifeq(keccak256(subject, searchLength), h) {
result :=sub(subject, add(end, 1))
break
}
subject :=add(subject, w) // `sub(subject, 1)`.ifiszero(gt(subject, end)) { break }
}
break
}
}
}
/// @dev Returns the byte index of the first location of `search` in `subject`,/// searching from right to left./// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.functionlastIndexOf(stringmemory subject, stringmemory search)
internalpurereturns (uint256 result)
{
result = lastIndexOf(subject, search, uint256(int256(-1)));
}
/// @dev Returns whether `subject` starts with `search`.functionstartsWith(stringmemory subject, stringmemory search)
internalpurereturns (bool result)
{
/// @solidity memory-safe-assemblyassembly {
let searchLength :=mload(search)
// Just using keccak256 directly is actually cheaper.// forgefmt: disable-next-item
result :=and(
iszero(gt(searchLength, mload(subject))),
eq(
keccak256(add(subject, 0x20), searchLength),
keccak256(add(search, 0x20), searchLength)
)
)
}
}
/// @dev Returns whether `subject` ends with `search`.functionendsWith(stringmemory subject, stringmemory search)
internalpurereturns (bool result)
{
/// @solidity memory-safe-assemblyassembly {
let searchLength :=mload(search)
let subjectLength :=mload(subject)
// Whether `search` is not longer than `subject`.let withinRange :=iszero(gt(searchLength, subjectLength))
// Just using keccak256 directly is actually cheaper.// forgefmt: disable-next-item
result :=and(
withinRange,
eq(
keccak256(
// `subject + 0x20 + max(subjectLength - searchLength, 0)`.add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))),
searchLength
),
keccak256(add(search, 0x20), searchLength)
)
)
}
}
/// @dev Returns `subject` repeated `times`.functionrepeat(stringmemory subject, uint256 times)
internalpurereturns (stringmemory result)
{
/// @solidity memory-safe-assemblyassembly {
let subjectLength :=mload(subject)
ifiszero(or(iszero(times), iszero(subjectLength))) {
subject :=add(subject, 0x20)
result :=mload(0x40)
let output :=add(result, 0x20)
for {} 1 {} {
// Copy the `subject` one word at a time.for { let o :=0 } 1 {} {
mstore(add(output, o), mload(add(subject, o)))
o :=add(o, 0x20)
ifiszero(lt(o, subjectLength)) { break }
}
output :=add(output, subjectLength)
times :=sub(times, 1)
ifiszero(times) { break }
}
mstore(output, 0) // Zeroize the slot after the string.let resultLength :=sub(output, add(result, 0x20))
mstore(result, resultLength) // Store the length.// Allocate the memory.mstore(0x40, add(result, add(resultLength, 0x20)))
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive)./// `start` and `end` are byte offsets.functionslice(stringmemory subject, uint256 start, uint256 end)
internalpurereturns (stringmemory result)
{
/// @solidity memory-safe-assemblyassembly {
let subjectLength :=mload(subject)
ifiszero(gt(subjectLength, end)) { end := subjectLength }
ifiszero(gt(subjectLength, start)) { start := subjectLength }
iflt(start, end) {
result :=mload(0x40)
let resultLength :=sub(end, start)
mstore(result, resultLength)
subject :=add(subject, start)
let w :=not(0x1f)
// Copy the `subject` one word at a time, backwards.for { let o :=and(add(resultLength, 0x1f), w) } 1 {} {
mstore(add(result, o), mload(add(subject, o)))
o :=add(o, w) // `sub(o, 0x20)`.ifiszero(o) { break }
}
// Zeroize the slot after the string.mstore(add(add(result, 0x20), resultLength), 0)
// Allocate memory for the length and the bytes,// rounded up to a multiple of 32.mstore(0x40, add(result, and(add(resultLength, 0x3f), w)))
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the string./// `start` is a byte offset.functionslice(stringmemory subject, uint256 start)
internalpurereturns (stringmemory result)
{
result = slice(subject, start, uint256(int256(-1)));
}
/// @dev Returns all the indices of `search` in `subject`./// The indices are byte offsets.functionindicesOf(stringmemory subject, stringmemory search)
internalpurereturns (uint256[] memory result)
{
/// @solidity memory-safe-assemblyassembly {
let subjectLength :=mload(subject)
let searchLength :=mload(search)
ifiszero(gt(searchLength, subjectLength)) {
subject :=add(subject, 0x20)
search :=add(search, 0x20)
result :=add(mload(0x40), 0x20)
let subjectStart := subject
let subjectSearchEnd :=add(sub(add(subject, subjectLength), searchLength), 1)
let h :=0ifiszero(lt(searchLength, 0x20)) { h :=keccak256(search, searchLength) }
let m :=shl(3, sub(0x20, and(searchLength, 0x1f)))
let s :=mload(search)
for {} 1 {} {
let t :=mload(subject)
// Whether the first `searchLength % 32` bytes of// `subject` and `search` matches.ifiszero(shr(m, xor(t, s))) {
if h {
ifiszero(eq(keccak256(subject, searchLength), h)) {
subject :=add(subject, 1)
ifiszero(lt(subject, subjectSearchEnd)) { break }
continue
}
}
// Append to `result`.mstore(result, sub(subject, subjectStart))
result :=add(result, 0x20)
// Advance `subject` by `searchLength`.
subject :=add(subject, searchLength)
if searchLength {
ifiszero(lt(subject, subjectSearchEnd)) { break }
continue
}
}
subject :=add(subject, 1)
ifiszero(lt(subject, subjectSearchEnd)) { break }
}
let resultEnd := result
// Assign `result` to the free memory pointer.
result :=mload(0x40)
// Store the length of `result`.mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))
// Allocate memory for result.// We allocate one more word, so this array can be recycled for {split}.mstore(0x40, add(resultEnd, 0x20))
}
}
}
/// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.functionsplit(stringmemory subject, stringmemory delimiter)
internalpurereturns (string[] memory result)
{
uint256[] memory indices = indicesOf(subject, delimiter);
/// @solidity memory-safe-assemblyassembly {
let w :=not(0x1f)
let indexPtr :=add(indices, 0x20)
let indicesEnd :=add(indexPtr, shl(5, add(mload(indices), 1)))
mstore(add(indicesEnd, w), mload(subject))
mstore(indices, add(mload(indices), 1))
let prevIndex :=0for {} 1 {} {
let index :=mload(indexPtr)
mstore(indexPtr, 0x60)
ifiszero(eq(index, prevIndex)) {
let element :=mload(0x40)
let elementLength :=sub(index, prevIndex)
mstore(element, elementLength)
// Copy the `subject` one word at a time, backwards.for { let o :=and(add(elementLength, 0x1f), w) } 1 {} {
mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
o :=add(o, w) // `sub(o, 0x20)`.ifiszero(o) { break }
}
// Zeroize the slot after the string.mstore(add(add(element, 0x20), elementLength), 0)
// Allocate memory for the length and the bytes,// rounded up to a multiple of 32.mstore(0x40, add(element, and(add(elementLength, 0x3f), w)))
// Store the `element` into the array.mstore(indexPtr, element)
}
prevIndex :=add(index, mload(delimiter))
indexPtr :=add(indexPtr, 0x20)
ifiszero(lt(indexPtr, indicesEnd)) { break }
}
result := indices
ifiszero(mload(delimiter)) {
result :=add(indices, 0x20)
mstore(result, sub(mload(indices), 2))
}
}
}
/// @dev Returns a concatenated string of `a` and `b`./// Cheaper than `string.concat()` and does not de-align the free memory pointer.functionconcat(stringmemory a, stringmemory b)
internalpurereturns (stringmemory result)
{
/// @solidity memory-safe-assemblyassembly {
let w :=not(0x1f)
result :=mload(0x40)
let aLength :=mload(a)
// Copy `a` one word at a time, backwards.for { let o :=and(add(aLength, 0x20), w) } 1 {} {
mstore(add(result, o), mload(add(a, o)))
o :=add(o, w) // `sub(o, 0x20)`.ifiszero(o) { break }
}
let bLength :=mload(b)
let output :=add(result, aLength)
// Copy `b` one word at a time, backwards.for { let o :=and(add(bLength, 0x20), w) } 1 {} {
mstore(add(output, o), mload(add(b, o)))
o :=add(o, w) // `sub(o, 0x20)`.ifiszero(o) { break }
}
let totalLength :=add(aLength, bLength)
let last :=add(add(result, 0x20), totalLength)
// Zeroize the slot after the string.mstore(last, 0)
// Stores the length.mstore(result, totalLength)
// Allocate memory for the length and the bytes,// rounded up to a multiple of 32.mstore(0x40, and(add(last, 0x1f), w))
}
}
/// @dev Returns a copy of the string in either lowercase or UPPERCASE./// WARNING! This function is only compatible with 7-bit ASCII strings.functiontoCase(stringmemory subject, bool toUpper)
internalpurereturns (stringmemory result)
{
/// @solidity memory-safe-assemblyassembly {
let length :=mload(subject)
if length {
result :=add(mload(0x40), 0x20)
subject :=add(subject, 1)
let flags :=shl(add(70, shl(5, toUpper)), 0x3ffffff)
let w :=not(0)
for { let o := length } 1 {} {
o :=add(o, w)
let b :=and(0xff, mload(add(subject, o)))
mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))
ifiszero(o) { break }
}
result :=mload(0x40)
mstore(result, length) // Store the length.let last :=add(add(result, 0x20), length)
mstore(last, 0) // Zeroize the slot after the string.mstore(0x40, add(last, 0x20)) // Allocate the memory.
}
}
}
/// @dev Returns a string from a small bytes32 string./// `smallString` must be null terminated, or behavior will be undefined.functionfromSmallString(bytes32 smallString) internalpurereturns (stringmemory result) {
if (smallString ==bytes32(0)) return result;
/// @solidity memory-safe-assemblyassembly {
result :=mload(0x40)
let n :=0for {} 1 {} {
n :=add(n, 1)
ifiszero(byte(n, smallString)) { break } // Scan for '\0'.
}
mstore(result, n)
let o :=add(result, 0x20)
mstore(o, smallString)
mstore(add(o, n), 0)
mstore(0x40, add(result, 0x40))
}
}
/// @dev Returns a lowercased copy of the string./// WARNING! This function is only compatible with 7-bit ASCII strings.functionlower(stringmemory subject) internalpurereturns (stringmemory result) {
result = toCase(subject, false);
}
/// @dev Returns an UPPERCASED copy of the string./// WARNING! This function is only compatible with 7-bit ASCII strings.functionupper(stringmemory subject) internalpurereturns (stringmemory result) {
result = toCase(subject, true);
}
/// @dev Escapes the string to be used within HTML tags.functionescapeHTML(stringmemory s) internalpurereturns (stringmemory result) {
/// @solidity memory-safe-assemblyassembly {
let end :=add(s, mload(s))
result :=add(mload(0x40), 0x20)
// Store the bytes of the packed offsets and strides into the scratch space.// `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.mstore(0x1f, 0x900094)
mstore(0x08, 0xc0000000a6ab)
// Store ""&'<>" into the scratch space.mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))
for {} iszero(eq(s, end)) {} {
s :=add(s, 1)
let c :=and(mload(s), 0xff)
// Not in `["\"","'","&","<",">"]`.ifiszero(and(shl(c, 1), 0x500000c400000000)) {
mstore8(result, c)
result :=add(result, 1)
continue
}
let t :=shr(248, mload(c))
mstore(result, mload(and(t, 0x1f)))
result :=add(result, shr(5, t))
}
let last := result
mstore(last, 0) // Zeroize the slot after the string.
result :=mload(0x40)
mstore(result, sub(last, add(result, 0x20))) // Store the length.mstore(0x40, add(last, 0x20)) // Allocate the memory.
}
}
/// @dev Escapes the string to be used within double-quotes in a JSON./// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.functionescapeJSON(stringmemory s, bool addDoubleQuotes)
internalpurereturns (stringmemory result)
{
/// @solidity memory-safe-assemblyassembly {
let end :=add(s, mload(s))
result :=add(mload(0x40), 0x20)
if addDoubleQuotes {
mstore8(result, 34)
result :=add(1, result)
}
// Store "\\u0000" in scratch space.// Store "0123456789abcdef" in scratch space.// Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`.// into the scratch space.mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)
// Bitmask for detecting `["\"","\\"]`.let e :=or(shl(0x22, 1), shl(0x5c, 1))
for {} iszero(eq(s, end)) {} {
s :=add(s, 1)
let c :=and(mload(s), 0xff)
ifiszero(lt(c, 0x20)) {
ifiszero(and(shl(c, 1), e)) {
// Not in `["\"","\\"]`.mstore8(result, c)
result :=add(result, 1)
continue
}
mstore8(result, 0x5c) // "\\".mstore8(add(result, 1), c)
result :=add(result, 2)
continue
}
ifiszero(and(shl(c, 1), 0x3700)) {
// Not in `["\b","\t","\n","\f","\d"]`.mstore8(0x1d, mload(shr(4, c))) // Hex value.mstore8(0x1e, mload(and(c, 15))) // Hex value.mstore(result, mload(0x19)) // "\\u00XX".
result :=add(result, 6)
continue
}
mstore8(result, 0x5c) // "\\".mstore8(add(result, 1), mload(add(c, 8)))
result :=add(result, 2)
}
if addDoubleQuotes {
mstore8(result, 34)
result :=add(1, result)
}
let last := result
mstore(last, 0) // Zeroize the slot after the string.
result :=mload(0x40)
mstore(result, sub(last, add(result, 0x20))) // Store the length.mstore(0x40, add(last, 0x20)) // Allocate the memory.
}
}
/// @dev Escapes the string to be used within double-quotes in a JSON.functionescapeJSON(stringmemory s) internalpurereturns (stringmemory result) {
result = escapeJSON(s, false);
}
/// @dev Returns whether `a` equals `b`.functioneq(stringmemory a, stringmemory b) internalpurereturns (bool result) {
/// @solidity memory-safe-assemblyassembly {
result :=eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
}
}
/// @dev Returns whether `a` equals `b`. For small strings up to 32 bytes./// `b` must be null terminated, or behavior will be undefined.functioneqs(stringmemory a, bytes32 b) internalpurereturns (bool result) {
/// @solidity memory-safe-assemblyassembly {
// These should be evaluated on compile time, as far as possible.let x :=and(b, add(not(b), 1))
let r :=or(shl(8, iszero(b)), shl(7, iszero(iszero(shr(128, x)))))
r :=or(r, shl(6, iszero(iszero(shr(64, 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))))
result :=gt(eq(mload(a), sub(32, shr(3, r))), shr(r, xor(b, mload(add(a, 0x20)))))
}
}
/// @dev Packs a single string with its length into a single word./// Returns `bytes32(0)` if the length is zero or greater than 31.functionpackOne(stringmemory a) internalpurereturns (bytes32 result) {
/// @solidity memory-safe-assemblyassembly {
// We don't need to zero right pad the string,// since this is our own custom non-standard packing scheme.
result :=mul(
// Load the length and the bytes.mload(add(a, 0x1f)),
// `length != 0 && length < 32`. Abuses underflow.// Assumes that the length is valid and within the block gas limit.lt(sub(mload(a), 1), 0x1f)
)
}
}
/// @dev Unpacks a string packed using {packOne}./// Returns the empty string if `packed` is `bytes32(0)`./// If `packed` is not an output of {packOne}, the output behavior is undefined.functionunpackOne(bytes32 packed) internalpurereturns (stringmemory result) {
/// @solidity memory-safe-assemblyassembly {
// Grab the free memory pointer.
result :=mload(0x40)
// Allocate 2 words (1 for the length, 1 for the bytes).mstore(0x40, add(result, 0x40))
// Zeroize the length slot.mstore(result, 0)
// Store the length and bytes.mstore(add(result, 0x1f), packed)
// Right pad with zeroes.mstore(add(add(result, 0x20), mload(result)), 0)
}
}
/// @dev Packs two strings with their lengths into a single word./// Returns `bytes32(0)` if combined length is zero or greater than 30.functionpackTwo(stringmemory a, stringmemory b) internalpurereturns (bytes32 result) {
/// @solidity memory-safe-assemblyassembly {
let aLength :=mload(a)
// We don't need to zero right pad the strings,// since this is our own custom non-standard packing scheme.
result :=mul(
// Load the length and the bytes of `a` and `b`.or(
shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))),
mload(sub(add(b, 0x1e), aLength))
),
// `totalLength != 0 && totalLength < 31`. Abuses underflow.// Assumes that the lengths are valid and within the block gas limit.lt(sub(add(aLength, mload(b)), 1), 0x1e)
)
}
}
/// @dev Unpacks strings packed using {packTwo}./// Returns the empty strings if `packed` is `bytes32(0)`./// If `packed` is not an output of {packTwo}, the output behavior is undefined.functionunpackTwo(bytes32 packed)
internalpurereturns (stringmemory resultA, stringmemory resultB)
{
/// @solidity memory-safe-assemblyassembly {
// Grab the free memory pointer.
resultA :=mload(0x40)
resultB :=add(resultA, 0x40)
// Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.mstore(0x40, add(resultB, 0x40))
// Zeroize the length slots.mstore(resultA, 0)
mstore(resultB, 0)
// Store the lengths and bytes.mstore(add(resultA, 0x1f), packed)
mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))
// Right pad with zeroes.mstore(add(add(resultA, 0x20), mload(resultA)), 0)
mstore(add(add(resultB, 0x20), mload(resultB)), 0)
}
}
/// @dev Directly returns `a` without copying.functiondirectReturn(stringmemory a) internalpure{
assembly {
// Assumes that the string does not start from the scratch space.let retStart :=sub(a, 0x20)
let retSize :=add(mload(a), 0x40)
// Right pad with zeroes. Just in case the string is produced// by a method that doesn't zero right pad.mstore(add(retStart, retSize), 0)
// Store the return offset.mstore(retStart, 0x20)
// End the transaction, returning the string.return(retStart, retSize)
}
}
}
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)pragmasolidity ^0.8.20;/**
* @dev Standard math utilities missing in the Solidity language.
*/libraryMath{
/**
* @dev Muldiv operation overflow.
*/errorMathOverflowedMulDiv();
enumRounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/functiontryAdd(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/functiontrySub(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/functiontryMul(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the// benefit is lost if 'b' is also tested.// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522if (a ==0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/functiontryDiv(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
unchecked {
if (b ==0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/functiontryMod(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
unchecked {
if (b ==0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/functionmax(uint256 a, uint256 b) internalpurereturns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/functionmin(uint256 a, uint256 b) internalpurereturns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/functionaverage(uint256 a, uint256 b) internalpurereturns (uint256) {
// (a + b) / 2 can overflow.return (a & b) + (a ^ b) /2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/functionceilDiv(uint256 a, uint256 b) internalpurereturns (uint256) {
if (b ==0) {
// Guarantee the same behavior as in a regular Solidity division.return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.return a ==0 ? 0 : (a -1) / b +1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/functionmulDiv(uint256 x, uint256 y, uint256 denominator) internalpurereturns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256// variables such that product = prod1 * 2^256 + prod0.uint256 prod0 = x * y; // Least significant 256 bits of the productuint256 prod1; // Most significant 256 bits of the productassembly {
let mm :=mulmod(x, y, not(0))
prod1 :=sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.if (prod1 ==0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.// The surrounding unchecked block does not change this fact.// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////// 512 by 256 division.///////////////////////////////////////////////// Make division exact by subtracting the remainder from [prod1 prod0].uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder :=mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 :=sub(prod1, gt(remainder, prod0))
prod0 :=sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.uint256 twos = denominator & (0- denominator);
assembly {
// Divide denominator by twos.
denominator :=div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 :=div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos :=add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for// four bits. That is, denominator * inv = 1 mod 2^4.uint256 inverse = (3* denominator) ^2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also// works in modular arithmetic, doubling the correct bits in each step.
inverse *=2- denominator * inverse; // inverse mod 2^8
inverse *=2- denominator * inverse; // inverse mod 2^16
inverse *=2- denominator * inverse; // inverse mod 2^32
inverse *=2- denominator * inverse; // inverse mod 2^64
inverse *=2- denominator * inverse; // inverse mod 2^128
inverse *=2- denominator * inverse; // inverse mod 2^256// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/functionmulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internalpurereturns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) &&mulmod(x, y, denominator) >0) {
result +=1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/functionsqrt(uint256 a) internalpurereturns (uint256) {
if (a ==0) {
return0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.//// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.//// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`//// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.uint256 result =1<< (log2(a) >>1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision// into the expected uint128 result.unchecked {
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
result = (result + a / result) >>1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/functionsqrt(uint256 a, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/functionlog2(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >>128>0) {
value >>=128;
result +=128;
}
if (value >>64>0) {
value >>=64;
result +=64;
}
if (value >>32>0) {
value >>=32;
result +=32;
}
if (value >>16>0) {
value >>=16;
result +=16;
}
if (value >>8>0) {
value >>=8;
result +=8;
}
if (value >>4>0) {
value >>=4;
result +=4;
}
if (value >>2>0) {
value >>=2;
result +=2;
}
if (value >>1>0) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog2(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result =log2(value);
return result + (unsignedRoundsUp(rounding) &&1<< result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/functionlog10(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >=10**64) {
value /=10**64;
result +=64;
}
if (value >=10**32) {
value /=10**32;
result +=32;
}
if (value >=10**16) {
value /=10**16;
result +=16;
}
if (value >=10**8) {
value /=10**8;
result +=8;
}
if (value >=10**4) {
value /=10**4;
result +=4;
}
if (value >=10**2) {
value /=10**2;
result +=2;
}
if (value >=10**1) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog10(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) &&10** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/functionlog256(uint256 value) internalpurereturns (uint256) {
uint256 result =0;
unchecked {
if (value >>128>0) {
value >>=128;
result +=16;
}
if (value >>64>0) {
value >>=64;
result +=8;
}
if (value >>32>0) {
value >>=32;
result +=4;
}
if (value >>16>0) {
value >>=16;
result +=2;
}
if (value >>8>0) {
result +=1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/functionlog256(uint256 value, Rounding rounding) internalpurereturns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) &&1<< (result <<3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/functionunsignedRoundsUp(Rounding rounding) internalpurereturns (bool) {
returnuint8(rounding) %2==1;
}
}
Contract Source Code
File 23 of 28: Ownable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)pragmasolidity ^0.8.20;import {Context} from"../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/abstractcontractOwnableisContext{
addressprivate _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/errorOwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/errorOwnableInvalidOwner(address owner);
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/constructor(address initialOwner) {
if (initialOwner ==address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/function_checkOwner() internalviewvirtual{
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/functionrenounceOwnership() publicvirtualonlyOwner{
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
if (newOwner ==address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/function_transferOwnership(address newOwner) internalvirtual{
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Contract Source Code
File 24 of 28: PullPayment.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.8.0) (security/PullPayment.sol)pragmasolidity ^0.8.0;import"./Escrow.sol";
/**
* @dev Simple implementation of a
* https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/external-calls/#favor-pull-over-push-for-external-calls[pull-payment]
* strategy, where the paying contract doesn't interact directly with the
* receiver account, which must withdraw its payments itself.
*
* Pull-payments are often considered the best practice when it comes to sending
* Ether, security-wise. It prevents recipients from blocking execution, and
* eliminates reentrancy concerns.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*
* To use, derive from the `PullPayment` contract, and use {_asyncTransfer}
* instead of Solidity's `transfer` function. Payees can query their due
* payments with {payments}, and retrieve them with {withdrawPayments}.
*/abstractcontractPullPayment{
Escrow privateimmutable _escrow;
constructor() {
_escrow =new Escrow();
}
/**
* @dev Withdraw accumulated payments, forwarding all gas to the recipient.
*
* Note that _any_ account can call this function, not just the `payee`.
* This means that contracts unaware of the `PullPayment` protocol can still
* receive funds this way, by having a separate account call
* {withdrawPayments}.
*
* WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities.
* Make sure you trust the recipient, or are either following the
* checks-effects-interactions pattern or using {ReentrancyGuard}.
*
* @param payee Whose payments will be withdrawn.
*
* Causes the `escrow` to emit a {Withdrawn} event.
*/functionwithdrawPayments(addresspayable payee) publicvirtual{
_escrow.withdraw(payee);
}
/**
* @dev Returns the payments owed to an address.
* @param dest The creditor's address.
*/functionpayments(address dest) publicviewreturns (uint256) {
return _escrow.depositsOf(dest);
}
/**
* @dev Called by the payer to store the sent amount as credit to be pulled.
* Funds sent in this way are stored in an intermediate {Escrow} contract, so
* there is no danger of them being spent before withdrawal.
*
* @param dest The destination address of the funds.
* @param amount The amount to transfer.
*
* Causes the `escrow` to emit a {Deposited} event.
*/function_asyncTransfer(address dest, uint256 amount) internalvirtual{
_escrow.deposit{value: amount}(dest);
}
}
Contract Source Code
File 25 of 28: ReentrancyGuard.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)pragmasolidity ^0.8.20;/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/abstractcontractReentrancyGuard{
// Booleans are more expensive than uint256 or any type that takes up a full// word because each write operation emits an extra SLOAD to first read the// slot's contents, replace the bits taken up by the boolean, and then write// back. This is the compiler's defense against contract upgrades and// pointer aliasing, and it cannot be disabled.// The values being non-zero value makes deployment a bit more expensive,// but in exchange the refund on every call to nonReentrant will be lower in// amount. Since refunds are capped to a percentage of the total// transaction's gas, it is best to keep them low in cases like this one, to// increase the likelihood of the full refund coming into effect.uint256privateconstant NOT_ENTERED =1;
uint256privateconstant ENTERED =2;
uint256private _status;
/**
* @dev Unauthorized reentrant call.
*/errorReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/modifiernonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function_nonReentrantBefore() private{
// On the first call to nonReentrant, _status will be NOT_ENTEREDif (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function_nonReentrantAfter() private{
// By storing the original value once again, a refund is triggered (see// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/function_reentrancyGuardEntered() internalviewreturns (bool) {
return _status == ENTERED;
}
}
Contract Source Code
File 26 of 28: SignedMath.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)pragmasolidity ^0.8.20;/**
* @dev Standard signed math utilities missing in the Solidity language.
*/librarySignedMath{
/**
* @dev Returns the largest of two signed numbers.
*/functionmax(int256 a, int256 b) internalpurereturns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/functionmin(int256 a, int256 b) internalpurereturns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/functionaverage(int256 a, int256 b) internalpurereturns (int256) {
// Formula from the book "Hacker's Delight"int256 x = (a & b) + ((a ^ b) >>1);
return x + (int256(uint256(x) >>255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/functionabs(int256 n) internalpurereturns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`returnuint256(n >=0 ? n : -n);
}
}
}
Contract Source Code
File 27 of 28: Strings.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)pragmasolidity ^0.8.20;import {Math} from"./math/Math.sol";
import {SignedMath} from"./math/SignedMath.sol";
/**
* @dev String operations.
*/libraryStrings{
bytes16privateconstant HEX_DIGITS ="0123456789abcdef";
uint8privateconstant ADDRESS_LENGTH =20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/errorStringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/functiontoString(uint256 value) internalpurereturns (stringmemory) {
unchecked {
uint256 length = Math.log10(value) +1;
stringmemory buffer =newstring(length);
uint256 ptr;
/// @solidity memory-safe-assemblyassembly {
ptr :=add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assemblyassembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /=10;
if (value ==0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/functiontoStringSigned(int256 value) internalpurereturns (stringmemory) {
returnstring.concat(value <0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/functiontoHexString(uint256 value) internalpurereturns (stringmemory) {
unchecked {
return toHexString(value, Math.log256(value) +1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/functiontoHexString(uint256 value, uint256 length) internalpurereturns (stringmemory) {
uint256 localValue = value;
bytesmemory buffer =newbytes(2* length +2);
buffer[0] ="0";
buffer[1] ="x";
for (uint256 i =2* length +1; i >1; --i) {
buffer[i] = HEX_DIGITS[localValue &0xf];
localValue >>=4;
}
if (localValue !=0) {
revert StringsInsufficientHexLength(value, length);
}
returnstring(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/functiontoHexString(address addr) internalpurereturns (stringmemory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/functionequal(stringmemory a, stringmemory b) internalpurereturns (bool) {
returnbytes(a).length==bytes(b).length&&keccak256(bytes(a)) ==keccak256(bytes(b));
}
}
Contract Source Code
File 28 of 28: TimeLock.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.23;/**
* @title TimeLock
* @dev This contract provides a time lock mechanism. Functions with the `timeLocked` modifier
* can only be called after either `startTime` or `lastTime` has expired.
*/contractTimeLock{
uint256internalconstant MAX_LOCK =type(uint256).max;
uint256public startTime;
uint256public lastTime;
uint256public startLock;
uint256public lastLock;
errorErrorTimeLocked(uint256 remaining);
/**
* @dev Initializes the contract setting the `startLock` and `lastLock` state variables.
* @param _startLock The max time after `startTime` when function can be called.
* @param _lastLock The max time after `lastTime` when function can be called.
*/constructor(uint256 _startLock, uint256 _lastLock) {
startLock = _startLock;
lastLock = _lastLock;
}
/**
* @dev Modifier to make a function callable only after the lock has expired.
*/modifiertimeLocked() {
uint256 t = timeLockLeft();
if (t >0) revert ErrorTimeLocked(t);
_;
}
/**
* @dev Set the last time and initialize start time if not set.
*/functiontimeLock() internal{
if (timeLockExpired()) return;
lastTime =block.timestamp;
if (startTime ==0) startTime = lastTime;
}
/**
* @dev Reset the start and last time to zero.
*/functionresetTimeLock() internal{
startTime = lastTime =0;
}
/**
* @dev Check if the time lock is active (not expired).
* @return Time remaining if lock is active, false otherwise.
*/functiontimeLockLeft() internalviewreturns (uint256) {
if (startTime ==0) return MAX_LOCK;
uint256 cancelTime = _cancelTime(startLock, lastLock);
return (block.timestamp< cancelTime) ? cancelTime -block.timestamp : 0;
}
/**
* @dev Check if the time is expired past the start time lock.
* @return True if time is expired past start time lock, false otherwise.
*/functiontimeLockExpired() internalviewreturns (bool) {
return startTime >0&&block.timestamp> (startTime + startLock);
}
/**
* @dev Calculate the time at which the lock will cancel.
* This is an assembly-optimized version of comparing startTime + startLock with lastTime + lastLock.
* @return The time at which the lock will cancel.
*/function_cancelTime(uint256 _startLock, uint256 _lastLock) privateviewreturns (uint256) {
uint256 result;
assembly {
let s :=add(sload(startTime.slot), _startLock)
let l :=add(sload(lastTime.slot), _lastLock)
result :=or(mul(lt(s, l), s), mul(iszero(lt(s, l)), l))
}
return result;
}
}