Transaction Hash:
Block:
20834506 at Sep-26-2024 11:31:35 AM +UTC
Transaction Fee:
0.000734510171154633 ETH
$1.94
Gas Used:
50,667 Gas / 14.496815899 Gwei
Emitted Events:
174 |
ERC1155SeaDropCloneable.TransferSingle( operator=[Sender] 0xc69088eb5f015fca5b385b8e3a0463749813093e, from=[Sender] 0xc69088eb5f015fca5b385b8e3a0463749813093e, to=0xaFf82c8D...2204C1347, id=1, amount=12 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x4838B106...B0BAD5f97
Miner
| (Titan Builder) | 12.281578747966767899 Eth | 12.281629414966767899 Eth | 0.000050667 | |
0x7931574A...d4AF0a151 | |||||
0xC69088eB...49813093e |
0.02506009492657523 Eth
Nonce: 558
|
0.024325584755420597 Eth
Nonce: 559
| 0.000734510171154633 |
Execution Trace
ERC1155SeaDropCloneable.safeTransferFrom( from=0xC69088eB5F015Fca5B385b8E3A0463749813093e, to=0xaFf82c8D46F4F6E6771f9f92e2E090e2204C1347, id=1, amount=12, data=0x )

ERC1155SeaDropCloneable.safeTransferFrom( from=0xC69088eB5F015Fca5B385b8E3A0463749813093e, to=0xaFf82c8D46F4F6E6771f9f92e2E090e2204C1347, id=1, amount=12, data=0x )
-
CreatorTokenTransferValidator.validateTransfer( caller=0xC69088eB5F015Fca5B385b8E3A0463749813093e, from=0xC69088eB5F015Fca5B385b8E3A0463749813093e, to=0xaFf82c8D46F4F6E6771f9f92e2E090e2204C1347, tokenId=1, 12 )
-
File 1 of 3: ERC1155SeaDropCloneable
File 2 of 3: ERC1155SeaDropCloneable
File 3 of 3: CreatorTokenTransferValidator
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { ERC1155SeaDropContractOffererCloneable } from "./ERC1155SeaDropContractOffererCloneable.sol"; /** * @title ERC1155SeaDropCloneable * @author James Wenzel (emo.eth) * @author Ryan Ghods (ralxz.eth) * @author Stephan Min (stephanm.eth) * @author Michael Cohen (notmichael.eth) * @custom:contributor Limit Break (@limitbreak) * @notice A cloneable ERC1155 token contract that can mint as a * Seaport contract offerer. * Implements Limit Break's Creator Token Standards transfer * validation for royalty enforcement. */ contract ERC1155SeaDropCloneable is ERC1155SeaDropContractOffererCloneable { /** * @notice Initialize the token contract. * * @param allowedConfigurer The address of the contract allowed to * implementation code. Also contains SeaDrop * implementation code. * @param allowedSeaport The address of the Seaport contract allowed to * interact. * @param name_ The name of the token. * @param symbol_ The symbol of the token. */ function initialize( address allowedConfigurer, address allowedSeaport, string memory name_, string memory symbol_, address initialOwner ) public initializer { // Initialize ownership. _initializeOwner(initialOwner); // Initialize ERC1155SeaDropContractOffererCloneable. __ERC1155SeaDropContractOffererCloneable_init( allowedConfigurer, allowedSeaport, name_, symbol_ ); } /** * @notice Burns a token, restricted to the owner or approved operator, * and must have sufficient balance. * * @param from The address to burn from. * @param id The token id to burn. * @param amount The amount to burn. */ function burn(address from, uint256 id, uint256 amount) external { // Burn the token. _burn(msg.sender, from, id, amount); } /** * @notice Burns a batch of tokens, restricted to the owner or * approved operator, and must have sufficient balance. * * @param from The address to burn from. * @param ids The token ids to burn. * @param amounts The amounts to burn per token id. */ function batchBurn( address from, uint256[] calldata ids, uint256[] calldata amounts ) external { // Burn the tokens. _batchBurn(msg.sender, from, ids, amounts); } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { IERC1155SeaDrop } from "../interfaces/IERC1155SeaDrop.sol"; import { ISeaDropToken } from "../interfaces/ISeaDropToken.sol"; import { ERC1155ContractMetadataCloneable } from "./ERC1155ContractMetadataCloneable.sol"; import { ERC1155SeaDropContractOffererStorage } from "../lib/ERC1155SeaDropContractOffererStorage.sol"; import { ERC1155SeaDropErrorsAndEvents } from "../lib/ERC1155SeaDropErrorsAndEvents.sol"; import { PublicDrop } from "../lib//ERC1155SeaDropStructs.sol"; import { AllowListData } from "../lib/SeaDropStructs.sol"; import { ERC1155ConduitPreapproved } from "../lib/ERC1155ConduitPreapproved.sol"; import { ERC1155 } from "solady/src/tokens/ERC1155.sol"; import { SpentItem } from "seaport-types/src/lib/ConsiderationStructs.sol"; import { ContractOffererInterface } from "seaport-types/src/interfaces/ContractOffererInterface.sol"; import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /** * @title ERC1155SeaDropContractOffererCloneable * @author James Wenzel (emo.eth) * @author Ryan Ghods (ralxz.eth) * @author Stephan Min (stephanm.eth) * @author Michael Cohen (notmichael.eth) * @notice A cloneable ERC1155 token contract that can mint as a * Seaport contract offerer. */ contract ERC1155SeaDropContractOffererCloneable is ERC1155ContractMetadataCloneable, ERC1155SeaDropErrorsAndEvents { using ERC1155SeaDropContractOffererStorage for ERC1155SeaDropContractOffererStorage.Layout; /** * @notice Initialize the token contract. * * @param allowedConfigurer The address of the contract allowed to * configure parameters. Also contains SeaDrop * implementation code. * @param allowedSeaport The address of the Seaport contract allowed to * interact. * @param name_ The name of the token. * @param symbol_ The symbol of the token. */ function __ERC1155SeaDropContractOffererCloneable_init( address allowedConfigurer, address allowedSeaport, string memory name_, string memory symbol_ ) internal onlyInitializing { // Set the allowed Seaport to interact with this contract. if (allowedSeaport == address(0)) { revert AllowedSeaportCannotBeZeroAddress(); } ERC1155SeaDropContractOffererStorage.layout()._allowedSeaport[ allowedSeaport ] = true; // Set the allowed Seaport enumeration. address[] memory enumeratedAllowedSeaport = new address[](1); enumeratedAllowedSeaport[0] = allowedSeaport; ERC1155SeaDropContractOffererStorage .layout() ._enumeratedAllowedSeaport = enumeratedAllowedSeaport; // Emit an event noting the contract deployment. emit SeaDropTokenDeployed(SEADROP_TOKEN_TYPE.ERC1155_CLONE); // Initialize ERC1155ContractMetadataCloneable. __ERC1155ContractMetadataCloneable_init( allowedConfigurer, name_, symbol_ ); } /** * @notice The fallback function is used as a dispatcher for SeaDrop * methods. */ fallback(bytes calldata) external returns (bytes memory output) { // Get the function selector. bytes4 selector = msg.sig; // Get the rest of the msg data after the selector. bytes calldata data = msg.data[4:]; // Determine if we should forward the call to the implementation // contract with SeaDrop logic. bool callSeaDropImplementation = selector == ISeaDropToken.updateAllowedSeaport.selector || selector == ISeaDropToken.updateDropURI.selector || selector == ISeaDropToken.updateAllowList.selector || selector == ISeaDropToken.updateCreatorPayouts.selector || selector == ISeaDropToken.updatePayer.selector || selector == ISeaDropToken.updateAllowedFeeRecipient.selector || selector == ISeaDropToken.updateSigner.selector || selector == IERC1155SeaDrop.updatePublicDrop.selector || selector == ContractOffererInterface.previewOrder.selector || selector == ContractOffererInterface.generateOrder.selector || selector == ContractOffererInterface.getSeaportMetadata.selector || selector == IERC1155SeaDrop.getPublicDrop.selector || selector == IERC1155SeaDrop.getPublicDropIndexes.selector || selector == ISeaDropToken.getAllowedSeaport.selector || selector == ISeaDropToken.getCreatorPayouts.selector || selector == ISeaDropToken.getAllowListMerkleRoot.selector || selector == ISeaDropToken.getAllowedFeeRecipients.selector || selector == ISeaDropToken.getSigners.selector || selector == ISeaDropToken.getDigestIsUsed.selector || selector == ISeaDropToken.getPayers.selector; // Determine if we should require only the owner or configurer calling. bool requireOnlyOwnerOrConfigurer = selector == ISeaDropToken.updateAllowedSeaport.selector || selector == ISeaDropToken.updateDropURI.selector || selector == ISeaDropToken.updateAllowList.selector || selector == ISeaDropToken.updateCreatorPayouts.selector || selector == ISeaDropToken.updatePayer.selector || selector == ISeaDropToken.updateAllowedFeeRecipient.selector || selector == IERC1155SeaDrop.updatePublicDrop.selector; if (callSeaDropImplementation) { // For update calls, ensure the sender is only the owner // or configurer contract. if (requireOnlyOwnerOrConfigurer) { _onlyOwnerOrConfigurer(); } else if (selector == ISeaDropToken.updateSigner.selector) { // For updateSigner, a signer can disallow themselves. // Get the signer parameter. address signer = address(bytes20(data[12:32])); // If the signer is not allowed, ensure sender is only owner // or configurer. if ( msg.sender != signer || (msg.sender == signer && !ERC1155SeaDropContractOffererStorage .layout() ._allowedSigners[signer]) ) { _onlyOwnerOrConfigurer(); } } // Forward the call to the implementation contract. (bool success, bytes memory returnedData) = _CONFIGURER .delegatecall(msg.data); // Require that the call was successful. if (!success) { // Bubble up the revert reason. assembly { revert(add(32, returnedData), mload(returnedData)) } } // If the call was to generateOrder, mint the tokens. if (selector == ContractOffererInterface.generateOrder.selector) { _mintOrder(data); } // Return the data from the delegate call. return returnedData; } else if (selector == IERC1155SeaDrop.getMintStats.selector) { // Get the minter and token id. (address minter, uint256 tokenId) = abi.decode( data, (address, uint256) ); // Get the mint stats. ( uint256 minterNumMinted, uint256 minterNumMintedForTokenId, uint256 totalMintedForTokenId, uint256 maxSupply ) = _getMintStats(minter, tokenId); // Encode the return data. return abi.encode( minterNumMinted, minterNumMintedForTokenId, totalMintedForTokenId, maxSupply ); } else if (selector == ContractOffererInterface.ratifyOrder.selector) { // This function is a no-op, nothing additional needs to happen here. // Utilize assembly to efficiently return the ratifyOrder magic value. assembly { mstore(0, 0xf4dd92ce) return(0x1c, 32) } } else if (selector == ISeaDropToken.configurer.selector) { // Return the configurer contract. return abi.encode(_CONFIGURER); } else if (selector == IERC1155SeaDrop.multiConfigureMint.selector) { // Ensure only the owner or configurer can call this function. _onlyOwnerOrConfigurer(); // Mint the tokens. _multiConfigureMint(data); } else { // Revert if the function selector is not supported. revert UnsupportedFunctionSelector(selector); } } /** * @notice Returns a set of mint stats for the address. * This assists in enforcing maxSupply, maxTotalMintableByWallet, * and maxTokenSupplyForStage checks. * * @dev NOTE: Implementing contracts should always update these numbers * before transferring any tokens with _safeMint() to mitigate * consequences of malicious onERC1155Received() hooks. * * @param minter The minter address. * @param tokenId The token id to return the stats for. */ function _getMintStats( address minter, uint256 tokenId ) internal view returns ( uint256 minterNumMinted, uint256 minterNumMintedForTokenId, uint256 totalMintedForTokenId, uint256 maxSupply ) { // Put the token supply on the stack. TokenSupply storage tokenSupply = _tokenSupply[tokenId]; // Assign the return values. totalMintedForTokenId = tokenSupply.totalMinted; maxSupply = tokenSupply.maxSupply; minterNumMinted = _totalMintedByUser[minter]; minterNumMintedForTokenId = _totalMintedByUserPerToken[minter][tokenId]; } /** * @dev Handle ERC-1155 safeTransferFrom. If "from" is this contract, * the sender can only be Seaport or the conduit. * * @param from The address to transfer from. * @param to The address to transfer to. * @param id The token id to transfer. * @param amount The amount of tokens to transfer. * @param data The data to pass to the onERC1155Received hook. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) public virtual override { if (from == address(this)) { // Only Seaport or the conduit can use this function // when "from" is this contract. if ( msg.sender != _CONDUIT && !ERC1155SeaDropContractOffererStorage.layout()._allowedSeaport[ msg.sender ] ) { revert InvalidCallerOnlyAllowedSeaport(msg.sender); } return; } ERC1155._safeTransfer(_by(), from, to, id, amount, data); } /** * @notice Returns whether the interface is supported. * * @param interfaceId The interface id to check against. */ function supportsInterface( bytes4 interfaceId ) public view virtual override(ERC1155ContractMetadataCloneable) returns (bool) { return interfaceId == type(IERC1155SeaDrop).interfaceId || interfaceId == type(ContractOffererInterface).interfaceId || interfaceId == 0x2e778efc || // SIP-5 (getSeaportMetadata) // ERC1155ContractMetadata returns supportsInterface true for // IERC1155ContractMetadata, ERC-4906, ERC-2981 // ERC1155A returns supportsInterface true for // ERC165, ERC1155, ERC1155MetadataURI ERC1155ContractMetadataCloneable.supportsInterface(interfaceId); } /** * @dev Internal function to mint tokens during a generateOrder call * from Seaport. * * @param data The original transaction calldata, without the selector. */ function _mintOrder(bytes calldata data) internal { // Decode fulfiller, minimumReceived, and context from calldata. ( address fulfiller, SpentItem[] memory minimumReceived, , bytes memory context ) = abi.decode(data, (address, SpentItem[], SpentItem[], bytes)); // Assign the minter from context[22:42]. We validate context has the // correct minimum length in the implementation's `_decodeOrder`. address minter; assembly { minter := shr(96, mload(add(add(context, 0x20), 22))) } // If the minter is the zero address, set it to the fulfiller. if (minter == address(0)) { minter = fulfiller; } // Set the token ids and quantities. uint256 minimumReceivedLength = minimumReceived.length; uint256[] memory tokenIds = new uint256[](minimumReceivedLength); uint256[] memory quantities = new uint256[](minimumReceivedLength); for (uint256 i = 0; i < minimumReceivedLength; ) { tokenIds[i] = minimumReceived[i].identifier; quantities[i] = minimumReceived[i].amount; unchecked { ++i; } } // Mint the tokens. _batchMint(minter, tokenIds, quantities, ""); } /** * @dev Internal function to mint tokens during a multiConfigureMint call * from the configurer contract. * * @param data The original transaction calldata, without the selector. */ function _multiConfigureMint(bytes calldata data) internal { // Decode the calldata. ( address recipient, uint256[] memory tokenIds, uint256[] memory amounts ) = abi.decode(data, (address, uint256[], uint256[])); _batchMint(recipient, tokenIds, amounts, ""); } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { ISeaDropToken } from "./ISeaDropToken.sol"; import { PublicDrop } from "../lib/ERC1155SeaDropStructs.sol"; /** * @dev A helper interface to get and set parameters for ERC1155SeaDrop. * The token does not expose these methods as part of its external * interface to optimize contract size, but does implement them. */ interface IERC1155SeaDrop is ISeaDropToken { /** * @notice Update the SeaDrop public drop parameters at a given index. * * @param publicDrop The new public drop parameters. * @param index The public drop index. */ function updatePublicDrop( PublicDrop calldata publicDrop, uint256 index ) external; /** * @notice Returns the public drop stage parameters at a given index. * * @param index The index of the public drop stage. */ function getPublicDrop( uint256 index ) external view returns (PublicDrop memory); /** * @notice Returns the public drop indexes. */ function getPublicDropIndexes() external view returns (uint256[] memory); /** * @notice Returns a set of mint stats for the address. * This assists SeaDrop in enforcing maxSupply, * maxTotalMintableByWallet, maxTotalMintableByWalletPerToken, * and maxTokenSupplyForStage checks. * * @dev NOTE: Implementing contracts should always update these numbers * before transferring any tokens with _safeMint() to mitigate * consequences of malicious onERC1155Received() hooks. * * @param minter The minter address. * @param tokenId The token id to return stats for. */ function getMintStats( address minter, uint256 tokenId ) external view returns ( uint256 minterNumMinted, uint256 minterNumMintedForTokenId, uint256 totalMintedForTokenId, uint256 maxSupply ); /** * @notice This function is only allowed to be called by the configurer * contract as a way to batch mints and configuration in one tx. * * @param recipient The address to receive the mints. * @param tokenIds The tokenIds to mint. * @param amounts The amounts to mint. */ function multiConfigureMint( address recipient, uint256[] calldata tokenIds, uint256[] calldata amounts ) external; } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { ISeaDropTokenContractMetadata } from "./ISeaDropTokenContractMetadata.sol"; import { AllowListData, CreatorPayout } from "../lib/SeaDropStructs.sol"; /** * @dev A helper base interface for IERC721SeaDrop and IERC1155SeaDrop. * The token does not expose these methods as part of its external * interface to optimize contract size, but does implement them. */ interface ISeaDropToken is ISeaDropTokenContractMetadata { /** * @notice Update the SeaDrop allowed Seaport contracts privileged to mint. * Only the owner can use this function. * * @param allowedSeaport The allowed Seaport addresses. */ function updateAllowedSeaport(address[] calldata allowedSeaport) external; /** * @notice Update the SeaDrop allowed fee recipient. * Only the owner can use this function. * * @param feeRecipient The new fee recipient. * @param allowed Whether the fee recipient is allowed. */ function updateAllowedFeeRecipient( address feeRecipient, bool allowed ) external; /** * @notice Update the SeaDrop creator payout addresses. * The total basis points must add up to exactly 10_000. * Only the owner can use this function. * * @param creatorPayouts The new creator payouts. */ function updateCreatorPayouts( CreatorPayout[] calldata creatorPayouts ) external; /** * @notice Update the SeaDrop drop URI. * Only the owner can use this function. * * @param dropURI The new drop URI. */ function updateDropURI(string calldata dropURI) external; /** * @notice Update the SeaDrop allow list data. * Only the owner can use this function. * * @param allowListData The new allow list data. */ function updateAllowList(AllowListData calldata allowListData) external; /** * @notice Update the SeaDrop allowed payers. * Only the owner can use this function. * * @param payer The payer to update. * @param allowed Whether the payer is allowed. */ function updatePayer(address payer, bool allowed) external; /** * @notice Update the SeaDrop allowed signer. * Only the owner can use this function. * An allowed signer can also disallow themselves. * * @param signer The signer to update. * @param allowed Whether the signer is allowed. */ function updateSigner(address signer, bool allowed) external; /** * @notice Get the SeaDrop allowed Seaport contracts privileged to mint. */ function getAllowedSeaport() external view returns (address[] memory); /** * @notice Returns the SeaDrop creator payouts. */ function getCreatorPayouts() external view returns (CreatorPayout[] memory); /** * @notice Returns the SeaDrop allow list merkle root. */ function getAllowListMerkleRoot() external view returns (bytes32); /** * @notice Returns the SeaDrop allowed fee recipients. */ function getAllowedFeeRecipients() external view returns (address[] memory); /** * @notice Returns the SeaDrop allowed signers. */ function getSigners() external view returns (address[] memory); /** * @notice Returns if the signed digest has been used. * * @param digest The digest hash. */ function getDigestIsUsed(bytes32 digest) external view returns (bool); /** * @notice Returns the SeaDrop allowed payers. */ function getPayers() external view returns (address[] memory); /** * @notice Returns the configurer contract. */ function configurer() external view returns (address); } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { IERC1155ContractMetadata } from "../interfaces/IERC1155ContractMetadata.sol"; import { ERC1155ConduitPreapproved } from "../lib/ERC1155ConduitPreapproved.sol"; import { ICreatorToken, ILegacyCreatorToken } from "../interfaces/ICreatorToken.sol"; import { ITransferValidator1155 } from "../interfaces/ITransferValidator.sol"; import { TokenTransferValidator } from "../lib/TokenTransferValidator.sol"; import { ERC1155 } from "solady/src/tokens/ERC1155.sol"; import { ERC2981 } from "solady/src/tokens/ERC2981.sol"; import { Ownable } from "solady/src/auth/Ownable.sol"; import { Initializable } from "@openzeppelin-upgradeable/contracts/proxy/utils/Initializable.sol"; /** * @title ERC1155ContractMetadataCloneable * @author James Wenzel (emo.eth) * @author Ryan Ghods (ralxz.eth) * @author Stephan Min (stephanm.eth) * @author Michael Cohen (notmichael.eth) * @notice A cloneable token contract that extends ERC-1155 * with additional metadata and ownership capabilities. */ contract ERC1155ContractMetadataCloneable is ERC1155ConduitPreapproved, TokenTransferValidator, ERC2981, Ownable, IERC1155ContractMetadata, Initializable { /// @notice A struct containing the token supply info per token id. mapping(uint256 => TokenSupply) _tokenSupply; /// @notice The total number of tokens minted by address. mapping(address => uint256) _totalMintedByUser; /// @notice The total number of tokens minted per token id by address. mapping(address => mapping(uint256 => uint256)) _totalMintedByUserPerToken; /// @notice The name of the token. string internal _name; /// @notice The symbol of the token. string internal _symbol; /// @notice The base URI for token metadata. string internal _baseURI; /// @notice The contract URI for contract metadata. string internal _contractURI; /// @notice The provenance hash for guaranteeing metadata order /// for random reveals. bytes32 internal _provenanceHash; /// @notice The allowed contract that can configure SeaDrop parameters. address internal _CONFIGURER; /** * @dev Reverts if the sender is not the owner or the allowed * configurer contract. * * This is used as a function instead of a modifier * to save contract space when used multiple times. */ function _onlyOwnerOrConfigurer() internal view { if (msg.sender != _CONFIGURER && msg.sender != owner()) { revert Unauthorized(); } } /** * @notice Deploy the token contract. * * @param allowedConfigurer The address of the contract allowed to * configure parameters. Also contains SeaDrop * implementation code. * @param name_ The name of the token. * @param symbol_ The symbol of the token. */ function __ERC1155ContractMetadataCloneable_init( address allowedConfigurer, string memory name_, string memory symbol_ ) internal onlyInitializing { // Set the name of the token. _name = name_; // Set the symbol of the token. _symbol = symbol_; // Set the allowed configurer contract to interact with this contract. _CONFIGURER = allowedConfigurer; } /** * @notice Sets the base URI for the token metadata and emits an event. * * @param newBaseURI The new base URI to set. */ function setBaseURI(string calldata newBaseURI) external override { // Ensure the sender is only the owner or configurer contract. _onlyOwnerOrConfigurer(); // Set the new base URI. _baseURI = newBaseURI; // Emit an event with the update. emit BatchMetadataUpdate(0, type(uint256).max); } /** * @notice Sets the contract URI for contract metadata. * * @param newContractURI The new contract URI. */ function setContractURI(string calldata newContractURI) external override { // Ensure the sender is only the owner or configurer contract. _onlyOwnerOrConfigurer(); // Set the new contract URI. _contractURI = newContractURI; // Emit an event with the update. emit ContractURIUpdated(newContractURI); } /** * @notice Emit an event notifying metadata updates for * a range of token ids, according to EIP-4906. * * @param fromTokenId The start token id. * @param toTokenId The end token id. */ function emitBatchMetadataUpdate( uint256 fromTokenId, uint256 toTokenId ) external { // Ensure the sender is only the owner or configurer contract. _onlyOwnerOrConfigurer(); // Emit an event with the update. if (fromTokenId == toTokenId) { // If only one token is being updated, use the event // in the 1155 spec. emit URI(uri(fromTokenId), fromTokenId); } else { emit BatchMetadataUpdate(fromTokenId, toTokenId); } } /** * @notice Sets the max token supply and emits an event. * * @param tokenId The token id to set the max supply for. * @param newMaxSupply The new max supply to set. */ function setMaxSupply(uint256 tokenId, uint256 newMaxSupply) external { // Ensure the sender is only the owner or configurer contract. _onlyOwnerOrConfigurer(); // Ensure the max supply does not exceed the maximum value of uint64, // a limit due to the storage of bit-packed variables in TokenSupply, if (newMaxSupply > 2 ** 64 - 1) { revert CannotExceedMaxSupplyOfUint64(newMaxSupply); } // Set the new max supply. _tokenSupply[tokenId].maxSupply = uint64(newMaxSupply); // Emit an event with the update. emit MaxSupplyUpdated(tokenId, newMaxSupply); } /** * @notice Sets the provenance hash and emits an event. * * The provenance hash is used for random reveals, which * is a hash of the ordered metadata to show it has not been * modified after mint started. * * This function will revert if the provenance hash has already * been set, so be sure to carefully set it only once. * * @param newProvenanceHash The new provenance hash to set. */ function setProvenanceHash(bytes32 newProvenanceHash) external { // Ensure the sender is only the owner or configurer contract. _onlyOwnerOrConfigurer(); // Keep track of the old provenance hash for emitting with the event. bytes32 oldProvenanceHash = _provenanceHash; // Revert if the provenance hash has already been set. if (oldProvenanceHash != bytes32(0)) { revert ProvenanceHashCannotBeSetAfterAlreadyBeingSet(); } // Set the new provenance hash. _provenanceHash = newProvenanceHash; // Emit an event with the update. emit ProvenanceHashUpdated(oldProvenanceHash, newProvenanceHash); } /** * @notice Sets the default royalty information. * * Requirements: * * - `receiver` cannot be the zero address. * - `feeNumerator` cannot be greater than the fee denominator of 10_000 basis points. */ function setDefaultRoyalty(address receiver, uint96 feeNumerator) external { // Ensure the sender is only the owner or configurer contract. _onlyOwnerOrConfigurer(); // Set the default royalty. // ERC2981 implementation ensures feeNumerator <= feeDenominator // and receiver != address(0). _setDefaultRoyalty(receiver, feeNumerator); // Emit an event with the updated params. emit RoyaltyInfoUpdated(receiver, feeNumerator); } /** * @notice Returns the name of the token. */ function name() external view returns (string memory) { return _name; } /** * @notice Returns the symbol of the token. */ function symbol() external view returns (string memory) { return _symbol; } /** * @notice Returns the base URI for token metadata. */ function baseURI() external view override returns (string memory) { return _baseURI; } /** * @notice Returns the contract URI for contract metadata. */ function contractURI() external view override returns (string memory) { return _contractURI; } /** * @notice Returns the max token supply for a token id. */ function maxSupply(uint256 tokenId) external view returns (uint256) { return _tokenSupply[tokenId].maxSupply; } /** * @notice Returns the total supply for a token id. */ function totalSupply(uint256 tokenId) external view returns (uint256) { return _tokenSupply[tokenId].totalSupply; } /** * @notice Returns the total minted for a token id. */ function totalMinted(uint256 tokenId) external view returns (uint256) { return _tokenSupply[tokenId].totalMinted; } /** * @notice Returns the provenance hash. * The provenance hash is used for random reveals, which * is a hash of the ordered metadata to show it is unmodified * after mint has started. */ function provenanceHash() external view override returns (bytes32) { return _provenanceHash; } /** * @notice Returns the URI for token metadata. * * This implementation returns the same URI for *all* token types. * It relies on the token type ID substitution mechanism defined * in the EIP to replace {id} with the token id. * * @custom:param tokenId The token id to get the URI for. */ function uri( uint256 /* tokenId */ ) public view virtual override returns (string memory) { // Return the base URI. return _baseURI; } /** * @notice Returns the transfer validation function used. */ function getTransferValidationFunction() external pure returns (bytes4 functionSignature, bool isViewFunction) { functionSignature = ITransferValidator1155.validateTransfer.selector; isViewFunction = true; } /** * @notice Set the transfer validator. Only callable by the token owner. */ function setTransferValidator(address newValidator) external onlyOwner { // Set the new transfer validator. _setTransferValidator(newValidator); } /// @dev Override this function to return true if `_beforeTokenTransfer` is used. function _useBeforeTokenTransfer() internal view virtual override returns (bool) { return true; } /** * @dev Hook that is called before any token transfer. * This includes minting and burning. */ function _beforeTokenTransfer( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory /* data */ ) internal virtual override { if (from != address(0) && to != address(0)) { // Call the transfer validator if one is set. address transferValidator = _transferValidator; if (transferValidator != address(0)) { for (uint256 i = 0; i < ids.length; i++) { ITransferValidator1155(transferValidator).validateTransfer( msg.sender, from, to, ids[i], amounts[i] ); } } } } /** * @notice Returns whether the interface is supported. * * @param interfaceId The interface id to check against. */ function supportsInterface( bytes4 interfaceId ) public view virtual override(ERC1155, ERC2981) returns (bool) { return interfaceId == type(IERC1155ContractMetadata).interfaceId || interfaceId == type(ICreatorToken).interfaceId || interfaceId == type(ILegacyCreatorToken).interfaceId || interfaceId == 0x49064906 || // ERC-4906 (MetadataUpdate) ERC2981.supportsInterface(interfaceId) || // ERC1155 returns supportsInterface true for // ERC165, ERC1155, ERC1155MetadataURI ERC1155.supportsInterface(interfaceId); } /** * @dev Adds to the internal counters for a mint. * * @param to The address to mint to. * @param id The token id to mint. * @param amount The quantity to mint. * @param data The data to pass if receiver is a contract. */ function _mint( address to, uint256 id, uint256 amount, bytes memory data ) internal virtual override { // Increment mint counts. _incrementMintCounts(to, id, amount); ERC1155._mint(to, id, amount, data); } /** * @dev Adds to the internal counters for a batch mint. * * @param to The address to mint to. * @param ids The token ids to mint. * @param amounts The quantities to mint. * @param data The data to pass if receiver is a contract. */ function _batchMint( address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual override { // Put ids length on the stack to save MLOADs. uint256 idsLength = ids.length; for (uint256 i = 0; i < idsLength; ) { // Increment mint counts. _incrementMintCounts(to, ids[i], amounts[i]); unchecked { ++i; } } ERC1155._batchMint(to, ids, amounts, data); } /** * @dev Subtracts from the internal counters for a burn. * * @param by The address calling the burn. * @param from The address to burn from. * @param id The token id to burn. * @param amount The amount to burn. */ function _burn( address by, address from, uint256 id, uint256 amount ) internal virtual override { // Reduce the supply. _reduceSupplyOnBurn(id, amount); ERC1155._burn(by, from, id, amount); } /** * @dev Subtracts from the internal counters for a batch burn. * * @param by The address calling the burn. * @param from The address to burn from. * @param ids The token ids to burn. * @param amounts The amounts to burn. */ function _batchBurn( address by, address from, uint256[] memory ids, uint256[] memory amounts ) internal virtual override { // Put ids length on the stack to save MLOADs. uint256 idsLength = ids.length; for (uint256 i = 0; i < idsLength; ) { // Reduce the supply. _reduceSupplyOnBurn(ids[i], amounts[i]); unchecked { ++i; } } ERC1155._batchBurn(by, from, ids, amounts); } function _reduceSupplyOnBurn(uint256 id, uint256 amount) internal { // Get the current token supply. TokenSupply storage tokenSupply = _tokenSupply[id]; // Reduce the totalSupply. unchecked { tokenSupply.totalSupply -= uint64(amount); } } /** * @dev Internal function to increment mint counts. * * Note that this function does not check if the mint exceeds * maxSupply, which should be validated before this function is called. * * @param to The address to mint to. * @param id The token id to mint. * @param amount The quantity to mint. */ function _incrementMintCounts( address to, uint256 id, uint256 amount ) internal { // Get the current token supply. TokenSupply storage tokenSupply = _tokenSupply[id]; if (tokenSupply.totalMinted + amount > tokenSupply.maxSupply) { revert MintExceedsMaxSupply( tokenSupply.totalMinted + amount, tokenSupply.maxSupply ); } // Increment supply and number minted. // Can be unchecked because maxSupply cannot be set to exceed uint64. unchecked { tokenSupply.totalSupply += uint64(amount); tokenSupply.totalMinted += uint64(amount); // Increment total minted by user. _totalMintedByUser[to] += amount; // Increment total minted by user per token. _totalMintedByUserPerToken[to][id] += amount; } } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { PublicDrop } from "./ERC1155SeaDropStructs.sol"; import { CreatorPayout } from "./SeaDropStructs.sol"; library ERC1155SeaDropContractOffererStorage { struct Layout { /// @notice The allowed Seaport addresses that can mint. mapping(address => bool) _allowedSeaport; /// @notice The enumerated allowed Seaport addresses. address[] _enumeratedAllowedSeaport; /// @notice The public drop data. mapping(uint256 => PublicDrop) _publicDrops; /// @notice The enumerated public drop indexes. uint256[] _enumeratedPublicDropIndexes; /// @notice The creator payout addresses and basis points. CreatorPayout[] _creatorPayouts; /// @notice The allow list merkle root. bytes32 _allowListMerkleRoot; /// @notice The allowed fee recipients. mapping(address => bool) _allowedFeeRecipients; /// @notice The enumerated allowed fee recipients. address[] _enumeratedFeeRecipients; /// @notice The allowed server-side signers. mapping(address => bool) _allowedSigners; /// @notice The enumerated allowed signers. address[] _enumeratedSigners; /// @notice The used signature digests. mapping(bytes32 => bool) _usedDigests; /// @notice The allowed payers. mapping(address => bool) _allowedPayers; /// @notice The enumerated allowed payers. address[] _enumeratedPayers; } bytes32 internal constant STORAGE_SLOT = bytes32( uint256( keccak256("contracts.storage.ERC1155SeaDropContractOfferer") ) - 1 ); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { PublicDrop } from "./ERC1155SeaDropStructs.sol"; import { SeaDropErrorsAndEvents } from "./SeaDropErrorsAndEvents.sol"; interface ERC1155SeaDropErrorsAndEvents is SeaDropErrorsAndEvents { /** * @dev Revert with an error if an empty PublicDrop is provided * for an already-empty public drop. */ error PublicDropStageNotPresent(); /** * @dev Revert with an error if the mint quantity exceeds the * max minted per wallet for a certain token id. */ error MintQuantityExceedsMaxMintedPerWalletForTokenId( uint256 tokenId, uint256 total, uint256 allowed ); /** * @dev Revert with an error if the target token id to mint is not within * the drop stage range. */ error TokenIdNotWithinDropStageRange( uint256 tokenId, uint256 startTokenId, uint256 endTokenId ); /** * @notice Revert with an error if the number of maxSupplyAmounts doesn't * match the number of maxSupplyTokenIds. */ error MaxSupplyMismatch(); /** * @notice Revert with an error if the number of mint tokenIds doesn't * match the number of mint amounts. */ error MintAmountsMismatch(); /** * @notice Revert with an error if the mint order offer contains * a duplicate tokenId. */ error OfferContainsDuplicateTokenId(uint256 tokenId); /** * @dev Revert if the fromTokenId is greater than the toTokenId. */ error InvalidFromAndToTokenId(uint256 fromTokenId, uint256 toTokenId); /** * @notice Revert with an error if the number of publicDropIndexes doesn't * match the number of publicDrops. */ error PublicDropsMismatch(); /** * @dev An event with updated public drop data. */ event PublicDropUpdated(PublicDrop publicDrop, uint256 index); } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { AllowListData, CreatorPayout } from "./SeaDropStructs.sol"; /** * @notice A struct defining public drop data. * Designed to fit efficiently in two storage slots. * * @param startPrice The start price per token. (Up to 1.2m * of native token, e.g. ETH, MATIC) * @param endPrice The end price per token. If this differs * from startPrice, the current price will * be calculated based on the current time. * @param startTime The start time, ensure this is not zero. * @param endTime The end time, ensure this is not zero. * @param restrictFeeRecipients If false, allow any fee recipient; * if true, check fee recipient is allowed. * @param paymentToken The payment token address. Null for * native token. * @param fromTokenId The start token id for the stage. * @param toTokenId The end token id for the stage. * @param maxTotalMintableByWallet Maximum total number of mints a user is * allowed. (The limit for this field is * 2^16 - 1) * @param maxTotalMintableByWalletPerToken Maximum total number of mints a user * is allowed for the token id. (The limit for * this field is 2^16 - 1) * @param feeBps Fee out of 10_000 basis points to be * collected. */ struct PublicDrop { // slot 1 uint80 startPrice; // 80/512 bits uint80 endPrice; // 160/512 bits uint40 startTime; // 200/512 bits uint40 endTime; // 240/512 bits bool restrictFeeRecipients; // 248/512 bits // uint8 unused; // slot 2 address paymentToken; // 408/512 bits uint24 fromTokenId; // 432/512 bits uint24 toTokenId; // 456/512 bits uint16 maxTotalMintableByWallet; // 472/512 bits uint16 maxTotalMintableByWalletPerToken; // 488/512 bits uint16 feeBps; // 504/512 bits } /** * @notice A struct defining mint params for an allow list. * An allow list leaf will be composed of `msg.sender` and * the following params. * * Note: Since feeBps is encoded in the leaf, backend should ensure * that feeBps is acceptable before generating a proof. * * @param startPrice The start price per token. (Up to 1.2m * of native token, e.g. ETH, MATIC) * @param endPrice The end price per token. If this differs * from startPrice, the current price will * be calculated based on the current time. * @param startTime The start time, ensure this is not zero. * @param endTime The end time, ensure this is not zero. * @param paymentToken The payment token for the mint. Null for * native token. * @param fromTokenId The start token id for the stage. * @param toTokenId The end token id for the stage. * @param maxTotalMintableByWallet Maximum total number of mints a user is * allowed. * @param maxTotalMintableByWalletPerToken Maximum total number of mints a user * is allowed for the token id. * @param maxTokenSupplyForStage The limit of token supply this stage can * mint within. * @param dropStageIndex The drop stage index to emit with the event * for analytical purposes. This should be * non-zero since the public mint emits with * index zero. * @param feeBps Fee out of 10_000 basis points to be * collected. * @param restrictFeeRecipients If false, allow any fee recipient; * if true, check fee recipient is allowed. */ struct MintParams { uint256 startPrice; uint256 endPrice; uint256 startTime; uint256 endTime; address paymentToken; uint256 fromTokenId; uint256 toTokenId; uint256 maxTotalMintableByWallet; uint256 maxTotalMintableByWalletPerToken; uint256 maxTokenSupplyForStage; uint256 dropStageIndex; // non-zero uint256 feeBps; bool restrictFeeRecipients; } /** * @dev Struct containing internal SeaDrop implementation logic * mint details to avoid stack too deep. * * @param feeRecipient The fee recipient. * @param payer The payer of the mint. * @param minter The mint recipient. * @param tokenIds The tokenIds to mint. * @param quantities The number of tokens to mint per tokenId. * @param withEffects Whether to apply state changes of the mint. */ struct MintDetails { address feeRecipient; address payer; address minter; uint256[] tokenIds; uint256[] quantities; bool withEffects; } /** * @notice A struct to configure multiple contract options in one transaction. */ struct MultiConfigureStruct { uint256[] maxSupplyTokenIds; uint256[] maxSupplyAmounts; string baseURI; string contractURI; PublicDrop[] publicDrops; uint256[] publicDropsIndexes; string dropURI; AllowListData allowListData; CreatorPayout[] creatorPayouts; bytes32 provenanceHash; address[] allowedFeeRecipients; address[] disallowedFeeRecipients; address[] allowedPayers; address[] disallowedPayers; // Server-signed address[] allowedSigners; address[] disallowedSigners; // ERC-2981 address royaltyReceiver; uint96 royaltyBps; // Mint address mintRecipient; uint256[] mintTokenIds; uint256[] mintAmounts; } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; /** * @notice A struct defining a creator payout address and basis points. * * @param payoutAddress The payout address. * @param basisPoints The basis points to pay out to the creator. * The total creator payouts must equal 10_000 bps. */ struct CreatorPayout { address payoutAddress; uint16 basisPoints; } /** * @notice A struct defining allow list data (for minting an allow list). * * @param merkleRoot The merkle root for the allow list. * @param publicKeyURIs If the allowListURI is encrypted, a list of URIs * pointing to the public keys. Empty if unencrypted. * @param allowListURI The URI for the allow list. */ struct AllowListData { bytes32 merkleRoot; string[] publicKeyURIs; string allowListURI; } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { ERC1155 } from "solady/src/tokens/ERC1155.sol"; /** * @title ERC1155ConduitPreapproved * @notice Solady's ERC1155 with the OpenSea conduit preapproved. */ abstract contract ERC1155ConduitPreapproved is ERC1155 { /// @dev The canonical OpenSea conduit. address internal constant _CONDUIT = 0x1E0049783F008A0085193E00003D00cd54003c71; function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) public virtual override { _safeTransfer(_by(), from, to, id, amount, data); } function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) public virtual override { _safeBatchTransfer(_by(), from, to, ids, amounts, data); } function isApprovedForAll( address owner, address operator ) public view virtual override returns (bool) { if (operator == _CONDUIT) return true; return ERC1155.isApprovedForAll(owner, operator); } function _by() internal view virtual returns (address result) { assembly { // `msg.sender == _CONDUIT ? address(0) : msg.sender`. result := mul(iszero(eq(caller(), _CONDUIT)), caller()) } } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC1155 implementation. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC1155.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC1155/ERC1155.sol) /// /// @dev Note: /// The ERC1155 standard allows for self-approvals. /// For performance, this implementation WILL NOT revert for such actions. /// Please add any checks with overrides if desired. abstract contract ERC1155 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The lengths of the input arrays are not the same. error ArrayLengthsMismatch(); /// @dev Cannot mint or transfer to the zero address. error TransferToZeroAddress(); /// @dev The recipient's balance has overflowed. error AccountBalanceOverflow(); /// @dev Insufficient balance. error InsufficientBalance(); /// @dev Only the token owner or an approved account can manage the tokens. error NotOwnerNorApproved(); /// @dev Cannot safely transfer to a contract that does not implement /// the ERC1155Receiver interface. error TransferToNonERC1155ReceiverImplementer(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when `amount` of token `id` is transferred /// from `from` to `to` by `operator`. event TransferSingle( address indexed operator, address indexed from, address indexed to, uint256 id, uint256 amount ); /// @dev Emitted when `amounts` of token `ids` are transferred /// from `from` to `to` by `operator`. event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] amounts ); /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens. event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved); /// @dev Emitted when the Uniform Resource Identifier (URI) for token `id` /// is updated to `value`. This event is not used in the base contract. /// You may need to emit this event depending on your URI logic. /// /// See: https://eips.ethereum.org/EIPS/eip-1155#metadata event URI(string value, uint256 indexed id); /// @dev `keccak256(bytes("TransferSingle(address,address,address,uint256,uint256)"))`. uint256 private constant _TRANSFER_SINGLE_EVENT_SIGNATURE = 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62; /// @dev `keccak256(bytes("TransferBatch(address,address,address,uint256[],uint256[])"))`. uint256 private constant _TRANSFER_BATCH_EVENT_SIGNATURE = 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb; /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`. uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE = 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `ownerSlotSeed` of a given owner is given by. /// ``` /// let ownerSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner)) /// ``` /// /// The balance slot of `owner` is given by. /// ``` /// mstore(0x20, ownerSlotSeed) /// mstore(0x00, id) /// let balanceSlot := keccak256(0x00, 0x40) /// ``` /// /// The operator approval slot of `owner` is given by. /// ``` /// mstore(0x20, ownerSlotSeed) /// mstore(0x00, operator) /// let operatorApprovalSlot := keccak256(0x0c, 0x34) /// ``` uint256 private constant _ERC1155_MASTER_SLOT_SEED = 0x9a31110384e0b0c9; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1155 METADATA */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the URI for token `id`. /// /// You can either return the same templated URI for all token IDs, /// (e.g. "https://example.com/api/{id}.json"), /// or return a unique URI for each `id`. /// /// See: https://eips.ethereum.org/EIPS/eip-1155#metadata function uri(uint256 id) public view virtual returns (string memory); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1155 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the amount of `id` owned by `owner`. function balanceOf(address owner, uint256 id) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, owner) mstore(0x00, id) result := sload(keccak256(0x00, 0x40)) } } /// @dev Returns whether `operator` is approved to manage the tokens of `owner`. function isApprovedForAll(address owner, address operator) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, owner) mstore(0x00, operator) result := sload(keccak256(0x0c, 0x34)) } } /// @dev Sets whether `operator` is approved to manage the tokens of the caller. /// /// Emits a {ApprovalForAll} event. function setApprovalForAll(address operator, bool isApproved) public virtual { /// @solidity memory-safe-assembly assembly { // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`msg.sender`, `operator`). mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, caller()) mstore(0x00, operator) sstore(keccak256(0x0c, 0x34), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) // forgefmt: disable-next-line log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator))) } } /// @dev Transfers `amount` of `id` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `from` must have at least `amount` of `id`. /// - If the caller is not `from`, /// it must be approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155Reveived}, which is called upon a batch transfer. /// /// Emits a {Transfer} event. function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) public virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from)) let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to)) mstore(0x20, fromSlotSeed) // Clear the upper 96 bits. from := shr(96, fromSlotSeed) to := shr(96, toSlotSeed) // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // If the caller is not `from`, do the authorization check. if iszero(eq(caller(), from)) { mstore(0x00, caller()) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Subtract and store the updated balance of `from`. { mstore(0x00, id) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, toSlotSeed) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } // Emit a {TransferSingle} event. mstore(0x20, amount) log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), from, to) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { // Do the {onERC1155Received} check if `to` is a smart contract. if extcodesize(to) { // Prepare the calldata. let m := mload(0x40) // `onERC1155Received(address,address,uint256,uint256,bytes)`. mstore(m, 0xf23a6e61) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), from) mstore(add(m, 0x60), id) mstore(add(m, 0x80), amount) mstore(add(m, 0xa0), 0xa0) calldatacopy(add(m, 0xc0), sub(data.offset, 0x20), add(0x20, data.length)) // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, data.length), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } mstore(m, 0) } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xf23a6e61))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } } /// @dev Transfers `amounts` of `ids` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `from` must have at least `amount` of `id`. /// - `ids` and `amounts` must have the same length. /// - If the caller is not `from`, /// it must be approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer. /// /// Emits a {TransferBatch} event. function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) public virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { if iszero(eq(ids.length, amounts.length)) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from)) let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to)) mstore(0x20, fromSlotSeed) // Clear the upper 96 bits. from := shr(96, fromSlotSeed) to := shr(96, toSlotSeed) // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // If the caller is not `from`, do the authorization check. if iszero(eq(caller(), from)) { mstore(0x00, caller()) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Loop through all the `ids` and update the balances. { let end := shl(5, ids.length) for { let i := 0 } iszero(eq(i, end)) { i := add(i, 0x20) } { let amount := calldataload(add(amounts.offset, i)) // Subtract and store the updated balance of `from`. { mstore(0x20, fromSlotSeed) mstore(0x00, calldataload(add(ids.offset, i))) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, toSlotSeed) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, ids.length)) let o := add(m, 0x40) calldatacopy(o, sub(ids.offset, 0x20), n) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, n)) o := add(o, n) n := add(0x20, shl(5, amounts.length)) calldatacopy(o, sub(amounts.offset, 0x20), n) n := sub(add(o, n), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), from, to) } } if (_useAfterTokenTransfer()) { _afterTokenTransferCalldata(from, to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { // Do the {onERC1155BatchReceived} check if `to` is a smart contract. if extcodesize(to) { let m := mload(0x40) // Prepare the calldata. // `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`. mstore(m, 0xbc197c81) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), from) // Copy the `ids`. mstore(add(m, 0x60), 0xa0) let n := add(0x20, shl(5, ids.length)) let o := add(m, 0xc0) calldatacopy(o, sub(ids.offset, 0x20), n) // Copy the `amounts`. let s := add(0xa0, n) mstore(add(m, 0x80), s) o := add(o, n) n := add(0x20, shl(5, amounts.length)) calldatacopy(o, sub(amounts.offset, 0x20), n) // Copy the `data`. mstore(add(m, 0xa0), add(s, n)) o := add(o, n) n := add(0x20, data.length) calldatacopy(o, sub(data.offset, 0x20), n) n := sub(add(o, n), add(m, 0x1c)) // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), n, m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } mstore(m, 0) } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xbc197c81))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } } /// @dev Returns the amounts of `ids` for `owners. /// /// Requirements: /// - `owners` and `ids` must have the same length. function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) public view virtual returns (uint256[] memory balances) { /// @solidity memory-safe-assembly assembly { if iszero(eq(ids.length, owners.length)) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } balances := mload(0x40) mstore(balances, ids.length) let o := add(balances, 0x20) let end := shl(5, ids.length) mstore(0x40, add(end, o)) // Loop through all the `ids` and load the balances. for { let i := 0 } iszero(eq(i, end)) { i := add(i, 0x20) } { let owner := calldataload(add(owners.offset, i)) mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner))) mstore(0x00, calldataload(add(ids.offset, i))) mstore(add(o, i), sload(keccak256(0x00, 0x40))) } } } /// @dev Returns true if this contract implements the interface defined by `interfaceId`. /// See: https://eips.ethereum.org/EIPS/eip-165 /// This function call must use less than 30000 gas. function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { let s := shr(224, interfaceId) // ERC165: 0x01ffc9a7, ERC1155: 0xd9b67a26, ERC1155MetadataURI: 0x0e89341c. result := or(or(eq(s, 0x01ffc9a7), eq(s, 0xd9b67a26)), eq(s, 0x0e89341c)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL MINT FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Mints `amount` of `id` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155Reveived}, which is called upon a batch transfer. /// /// Emits a {Transfer} event. function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(address(0), to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Increase and store the updated balance of `to`. { mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, to) mstore(0x00, id) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } // Emit a {TransferSingle} event. mstore(0x00, id) mstore(0x20, amount) log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), 0, shr(96, to_)) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(address(0), to, _single(id), _single(amount), data); } if (_hasCode(to)) _checkOnERC1155Received(address(0), to, id, amount, data); } /// @dev Mints `amounts` of `ids` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `ids` and `amounts` must have the same length. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer. /// /// Emits a {TransferBatch} event. function _batchMint( address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(address(0), to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { if iszero(eq(mload(ids), mload(amounts))) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Loop through all the `ids` and update the balances. { mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_)) let end := shl(5, mload(ids)) for { let i := 0 } iszero(eq(i, end)) {} { i := add(i, 0x20) let amount := mload(add(amounts, i)) // Increase and store the updated balance of `to`. { mstore(0x00, mload(add(ids, i))) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0x40) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, returndatasize())) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) n := sub(add(o, returndatasize()), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), 0, shr(96, to_)) } } if (_useAfterTokenTransfer()) { _afterTokenTransfer(address(0), to, ids, amounts, data); } if (_hasCode(to)) _checkOnERC1155BatchReceived(address(0), to, ids, amounts, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL BURN FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_burn(address(0), from, id, amount)`. function _burn(address from, uint256 id, uint256 amount) internal virtual { _burn(address(0), from, id, amount); } /// @dev Destroys `amount` of `id` from `from`. /// /// Requirements: /// - `from` must have at least `amount` of `id`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// /// Emits a {Transfer} event. function _burn(address by, address from, uint256 id, uint256 amount) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, address(0), _single(id), _single(amount), ""); } /// @solidity memory-safe-assembly assembly { let from_ := shl(96, from) mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_)) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. if iszero(or(iszero(shl(96, by)), eq(shl(96, by), from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Decrease and store the updated balance of `from`. { mstore(0x00, id) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Emit a {TransferSingle} event. mstore(0x00, id) mstore(0x20, amount) log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), 0) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, address(0), _single(id), _single(amount), ""); } } /// @dev Equivalent to `_batchBurn(address(0), from, ids, amounts)`. function _batchBurn(address from, uint256[] memory ids, uint256[] memory amounts) internal virtual { _batchBurn(address(0), from, ids, amounts); } /// @dev Destroys `amounts` of `ids` from `from`. /// /// Requirements: /// - `ids` and `amounts` must have the same length. /// - `from` must have at least `amounts` of `ids`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// /// Emits a {TransferBatch} event. function _batchBurn(address by, address from, uint256[] memory ids, uint256[] memory amounts) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, address(0), ids, amounts, ""); } /// @solidity memory-safe-assembly assembly { if iszero(eq(mload(ids), mload(amounts))) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let from_ := shl(96, from) mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_)) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. let by_ := shl(96, by) if iszero(or(iszero(by_), eq(by_, from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Loop through all the `ids` and update the balances. { let end := shl(5, mload(ids)) for { let i := 0 } iszero(eq(i, end)) {} { i := add(i, 0x20) let amount := mload(add(amounts, i)) // Decrease and store the updated balance of `to`. { mstore(0x00, mload(add(ids, i))) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0x40) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, returndatasize())) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) n := sub(add(o, returndatasize()), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), 0) } } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, address(0), ids, amounts, ""); } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL APPROVAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Approve or remove the `operator` as an operator for `by`, /// without authorization checks. /// /// Emits a {ApprovalForAll} event. function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual { /// @solidity memory-safe-assembly assembly { // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`by`, `operator`). mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, by) mstore(0x00, operator) sstore(keccak256(0x0c, 0x34), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) let m := shr(96, not(0)) log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, and(m, by), and(m, operator)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL TRANSFER FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_safeTransfer(address(0), from, to, id, amount, data)`. function _safeTransfer(address from, address to, uint256 id, uint256 amount, bytes memory data) internal virtual { _safeTransfer(address(0), from, to, id, amount, data); } /// @dev Transfers `amount` of `id` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `from` must have at least `amount` of `id`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155Reveived}, which is called upon a batch transfer. /// /// Emits a {Transfer} event. function _safeTransfer( address by, address from, address to, uint256 id, uint256 amount, bytes memory data ) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { let from_ := shl(96, from) let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_)) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. let by_ := shl(96, by) if iszero(or(iszero(by_), eq(by_, from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Subtract and store the updated balance of `from`. { mstore(0x00, id) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_)) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } // Emit a {TransferSingle} event. mstore(0x20, amount) // forgefmt: disable-next-line log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_)) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, _single(id), _single(amount), data); } if (_hasCode(to)) _checkOnERC1155Received(from, to, id, amount, data); } /// @dev Equivalent to `_safeBatchTransfer(address(0), from, to, ids, amounts, data)`. function _safeBatchTransfer( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { _safeBatchTransfer(address(0), from, to, ids, amounts, data); } /// @dev Transfers `amounts` of `ids` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `ids` and `amounts` must have the same length. /// - `from` must have at least `amounts` of `ids`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer. /// /// Emits a {TransferBatch} event. function _safeBatchTransfer( address by, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { if iszero(eq(mload(ids), mload(amounts))) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let from_ := shl(96, from) let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, from_) let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, to_) mstore(0x20, fromSlotSeed) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. let by_ := shl(96, by) if iszero(or(iszero(by_), eq(by_, from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Loop through all the `ids` and update the balances. { let end := shl(5, mload(ids)) for { let i := 0 } iszero(eq(i, end)) {} { i := add(i, 0x20) let amount := mload(add(amounts, i)) // Subtract and store the updated balance of `from`. { mstore(0x20, fromSlotSeed) mstore(0x00, mload(add(ids, i))) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, toSlotSeed) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0x40) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, returndatasize())) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) n := sub(add(o, returndatasize()), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_)) } } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, ids, amounts, data); } if (_hasCode(to)) _checkOnERC1155BatchReceived(from, to, ids, amounts, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HOOKS FOR OVERRIDING */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override this function to return true if `_beforeTokenTransfer` is used. /// The is to help the compiler avoid producing dead bytecode. function _useBeforeTokenTransfer() internal view virtual returns (bool) { return false; } /// @dev Hook that is called before any token transfer. /// This includes minting and burning, as well as batched variants. /// /// The same hook is called on both single and batched variants. /// For single transfers, the length of the `id` and `amount` arrays are 1. function _beforeTokenTransfer( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual {} /// @dev Override this function to return true if `_afterTokenTransfer` is used. /// The is to help the compiler avoid producing dead bytecode. function _useAfterTokenTransfer() internal view virtual returns (bool) { return false; } /// @dev Hook that is called after any token transfer. /// This includes minting and burning, as well as batched variants. /// /// The same hook is called on both single and batched variants. /// For single transfers, the length of the `id` and `amount` arrays are 1. function _afterTokenTransfer( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual {} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Helper for calling the `_afterTokenTransfer` hook. /// The is to help the compiler avoid producing dead bytecode. function _afterTokenTransferCalldata( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) private { if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, ids, amounts, data); } } /// @dev Returns if `a` has bytecode of non-zero length. function _hasCode(address a) private view returns (bool result) { /// @solidity memory-safe-assembly assembly { result := extcodesize(a) // Can handle dirty upper bits. } } /// @dev Perform a call to invoke {IERC1155Receiver-onERC1155Received} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC1155Received( address from, address to, uint256 id, uint256 amount, bytes memory data ) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) // `onERC1155Received(address,address,uint256,uint256,bytes)`. mstore(m, 0xf23a6e61) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), shr(96, shl(96, from))) mstore(add(m, 0x60), id) mstore(add(m, 0x80), amount) mstore(add(m, 0xa0), 0xa0) let n := mload(data) mstore(add(m, 0xc0), n) if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xe0), n)) } // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, n), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } mstore(m, 0) } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xf23a6e61))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } /// @dev Perform a call to invoke {IERC1155Receiver-onERC1155BatchReceived} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC1155BatchReceived( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) // `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`. mstore(m, 0xbc197c81) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), shr(96, shl(96, from))) // Copy the `ids`. mstore(add(m, 0x60), 0xa0) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0xc0) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. let s := add(0xa0, returndatasize()) mstore(add(m, 0x80), s) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) // Copy the `data`. mstore(add(m, 0xa0), add(s, returndatasize())) o := add(o, returndatasize()) n := add(0x20, mload(data)) pop(staticcall(gas(), 4, data, n, o, n)) n := sub(add(o, returndatasize()), add(m, 0x1c)) // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), n, m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } mstore(m, 0) } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xbc197c81))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } /// @dev Returns `x` in an array with a single element. function _single(uint256 x) private pure returns (uint256[] memory result) { assembly { result := mload(0x40) mstore(0x40, add(result, 0x40)) mstore(result, 1) mstore(add(result, 0x20), x) } } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { BasicOrderType, ItemType, OrderType, Side } from "./ConsiderationEnums.sol"; import { CalldataPointer, MemoryPointer } from "../helpers/PointerLibraries.sol"; /** * @dev An order contains eleven components: an offerer, a zone (or account that * can cancel the order or restrict who can fulfill the order depending on * the type), the order type (specifying partial fill support as well as * restricted order status), the start and end time, a hash that will be * provided to the zone when validating restricted orders, a salt, a key * corresponding to a given conduit, a counter, and an arbitrary number of * offer items that can be spent along with consideration items that must * be received by their respective recipient. */ struct OrderComponents { address offerer; address zone; OfferItem[] offer; ConsiderationItem[] consideration; OrderType orderType; uint256 startTime; uint256 endTime; bytes32 zoneHash; uint256 salt; bytes32 conduitKey; uint256 counter; } /** * @dev An offer item has five components: an item type (ETH or other native * tokens, ERC20, ERC721, and ERC1155, as well as criteria-based ERC721 and * ERC1155), a token address, a dual-purpose "identifierOrCriteria" * component that will either represent a tokenId or a merkle root * depending on the item type, and a start and end amount that support * increasing or decreasing amounts over the duration of the respective * order. */ struct OfferItem { ItemType itemType; address token; uint256 identifierOrCriteria; uint256 startAmount; uint256 endAmount; } /** * @dev A consideration item has the same five components as an offer item and * an additional sixth component designating the required recipient of the * item. */ struct ConsiderationItem { ItemType itemType; address token; uint256 identifierOrCriteria; uint256 startAmount; uint256 endAmount; address payable recipient; } /** * @dev A spent item is translated from a utilized offer item and has four * components: an item type (ETH or other native tokens, ERC20, ERC721, and * ERC1155), a token address, a tokenId, and an amount. */ struct SpentItem { ItemType itemType; address token; uint256 identifier; uint256 amount; } /** * @dev A received item is translated from a utilized consideration item and has * the same four components as a spent item, as well as an additional fifth * component designating the required recipient of the item. */ struct ReceivedItem { ItemType itemType; address token; uint256 identifier; uint256 amount; address payable recipient; } /** * @dev For basic orders involving ETH / native / ERC20 <=> ERC721 / ERC1155 * matching, a group of six functions may be called that only requires a * subset of the usual order arguments. Note the use of a "basicOrderType" * enum; this represents both the usual order type as well as the "route" * of the basic order (a simple derivation function for the basic order * type is `basicOrderType = orderType + (4 * basicOrderRoute)`.) */ struct BasicOrderParameters { // calldata offset address considerationToken; // 0x24 uint256 considerationIdentifier; // 0x44 uint256 considerationAmount; // 0x64 address payable offerer; // 0x84 address zone; // 0xa4 address offerToken; // 0xc4 uint256 offerIdentifier; // 0xe4 uint256 offerAmount; // 0x104 BasicOrderType basicOrderType; // 0x124 uint256 startTime; // 0x144 uint256 endTime; // 0x164 bytes32 zoneHash; // 0x184 uint256 salt; // 0x1a4 bytes32 offererConduitKey; // 0x1c4 bytes32 fulfillerConduitKey; // 0x1e4 uint256 totalOriginalAdditionalRecipients; // 0x204 AdditionalRecipient[] additionalRecipients; // 0x224 bytes signature; // 0x244 // Total length, excluding dynamic array data: 0x264 (580) } /** * @dev Basic orders can supply any number of additional recipients, with the * implied assumption that they are supplied from the offered ETH (or other * native token) or ERC20 token for the order. */ struct AdditionalRecipient { uint256 amount; address payable recipient; } /** * @dev The full set of order components, with the exception of the counter, * must be supplied when fulfilling more sophisticated orders or groups of * orders. The total number of original consideration items must also be * supplied, as the caller may specify additional consideration items. */ struct OrderParameters { address offerer; // 0x00 address zone; // 0x20 OfferItem[] offer; // 0x40 ConsiderationItem[] consideration; // 0x60 OrderType orderType; // 0x80 uint256 startTime; // 0xa0 uint256 endTime; // 0xc0 bytes32 zoneHash; // 0xe0 uint256 salt; // 0x100 bytes32 conduitKey; // 0x120 uint256 totalOriginalConsiderationItems; // 0x140 // offer.length // 0x160 } /** * @dev Orders require a signature in addition to the other order parameters. */ struct Order { OrderParameters parameters; bytes signature; } /** * @dev Advanced orders include a numerator (i.e. a fraction to attempt to fill) * and a denominator (the total size of the order) in addition to the * signature and other order parameters. It also supports an optional field * for supplying extra data; this data will be provided to the zone if the * order type is restricted and the zone is not the caller, or will be * provided to the offerer as context for contract order types. */ struct AdvancedOrder { OrderParameters parameters; uint120 numerator; uint120 denominator; bytes signature; bytes extraData; } /** * @dev Orders can be validated (either explicitly via `validate`, or as a * consequence of a full or partial fill), specifically cancelled (they can * also be cancelled in bulk via incrementing a per-zone counter), and * partially or fully filled (with the fraction filled represented by a * numerator and denominator). */ struct OrderStatus { bool isValidated; bool isCancelled; uint120 numerator; uint120 denominator; } /** * @dev A criteria resolver specifies an order, side (offer vs. consideration), * and item index. It then provides a chosen identifier (i.e. tokenId) * alongside a merkle proof demonstrating the identifier meets the required * criteria. */ struct CriteriaResolver { uint256 orderIndex; Side side; uint256 index; uint256 identifier; bytes32[] criteriaProof; } /** * @dev A fulfillment is applied to a group of orders. It decrements a series of * offer and consideration items, then generates a single execution * element. A given fulfillment can be applied to as many offer and * consideration items as desired, but must contain at least one offer and * at least one consideration that match. The fulfillment must also remain * consistent on all key parameters across all offer items (same offerer, * token, type, tokenId, and conduit preference) as well as across all * consideration items (token, type, tokenId, and recipient). */ struct Fulfillment { FulfillmentComponent[] offerComponents; FulfillmentComponent[] considerationComponents; } /** * @dev Each fulfillment component contains one index referencing a specific * order and another referencing a specific offer or consideration item. */ struct FulfillmentComponent { uint256 orderIndex; uint256 itemIndex; } /** * @dev An execution is triggered once all consideration items have been zeroed * out. It sends the item in question from the offerer to the item's * recipient, optionally sourcing approvals from either this contract * directly or from the offerer's chosen conduit if one is specified. An * execution is not provided as an argument, but rather is derived via * orders, criteria resolvers, and fulfillments (where the total number of * executions will be less than or equal to the total number of indicated * fulfillments) and returned as part of `matchOrders`. */ struct Execution { ReceivedItem item; address offerer; bytes32 conduitKey; } /** * @dev Restricted orders are validated post-execution by calling validateOrder * on the zone. This struct provides context about the order fulfillment * and any supplied extraData, as well as all order hashes fulfilled in a * call to a match or fulfillAvailable method. */ struct ZoneParameters { bytes32 orderHash; address fulfiller; address offerer; SpentItem[] offer; ReceivedItem[] consideration; bytes extraData; bytes32[] orderHashes; uint256 startTime; uint256 endTime; bytes32 zoneHash; } /** * @dev Zones and contract offerers can communicate which schemas they implement * along with any associated metadata related to each schema. */ struct Schema { uint256 id; bytes metadata; } using StructPointers for OrderComponents global; using StructPointers for OfferItem global; using StructPointers for ConsiderationItem global; using StructPointers for SpentItem global; using StructPointers for ReceivedItem global; using StructPointers for BasicOrderParameters global; using StructPointers for AdditionalRecipient global; using StructPointers for OrderParameters global; using StructPointers for Order global; using StructPointers for AdvancedOrder global; using StructPointers for OrderStatus global; using StructPointers for CriteriaResolver global; using StructPointers for Fulfillment global; using StructPointers for FulfillmentComponent global; using StructPointers for Execution global; using StructPointers for ZoneParameters global; /** * @dev This library provides a set of functions for converting structs to * pointers. */ library StructPointers { /** * @dev Get a MemoryPointer from OrderComponents. * * @param obj The OrderComponents object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( OrderComponents memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from OrderComponents. * * @param obj The OrderComponents object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( OrderComponents calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from OfferItem. * * @param obj The OfferItem object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( OfferItem memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from OfferItem. * * @param obj The OfferItem object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( OfferItem calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from ConsiderationItem. * * @param obj The ConsiderationItem object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( ConsiderationItem memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from ConsiderationItem. * * @param obj The ConsiderationItem object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( ConsiderationItem calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from SpentItem. * * @param obj The SpentItem object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( SpentItem memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from SpentItem. * * @param obj The SpentItem object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( SpentItem calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from ReceivedItem. * * @param obj The ReceivedItem object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( ReceivedItem memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from ReceivedItem. * * @param obj The ReceivedItem object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( ReceivedItem calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from BasicOrderParameters. * * @param obj The BasicOrderParameters object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( BasicOrderParameters memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from BasicOrderParameters. * * @param obj The BasicOrderParameters object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( BasicOrderParameters calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from AdditionalRecipient. * * @param obj The AdditionalRecipient object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( AdditionalRecipient memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from AdditionalRecipient. * * @param obj The AdditionalRecipient object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( AdditionalRecipient calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from OrderParameters. * * @param obj The OrderParameters object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( OrderParameters memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from OrderParameters. * * @param obj The OrderParameters object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( OrderParameters calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from Order. * * @param obj The Order object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( Order memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from Order. * * @param obj The Order object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( Order calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from AdvancedOrder. * * @param obj The AdvancedOrder object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( AdvancedOrder memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from AdvancedOrder. * * @param obj The AdvancedOrder object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( AdvancedOrder calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from OrderStatus. * * @param obj The OrderStatus object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( OrderStatus memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from OrderStatus. * * @param obj The OrderStatus object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( OrderStatus calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from CriteriaResolver. * * @param obj The CriteriaResolver object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( CriteriaResolver memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from CriteriaResolver. * * @param obj The CriteriaResolver object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( CriteriaResolver calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from Fulfillment. * * @param obj The Fulfillment object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( Fulfillment memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from Fulfillment. * * @param obj The Fulfillment object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( Fulfillment calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from FulfillmentComponent. * * @param obj The FulfillmentComponent object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( FulfillmentComponent memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from FulfillmentComponent. * * @param obj The FulfillmentComponent object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( FulfillmentComponent calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from Execution. * * @param obj The Execution object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( Execution memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from Execution. * * @param obj The Execution object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( Execution calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from ZoneParameters. * * @param obj The ZoneParameters object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( ZoneParameters memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from ZoneParameters. * * @param obj The ZoneParameters object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( ZoneParameters calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {ReceivedItem, Schema, SpentItem} from "../lib/ConsiderationStructs.sol"; import {IERC165} from "../interfaces/IERC165.sol"; /** * @title ContractOffererInterface * @notice Contains the minimum interfaces needed to interact with a contract * offerer. */ interface ContractOffererInterface is IERC165 { /** * @dev Generates an order with the specified minimum and maximum spent * items, and optional context (supplied as extraData). * * @param fulfiller The address of the fulfiller. * @param minimumReceived The minimum items that the caller is willing to * receive. * @param maximumSpent The maximum items the caller is willing to spend. * @param context Additional context of the order. * * @return offer A tuple containing the offer items. * @return consideration A tuple containing the consideration items. */ function generateOrder( address fulfiller, SpentItem[] calldata minimumReceived, SpentItem[] calldata maximumSpent, bytes calldata context // encoded based on the schemaID ) external returns (SpentItem[] memory offer, ReceivedItem[] memory consideration); /** * @dev Ratifies an order with the specified offer, consideration, and * optional context (supplied as extraData). * * @param offer The offer items. * @param consideration The consideration items. * @param context Additional context of the order. * @param orderHashes The hashes to ratify. * @param contractNonce The nonce of the contract. * * @return ratifyOrderMagicValue The magic value returned by the contract * offerer. */ function ratifyOrder( SpentItem[] calldata offer, ReceivedItem[] calldata consideration, bytes calldata context, // encoded based on the schemaID bytes32[] calldata orderHashes, uint256 contractNonce ) external returns (bytes4 ratifyOrderMagicValue); /** * @dev View function to preview an order generated in response to a minimum * set of received items, maximum set of spent items, and context * (supplied as extraData). * * @param caller The address of the caller (e.g. Seaport). * @param fulfiller The address of the fulfiller (e.g. the account * calling Seaport). * @param minimumReceived The minimum items that the caller is willing to * receive. * @param maximumSpent The maximum items the caller is willing to spend. * @param context Additional context of the order. * * @return offer A tuple containing the offer items. * @return consideration A tuple containing the consideration items. */ function previewOrder( address caller, address fulfiller, SpentItem[] calldata minimumReceived, SpentItem[] calldata maximumSpent, bytes calldata context // encoded based on the schemaID ) external view returns (SpentItem[] memory offer, ReceivedItem[] memory consideration); /** * @dev Gets the metadata for this contract offerer. * * @return name The name of the contract offerer. * @return schemas The schemas supported by the contract offerer. */ function getSeaportMetadata() external view returns (string memory name, Schema[] memory schemas); // map to Seaport Improvement Proposal IDs function supportsInterface(bytes4 interfaceId) external view override returns (bool); // Additional functions and/or events based on implemented schemaIDs } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.19; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; interface ISeaDropTokenContractMetadata { /** * @dev Emit an event for token metadata reveals/updates, * according to EIP-4906. * * @param _fromTokenId The start token id. * @param _toTokenId The end token id. */ event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); /** * @dev Emit an event when the URI for the collection-level metadata * is updated. */ event ContractURIUpdated(string newContractURI); /** * @dev Emit an event with the previous and new provenance hash after * being updated. */ event ProvenanceHashUpdated(bytes32 previousHash, bytes32 newHash); /** * @dev Emit an event when the EIP-2981 royalty info is updated. */ event RoyaltyInfoUpdated(address receiver, uint256 basisPoints); /** * @notice Throw if the max supply exceeds uint64, a limit * due to the storage of bit-packed variables. */ error CannotExceedMaxSupplyOfUint64(uint256 got); /** * @dev Revert with an error when attempting to set the provenance * hash after the mint has started. */ error ProvenanceHashCannotBeSetAfterMintStarted(); /** * @dev Revert with an error when attempting to set the provenance * hash after it has already been set. */ error ProvenanceHashCannotBeSetAfterAlreadyBeingSet(); /** * @notice Sets the base URI for the token metadata and emits an event. * * @param tokenURI The new base URI to set. */ function setBaseURI(string calldata tokenURI) external; /** * @notice Sets the contract URI for contract metadata. * * @param newContractURI The new contract URI. */ function setContractURI(string calldata newContractURI) external; /** * @notice Sets the provenance hash and emits an event. * * The provenance hash is used for random reveals, which * is a hash of the ordered metadata to show it has not been * modified after mint started. * * This function will revert after the first item has been minted. * * @param newProvenanceHash The new provenance hash to set. */ function setProvenanceHash(bytes32 newProvenanceHash) external; /** * @notice Sets the default royalty information. * * Requirements: * * - `receiver` cannot be the zero address. * - `feeNumerator` cannot be greater than the fee denominator of * 10_000 basis points. */ function setDefaultRoyalty(address receiver, uint96 feeNumerator) external; /** * @notice Returns the base URI for token metadata. */ function baseURI() external view returns (string memory); /** * @notice Returns the contract URI. */ function contractURI() external view returns (string memory); /** * @notice Returns the provenance hash. * The provenance hash is used for random reveals, which * is a hash of the ordered metadata to show it is unmodified * after mint has started. */ function provenanceHash() external view returns (bytes32); } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { ISeaDropTokenContractMetadata } from "./ISeaDropTokenContractMetadata.sol"; interface IERC1155ContractMetadata is ISeaDropTokenContractMetadata { /** * @dev A struct representing the supply info for a token id, * packed into one storage slot. * * @param maxSupply The max supply for the token id. * @param totalSupply The total token supply for the token id. * Subtracted when an item is burned. * @param totalMinted The total number of tokens minted for the token id. */ struct TokenSupply { uint64 maxSupply; // 64/256 bits uint64 totalSupply; // 128/256 bits uint64 totalMinted; // 192/256 bits } /** * @dev Emit an event when the max token supply for a token id is updated. */ event MaxSupplyUpdated(uint256 tokenId, uint256 newMaxSupply); /** * @dev Revert with an error if the mint quantity exceeds the max token * supply. */ error MintExceedsMaxSupply(uint256 total, uint256 maxSupply); /** * @notice Sets the max supply for a token id and emits an event. * * @param tokenId The token id to set the max supply for. * @param newMaxSupply The new max supply to set. */ function setMaxSupply(uint256 tokenId, uint256 newMaxSupply) external; /** * @notice Returns the name of the token. */ function name() external view returns (string memory); /** * @notice Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @notice Returns the max token supply for a token id. */ function maxSupply(uint256 tokenId) external view returns (uint256); /** * @notice Returns the total supply for a token id. */ function totalSupply(uint256 tokenId) external view returns (uint256); /** * @notice Returns the total minted for a token id. */ function totalMinted(uint256 tokenId) external view returns (uint256); } // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface ICreatorToken { event TransferValidatorUpdated(address oldValidator, address newValidator); function getTransferValidator() external view returns (address validator); function getTransferValidationFunction() external view returns (bytes4 functionSignature, bool isViewFunction); function setTransferValidator(address validator) external; } interface ILegacyCreatorToken { event TransferValidatorUpdated(address oldValidator, address newValidator); function getTransferValidator() external view returns (address validator); function setTransferValidator(address validator) external; } // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface ITransferValidator721 { /// @notice Ensure that a transfer has been authorized for a specific tokenId function validateTransfer( address caller, address from, address to, uint256 tokenId ) external view; } interface ITransferValidator1155 { /// @notice Ensure that a transfer has been authorized for a specific amount of a specific tokenId, and reduce the transferable amount remaining function validateTransfer( address caller, address from, address to, uint256 tokenId, uint256 amount ) external; } // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { ICreatorToken } from "../interfaces/ICreatorToken.sol"; /** * @title TokenTransferValidator * @notice Functionality to use a transfer validator. */ abstract contract TokenTransferValidator is ICreatorToken { /// @dev Store the transfer validator. The null address means no transfer validator is set. address internal _transferValidator; /// @notice Revert with an error if the transfer validator is being set to the same address. error SameTransferValidator(); /// @notice Returns the currently active transfer validator. /// The null address means no transfer validator is set. function getTransferValidator() external view returns (address) { return _transferValidator; } /// @notice Set the transfer validator. /// The external method that uses this must include access control. function _setTransferValidator(address newValidator) internal { address oldValidator = _transferValidator; if (oldValidator == newValidator) { revert SameTransferValidator(); } _transferValidator = newValidator; emit TransferValidatorUpdated(oldValidator, newValidator); } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC2981 NFT Royalty Standard implementation. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC2981.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/common/ERC2981.sol) abstract contract ERC2981 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The royalty fee numerator exceeds the fee denominator. error RoyaltyOverflow(); /// @dev The royalty receiver cannot be the zero address. error RoyaltyReceiverIsZeroAddress(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The default royalty info is given by: /// ``` /// let packed := sload(_ERC2981_MASTER_SLOT_SEED) /// let receiver := shr(96, packed) /// let royaltyFraction := xor(packed, shl(96, receiver)) /// ``` /// /// The per token royalty info is given by. /// ``` /// mstore(0x00, tokenId) /// mstore(0x20, _ERC2981_MASTER_SLOT_SEED) /// let packed := sload(keccak256(0x00, 0x40)) /// let receiver := shr(96, packed) /// let royaltyFraction := xor(packed, shl(96, receiver)) /// ``` uint256 private constant _ERC2981_MASTER_SLOT_SEED = 0xaa4ec00224afccfdb7; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC2981 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Checks that `_feeDenominator` is non-zero. constructor() { require(_feeDenominator() != 0, "Fee denominator cannot be zero."); } /// @dev Returns the denominator for the royalty amount. /// Defaults to 10000, which represents fees in basis points. /// Override this function to return a custom amount if needed. function _feeDenominator() internal pure virtual returns (uint96) { return 10000; } /// @dev Returns true if this contract implements the interface defined by `interfaceId`. /// See: https://eips.ethereum.org/EIPS/eip-165 /// This function call must use less than 30000 gas. function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { let s := shr(224, interfaceId) // ERC165: 0x01ffc9a7, ERC2981: 0x2a55205a. result := or(eq(s, 0x01ffc9a7), eq(s, 0x2a55205a)) } } /// @dev Returns the `receiver` and `royaltyAmount` for `tokenId` sold at `salePrice`. function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual returns (address receiver, uint256 royaltyAmount) { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) let packed := sload(keccak256(0x00, 0x40)) receiver := shr(96, packed) if iszero(receiver) { packed := sload(mload(0x20)) receiver := shr(96, packed) } let x := salePrice let y := xor(packed, shl(96, receiver)) // `feeNumerator`. // Overflow check, equivalent to `require(y == 0 || x <= type(uint256).max / y)`. // Out-of-gas revert. Should not be triggered in practice, but included for safety. returndatacopy(returndatasize(), returndatasize(), mul(y, gt(x, div(not(0), y)))) royaltyAmount := div(mul(x, y), feeDenominator) } } /// @dev Sets the default royalty `receiver` and `feeNumerator`. /// /// Requirements: /// - `receiver` must not be the zero address. /// - `feeNumerator` must not be greater than the fee denominator. function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { feeNumerator := shr(160, shl(160, feeNumerator)) if gt(feeNumerator, feeDenominator) { mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`. revert(0x1c, 0x04) } let packed := shl(96, receiver) if iszero(packed) { mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`. revert(0x1c, 0x04) } sstore(_ERC2981_MASTER_SLOT_SEED, or(packed, feeNumerator)) } } /// @dev Sets the default royalty `receiver` and `feeNumerator` to zero. function _deleteDefaultRoyalty() internal virtual { /// @solidity memory-safe-assembly assembly { sstore(_ERC2981_MASTER_SLOT_SEED, 0) } } /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId`. /// /// Requirements: /// - `receiver` must not be the zero address. /// - `feeNumerator` must not be greater than the fee denominator. function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { feeNumerator := shr(160, shl(160, feeNumerator)) if gt(feeNumerator, feeDenominator) { mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`. revert(0x1c, 0x04) } let packed := shl(96, receiver) if iszero(packed) { mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`. revert(0x1c, 0x04) } mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) sstore(keccak256(0x00, 0x40), or(packed, feeNumerator)) } } /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId` to zero. function _resetTokenRoyalty(uint256 tokenId) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) sstore(keccak256(0x00, 0x40), 0) } } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// @dev While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. /// It is intentionally chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(not(_OWNER_SLOT_NOT), newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { /// @solidity memory-safe-assembly assembly { let ownerSlot := not(_OWNER_SLOT_NOT) // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(not(_OWNER_SLOT_NOT)) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. function ownershipHandoverValidFor() public view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.19; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (address(this).code.length == 0 && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { CreatorPayout, PublicDrop } from "./ERC721SeaDropStructs.sol"; interface SeaDropErrorsAndEvents { /** * @notice The SeaDrop token types, emitted as part of * `event SeaDropTokenDeployed`. */ enum SEADROP_TOKEN_TYPE { ERC721_STANDARD, ERC721_CLONE, ERC721_UPGRADEABLE, ERC1155_STANDARD, ERC1155_CLONE, ERC1155_UPGRADEABLE } /** * @notice An event to signify that a SeaDrop token contract was deployed. */ event SeaDropTokenDeployed(SEADROP_TOKEN_TYPE tokenType); /** * @notice Revert with an error if the function selector is not supported. */ error UnsupportedFunctionSelector(bytes4 selector); /** * @dev Revert with an error if the drop stage is not active. */ error NotActive( uint256 currentTimestamp, uint256 startTimestamp, uint256 endTimestamp ); /** * @dev Revert with an error if the mint quantity exceeds the max allowed * to be minted per wallet. */ error MintQuantityExceedsMaxMintedPerWallet(uint256 total, uint256 allowed); /** * @dev Revert with an error if the mint quantity exceeds the max token * supply. */ error MintQuantityExceedsMaxSupply(uint256 total, uint256 maxSupply); /** * @dev Revert with an error if the mint quantity exceeds the max token * supply for the stage. * Note: The `maxTokenSupplyForStage` for public mint is * always `type(uint).max`. */ error MintQuantityExceedsMaxTokenSupplyForStage( uint256 total, uint256 maxTokenSupplyForStage ); /** * @dev Revert if the fee recipient is the zero address. */ error FeeRecipientCannotBeZeroAddress(); /** * @dev Revert if the fee recipient is not already included. */ error FeeRecipientNotPresent(); /** * @dev Revert if the fee basis points is greater than 10_000. */ error InvalidFeeBps(uint256 feeBps); /** * @dev Revert if the fee recipient is already included. */ error DuplicateFeeRecipient(); /** * @dev Revert if the fee recipient is restricted and not allowed. */ error FeeRecipientNotAllowed(address got); /** * @dev Revert if the creator payout address is the zero address. */ error CreatorPayoutAddressCannotBeZeroAddress(); /** * @dev Revert if the creator payouts are not set. */ error CreatorPayoutsNotSet(); /** * @dev Revert if the creator payout basis points are zero. */ error CreatorPayoutBasisPointsCannotBeZero(); /** * @dev Revert if the total basis points for the creator payouts * don't equal exactly 10_000. */ error InvalidCreatorPayoutTotalBasisPoints( uint256 totalReceivedBasisPoints ); /** * @dev Revert if the creator payout basis points don't add up to 10_000. */ error InvalidCreatorPayoutBasisPoints(uint256 totalReceivedBasisPoints); /** * @dev Revert with an error if the allow list proof is invalid. */ error InvalidProof(); /** * @dev Revert if a supplied signer address is the zero address. */ error SignerCannotBeZeroAddress(); /** * @dev Revert with an error if a signer is not included in * the enumeration when removing. */ error SignerNotPresent(); /** * @dev Revert with an error if a payer is not included in * the enumeration when removing. */ error PayerNotPresent(); /** * @dev Revert with an error if a payer is already included in mapping * when adding. */ error DuplicatePayer(); /** * @dev Revert with an error if a signer is already included in mapping * when adding. */ error DuplicateSigner(); /** * @dev Revert with an error if the payer is not allowed. The minter must * pay for their own mint. */ error PayerNotAllowed(address got); /** * @dev Revert if a supplied payer address is the zero address. */ error PayerCannotBeZeroAddress(); /** * @dev Revert if the start time is greater than the end time. */ error InvalidStartAndEndTime(uint256 startTime, uint256 endTime); /** * @dev Revert with an error if the signer payment token is not the same. */ error InvalidSignedPaymentToken(address got, address want); /** * @dev Revert with an error if supplied signed mint price is less than * the minimum specified. */ error InvalidSignedMintPrice( address paymentToken, uint256 got, uint256 minimum ); /** * @dev Revert with an error if supplied signed maxTotalMintableByWallet * is greater than the maximum specified. */ error InvalidSignedMaxTotalMintableByWallet(uint256 got, uint256 maximum); /** * @dev Revert with an error if supplied signed * maxTotalMintableByWalletPerToken is greater than the maximum * specified. */ error InvalidSignedMaxTotalMintableByWalletPerToken( uint256 got, uint256 maximum ); /** * @dev Revert with an error if the fromTokenId is not within range. */ error InvalidSignedFromTokenId(uint256 got, uint256 minimum); /** * @dev Revert with an error if the toTokenId is not within range. */ error InvalidSignedToTokenId(uint256 got, uint256 maximum); /** * @dev Revert with an error if supplied signed start time is less than * the minimum specified. */ error InvalidSignedStartTime(uint256 got, uint256 minimum); /** * @dev Revert with an error if supplied signed end time is greater than * the maximum specified. */ error InvalidSignedEndTime(uint256 got, uint256 maximum); /** * @dev Revert with an error if supplied signed maxTokenSupplyForStage * is greater than the maximum specified. */ error InvalidSignedMaxTokenSupplyForStage(uint256 got, uint256 maximum); /** * @dev Revert with an error if supplied signed feeBps is greater than * the maximum specified, or less than the minimum. */ error InvalidSignedFeeBps(uint256 got, uint256 minimumOrMaximum); /** * @dev Revert with an error if signed mint did not specify to restrict * fee recipients. */ error SignedMintsMustRestrictFeeRecipients(); /** * @dev Revert with an error if a signature for a signed mint has already * been used. */ error SignatureAlreadyUsed(); /** * @dev Revert with an error if the contract has no balance to withdraw. */ error NoBalanceToWithdraw(); /** * @dev Revert with an error if the caller is not an allowed Seaport. */ error InvalidCallerOnlyAllowedSeaport(address caller); /** * @dev Revert with an error if the order does not have the ERC1155 magic * consideration item to signify a consecutive mint. */ error MustSpecifyERC1155ConsiderationItemForSeaDropMint(); /** * @dev Revert with an error if the extra data version is not supported. */ error UnsupportedExtraDataVersion(uint8 version); /** * @dev Revert with an error if the extra data encoding is not supported. */ error InvalidExtraDataEncoding(uint8 version); /** * @dev Revert with an error if the provided substandard is not supported. */ error InvalidSubstandard(uint8 substandard); /** * @dev Revert with an error if the implementation contract is called without * delegatecall. */ error OnlyDelegateCalled(); /** * @dev Revert with an error if the provided allowed Seaport is the * zero address. */ error AllowedSeaportCannotBeZeroAddress(); /** * @dev Emit an event when allowed Seaport contracts are updated. */ event AllowedSeaportUpdated(address[] allowedSeaport); /** * @dev An event with details of a SeaDrop mint, for analytical purposes. * * @param payer The address who payed for the tx. * @param dropStageIndex The drop stage index. Items minted through * public mint have dropStageIndex of 0 */ event SeaDropMint(address payer, uint256 dropStageIndex); /** * @dev An event with updated allow list data. * * @param previousMerkleRoot The previous allow list merkle root. * @param newMerkleRoot The new allow list merkle root. * @param publicKeyURI If the allow list is encrypted, the public key * URIs that can decrypt the list. * Empty if unencrypted. * @param allowListURI The URI for the allow list. */ event AllowListUpdated( bytes32 indexed previousMerkleRoot, bytes32 indexed newMerkleRoot, string[] publicKeyURI, string allowListURI ); /** * @dev An event with updated drop URI. */ event DropURIUpdated(string newDropURI); /** * @dev An event with the updated creator payout address. */ event CreatorPayoutsUpdated(CreatorPayout[] creatorPayouts); /** * @dev An event with the updated allowed fee recipient. */ event AllowedFeeRecipientUpdated( address indexed feeRecipient, bool indexed allowed ); /** * @dev An event with the updated signer. */ event SignerUpdated(address indexed signer, bool indexed allowed); /** * @dev An event with the updated payer. */ event PayerUpdated(address indexed payer, bool indexed allowed); } // SPDX-License-Identifier: MIT pragma solidity ^0.8.13; enum OrderType { // 0: no partial fills, anyone can execute FULL_OPEN, // 1: partial fills supported, anyone can execute PARTIAL_OPEN, // 2: no partial fills, only offerer or zone can execute FULL_RESTRICTED, // 3: partial fills supported, only offerer or zone can execute PARTIAL_RESTRICTED, // 4: contract order type CONTRACT } enum BasicOrderType { // 0: no partial fills, anyone can execute ETH_TO_ERC721_FULL_OPEN, // 1: partial fills supported, anyone can execute ETH_TO_ERC721_PARTIAL_OPEN, // 2: no partial fills, only offerer or zone can execute ETH_TO_ERC721_FULL_RESTRICTED, // 3: partial fills supported, only offerer or zone can execute ETH_TO_ERC721_PARTIAL_RESTRICTED, // 4: no partial fills, anyone can execute ETH_TO_ERC1155_FULL_OPEN, // 5: partial fills supported, anyone can execute ETH_TO_ERC1155_PARTIAL_OPEN, // 6: no partial fills, only offerer or zone can execute ETH_TO_ERC1155_FULL_RESTRICTED, // 7: partial fills supported, only offerer or zone can execute ETH_TO_ERC1155_PARTIAL_RESTRICTED, // 8: no partial fills, anyone can execute ERC20_TO_ERC721_FULL_OPEN, // 9: partial fills supported, anyone can execute ERC20_TO_ERC721_PARTIAL_OPEN, // 10: no partial fills, only offerer or zone can execute ERC20_TO_ERC721_FULL_RESTRICTED, // 11: partial fills supported, only offerer or zone can execute ERC20_TO_ERC721_PARTIAL_RESTRICTED, // 12: no partial fills, anyone can execute ERC20_TO_ERC1155_FULL_OPEN, // 13: partial fills supported, anyone can execute ERC20_TO_ERC1155_PARTIAL_OPEN, // 14: no partial fills, only offerer or zone can execute ERC20_TO_ERC1155_FULL_RESTRICTED, // 15: partial fills supported, only offerer or zone can execute ERC20_TO_ERC1155_PARTIAL_RESTRICTED, // 16: no partial fills, anyone can execute ERC721_TO_ERC20_FULL_OPEN, // 17: partial fills supported, anyone can execute ERC721_TO_ERC20_PARTIAL_OPEN, // 18: no partial fills, only offerer or zone can execute ERC721_TO_ERC20_FULL_RESTRICTED, // 19: partial fills supported, only offerer or zone can execute ERC721_TO_ERC20_PARTIAL_RESTRICTED, // 20: no partial fills, anyone can execute ERC1155_TO_ERC20_FULL_OPEN, // 21: partial fills supported, anyone can execute ERC1155_TO_ERC20_PARTIAL_OPEN, // 22: no partial fills, only offerer or zone can execute ERC1155_TO_ERC20_FULL_RESTRICTED, // 23: partial fills supported, only offerer or zone can execute ERC1155_TO_ERC20_PARTIAL_RESTRICTED } enum BasicOrderRouteType { // 0: provide Ether (or other native token) to receive offered ERC721 item. ETH_TO_ERC721, // 1: provide Ether (or other native token) to receive offered ERC1155 item. ETH_TO_ERC1155, // 2: provide ERC20 item to receive offered ERC721 item. ERC20_TO_ERC721, // 3: provide ERC20 item to receive offered ERC1155 item. ERC20_TO_ERC1155, // 4: provide ERC721 item to receive offered ERC20 item. ERC721_TO_ERC20, // 5: provide ERC1155 item to receive offered ERC20 item. ERC1155_TO_ERC20 } enum ItemType { // 0: ETH on mainnet, MATIC on polygon, etc. NATIVE, // 1: ERC20 items (ERC777 and ERC20 analogues could also technically work) ERC20, // 2: ERC721 items ERC721, // 3: ERC1155 items ERC1155, // 4: ERC721 items where a number of tokenIds are supported ERC721_WITH_CRITERIA, // 5: ERC1155 items where a number of ids are supported ERC1155_WITH_CRITERIA } enum Side { // 0: Items that can be spent OFFER, // 1: Items that must be received CONSIDERATION } // SPDX-License-Identifier: MIT pragma solidity ^0.8.13; type CalldataPointer is uint256; type ReturndataPointer is uint256; type MemoryPointer is uint256; using CalldataPointerLib for CalldataPointer global; using MemoryPointerLib for MemoryPointer global; using ReturndataPointerLib for ReturndataPointer global; using CalldataReaders for CalldataPointer global; using ReturndataReaders for ReturndataPointer global; using MemoryReaders for MemoryPointer global; using MemoryWriters for MemoryPointer global; CalldataPointer constant CalldataStart = CalldataPointer.wrap(0x04); MemoryPointer constant FreeMemoryPPtr = MemoryPointer.wrap(0x40); uint256 constant IdentityPrecompileAddress = 0x4; uint256 constant OffsetOrLengthMask = 0xffffffff; uint256 constant _OneWord = 0x20; uint256 constant _FreeMemoryPointerSlot = 0x40; /// @dev Allocates `size` bytes in memory by increasing the free memory pointer /// and returns the memory pointer to the first byte of the allocated region. // (Free functions cannot have visibility.) // solhint-disable-next-line func-visibility function malloc(uint256 size) pure returns (MemoryPointer mPtr) { assembly { mPtr := mload(_FreeMemoryPointerSlot) mstore(_FreeMemoryPointerSlot, add(mPtr, size)) } } // (Free functions cannot have visibility.) // solhint-disable-next-line func-visibility function getFreeMemoryPointer() pure returns (MemoryPointer mPtr) { mPtr = FreeMemoryPPtr.readMemoryPointer(); } // (Free functions cannot have visibility.) // solhint-disable-next-line func-visibility function setFreeMemoryPointer(MemoryPointer mPtr) pure { FreeMemoryPPtr.write(mPtr); } library CalldataPointerLib { function lt( CalldataPointer a, CalldataPointer b ) internal pure returns (bool c) { assembly { c := lt(a, b) } } function gt( CalldataPointer a, CalldataPointer b ) internal pure returns (bool c) { assembly { c := gt(a, b) } } function eq( CalldataPointer a, CalldataPointer b ) internal pure returns (bool c) { assembly { c := eq(a, b) } } function isNull(CalldataPointer a) internal pure returns (bool b) { assembly { b := iszero(a) } } /// @dev Resolves an offset stored at `cdPtr + headOffset` to a calldata. /// pointer `cdPtr` must point to some parent object with a dynamic /// type's head stored at `cdPtr + headOffset`. function pptr( CalldataPointer cdPtr, uint256 headOffset ) internal pure returns (CalldataPointer cdPtrChild) { cdPtrChild = cdPtr.offset( cdPtr.offset(headOffset).readUint256() & OffsetOrLengthMask ); } /// @dev Resolves an offset stored at `cdPtr` to a calldata pointer. /// `cdPtr` must point to some parent object with a dynamic type as its /// first member, e.g. `struct { bytes data; }` function pptr( CalldataPointer cdPtr ) internal pure returns (CalldataPointer cdPtrChild) { cdPtrChild = cdPtr.offset(cdPtr.readUint256() & OffsetOrLengthMask); } /// @dev Returns the calldata pointer one word after `cdPtr`. function next( CalldataPointer cdPtr ) internal pure returns (CalldataPointer cdPtrNext) { assembly { cdPtrNext := add(cdPtr, _OneWord) } } /// @dev Returns the calldata pointer `_offset` bytes after `cdPtr`. function offset( CalldataPointer cdPtr, uint256 _offset ) internal pure returns (CalldataPointer cdPtrNext) { assembly { cdPtrNext := add(cdPtr, _offset) } } /// @dev Copies `size` bytes from calldata starting at `src` to memory at /// `dst`. function copy( CalldataPointer src, MemoryPointer dst, uint256 size ) internal pure { assembly { calldatacopy(dst, src, size) } } } library ReturndataPointerLib { function lt( ReturndataPointer a, ReturndataPointer b ) internal pure returns (bool c) { assembly { c := lt(a, b) } } function gt( ReturndataPointer a, ReturndataPointer b ) internal pure returns (bool c) { assembly { c := gt(a, b) } } function eq( ReturndataPointer a, ReturndataPointer b ) internal pure returns (bool c) { assembly { c := eq(a, b) } } function isNull(ReturndataPointer a) internal pure returns (bool b) { assembly { b := iszero(a) } } /// @dev Resolves an offset stored at `rdPtr + headOffset` to a returndata /// pointer. `rdPtr` must point to some parent object with a dynamic /// type's head stored at `rdPtr + headOffset`. function pptr( ReturndataPointer rdPtr, uint256 headOffset ) internal pure returns (ReturndataPointer rdPtrChild) { rdPtrChild = rdPtr.offset( rdPtr.offset(headOffset).readUint256() & OffsetOrLengthMask ); } /// @dev Resolves an offset stored at `rdPtr` to a returndata pointer. /// `rdPtr` must point to some parent object with a dynamic type as its /// first member, e.g. `struct { bytes data; }` function pptr( ReturndataPointer rdPtr ) internal pure returns (ReturndataPointer rdPtrChild) { rdPtrChild = rdPtr.offset(rdPtr.readUint256() & OffsetOrLengthMask); } /// @dev Returns the returndata pointer one word after `cdPtr`. function next( ReturndataPointer rdPtr ) internal pure returns (ReturndataPointer rdPtrNext) { assembly { rdPtrNext := add(rdPtr, _OneWord) } } /// @dev Returns the returndata pointer `_offset` bytes after `cdPtr`. function offset( ReturndataPointer rdPtr, uint256 _offset ) internal pure returns (ReturndataPointer rdPtrNext) { assembly { rdPtrNext := add(rdPtr, _offset) } } /// @dev Copies `size` bytes from returndata starting at `src` to memory at /// `dst`. function copy( ReturndataPointer src, MemoryPointer dst, uint256 size ) internal pure { assembly { returndatacopy(dst, src, size) } } } library MemoryPointerLib { function copy( MemoryPointer src, MemoryPointer dst, uint256 size ) internal view { assembly { let success := staticcall( gas(), IdentityPrecompileAddress, src, size, dst, size ) if or(iszero(returndatasize()), iszero(success)) { revert(0, 0) } } } function lt( MemoryPointer a, MemoryPointer b ) internal pure returns (bool c) { assembly { c := lt(a, b) } } function gt( MemoryPointer a, MemoryPointer b ) internal pure returns (bool c) { assembly { c := gt(a, b) } } function eq( MemoryPointer a, MemoryPointer b ) internal pure returns (bool c) { assembly { c := eq(a, b) } } function isNull(MemoryPointer a) internal pure returns (bool b) { assembly { b := iszero(a) } } function hash( MemoryPointer ptr, uint256 length ) internal pure returns (bytes32 _hash) { assembly { _hash := keccak256(ptr, length) } } /// @dev Returns the memory pointer one word after `mPtr`. function next( MemoryPointer mPtr ) internal pure returns (MemoryPointer mPtrNext) { assembly { mPtrNext := add(mPtr, _OneWord) } } /// @dev Returns the memory pointer `_offset` bytes after `mPtr`. function offset( MemoryPointer mPtr, uint256 _offset ) internal pure returns (MemoryPointer mPtrNext) { assembly { mPtrNext := add(mPtr, _offset) } } /// @dev Resolves a pointer at `mPtr + headOffset` to a memory /// pointer. `mPtr` must point to some parent object with a dynamic /// type's pointer stored at `mPtr + headOffset`. function pptr( MemoryPointer mPtr, uint256 headOffset ) internal pure returns (MemoryPointer mPtrChild) { mPtrChild = mPtr.offset(headOffset).readMemoryPointer(); } /// @dev Resolves a pointer stored at `mPtr` to a memory pointer. /// `mPtr` must point to some parent object with a dynamic type as its /// first member, e.g. `struct { bytes data; }` function pptr( MemoryPointer mPtr ) internal pure returns (MemoryPointer mPtrChild) { mPtrChild = mPtr.readMemoryPointer(); } } library CalldataReaders { /// @dev Reads the value at `cdPtr` and applies a mask to return only the /// last 4 bytes. function readMaskedUint256( CalldataPointer cdPtr ) internal pure returns (uint256 value) { value = cdPtr.readUint256() & OffsetOrLengthMask; } /// @dev Reads the bool at `cdPtr` in calldata. function readBool( CalldataPointer cdPtr ) internal pure returns (bool value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the address at `cdPtr` in calldata. function readAddress( CalldataPointer cdPtr ) internal pure returns (address value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes1 at `cdPtr` in calldata. function readBytes1( CalldataPointer cdPtr ) internal pure returns (bytes1 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes2 at `cdPtr` in calldata. function readBytes2( CalldataPointer cdPtr ) internal pure returns (bytes2 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes3 at `cdPtr` in calldata. function readBytes3( CalldataPointer cdPtr ) internal pure returns (bytes3 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes4 at `cdPtr` in calldata. function readBytes4( CalldataPointer cdPtr ) internal pure returns (bytes4 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes5 at `cdPtr` in calldata. function readBytes5( CalldataPointer cdPtr ) internal pure returns (bytes5 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes6 at `cdPtr` in calldata. function readBytes6( CalldataPointer cdPtr ) internal pure returns (bytes6 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes7 at `cdPtr` in calldata. function readBytes7( CalldataPointer cdPtr ) internal pure returns (bytes7 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes8 at `cdPtr` in calldata. function readBytes8( CalldataPointer cdPtr ) internal pure returns (bytes8 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes9 at `cdPtr` in calldata. function readBytes9( CalldataPointer cdPtr ) internal pure returns (bytes9 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes10 at `cdPtr` in calldata. function readBytes10( CalldataPointer cdPtr ) internal pure returns (bytes10 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes11 at `cdPtr` in calldata. function readBytes11( CalldataPointer cdPtr ) internal pure returns (bytes11 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes12 at `cdPtr` in calldata. function readBytes12( CalldataPointer cdPtr ) internal pure returns (bytes12 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes13 at `cdPtr` in calldata. function readBytes13( CalldataPointer cdPtr ) internal pure returns (bytes13 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes14 at `cdPtr` in calldata. function readBytes14( CalldataPointer cdPtr ) internal pure returns (bytes14 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes15 at `cdPtr` in calldata. function readBytes15( CalldataPointer cdPtr ) internal pure returns (bytes15 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes16 at `cdPtr` in calldata. function readBytes16( CalldataPointer cdPtr ) internal pure returns (bytes16 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes17 at `cdPtr` in calldata. function readBytes17( CalldataPointer cdPtr ) internal pure returns (bytes17 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes18 at `cdPtr` in calldata. function readBytes18( CalldataPointer cdPtr ) internal pure returns (bytes18 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes19 at `cdPtr` in calldata. function readBytes19( CalldataPointer cdPtr ) internal pure returns (bytes19 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes20 at `cdPtr` in calldata. function readBytes20( CalldataPointer cdPtr ) internal pure returns (bytes20 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes21 at `cdPtr` in calldata. function readBytes21( CalldataPointer cdPtr ) internal pure returns (bytes21 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes22 at `cdPtr` in calldata. function readBytes22( CalldataPointer cdPtr ) internal pure returns (bytes22 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes23 at `cdPtr` in calldata. function readBytes23( CalldataPointer cdPtr ) internal pure returns (bytes23 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes24 at `cdPtr` in calldata. function readBytes24( CalldataPointer cdPtr ) internal pure returns (bytes24 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes25 at `cdPtr` in calldata. function readBytes25( CalldataPointer cdPtr ) internal pure returns (bytes25 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes26 at `cdPtr` in calldata. function readBytes26( CalldataPointer cdPtr ) internal pure returns (bytes26 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes27 at `cdPtr` in calldata. function readBytes27( CalldataPointer cdPtr ) internal pure returns (bytes27 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes28 at `cdPtr` in calldata. function readBytes28( CalldataPointer cdPtr ) internal pure returns (bytes28 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes29 at `cdPtr` in calldata. function readBytes29( CalldataPointer cdPtr ) internal pure returns (bytes29 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes30 at `cdPtr` in calldata. function readBytes30( CalldataPointer cdPtr ) internal pure returns (bytes30 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes31 at `cdPtr` in calldata. function readBytes31( CalldataPointer cdPtr ) internal pure returns (bytes31 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes32 at `cdPtr` in calldata. function readBytes32( CalldataPointer cdPtr ) internal pure returns (bytes32 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint8 at `cdPtr` in calldata. function readUint8( CalldataPointer cdPtr ) internal pure returns (uint8 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint16 at `cdPtr` in calldata. function readUint16( CalldataPointer cdPtr ) internal pure returns (uint16 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint24 at `cdPtr` in calldata. function readUint24( CalldataPointer cdPtr ) internal pure returns (uint24 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint32 at `cdPtr` in calldata. function readUint32( CalldataPointer cdPtr ) internal pure returns (uint32 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint40 at `cdPtr` in calldata. function readUint40( CalldataPointer cdPtr ) internal pure returns (uint40 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint48 at `cdPtr` in calldata. function readUint48( CalldataPointer cdPtr ) internal pure returns (uint48 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint56 at `cdPtr` in calldata. function readUint56( CalldataPointer cdPtr ) internal pure returns (uint56 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint64 at `cdPtr` in calldata. function readUint64( CalldataPointer cdPtr ) internal pure returns (uint64 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint72 at `cdPtr` in calldata. function readUint72( CalldataPointer cdPtr ) internal pure returns (uint72 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint80 at `cdPtr` in calldata. function readUint80( CalldataPointer cdPtr ) internal pure returns (uint80 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint88 at `cdPtr` in calldata. function readUint88( CalldataPointer cdPtr ) internal pure returns (uint88 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint96 at `cdPtr` in calldata. function readUint96( CalldataPointer cdPtr ) internal pure returns (uint96 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint104 at `cdPtr` in calldata. function readUint104( CalldataPointer cdPtr ) internal pure returns (uint104 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint112 at `cdPtr` in calldata. function readUint112( CalldataPointer cdPtr ) internal pure returns (uint112 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint120 at `cdPtr` in calldata. function readUint120( CalldataPointer cdPtr ) internal pure returns (uint120 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint128 at `cdPtr` in calldata. function readUint128( CalldataPointer cdPtr ) internal pure returns (uint128 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint136 at `cdPtr` in calldata. function readUint136( CalldataPointer cdPtr ) internal pure returns (uint136 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint144 at `cdPtr` in calldata. function readUint144( CalldataPointer cdPtr ) internal pure returns (uint144 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint152 at `cdPtr` in calldata. function readUint152( CalldataPointer cdPtr ) internal pure returns (uint152 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint160 at `cdPtr` in calldata. function readUint160( CalldataPointer cdPtr ) internal pure returns (uint160 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint168 at `cdPtr` in calldata. function readUint168( CalldataPointer cdPtr ) internal pure returns (uint168 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint176 at `cdPtr` in calldata. function readUint176( CalldataPointer cdPtr ) internal pure returns (uint176 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint184 at `cdPtr` in calldata. function readUint184( CalldataPointer cdPtr ) internal pure returns (uint184 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint192 at `cdPtr` in calldata. function readUint192( CalldataPointer cdPtr ) internal pure returns (uint192 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint200 at `cdPtr` in calldata. function readUint200( CalldataPointer cdPtr ) internal pure returns (uint200 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint208 at `cdPtr` in calldata. function readUint208( CalldataPointer cdPtr ) internal pure returns (uint208 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint216 at `cdPtr` in calldata. function readUint216( CalldataPointer cdPtr ) internal pure returns (uint216 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint224 at `cdPtr` in calldata. function readUint224( CalldataPointer cdPtr ) internal pure returns (uint224 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint232 at `cdPtr` in calldata. function readUint232( CalldataPointer cdPtr ) internal pure returns (uint232 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint240 at `cdPtr` in calldata. function readUint240( CalldataPointer cdPtr ) internal pure returns (uint240 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint248 at `cdPtr` in calldata. function readUint248( CalldataPointer cdPtr ) internal pure returns (uint248 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint256 at `cdPtr` in calldata. function readUint256( CalldataPointer cdPtr ) internal pure returns (uint256 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int8 at `cdPtr` in calldata. function readInt8( CalldataPointer cdPtr ) internal pure returns (int8 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int16 at `cdPtr` in calldata. function readInt16( CalldataPointer cdPtr ) internal pure returns (int16 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int24 at `cdPtr` in calldata. function readInt24( CalldataPointer cdPtr ) internal pure returns (int24 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int32 at `cdPtr` in calldata. function readInt32( CalldataPointer cdPtr ) internal pure returns (int32 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int40 at `cdPtr` in calldata. function readInt40( CalldataPointer cdPtr ) internal pure returns (int40 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int48 at `cdPtr` in calldata. function readInt48( CalldataPointer cdPtr ) internal pure returns (int48 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int56 at `cdPtr` in calldata. function readInt56( CalldataPointer cdPtr ) internal pure returns (int56 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int64 at `cdPtr` in calldata. function readInt64( CalldataPointer cdPtr ) internal pure returns (int64 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int72 at `cdPtr` in calldata. function readInt72( CalldataPointer cdPtr ) internal pure returns (int72 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int80 at `cdPtr` in calldata. function readInt80( CalldataPointer cdPtr ) internal pure returns (int80 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int88 at `cdPtr` in calldata. function readInt88( CalldataPointer cdPtr ) internal pure returns (int88 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int96 at `cdPtr` in calldata. function readInt96( CalldataPointer cdPtr ) internal pure returns (int96 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int104 at `cdPtr` in calldata. function readInt104( CalldataPointer cdPtr ) internal pure returns (int104 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int112 at `cdPtr` in calldata. function readInt112( CalldataPointer cdPtr ) internal pure returns (int112 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int120 at `cdPtr` in calldata. function readInt120( CalldataPointer cdPtr ) internal pure returns (int120 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int128 at `cdPtr` in calldata. function readInt128( CalldataPointer cdPtr ) internal pure returns (int128 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int136 at `cdPtr` in calldata. function readInt136( CalldataPointer cdPtr ) internal pure returns (int136 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int144 at `cdPtr` in calldata. function readInt144( CalldataPointer cdPtr ) internal pure returns (int144 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int152 at `cdPtr` in calldata. function readInt152( CalldataPointer cdPtr ) internal pure returns (int152 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int160 at `cdPtr` in calldata. function readInt160( CalldataPointer cdPtr ) internal pure returns (int160 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int168 at `cdPtr` in calldata. function readInt168( CalldataPointer cdPtr ) internal pure returns (int168 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int176 at `cdPtr` in calldata. function readInt176( CalldataPointer cdPtr ) internal pure returns (int176 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int184 at `cdPtr` in calldata. function readInt184( CalldataPointer cdPtr ) internal pure returns (int184 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int192 at `cdPtr` in calldata. function readInt192( CalldataPointer cdPtr ) internal pure returns (int192 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int200 at `cdPtr` in calldata. function readInt200( CalldataPointer cdPtr ) internal pure returns (int200 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int208 at `cdPtr` in calldata. function readInt208( CalldataPointer cdPtr ) internal pure returns (int208 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int216 at `cdPtr` in calldata. function readInt216( CalldataPointer cdPtr ) internal pure returns (int216 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int224 at `cdPtr` in calldata. function readInt224( CalldataPointer cdPtr ) internal pure returns (int224 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int232 at `cdPtr` in calldata. function readInt232( CalldataPointer cdPtr ) internal pure returns (int232 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int240 at `cdPtr` in calldata. function readInt240( CalldataPointer cdPtr ) internal pure returns (int240 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int248 at `cdPtr` in calldata. function readInt248( CalldataPointer cdPtr ) internal pure returns (int248 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int256 at `cdPtr` in calldata. function readInt256( CalldataPointer cdPtr ) internal pure returns (int256 value) { assembly { value := calldataload(cdPtr) } } } library ReturndataReaders { /// @dev Reads value at `rdPtr` & applies a mask to return only last 4 bytes function readMaskedUint256( ReturndataPointer rdPtr ) internal pure returns (uint256 value) { value = rdPtr.readUint256() & OffsetOrLengthMask; } /// @dev Reads the bool at `rdPtr` in returndata. function readBool( ReturndataPointer rdPtr ) internal pure returns (bool value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the address at `rdPtr` in returndata. function readAddress( ReturndataPointer rdPtr ) internal pure returns (address value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes1 at `rdPtr` in returndata. function readBytes1( ReturndataPointer rdPtr ) internal pure returns (bytes1 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes2 at `rdPtr` in returndata. function readBytes2( ReturndataPointer rdPtr ) internal pure returns (bytes2 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes3 at `rdPtr` in returndata. function readBytes3( ReturndataPointer rdPtr ) internal pure returns (bytes3 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes4 at `rdPtr` in returndata. function readBytes4( ReturndataPointer rdPtr ) internal pure returns (bytes4 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes5 at `rdPtr` in returndata. function readBytes5( ReturndataPointer rdPtr ) internal pure returns (bytes5 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes6 at `rdPtr` in returndata. function readBytes6( ReturndataPointer rdPtr ) internal pure returns (bytes6 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes7 at `rdPtr` in returndata. function readBytes7( ReturndataPointer rdPtr ) internal pure returns (bytes7 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes8 at `rdPtr` in returndata. function readBytes8( ReturndataPointer rdPtr ) internal pure returns (bytes8 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes9 at `rdPtr` in returndata. function readBytes9( ReturndataPointer rdPtr ) internal pure returns (bytes9 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes10 at `rdPtr` in returndata. function readBytes10( ReturndataPointer rdPtr ) internal pure returns (bytes10 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes11 at `rdPtr` in returndata. function readBytes11( ReturndataPointer rdPtr ) internal pure returns (bytes11 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes12 at `rdPtr` in returndata. function readBytes12( ReturndataPointer rdPtr ) internal pure returns (bytes12 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes13 at `rdPtr` in returndata. function readBytes13( ReturndataPointer rdPtr ) internal pure returns (bytes13 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes14 at `rdPtr` in returndata. function readBytes14( ReturndataPointer rdPtr ) internal pure returns (bytes14 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes15 at `rdPtr` in returndata. function readBytes15( ReturndataPointer rdPtr ) internal pure returns (bytes15 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes16 at `rdPtr` in returndata. function readBytes16( ReturndataPointer rdPtr ) internal pure returns (bytes16 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes17 at `rdPtr` in returndata. function readBytes17( ReturndataPointer rdPtr ) internal pure returns (bytes17 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes18 at `rdPtr` in returndata. function readBytes18( ReturndataPointer rdPtr ) internal pure returns (bytes18 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes19 at `rdPtr` in returndata. function readBytes19( ReturndataPointer rdPtr ) internal pure returns (bytes19 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes20 at `rdPtr` in returndata. function readBytes20( ReturndataPointer rdPtr ) internal pure returns (bytes20 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes21 at `rdPtr` in returndata. function readBytes21( ReturndataPointer rdPtr ) internal pure returns (bytes21 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes22 at `rdPtr` in returndata. function readBytes22( ReturndataPointer rdPtr ) internal pure returns (bytes22 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes23 at `rdPtr` in returndata. function readBytes23( ReturndataPointer rdPtr ) internal pure returns (bytes23 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes24 at `rdPtr` in returndata. function readBytes24( ReturndataPointer rdPtr ) internal pure returns (bytes24 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes25 at `rdPtr` in returndata. function readBytes25( ReturndataPointer rdPtr ) internal pure returns (bytes25 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes26 at `rdPtr` in returndata. function readBytes26( ReturndataPointer rdPtr ) internal pure returns (bytes26 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes27 at `rdPtr` in returndata. function readBytes27( ReturndataPointer rdPtr ) internal pure returns (bytes27 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes28 at `rdPtr` in returndata. function readBytes28( ReturndataPointer rdPtr ) internal pure returns (bytes28 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes29 at `rdPtr` in returndata. function readBytes29( ReturndataPointer rdPtr ) internal pure returns (bytes29 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes30 at `rdPtr` in returndata. function readBytes30( ReturndataPointer rdPtr ) internal pure returns (bytes30 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes31 at `rdPtr` in returndata. function readBytes31( ReturndataPointer rdPtr ) internal pure returns (bytes31 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes32 at `rdPtr` in returndata. function readBytes32( ReturndataPointer rdPtr ) internal pure returns (bytes32 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint8 at `rdPtr` in returndata. function readUint8( ReturndataPointer rdPtr ) internal pure returns (uint8 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint16 at `rdPtr` in returndata. function readUint16( ReturndataPointer rdPtr ) internal pure returns (uint16 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint24 at `rdPtr` in returndata. function readUint24( ReturndataPointer rdPtr ) internal pure returns (uint24 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint32 at `rdPtr` in returndata. function readUint32( ReturndataPointer rdPtr ) internal pure returns (uint32 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint40 at `rdPtr` in returndata. function readUint40( ReturndataPointer rdPtr ) internal pure returns (uint40 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint48 at `rdPtr` in returndata. function readUint48( ReturndataPointer rdPtr ) internal pure returns (uint48 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint56 at `rdPtr` in returndata. function readUint56( ReturndataPointer rdPtr ) internal pure returns (uint56 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint64 at `rdPtr` in returndata. function readUint64( ReturndataPointer rdPtr ) internal pure returns (uint64 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint72 at `rdPtr` in returndata. function readUint72( ReturndataPointer rdPtr ) internal pure returns (uint72 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint80 at `rdPtr` in returndata. function readUint80( ReturndataPointer rdPtr ) internal pure returns (uint80 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint88 at `rdPtr` in returndata. function readUint88( ReturndataPointer rdPtr ) internal pure returns (uint88 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint96 at `rdPtr` in returndata. function readUint96( ReturndataPointer rdPtr ) internal pure returns (uint96 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint104 at `rdPtr` in returndata. function readUint104( ReturndataPointer rdPtr ) internal pure returns (uint104 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint112 at `rdPtr` in returndata. function readUint112( ReturndataPointer rdPtr ) internal pure returns (uint112 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint120 at `rdPtr` in returndata. function readUint120( ReturndataPointer rdPtr ) internal pure returns (uint120 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint128 at `rdPtr` in returndata. function readUint128( ReturndataPointer rdPtr ) internal pure returns (uint128 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint136 at `rdPtr` in returndata. function readUint136( ReturndataPointer rdPtr ) internal pure returns (uint136 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint144 at `rdPtr` in returndata. function readUint144( ReturndataPointer rdPtr ) internal pure returns (uint144 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint152 at `rdPtr` in returndata. function readUint152( ReturndataPointer rdPtr ) internal pure returns (uint152 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint160 at `rdPtr` in returndata. function readUint160( ReturndataPointer rdPtr ) internal pure returns (uint160 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint168 at `rdPtr` in returndata. function readUint168( ReturndataPointer rdPtr ) internal pure returns (uint168 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint176 at `rdPtr` in returndata. function readUint176( ReturndataPointer rdPtr ) internal pure returns (uint176 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint184 at `rdPtr` in returndata. function readUint184( ReturndataPointer rdPtr ) internal pure returns (uint184 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint192 at `rdPtr` in returndata. function readUint192( ReturndataPointer rdPtr ) internal pure returns (uint192 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint200 at `rdPtr` in returndata. function readUint200( ReturndataPointer rdPtr ) internal pure returns (uint200 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint208 at `rdPtr` in returndata. function readUint208( ReturndataPointer rdPtr ) internal pure returns (uint208 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint216 at `rdPtr` in returndata. function readUint216( ReturndataPointer rdPtr ) internal pure returns (uint216 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint224 at `rdPtr` in returndata. function readUint224( ReturndataPointer rdPtr ) internal pure returns (uint224 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint232 at `rdPtr` in returndata. function readUint232( ReturndataPointer rdPtr ) internal pure returns (uint232 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint240 at `rdPtr` in returndata. function readUint240( ReturndataPointer rdPtr ) internal pure returns (uint240 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint248 at `rdPtr` in returndata. function readUint248( ReturndataPointer rdPtr ) internal pure returns (uint248 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint256 at `rdPtr` in returndata. function readUint256( ReturndataPointer rdPtr ) internal pure returns (uint256 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int8 at `rdPtr` in returndata. function readInt8( ReturndataPointer rdPtr ) internal pure returns (int8 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int16 at `rdPtr` in returndata. function readInt16( ReturndataPointer rdPtr ) internal pure returns (int16 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int24 at `rdPtr` in returndata. function readInt24( ReturndataPointer rdPtr ) internal pure returns (int24 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int32 at `rdPtr` in returndata. function readInt32( ReturndataPointer rdPtr ) internal pure returns (int32 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int40 at `rdPtr` in returndata. function readInt40( ReturndataPointer rdPtr ) internal pure returns (int40 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int48 at `rdPtr` in returndata. function readInt48( ReturndataPointer rdPtr ) internal pure returns (int48 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int56 at `rdPtr` in returndata. function readInt56( ReturndataPointer rdPtr ) internal pure returns (int56 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int64 at `rdPtr` in returndata. function readInt64( ReturndataPointer rdPtr ) internal pure returns (int64 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int72 at `rdPtr` in returndata. function readInt72( ReturndataPointer rdPtr ) internal pure returns (int72 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int80 at `rdPtr` in returndata. function readInt80( ReturndataPointer rdPtr ) internal pure returns (int80 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int88 at `rdPtr` in returndata. function readInt88( ReturndataPointer rdPtr ) internal pure returns (int88 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int96 at `rdPtr` in returndata. function readInt96( ReturndataPointer rdPtr ) internal pure returns (int96 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int104 at `rdPtr` in returndata. function readInt104( ReturndataPointer rdPtr ) internal pure returns (int104 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int112 at `rdPtr` in returndata. function readInt112( ReturndataPointer rdPtr ) internal pure returns (int112 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int120 at `rdPtr` in returndata. function readInt120( ReturndataPointer rdPtr ) internal pure returns (int120 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int128 at `rdPtr` in returndata. function readInt128( ReturndataPointer rdPtr ) internal pure returns (int128 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int136 at `rdPtr` in returndata. function readInt136( ReturndataPointer rdPtr ) internal pure returns (int136 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int144 at `rdPtr` in returndata. function readInt144( ReturndataPointer rdPtr ) internal pure returns (int144 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int152 at `rdPtr` in returndata. function readInt152( ReturndataPointer rdPtr ) internal pure returns (int152 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int160 at `rdPtr` in returndata. function readInt160( ReturndataPointer rdPtr ) internal pure returns (int160 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int168 at `rdPtr` in returndata. function readInt168( ReturndataPointer rdPtr ) internal pure returns (int168 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int176 at `rdPtr` in returndata. function readInt176( ReturndataPointer rdPtr ) internal pure returns (int176 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int184 at `rdPtr` in returndata. function readInt184( ReturndataPointer rdPtr ) internal pure returns (int184 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int192 at `rdPtr` in returndata. function readInt192( ReturndataPointer rdPtr ) internal pure returns (int192 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int200 at `rdPtr` in returndata. function readInt200( ReturndataPointer rdPtr ) internal pure returns (int200 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int208 at `rdPtr` in returndata. function readInt208( ReturndataPointer rdPtr ) internal pure returns (int208 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int216 at `rdPtr` in returndata. function readInt216( ReturndataPointer rdPtr ) internal pure returns (int216 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int224 at `rdPtr` in returndata. function readInt224( ReturndataPointer rdPtr ) internal pure returns (int224 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int232 at `rdPtr` in returndata. function readInt232( ReturndataPointer rdPtr ) internal pure returns (int232 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int240 at `rdPtr` in returndata. function readInt240( ReturndataPointer rdPtr ) internal pure returns (int240 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int248 at `rdPtr` in returndata. function readInt248( ReturndataPointer rdPtr ) internal pure returns (int248 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int256 at `rdPtr` in returndata. function readInt256( ReturndataPointer rdPtr ) internal pure returns (int256 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } } library MemoryReaders { /// @dev Reads the memory pointer at `mPtr` in memory. function readMemoryPointer( MemoryPointer mPtr ) internal pure returns (MemoryPointer value) { assembly { value := mload(mPtr) } } /// @dev Reads value at `mPtr` & applies a mask to return only last 4 bytes function readMaskedUint256( MemoryPointer mPtr ) internal pure returns (uint256 value) { value = mPtr.readUint256() & OffsetOrLengthMask; } /// @dev Reads the bool at `mPtr` in memory. function readBool(MemoryPointer mPtr) internal pure returns (bool value) { assembly { value := mload(mPtr) } } /// @dev Reads the address at `mPtr` in memory. function readAddress( MemoryPointer mPtr ) internal pure returns (address value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes1 at `mPtr` in memory. function readBytes1( MemoryPointer mPtr ) internal pure returns (bytes1 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes2 at `mPtr` in memory. function readBytes2( MemoryPointer mPtr ) internal pure returns (bytes2 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes3 at `mPtr` in memory. function readBytes3( MemoryPointer mPtr ) internal pure returns (bytes3 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes4 at `mPtr` in memory. function readBytes4( MemoryPointer mPtr ) internal pure returns (bytes4 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes5 at `mPtr` in memory. function readBytes5( MemoryPointer mPtr ) internal pure returns (bytes5 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes6 at `mPtr` in memory. function readBytes6( MemoryPointer mPtr ) internal pure returns (bytes6 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes7 at `mPtr` in memory. function readBytes7( MemoryPointer mPtr ) internal pure returns (bytes7 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes8 at `mPtr` in memory. function readBytes8( MemoryPointer mPtr ) internal pure returns (bytes8 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes9 at `mPtr` in memory. function readBytes9( MemoryPointer mPtr ) internal pure returns (bytes9 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes10 at `mPtr` in memory. function readBytes10( MemoryPointer mPtr ) internal pure returns (bytes10 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes11 at `mPtr` in memory. function readBytes11( MemoryPointer mPtr ) internal pure returns (bytes11 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes12 at `mPtr` in memory. function readBytes12( MemoryPointer mPtr ) internal pure returns (bytes12 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes13 at `mPtr` in memory. function readBytes13( MemoryPointer mPtr ) internal pure returns (bytes13 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes14 at `mPtr` in memory. function readBytes14( MemoryPointer mPtr ) internal pure returns (bytes14 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes15 at `mPtr` in memory. function readBytes15( MemoryPointer mPtr ) internal pure returns (bytes15 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes16 at `mPtr` in memory. function readBytes16( MemoryPointer mPtr ) internal pure returns (bytes16 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes17 at `mPtr` in memory. function readBytes17( MemoryPointer mPtr ) internal pure returns (bytes17 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes18 at `mPtr` in memory. function readBytes18( MemoryPointer mPtr ) internal pure returns (bytes18 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes19 at `mPtr` in memory. function readBytes19( MemoryPointer mPtr ) internal pure returns (bytes19 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes20 at `mPtr` in memory. function readBytes20( MemoryPointer mPtr ) internal pure returns (bytes20 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes21 at `mPtr` in memory. function readBytes21( MemoryPointer mPtr ) internal pure returns (bytes21 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes22 at `mPtr` in memory. function readBytes22( MemoryPointer mPtr ) internal pure returns (bytes22 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes23 at `mPtr` in memory. function readBytes23( MemoryPointer mPtr ) internal pure returns (bytes23 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes24 at `mPtr` in memory. function readBytes24( MemoryPointer mPtr ) internal pure returns (bytes24 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes25 at `mPtr` in memory. function readBytes25( MemoryPointer mPtr ) internal pure returns (bytes25 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes26 at `mPtr` in memory. function readBytes26( MemoryPointer mPtr ) internal pure returns (bytes26 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes27 at `mPtr` in memory. function readBytes27( MemoryPointer mPtr ) internal pure returns (bytes27 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes28 at `mPtr` in memory. function readBytes28( MemoryPointer mPtr ) internal pure returns (bytes28 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes29 at `mPtr` in memory. function readBytes29( MemoryPointer mPtr ) internal pure returns (bytes29 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes30 at `mPtr` in memory. function readBytes30( MemoryPointer mPtr ) internal pure returns (bytes30 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes31 at `mPtr` in memory. function readBytes31( MemoryPointer mPtr ) internal pure returns (bytes31 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes32 at `mPtr` in memory. function readBytes32( MemoryPointer mPtr ) internal pure returns (bytes32 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint8 at `mPtr` in memory. function readUint8(MemoryPointer mPtr) internal pure returns (uint8 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint16 at `mPtr` in memory. function readUint16( MemoryPointer mPtr ) internal pure returns (uint16 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint24 at `mPtr` in memory. function readUint24( MemoryPointer mPtr ) internal pure returns (uint24 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint32 at `mPtr` in memory. function readUint32( MemoryPointer mPtr ) internal pure returns (uint32 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint40 at `mPtr` in memory. function readUint40( MemoryPointer mPtr ) internal pure returns (uint40 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint48 at `mPtr` in memory. function readUint48( MemoryPointer mPtr ) internal pure returns (uint48 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint56 at `mPtr` in memory. function readUint56( MemoryPointer mPtr ) internal pure returns (uint56 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint64 at `mPtr` in memory. function readUint64( MemoryPointer mPtr ) internal pure returns (uint64 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint72 at `mPtr` in memory. function readUint72( MemoryPointer mPtr ) internal pure returns (uint72 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint80 at `mPtr` in memory. function readUint80( MemoryPointer mPtr ) internal pure returns (uint80 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint88 at `mPtr` in memory. function readUint88( MemoryPointer mPtr ) internal pure returns (uint88 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint96 at `mPtr` in memory. function readUint96( MemoryPointer mPtr ) internal pure returns (uint96 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint104 at `mPtr` in memory. function readUint104( MemoryPointer mPtr ) internal pure returns (uint104 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint112 at `mPtr` in memory. function readUint112( MemoryPointer mPtr ) internal pure returns (uint112 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint120 at `mPtr` in memory. function readUint120( MemoryPointer mPtr ) internal pure returns (uint120 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint128 at `mPtr` in memory. function readUint128( MemoryPointer mPtr ) internal pure returns (uint128 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint136 at `mPtr` in memory. function readUint136( MemoryPointer mPtr ) internal pure returns (uint136 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint144 at `mPtr` in memory. function readUint144( MemoryPointer mPtr ) internal pure returns (uint144 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint152 at `mPtr` in memory. function readUint152( MemoryPointer mPtr ) internal pure returns (uint152 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint160 at `mPtr` in memory. function readUint160( MemoryPointer mPtr ) internal pure returns (uint160 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint168 at `mPtr` in memory. function readUint168( MemoryPointer mPtr ) internal pure returns (uint168 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint176 at `mPtr` in memory. function readUint176( MemoryPointer mPtr ) internal pure returns (uint176 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint184 at `mPtr` in memory. function readUint184( MemoryPointer mPtr ) internal pure returns (uint184 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint192 at `mPtr` in memory. function readUint192( MemoryPointer mPtr ) internal pure returns (uint192 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint200 at `mPtr` in memory. function readUint200( MemoryPointer mPtr ) internal pure returns (uint200 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint208 at `mPtr` in memory. function readUint208( MemoryPointer mPtr ) internal pure returns (uint208 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint216 at `mPtr` in memory. function readUint216( MemoryPointer mPtr ) internal pure returns (uint216 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint224 at `mPtr` in memory. function readUint224( MemoryPointer mPtr ) internal pure returns (uint224 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint232 at `mPtr` in memory. function readUint232( MemoryPointer mPtr ) internal pure returns (uint232 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint240 at `mPtr` in memory. function readUint240( MemoryPointer mPtr ) internal pure returns (uint240 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint248 at `mPtr` in memory. function readUint248( MemoryPointer mPtr ) internal pure returns (uint248 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint256 at `mPtr` in memory. function readUint256( MemoryPointer mPtr ) internal pure returns (uint256 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int8 at `mPtr` in memory. function readInt8(MemoryPointer mPtr) internal pure returns (int8 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int16 at `mPtr` in memory. function readInt16(MemoryPointer mPtr) internal pure returns (int16 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int24 at `mPtr` in memory. function readInt24(MemoryPointer mPtr) internal pure returns (int24 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int32 at `mPtr` in memory. function readInt32(MemoryPointer mPtr) internal pure returns (int32 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int40 at `mPtr` in memory. function readInt40(MemoryPointer mPtr) internal pure returns (int40 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int48 at `mPtr` in memory. function readInt48(MemoryPointer mPtr) internal pure returns (int48 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int56 at `mPtr` in memory. function readInt56(MemoryPointer mPtr) internal pure returns (int56 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int64 at `mPtr` in memory. function readInt64(MemoryPointer mPtr) internal pure returns (int64 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int72 at `mPtr` in memory. function readInt72(MemoryPointer mPtr) internal pure returns (int72 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int80 at `mPtr` in memory. function readInt80(MemoryPointer mPtr) internal pure returns (int80 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int88 at `mPtr` in memory. function readInt88(MemoryPointer mPtr) internal pure returns (int88 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int96 at `mPtr` in memory. function readInt96(MemoryPointer mPtr) internal pure returns (int96 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int104 at `mPtr` in memory. function readInt104( MemoryPointer mPtr ) internal pure returns (int104 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int112 at `mPtr` in memory. function readInt112( MemoryPointer mPtr ) internal pure returns (int112 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int120 at `mPtr` in memory. function readInt120( MemoryPointer mPtr ) internal pure returns (int120 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int128 at `mPtr` in memory. function readInt128( MemoryPointer mPtr ) internal pure returns (int128 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int136 at `mPtr` in memory. function readInt136( MemoryPointer mPtr ) internal pure returns (int136 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int144 at `mPtr` in memory. function readInt144( MemoryPointer mPtr ) internal pure returns (int144 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int152 at `mPtr` in memory. function readInt152( MemoryPointer mPtr ) internal pure returns (int152 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int160 at `mPtr` in memory. function readInt160( MemoryPointer mPtr ) internal pure returns (int160 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int168 at `mPtr` in memory. function readInt168( MemoryPointer mPtr ) internal pure returns (int168 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int176 at `mPtr` in memory. function readInt176( MemoryPointer mPtr ) internal pure returns (int176 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int184 at `mPtr` in memory. function readInt184( MemoryPointer mPtr ) internal pure returns (int184 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int192 at `mPtr` in memory. function readInt192( MemoryPointer mPtr ) internal pure returns (int192 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int200 at `mPtr` in memory. function readInt200( MemoryPointer mPtr ) internal pure returns (int200 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int208 at `mPtr` in memory. function readInt208( MemoryPointer mPtr ) internal pure returns (int208 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int216 at `mPtr` in memory. function readInt216( MemoryPointer mPtr ) internal pure returns (int216 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int224 at `mPtr` in memory. function readInt224( MemoryPointer mPtr ) internal pure returns (int224 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int232 at `mPtr` in memory. function readInt232( MemoryPointer mPtr ) internal pure returns (int232 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int240 at `mPtr` in memory. function readInt240( MemoryPointer mPtr ) internal pure returns (int240 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int248 at `mPtr` in memory. function readInt248( MemoryPointer mPtr ) internal pure returns (int248 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int256 at `mPtr` in memory. function readInt256( MemoryPointer mPtr ) internal pure returns (int256 value) { assembly { value := mload(mPtr) } } } library MemoryWriters { /// @dev Writes `valuePtr` to memory at `mPtr`. function write(MemoryPointer mPtr, MemoryPointer valuePtr) internal pure { assembly { mstore(mPtr, valuePtr) } } /// @dev Writes a boolean `value` to `mPtr` in memory. function write(MemoryPointer mPtr, bool value) internal pure { assembly { mstore(mPtr, value) } } /// @dev Writes an address `value` to `mPtr` in memory. function write(MemoryPointer mPtr, address value) internal pure { assembly { mstore(mPtr, value) } } /// @dev Writes a bytes32 `value` to `mPtr` in memory. /// Separate name to disambiguate literal write parameters. function writeBytes32(MemoryPointer mPtr, bytes32 value) internal pure { assembly { mstore(mPtr, value) } } /// @dev Writes a uint256 `value` to `mPtr` in memory. function write(MemoryPointer mPtr, uint256 value) internal pure { assembly { mstore(mPtr, value) } } /// @dev Writes an int256 `value` to `mPtr` in memory. /// Separate name to disambiguate literal write parameters. function writeInt(MemoryPointer mPtr, int256 value) internal pure { assembly { mstore(mPtr, value) } } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.7; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.19; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @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, it is bubbled up by this * function (like regular Solidity function calls). * * 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. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @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`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(target.code.length > 0, "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { AllowListData, CreatorPayout } from "./SeaDropStructs.sol"; /** * @notice A struct defining public drop data. * Designed to fit efficiently in two storage slots. * * @param startPrice The start price per token. (Up to 1.2m * of native token, e.g. ETH, MATIC) * @param endPrice The end price per token. If this differs * from startPrice, the current price will * be calculated based on the current time. * @param startTime The start time, ensure this is not zero. * @param endTime The end time, ensure this is not zero. * @param paymentToken The payment token address. Null for * native token. * @param maxTotalMintableByWallet Maximum total number of mints a user is * allowed. (The limit for this field is * 2^16 - 1) * @param feeBps Fee out of 10_000 basis points to be * collected. * @param restrictFeeRecipients If false, allow any fee recipient; * if true, check fee recipient is allowed. */ struct PublicDrop { uint80 startPrice; // 80/512 bits uint80 endPrice; // 160/512 bits uint40 startTime; // 200/512 bits uint40 endTime; // 240/512 bits address paymentToken; // 400/512 bits uint16 maxTotalMintableByWallet; // 416/512 bits uint16 feeBps; // 432/512 bits bool restrictFeeRecipients; // 440/512 bits } /** * @notice A struct defining mint params for an allow list. * An allow list leaf will be composed of `msg.sender` and * the following params. * * Note: Since feeBps is encoded in the leaf, backend should ensure * that feeBps is acceptable before generating a proof. * * @param startPrice The start price per token. (Up to 1.2m * of native token, e.g. ETH, MATIC) * @param endPrice The end price per token. If this differs * from startPrice, the current price will * be calculated based on the current time. * @param startTime The start time, ensure this is not zero. * @param endTime The end time, ensure this is not zero. * @param paymentToken The payment token for the mint. Null for * native token. * @param maxTotalMintableByWallet Maximum total number of mints a user is * allowed. * @param maxTokenSupplyForStage The limit of token supply this stage can * mint within. * @param dropStageIndex The drop stage index to emit with the event * for analytical purposes. This should be * non-zero since the public mint emits with * index zero. * @param feeBps Fee out of 10_000 basis points to be * collected. * @param restrictFeeRecipients If false, allow any fee recipient; * if true, check fee recipient is allowed. */ struct MintParams { uint256 startPrice; uint256 endPrice; uint256 startTime; uint256 endTime; address paymentToken; uint256 maxTotalMintableByWallet; uint256 maxTokenSupplyForStage; uint256 dropStageIndex; // non-zero uint256 feeBps; bool restrictFeeRecipients; } /** * @dev Struct containing internal SeaDrop implementation logic * mint details to avoid stack too deep. * * @param feeRecipient The fee recipient. * @param payer The payer of the mint. * @param minter The mint recipient. * @param quantity The number of tokens to mint. * @param withEffects Whether to apply state changes of the mint. */ struct MintDetails { address feeRecipient; address payer; address minter; uint256 quantity; bool withEffects; } /** * @notice A struct to configure multiple contract options in one transaction. */ struct MultiConfigureStruct { uint256 maxSupply; string baseURI; string contractURI; PublicDrop publicDrop; string dropURI; AllowListData allowListData; CreatorPayout[] creatorPayouts; bytes32 provenanceHash; address[] allowedFeeRecipients; address[] disallowedFeeRecipients; address[] allowedPayers; address[] disallowedPayers; // Server-signed address[] allowedSigners; address[] disallowedSigners; // ERC-2981 address royaltyReceiver; uint96 royaltyBps; // Mint address mintRecipient; uint256 mintQuantity; }
File 2 of 3: ERC1155SeaDropCloneable
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { ERC1155SeaDropContractOffererCloneable } from "./ERC1155SeaDropContractOffererCloneable.sol"; /** * @title ERC1155SeaDropCloneable * @author James Wenzel (emo.eth) * @author Ryan Ghods (ralxz.eth) * @author Stephan Min (stephanm.eth) * @author Michael Cohen (notmichael.eth) * @custom:contributor Limit Break (@limitbreak) * @notice A cloneable ERC1155 token contract that can mint as a * Seaport contract offerer. * Implements Limit Break's Creator Token Standards transfer * validation for royalty enforcement. */ contract ERC1155SeaDropCloneable is ERC1155SeaDropContractOffererCloneable { /** * @notice Initialize the token contract. * * @param allowedConfigurer The address of the contract allowed to * implementation code. Also contains SeaDrop * implementation code. * @param allowedSeaport The address of the Seaport contract allowed to * interact. * @param name_ The name of the token. * @param symbol_ The symbol of the token. */ function initialize( address allowedConfigurer, address allowedSeaport, string memory name_, string memory symbol_, address initialOwner ) public initializer { // Initialize ownership. _initializeOwner(initialOwner); // Initialize ERC1155SeaDropContractOffererCloneable. __ERC1155SeaDropContractOffererCloneable_init( allowedConfigurer, allowedSeaport, name_, symbol_ ); } /** * @notice Burns a token, restricted to the owner or approved operator, * and must have sufficient balance. * * @param from The address to burn from. * @param id The token id to burn. * @param amount The amount to burn. */ function burn(address from, uint256 id, uint256 amount) external { // Burn the token. _burn(msg.sender, from, id, amount); } /** * @notice Burns a batch of tokens, restricted to the owner or * approved operator, and must have sufficient balance. * * @param from The address to burn from. * @param ids The token ids to burn. * @param amounts The amounts to burn per token id. */ function batchBurn( address from, uint256[] calldata ids, uint256[] calldata amounts ) external { // Burn the tokens. _batchBurn(msg.sender, from, ids, amounts); } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { IERC1155SeaDrop } from "../interfaces/IERC1155SeaDrop.sol"; import { ISeaDropToken } from "../interfaces/ISeaDropToken.sol"; import { ERC1155ContractMetadataCloneable } from "./ERC1155ContractMetadataCloneable.sol"; import { ERC1155SeaDropContractOffererStorage } from "../lib/ERC1155SeaDropContractOffererStorage.sol"; import { ERC1155SeaDropErrorsAndEvents } from "../lib/ERC1155SeaDropErrorsAndEvents.sol"; import { PublicDrop } from "../lib//ERC1155SeaDropStructs.sol"; import { AllowListData } from "../lib/SeaDropStructs.sol"; import { ERC1155ConduitPreapproved } from "../lib/ERC1155ConduitPreapproved.sol"; import { ERC1155 } from "solady/src/tokens/ERC1155.sol"; import { SpentItem } from "seaport-types/src/lib/ConsiderationStructs.sol"; import { ContractOffererInterface } from "seaport-types/src/interfaces/ContractOffererInterface.sol"; import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /** * @title ERC1155SeaDropContractOffererCloneable * @author James Wenzel (emo.eth) * @author Ryan Ghods (ralxz.eth) * @author Stephan Min (stephanm.eth) * @author Michael Cohen (notmichael.eth) * @notice A cloneable ERC1155 token contract that can mint as a * Seaport contract offerer. */ contract ERC1155SeaDropContractOffererCloneable is ERC1155ContractMetadataCloneable, ERC1155SeaDropErrorsAndEvents { using ERC1155SeaDropContractOffererStorage for ERC1155SeaDropContractOffererStorage.Layout; /** * @notice Initialize the token contract. * * @param allowedConfigurer The address of the contract allowed to * configure parameters. Also contains SeaDrop * implementation code. * @param allowedSeaport The address of the Seaport contract allowed to * interact. * @param name_ The name of the token. * @param symbol_ The symbol of the token. */ function __ERC1155SeaDropContractOffererCloneable_init( address allowedConfigurer, address allowedSeaport, string memory name_, string memory symbol_ ) internal onlyInitializing { // Set the allowed Seaport to interact with this contract. if (allowedSeaport == address(0)) { revert AllowedSeaportCannotBeZeroAddress(); } ERC1155SeaDropContractOffererStorage.layout()._allowedSeaport[ allowedSeaport ] = true; // Set the allowed Seaport enumeration. address[] memory enumeratedAllowedSeaport = new address[](1); enumeratedAllowedSeaport[0] = allowedSeaport; ERC1155SeaDropContractOffererStorage .layout() ._enumeratedAllowedSeaport = enumeratedAllowedSeaport; // Emit an event noting the contract deployment. emit SeaDropTokenDeployed(SEADROP_TOKEN_TYPE.ERC1155_CLONE); // Initialize ERC1155ContractMetadataCloneable. __ERC1155ContractMetadataCloneable_init( allowedConfigurer, name_, symbol_ ); } /** * @notice The fallback function is used as a dispatcher for SeaDrop * methods. */ fallback(bytes calldata) external returns (bytes memory output) { // Get the function selector. bytes4 selector = msg.sig; // Get the rest of the msg data after the selector. bytes calldata data = msg.data[4:]; // Determine if we should forward the call to the implementation // contract with SeaDrop logic. bool callSeaDropImplementation = selector == ISeaDropToken.updateAllowedSeaport.selector || selector == ISeaDropToken.updateDropURI.selector || selector == ISeaDropToken.updateAllowList.selector || selector == ISeaDropToken.updateCreatorPayouts.selector || selector == ISeaDropToken.updatePayer.selector || selector == ISeaDropToken.updateAllowedFeeRecipient.selector || selector == ISeaDropToken.updateSigner.selector || selector == IERC1155SeaDrop.updatePublicDrop.selector || selector == ContractOffererInterface.previewOrder.selector || selector == ContractOffererInterface.generateOrder.selector || selector == ContractOffererInterface.getSeaportMetadata.selector || selector == IERC1155SeaDrop.getPublicDrop.selector || selector == IERC1155SeaDrop.getPublicDropIndexes.selector || selector == ISeaDropToken.getAllowedSeaport.selector || selector == ISeaDropToken.getCreatorPayouts.selector || selector == ISeaDropToken.getAllowListMerkleRoot.selector || selector == ISeaDropToken.getAllowedFeeRecipients.selector || selector == ISeaDropToken.getSigners.selector || selector == ISeaDropToken.getDigestIsUsed.selector || selector == ISeaDropToken.getPayers.selector; // Determine if we should require only the owner or configurer calling. bool requireOnlyOwnerOrConfigurer = selector == ISeaDropToken.updateAllowedSeaport.selector || selector == ISeaDropToken.updateDropURI.selector || selector == ISeaDropToken.updateAllowList.selector || selector == ISeaDropToken.updateCreatorPayouts.selector || selector == ISeaDropToken.updatePayer.selector || selector == ISeaDropToken.updateAllowedFeeRecipient.selector || selector == IERC1155SeaDrop.updatePublicDrop.selector; if (callSeaDropImplementation) { // For update calls, ensure the sender is only the owner // or configurer contract. if (requireOnlyOwnerOrConfigurer) { _onlyOwnerOrConfigurer(); } else if (selector == ISeaDropToken.updateSigner.selector) { // For updateSigner, a signer can disallow themselves. // Get the signer parameter. address signer = address(bytes20(data[12:32])); // If the signer is not allowed, ensure sender is only owner // or configurer. if ( msg.sender != signer || (msg.sender == signer && !ERC1155SeaDropContractOffererStorage .layout() ._allowedSigners[signer]) ) { _onlyOwnerOrConfigurer(); } } // Forward the call to the implementation contract. (bool success, bytes memory returnedData) = _CONFIGURER .delegatecall(msg.data); // Require that the call was successful. if (!success) { // Bubble up the revert reason. assembly { revert(add(32, returnedData), mload(returnedData)) } } // If the call was to generateOrder, mint the tokens. if (selector == ContractOffererInterface.generateOrder.selector) { _mintOrder(data); } // Return the data from the delegate call. return returnedData; } else if (selector == IERC1155SeaDrop.getMintStats.selector) { // Get the minter and token id. (address minter, uint256 tokenId) = abi.decode( data, (address, uint256) ); // Get the mint stats. ( uint256 minterNumMinted, uint256 minterNumMintedForTokenId, uint256 totalMintedForTokenId, uint256 maxSupply ) = _getMintStats(minter, tokenId); // Encode the return data. return abi.encode( minterNumMinted, minterNumMintedForTokenId, totalMintedForTokenId, maxSupply ); } else if (selector == ContractOffererInterface.ratifyOrder.selector) { // This function is a no-op, nothing additional needs to happen here. // Utilize assembly to efficiently return the ratifyOrder magic value. assembly { mstore(0, 0xf4dd92ce) return(0x1c, 32) } } else if (selector == ISeaDropToken.configurer.selector) { // Return the configurer contract. return abi.encode(_CONFIGURER); } else if (selector == IERC1155SeaDrop.multiConfigureMint.selector) { // Ensure only the owner or configurer can call this function. _onlyOwnerOrConfigurer(); // Mint the tokens. _multiConfigureMint(data); } else { // Revert if the function selector is not supported. revert UnsupportedFunctionSelector(selector); } } /** * @notice Returns a set of mint stats for the address. * This assists in enforcing maxSupply, maxTotalMintableByWallet, * and maxTokenSupplyForStage checks. * * @dev NOTE: Implementing contracts should always update these numbers * before transferring any tokens with _safeMint() to mitigate * consequences of malicious onERC1155Received() hooks. * * @param minter The minter address. * @param tokenId The token id to return the stats for. */ function _getMintStats( address minter, uint256 tokenId ) internal view returns ( uint256 minterNumMinted, uint256 minterNumMintedForTokenId, uint256 totalMintedForTokenId, uint256 maxSupply ) { // Put the token supply on the stack. TokenSupply storage tokenSupply = _tokenSupply[tokenId]; // Assign the return values. totalMintedForTokenId = tokenSupply.totalMinted; maxSupply = tokenSupply.maxSupply; minterNumMinted = _totalMintedByUser[minter]; minterNumMintedForTokenId = _totalMintedByUserPerToken[minter][tokenId]; } /** * @dev Handle ERC-1155 safeTransferFrom. If "from" is this contract, * the sender can only be Seaport or the conduit. * * @param from The address to transfer from. * @param to The address to transfer to. * @param id The token id to transfer. * @param amount The amount of tokens to transfer. * @param data The data to pass to the onERC1155Received hook. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) public virtual override { if (from == address(this)) { // Only Seaport or the conduit can use this function // when "from" is this contract. if ( msg.sender != _CONDUIT && !ERC1155SeaDropContractOffererStorage.layout()._allowedSeaport[ msg.sender ] ) { revert InvalidCallerOnlyAllowedSeaport(msg.sender); } return; } ERC1155._safeTransfer(_by(), from, to, id, amount, data); } /** * @notice Returns whether the interface is supported. * * @param interfaceId The interface id to check against. */ function supportsInterface( bytes4 interfaceId ) public view virtual override(ERC1155ContractMetadataCloneable) returns (bool) { return interfaceId == type(IERC1155SeaDrop).interfaceId || interfaceId == type(ContractOffererInterface).interfaceId || interfaceId == 0x2e778efc || // SIP-5 (getSeaportMetadata) // ERC1155ContractMetadata returns supportsInterface true for // IERC1155ContractMetadata, ERC-4906, ERC-2981 // ERC1155A returns supportsInterface true for // ERC165, ERC1155, ERC1155MetadataURI ERC1155ContractMetadataCloneable.supportsInterface(interfaceId); } /** * @dev Internal function to mint tokens during a generateOrder call * from Seaport. * * @param data The original transaction calldata, without the selector. */ function _mintOrder(bytes calldata data) internal { // Decode fulfiller, minimumReceived, and context from calldata. ( address fulfiller, SpentItem[] memory minimumReceived, , bytes memory context ) = abi.decode(data, (address, SpentItem[], SpentItem[], bytes)); // Assign the minter from context[22:42]. We validate context has the // correct minimum length in the implementation's `_decodeOrder`. address minter; assembly { minter := shr(96, mload(add(add(context, 0x20), 22))) } // If the minter is the zero address, set it to the fulfiller. if (minter == address(0)) { minter = fulfiller; } // Set the token ids and quantities. uint256 minimumReceivedLength = minimumReceived.length; uint256[] memory tokenIds = new uint256[](minimumReceivedLength); uint256[] memory quantities = new uint256[](minimumReceivedLength); for (uint256 i = 0; i < minimumReceivedLength; ) { tokenIds[i] = minimumReceived[i].identifier; quantities[i] = minimumReceived[i].amount; unchecked { ++i; } } // Mint the tokens. _batchMint(minter, tokenIds, quantities, ""); } /** * @dev Internal function to mint tokens during a multiConfigureMint call * from the configurer contract. * * @param data The original transaction calldata, without the selector. */ function _multiConfigureMint(bytes calldata data) internal { // Decode the calldata. ( address recipient, uint256[] memory tokenIds, uint256[] memory amounts ) = abi.decode(data, (address, uint256[], uint256[])); _batchMint(recipient, tokenIds, amounts, ""); } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { ISeaDropToken } from "./ISeaDropToken.sol"; import { PublicDrop } from "../lib/ERC1155SeaDropStructs.sol"; /** * @dev A helper interface to get and set parameters for ERC1155SeaDrop. * The token does not expose these methods as part of its external * interface to optimize contract size, but does implement them. */ interface IERC1155SeaDrop is ISeaDropToken { /** * @notice Update the SeaDrop public drop parameters at a given index. * * @param publicDrop The new public drop parameters. * @param index The public drop index. */ function updatePublicDrop( PublicDrop calldata publicDrop, uint256 index ) external; /** * @notice Returns the public drop stage parameters at a given index. * * @param index The index of the public drop stage. */ function getPublicDrop( uint256 index ) external view returns (PublicDrop memory); /** * @notice Returns the public drop indexes. */ function getPublicDropIndexes() external view returns (uint256[] memory); /** * @notice Returns a set of mint stats for the address. * This assists SeaDrop in enforcing maxSupply, * maxTotalMintableByWallet, maxTotalMintableByWalletPerToken, * and maxTokenSupplyForStage checks. * * @dev NOTE: Implementing contracts should always update these numbers * before transferring any tokens with _safeMint() to mitigate * consequences of malicious onERC1155Received() hooks. * * @param minter The minter address. * @param tokenId The token id to return stats for. */ function getMintStats( address minter, uint256 tokenId ) external view returns ( uint256 minterNumMinted, uint256 minterNumMintedForTokenId, uint256 totalMintedForTokenId, uint256 maxSupply ); /** * @notice This function is only allowed to be called by the configurer * contract as a way to batch mints and configuration in one tx. * * @param recipient The address to receive the mints. * @param tokenIds The tokenIds to mint. * @param amounts The amounts to mint. */ function multiConfigureMint( address recipient, uint256[] calldata tokenIds, uint256[] calldata amounts ) external; } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { ISeaDropTokenContractMetadata } from "./ISeaDropTokenContractMetadata.sol"; import { AllowListData, CreatorPayout } from "../lib/SeaDropStructs.sol"; /** * @dev A helper base interface for IERC721SeaDrop and IERC1155SeaDrop. * The token does not expose these methods as part of its external * interface to optimize contract size, but does implement them. */ interface ISeaDropToken is ISeaDropTokenContractMetadata { /** * @notice Update the SeaDrop allowed Seaport contracts privileged to mint. * Only the owner can use this function. * * @param allowedSeaport The allowed Seaport addresses. */ function updateAllowedSeaport(address[] calldata allowedSeaport) external; /** * @notice Update the SeaDrop allowed fee recipient. * Only the owner can use this function. * * @param feeRecipient The new fee recipient. * @param allowed Whether the fee recipient is allowed. */ function updateAllowedFeeRecipient( address feeRecipient, bool allowed ) external; /** * @notice Update the SeaDrop creator payout addresses. * The total basis points must add up to exactly 10_000. * Only the owner can use this function. * * @param creatorPayouts The new creator payouts. */ function updateCreatorPayouts( CreatorPayout[] calldata creatorPayouts ) external; /** * @notice Update the SeaDrop drop URI. * Only the owner can use this function. * * @param dropURI The new drop URI. */ function updateDropURI(string calldata dropURI) external; /** * @notice Update the SeaDrop allow list data. * Only the owner can use this function. * * @param allowListData The new allow list data. */ function updateAllowList(AllowListData calldata allowListData) external; /** * @notice Update the SeaDrop allowed payers. * Only the owner can use this function. * * @param payer The payer to update. * @param allowed Whether the payer is allowed. */ function updatePayer(address payer, bool allowed) external; /** * @notice Update the SeaDrop allowed signer. * Only the owner can use this function. * An allowed signer can also disallow themselves. * * @param signer The signer to update. * @param allowed Whether the signer is allowed. */ function updateSigner(address signer, bool allowed) external; /** * @notice Get the SeaDrop allowed Seaport contracts privileged to mint. */ function getAllowedSeaport() external view returns (address[] memory); /** * @notice Returns the SeaDrop creator payouts. */ function getCreatorPayouts() external view returns (CreatorPayout[] memory); /** * @notice Returns the SeaDrop allow list merkle root. */ function getAllowListMerkleRoot() external view returns (bytes32); /** * @notice Returns the SeaDrop allowed fee recipients. */ function getAllowedFeeRecipients() external view returns (address[] memory); /** * @notice Returns the SeaDrop allowed signers. */ function getSigners() external view returns (address[] memory); /** * @notice Returns if the signed digest has been used. * * @param digest The digest hash. */ function getDigestIsUsed(bytes32 digest) external view returns (bool); /** * @notice Returns the SeaDrop allowed payers. */ function getPayers() external view returns (address[] memory); /** * @notice Returns the configurer contract. */ function configurer() external view returns (address); } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { IERC1155ContractMetadata } from "../interfaces/IERC1155ContractMetadata.sol"; import { ERC1155ConduitPreapproved } from "../lib/ERC1155ConduitPreapproved.sol"; import { ICreatorToken, ILegacyCreatorToken } from "../interfaces/ICreatorToken.sol"; import { ITransferValidator1155 } from "../interfaces/ITransferValidator.sol"; import { TokenTransferValidator } from "../lib/TokenTransferValidator.sol"; import { ERC1155 } from "solady/src/tokens/ERC1155.sol"; import { ERC2981 } from "solady/src/tokens/ERC2981.sol"; import { Ownable } from "solady/src/auth/Ownable.sol"; import { Initializable } from "@openzeppelin-upgradeable/contracts/proxy/utils/Initializable.sol"; /** * @title ERC1155ContractMetadataCloneable * @author James Wenzel (emo.eth) * @author Ryan Ghods (ralxz.eth) * @author Stephan Min (stephanm.eth) * @author Michael Cohen (notmichael.eth) * @notice A cloneable token contract that extends ERC-1155 * with additional metadata and ownership capabilities. */ contract ERC1155ContractMetadataCloneable is ERC1155ConduitPreapproved, TokenTransferValidator, ERC2981, Ownable, IERC1155ContractMetadata, Initializable { /// @notice A struct containing the token supply info per token id. mapping(uint256 => TokenSupply) _tokenSupply; /// @notice The total number of tokens minted by address. mapping(address => uint256) _totalMintedByUser; /// @notice The total number of tokens minted per token id by address. mapping(address => mapping(uint256 => uint256)) _totalMintedByUserPerToken; /// @notice The name of the token. string internal _name; /// @notice The symbol of the token. string internal _symbol; /// @notice The base URI for token metadata. string internal _baseURI; /// @notice The contract URI for contract metadata. string internal _contractURI; /// @notice The provenance hash for guaranteeing metadata order /// for random reveals. bytes32 internal _provenanceHash; /// @notice The allowed contract that can configure SeaDrop parameters. address internal _CONFIGURER; /** * @dev Reverts if the sender is not the owner or the allowed * configurer contract. * * This is used as a function instead of a modifier * to save contract space when used multiple times. */ function _onlyOwnerOrConfigurer() internal view { if (msg.sender != _CONFIGURER && msg.sender != owner()) { revert Unauthorized(); } } /** * @notice Deploy the token contract. * * @param allowedConfigurer The address of the contract allowed to * configure parameters. Also contains SeaDrop * implementation code. * @param name_ The name of the token. * @param symbol_ The symbol of the token. */ function __ERC1155ContractMetadataCloneable_init( address allowedConfigurer, string memory name_, string memory symbol_ ) internal onlyInitializing { // Set the name of the token. _name = name_; // Set the symbol of the token. _symbol = symbol_; // Set the allowed configurer contract to interact with this contract. _CONFIGURER = allowedConfigurer; } /** * @notice Sets the base URI for the token metadata and emits an event. * * @param newBaseURI The new base URI to set. */ function setBaseURI(string calldata newBaseURI) external override { // Ensure the sender is only the owner or configurer contract. _onlyOwnerOrConfigurer(); // Set the new base URI. _baseURI = newBaseURI; // Emit an event with the update. emit BatchMetadataUpdate(0, type(uint256).max); } /** * @notice Sets the contract URI for contract metadata. * * @param newContractURI The new contract URI. */ function setContractURI(string calldata newContractURI) external override { // Ensure the sender is only the owner or configurer contract. _onlyOwnerOrConfigurer(); // Set the new contract URI. _contractURI = newContractURI; // Emit an event with the update. emit ContractURIUpdated(newContractURI); } /** * @notice Emit an event notifying metadata updates for * a range of token ids, according to EIP-4906. * * @param fromTokenId The start token id. * @param toTokenId The end token id. */ function emitBatchMetadataUpdate( uint256 fromTokenId, uint256 toTokenId ) external { // Ensure the sender is only the owner or configurer contract. _onlyOwnerOrConfigurer(); // Emit an event with the update. if (fromTokenId == toTokenId) { // If only one token is being updated, use the event // in the 1155 spec. emit URI(uri(fromTokenId), fromTokenId); } else { emit BatchMetadataUpdate(fromTokenId, toTokenId); } } /** * @notice Sets the max token supply and emits an event. * * @param tokenId The token id to set the max supply for. * @param newMaxSupply The new max supply to set. */ function setMaxSupply(uint256 tokenId, uint256 newMaxSupply) external { // Ensure the sender is only the owner or configurer contract. _onlyOwnerOrConfigurer(); // Ensure the max supply does not exceed the maximum value of uint64, // a limit due to the storage of bit-packed variables in TokenSupply, if (newMaxSupply > 2 ** 64 - 1) { revert CannotExceedMaxSupplyOfUint64(newMaxSupply); } // Set the new max supply. _tokenSupply[tokenId].maxSupply = uint64(newMaxSupply); // Emit an event with the update. emit MaxSupplyUpdated(tokenId, newMaxSupply); } /** * @notice Sets the provenance hash and emits an event. * * The provenance hash is used for random reveals, which * is a hash of the ordered metadata to show it has not been * modified after mint started. * * This function will revert if the provenance hash has already * been set, so be sure to carefully set it only once. * * @param newProvenanceHash The new provenance hash to set. */ function setProvenanceHash(bytes32 newProvenanceHash) external { // Ensure the sender is only the owner or configurer contract. _onlyOwnerOrConfigurer(); // Keep track of the old provenance hash for emitting with the event. bytes32 oldProvenanceHash = _provenanceHash; // Revert if the provenance hash has already been set. if (oldProvenanceHash != bytes32(0)) { revert ProvenanceHashCannotBeSetAfterAlreadyBeingSet(); } // Set the new provenance hash. _provenanceHash = newProvenanceHash; // Emit an event with the update. emit ProvenanceHashUpdated(oldProvenanceHash, newProvenanceHash); } /** * @notice Sets the default royalty information. * * Requirements: * * - `receiver` cannot be the zero address. * - `feeNumerator` cannot be greater than the fee denominator of 10_000 basis points. */ function setDefaultRoyalty(address receiver, uint96 feeNumerator) external { // Ensure the sender is only the owner or configurer contract. _onlyOwnerOrConfigurer(); // Set the default royalty. // ERC2981 implementation ensures feeNumerator <= feeDenominator // and receiver != address(0). _setDefaultRoyalty(receiver, feeNumerator); // Emit an event with the updated params. emit RoyaltyInfoUpdated(receiver, feeNumerator); } /** * @notice Returns the name of the token. */ function name() external view returns (string memory) { return _name; } /** * @notice Returns the symbol of the token. */ function symbol() external view returns (string memory) { return _symbol; } /** * @notice Returns the base URI for token metadata. */ function baseURI() external view override returns (string memory) { return _baseURI; } /** * @notice Returns the contract URI for contract metadata. */ function contractURI() external view override returns (string memory) { return _contractURI; } /** * @notice Returns the max token supply for a token id. */ function maxSupply(uint256 tokenId) external view returns (uint256) { return _tokenSupply[tokenId].maxSupply; } /** * @notice Returns the total supply for a token id. */ function totalSupply(uint256 tokenId) external view returns (uint256) { return _tokenSupply[tokenId].totalSupply; } /** * @notice Returns the total minted for a token id. */ function totalMinted(uint256 tokenId) external view returns (uint256) { return _tokenSupply[tokenId].totalMinted; } /** * @notice Returns the provenance hash. * The provenance hash is used for random reveals, which * is a hash of the ordered metadata to show it is unmodified * after mint has started. */ function provenanceHash() external view override returns (bytes32) { return _provenanceHash; } /** * @notice Returns the URI for token metadata. * * This implementation returns the same URI for *all* token types. * It relies on the token type ID substitution mechanism defined * in the EIP to replace {id} with the token id. * * @custom:param tokenId The token id to get the URI for. */ function uri( uint256 /* tokenId */ ) public view virtual override returns (string memory) { // Return the base URI. return _baseURI; } /** * @notice Returns the transfer validation function used. */ function getTransferValidationFunction() external pure returns (bytes4 functionSignature, bool isViewFunction) { functionSignature = ITransferValidator1155.validateTransfer.selector; isViewFunction = true; } /** * @notice Set the transfer validator. Only callable by the token owner. */ function setTransferValidator(address newValidator) external onlyOwner { // Set the new transfer validator. _setTransferValidator(newValidator); } /// @dev Override this function to return true if `_beforeTokenTransfer` is used. function _useBeforeTokenTransfer() internal view virtual override returns (bool) { return true; } /** * @dev Hook that is called before any token transfer. * This includes minting and burning. */ function _beforeTokenTransfer( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory /* data */ ) internal virtual override { if (from != address(0) && to != address(0)) { // Call the transfer validator if one is set. address transferValidator = _transferValidator; if (transferValidator != address(0)) { for (uint256 i = 0; i < ids.length; i++) { ITransferValidator1155(transferValidator).validateTransfer( msg.sender, from, to, ids[i], amounts[i] ); } } } } /** * @notice Returns whether the interface is supported. * * @param interfaceId The interface id to check against. */ function supportsInterface( bytes4 interfaceId ) public view virtual override(ERC1155, ERC2981) returns (bool) { return interfaceId == type(IERC1155ContractMetadata).interfaceId || interfaceId == type(ICreatorToken).interfaceId || interfaceId == type(ILegacyCreatorToken).interfaceId || interfaceId == 0x49064906 || // ERC-4906 (MetadataUpdate) ERC2981.supportsInterface(interfaceId) || // ERC1155 returns supportsInterface true for // ERC165, ERC1155, ERC1155MetadataURI ERC1155.supportsInterface(interfaceId); } /** * @dev Adds to the internal counters for a mint. * * @param to The address to mint to. * @param id The token id to mint. * @param amount The quantity to mint. * @param data The data to pass if receiver is a contract. */ function _mint( address to, uint256 id, uint256 amount, bytes memory data ) internal virtual override { // Increment mint counts. _incrementMintCounts(to, id, amount); ERC1155._mint(to, id, amount, data); } /** * @dev Adds to the internal counters for a batch mint. * * @param to The address to mint to. * @param ids The token ids to mint. * @param amounts The quantities to mint. * @param data The data to pass if receiver is a contract. */ function _batchMint( address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual override { // Put ids length on the stack to save MLOADs. uint256 idsLength = ids.length; for (uint256 i = 0; i < idsLength; ) { // Increment mint counts. _incrementMintCounts(to, ids[i], amounts[i]); unchecked { ++i; } } ERC1155._batchMint(to, ids, amounts, data); } /** * @dev Subtracts from the internal counters for a burn. * * @param by The address calling the burn. * @param from The address to burn from. * @param id The token id to burn. * @param amount The amount to burn. */ function _burn( address by, address from, uint256 id, uint256 amount ) internal virtual override { // Reduce the supply. _reduceSupplyOnBurn(id, amount); ERC1155._burn(by, from, id, amount); } /** * @dev Subtracts from the internal counters for a batch burn. * * @param by The address calling the burn. * @param from The address to burn from. * @param ids The token ids to burn. * @param amounts The amounts to burn. */ function _batchBurn( address by, address from, uint256[] memory ids, uint256[] memory amounts ) internal virtual override { // Put ids length on the stack to save MLOADs. uint256 idsLength = ids.length; for (uint256 i = 0; i < idsLength; ) { // Reduce the supply. _reduceSupplyOnBurn(ids[i], amounts[i]); unchecked { ++i; } } ERC1155._batchBurn(by, from, ids, amounts); } function _reduceSupplyOnBurn(uint256 id, uint256 amount) internal { // Get the current token supply. TokenSupply storage tokenSupply = _tokenSupply[id]; // Reduce the totalSupply. unchecked { tokenSupply.totalSupply -= uint64(amount); } } /** * @dev Internal function to increment mint counts. * * Note that this function does not check if the mint exceeds * maxSupply, which should be validated before this function is called. * * @param to The address to mint to. * @param id The token id to mint. * @param amount The quantity to mint. */ function _incrementMintCounts( address to, uint256 id, uint256 amount ) internal { // Get the current token supply. TokenSupply storage tokenSupply = _tokenSupply[id]; if (tokenSupply.totalMinted + amount > tokenSupply.maxSupply) { revert MintExceedsMaxSupply( tokenSupply.totalMinted + amount, tokenSupply.maxSupply ); } // Increment supply and number minted. // Can be unchecked because maxSupply cannot be set to exceed uint64. unchecked { tokenSupply.totalSupply += uint64(amount); tokenSupply.totalMinted += uint64(amount); // Increment total minted by user. _totalMintedByUser[to] += amount; // Increment total minted by user per token. _totalMintedByUserPerToken[to][id] += amount; } } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { PublicDrop } from "./ERC1155SeaDropStructs.sol"; import { CreatorPayout } from "./SeaDropStructs.sol"; library ERC1155SeaDropContractOffererStorage { struct Layout { /// @notice The allowed Seaport addresses that can mint. mapping(address => bool) _allowedSeaport; /// @notice The enumerated allowed Seaport addresses. address[] _enumeratedAllowedSeaport; /// @notice The public drop data. mapping(uint256 => PublicDrop) _publicDrops; /// @notice The enumerated public drop indexes. uint256[] _enumeratedPublicDropIndexes; /// @notice The creator payout addresses and basis points. CreatorPayout[] _creatorPayouts; /// @notice The allow list merkle root. bytes32 _allowListMerkleRoot; /// @notice The allowed fee recipients. mapping(address => bool) _allowedFeeRecipients; /// @notice The enumerated allowed fee recipients. address[] _enumeratedFeeRecipients; /// @notice The allowed server-side signers. mapping(address => bool) _allowedSigners; /// @notice The enumerated allowed signers. address[] _enumeratedSigners; /// @notice The used signature digests. mapping(bytes32 => bool) _usedDigests; /// @notice The allowed payers. mapping(address => bool) _allowedPayers; /// @notice The enumerated allowed payers. address[] _enumeratedPayers; } bytes32 internal constant STORAGE_SLOT = bytes32( uint256( keccak256("contracts.storage.ERC1155SeaDropContractOfferer") ) - 1 ); function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { PublicDrop } from "./ERC1155SeaDropStructs.sol"; import { SeaDropErrorsAndEvents } from "./SeaDropErrorsAndEvents.sol"; interface ERC1155SeaDropErrorsAndEvents is SeaDropErrorsAndEvents { /** * @dev Revert with an error if an empty PublicDrop is provided * for an already-empty public drop. */ error PublicDropStageNotPresent(); /** * @dev Revert with an error if the mint quantity exceeds the * max minted per wallet for a certain token id. */ error MintQuantityExceedsMaxMintedPerWalletForTokenId( uint256 tokenId, uint256 total, uint256 allowed ); /** * @dev Revert with an error if the target token id to mint is not within * the drop stage range. */ error TokenIdNotWithinDropStageRange( uint256 tokenId, uint256 startTokenId, uint256 endTokenId ); /** * @notice Revert with an error if the number of maxSupplyAmounts doesn't * match the number of maxSupplyTokenIds. */ error MaxSupplyMismatch(); /** * @notice Revert with an error if the number of mint tokenIds doesn't * match the number of mint amounts. */ error MintAmountsMismatch(); /** * @notice Revert with an error if the mint order offer contains * a duplicate tokenId. */ error OfferContainsDuplicateTokenId(uint256 tokenId); /** * @dev Revert if the fromTokenId is greater than the toTokenId. */ error InvalidFromAndToTokenId(uint256 fromTokenId, uint256 toTokenId); /** * @notice Revert with an error if the number of publicDropIndexes doesn't * match the number of publicDrops. */ error PublicDropsMismatch(); /** * @dev An event with updated public drop data. */ event PublicDropUpdated(PublicDrop publicDrop, uint256 index); } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { AllowListData, CreatorPayout } from "./SeaDropStructs.sol"; /** * @notice A struct defining public drop data. * Designed to fit efficiently in two storage slots. * * @param startPrice The start price per token. (Up to 1.2m * of native token, e.g. ETH, MATIC) * @param endPrice The end price per token. If this differs * from startPrice, the current price will * be calculated based on the current time. * @param startTime The start time, ensure this is not zero. * @param endTime The end time, ensure this is not zero. * @param restrictFeeRecipients If false, allow any fee recipient; * if true, check fee recipient is allowed. * @param paymentToken The payment token address. Null for * native token. * @param fromTokenId The start token id for the stage. * @param toTokenId The end token id for the stage. * @param maxTotalMintableByWallet Maximum total number of mints a user is * allowed. (The limit for this field is * 2^16 - 1) * @param maxTotalMintableByWalletPerToken Maximum total number of mints a user * is allowed for the token id. (The limit for * this field is 2^16 - 1) * @param feeBps Fee out of 10_000 basis points to be * collected. */ struct PublicDrop { // slot 1 uint80 startPrice; // 80/512 bits uint80 endPrice; // 160/512 bits uint40 startTime; // 200/512 bits uint40 endTime; // 240/512 bits bool restrictFeeRecipients; // 248/512 bits // uint8 unused; // slot 2 address paymentToken; // 408/512 bits uint24 fromTokenId; // 432/512 bits uint24 toTokenId; // 456/512 bits uint16 maxTotalMintableByWallet; // 472/512 bits uint16 maxTotalMintableByWalletPerToken; // 488/512 bits uint16 feeBps; // 504/512 bits } /** * @notice A struct defining mint params for an allow list. * An allow list leaf will be composed of `msg.sender` and * the following params. * * Note: Since feeBps is encoded in the leaf, backend should ensure * that feeBps is acceptable before generating a proof. * * @param startPrice The start price per token. (Up to 1.2m * of native token, e.g. ETH, MATIC) * @param endPrice The end price per token. If this differs * from startPrice, the current price will * be calculated based on the current time. * @param startTime The start time, ensure this is not zero. * @param endTime The end time, ensure this is not zero. * @param paymentToken The payment token for the mint. Null for * native token. * @param fromTokenId The start token id for the stage. * @param toTokenId The end token id for the stage. * @param maxTotalMintableByWallet Maximum total number of mints a user is * allowed. * @param maxTotalMintableByWalletPerToken Maximum total number of mints a user * is allowed for the token id. * @param maxTokenSupplyForStage The limit of token supply this stage can * mint within. * @param dropStageIndex The drop stage index to emit with the event * for analytical purposes. This should be * non-zero since the public mint emits with * index zero. * @param feeBps Fee out of 10_000 basis points to be * collected. * @param restrictFeeRecipients If false, allow any fee recipient; * if true, check fee recipient is allowed. */ struct MintParams { uint256 startPrice; uint256 endPrice; uint256 startTime; uint256 endTime; address paymentToken; uint256 fromTokenId; uint256 toTokenId; uint256 maxTotalMintableByWallet; uint256 maxTotalMintableByWalletPerToken; uint256 maxTokenSupplyForStage; uint256 dropStageIndex; // non-zero uint256 feeBps; bool restrictFeeRecipients; } /** * @dev Struct containing internal SeaDrop implementation logic * mint details to avoid stack too deep. * * @param feeRecipient The fee recipient. * @param payer The payer of the mint. * @param minter The mint recipient. * @param tokenIds The tokenIds to mint. * @param quantities The number of tokens to mint per tokenId. * @param withEffects Whether to apply state changes of the mint. */ struct MintDetails { address feeRecipient; address payer; address minter; uint256[] tokenIds; uint256[] quantities; bool withEffects; } /** * @notice A struct to configure multiple contract options in one transaction. */ struct MultiConfigureStruct { uint256[] maxSupplyTokenIds; uint256[] maxSupplyAmounts; string baseURI; string contractURI; PublicDrop[] publicDrops; uint256[] publicDropsIndexes; string dropURI; AllowListData allowListData; CreatorPayout[] creatorPayouts; bytes32 provenanceHash; address[] allowedFeeRecipients; address[] disallowedFeeRecipients; address[] allowedPayers; address[] disallowedPayers; // Server-signed address[] allowedSigners; address[] disallowedSigners; // ERC-2981 address royaltyReceiver; uint96 royaltyBps; // Mint address mintRecipient; uint256[] mintTokenIds; uint256[] mintAmounts; } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; /** * @notice A struct defining a creator payout address and basis points. * * @param payoutAddress The payout address. * @param basisPoints The basis points to pay out to the creator. * The total creator payouts must equal 10_000 bps. */ struct CreatorPayout { address payoutAddress; uint16 basisPoints; } /** * @notice A struct defining allow list data (for minting an allow list). * * @param merkleRoot The merkle root for the allow list. * @param publicKeyURIs If the allowListURI is encrypted, a list of URIs * pointing to the public keys. Empty if unencrypted. * @param allowListURI The URI for the allow list. */ struct AllowListData { bytes32 merkleRoot; string[] publicKeyURIs; string allowListURI; } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { ERC1155 } from "solady/src/tokens/ERC1155.sol"; /** * @title ERC1155ConduitPreapproved * @notice Solady's ERC1155 with the OpenSea conduit preapproved. */ abstract contract ERC1155ConduitPreapproved is ERC1155 { /// @dev The canonical OpenSea conduit. address internal constant _CONDUIT = 0x1E0049783F008A0085193E00003D00cd54003c71; function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) public virtual override { _safeTransfer(_by(), from, to, id, amount, data); } function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) public virtual override { _safeBatchTransfer(_by(), from, to, ids, amounts, data); } function isApprovedForAll( address owner, address operator ) public view virtual override returns (bool) { if (operator == _CONDUIT) return true; return ERC1155.isApprovedForAll(owner, operator); } function _by() internal view virtual returns (address result) { assembly { // `msg.sender == _CONDUIT ? address(0) : msg.sender`. result := mul(iszero(eq(caller(), _CONDUIT)), caller()) } } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC1155 implementation. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC1155.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC1155/ERC1155.sol) /// /// @dev Note: /// The ERC1155 standard allows for self-approvals. /// For performance, this implementation WILL NOT revert for such actions. /// Please add any checks with overrides if desired. abstract contract ERC1155 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The lengths of the input arrays are not the same. error ArrayLengthsMismatch(); /// @dev Cannot mint or transfer to the zero address. error TransferToZeroAddress(); /// @dev The recipient's balance has overflowed. error AccountBalanceOverflow(); /// @dev Insufficient balance. error InsufficientBalance(); /// @dev Only the token owner or an approved account can manage the tokens. error NotOwnerNorApproved(); /// @dev Cannot safely transfer to a contract that does not implement /// the ERC1155Receiver interface. error TransferToNonERC1155ReceiverImplementer(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when `amount` of token `id` is transferred /// from `from` to `to` by `operator`. event TransferSingle( address indexed operator, address indexed from, address indexed to, uint256 id, uint256 amount ); /// @dev Emitted when `amounts` of token `ids` are transferred /// from `from` to `to` by `operator`. event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] amounts ); /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens. event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved); /// @dev Emitted when the Uniform Resource Identifier (URI) for token `id` /// is updated to `value`. This event is not used in the base contract. /// You may need to emit this event depending on your URI logic. /// /// See: https://eips.ethereum.org/EIPS/eip-1155#metadata event URI(string value, uint256 indexed id); /// @dev `keccak256(bytes("TransferSingle(address,address,address,uint256,uint256)"))`. uint256 private constant _TRANSFER_SINGLE_EVENT_SIGNATURE = 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62; /// @dev `keccak256(bytes("TransferBatch(address,address,address,uint256[],uint256[])"))`. uint256 private constant _TRANSFER_BATCH_EVENT_SIGNATURE = 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb; /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`. uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE = 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `ownerSlotSeed` of a given owner is given by. /// ``` /// let ownerSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner)) /// ``` /// /// The balance slot of `owner` is given by. /// ``` /// mstore(0x20, ownerSlotSeed) /// mstore(0x00, id) /// let balanceSlot := keccak256(0x00, 0x40) /// ``` /// /// The operator approval slot of `owner` is given by. /// ``` /// mstore(0x20, ownerSlotSeed) /// mstore(0x00, operator) /// let operatorApprovalSlot := keccak256(0x0c, 0x34) /// ``` uint256 private constant _ERC1155_MASTER_SLOT_SEED = 0x9a31110384e0b0c9; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1155 METADATA */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the URI for token `id`. /// /// You can either return the same templated URI for all token IDs, /// (e.g. "https://example.com/api/{id}.json"), /// or return a unique URI for each `id`. /// /// See: https://eips.ethereum.org/EIPS/eip-1155#metadata function uri(uint256 id) public view virtual returns (string memory); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1155 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the amount of `id` owned by `owner`. function balanceOf(address owner, uint256 id) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, owner) mstore(0x00, id) result := sload(keccak256(0x00, 0x40)) } } /// @dev Returns whether `operator` is approved to manage the tokens of `owner`. function isApprovedForAll(address owner, address operator) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, owner) mstore(0x00, operator) result := sload(keccak256(0x0c, 0x34)) } } /// @dev Sets whether `operator` is approved to manage the tokens of the caller. /// /// Emits a {ApprovalForAll} event. function setApprovalForAll(address operator, bool isApproved) public virtual { /// @solidity memory-safe-assembly assembly { // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`msg.sender`, `operator`). mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, caller()) mstore(0x00, operator) sstore(keccak256(0x0c, 0x34), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) // forgefmt: disable-next-line log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator))) } } /// @dev Transfers `amount` of `id` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `from` must have at least `amount` of `id`. /// - If the caller is not `from`, /// it must be approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155Reveived}, which is called upon a batch transfer. /// /// Emits a {Transfer} event. function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) public virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from)) let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to)) mstore(0x20, fromSlotSeed) // Clear the upper 96 bits. from := shr(96, fromSlotSeed) to := shr(96, toSlotSeed) // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // If the caller is not `from`, do the authorization check. if iszero(eq(caller(), from)) { mstore(0x00, caller()) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Subtract and store the updated balance of `from`. { mstore(0x00, id) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, toSlotSeed) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } // Emit a {TransferSingle} event. mstore(0x20, amount) log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), from, to) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { // Do the {onERC1155Received} check if `to` is a smart contract. if extcodesize(to) { // Prepare the calldata. let m := mload(0x40) // `onERC1155Received(address,address,uint256,uint256,bytes)`. mstore(m, 0xf23a6e61) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), from) mstore(add(m, 0x60), id) mstore(add(m, 0x80), amount) mstore(add(m, 0xa0), 0xa0) calldatacopy(add(m, 0xc0), sub(data.offset, 0x20), add(0x20, data.length)) // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, data.length), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } mstore(m, 0) } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xf23a6e61))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } } /// @dev Transfers `amounts` of `ids` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `from` must have at least `amount` of `id`. /// - `ids` and `amounts` must have the same length. /// - If the caller is not `from`, /// it must be approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer. /// /// Emits a {TransferBatch} event. function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) public virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { if iszero(eq(ids.length, amounts.length)) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from)) let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to)) mstore(0x20, fromSlotSeed) // Clear the upper 96 bits. from := shr(96, fromSlotSeed) to := shr(96, toSlotSeed) // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // If the caller is not `from`, do the authorization check. if iszero(eq(caller(), from)) { mstore(0x00, caller()) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Loop through all the `ids` and update the balances. { let end := shl(5, ids.length) for { let i := 0 } iszero(eq(i, end)) { i := add(i, 0x20) } { let amount := calldataload(add(amounts.offset, i)) // Subtract and store the updated balance of `from`. { mstore(0x20, fromSlotSeed) mstore(0x00, calldataload(add(ids.offset, i))) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, toSlotSeed) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, ids.length)) let o := add(m, 0x40) calldatacopy(o, sub(ids.offset, 0x20), n) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, n)) o := add(o, n) n := add(0x20, shl(5, amounts.length)) calldatacopy(o, sub(amounts.offset, 0x20), n) n := sub(add(o, n), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), from, to) } } if (_useAfterTokenTransfer()) { _afterTokenTransferCalldata(from, to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { // Do the {onERC1155BatchReceived} check if `to` is a smart contract. if extcodesize(to) { let m := mload(0x40) // Prepare the calldata. // `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`. mstore(m, 0xbc197c81) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), from) // Copy the `ids`. mstore(add(m, 0x60), 0xa0) let n := add(0x20, shl(5, ids.length)) let o := add(m, 0xc0) calldatacopy(o, sub(ids.offset, 0x20), n) // Copy the `amounts`. let s := add(0xa0, n) mstore(add(m, 0x80), s) o := add(o, n) n := add(0x20, shl(5, amounts.length)) calldatacopy(o, sub(amounts.offset, 0x20), n) // Copy the `data`. mstore(add(m, 0xa0), add(s, n)) o := add(o, n) n := add(0x20, data.length) calldatacopy(o, sub(data.offset, 0x20), n) n := sub(add(o, n), add(m, 0x1c)) // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), n, m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } mstore(m, 0) } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xbc197c81))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } } /// @dev Returns the amounts of `ids` for `owners. /// /// Requirements: /// - `owners` and `ids` must have the same length. function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) public view virtual returns (uint256[] memory balances) { /// @solidity memory-safe-assembly assembly { if iszero(eq(ids.length, owners.length)) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } balances := mload(0x40) mstore(balances, ids.length) let o := add(balances, 0x20) let end := shl(5, ids.length) mstore(0x40, add(end, o)) // Loop through all the `ids` and load the balances. for { let i := 0 } iszero(eq(i, end)) { i := add(i, 0x20) } { let owner := calldataload(add(owners.offset, i)) mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner))) mstore(0x00, calldataload(add(ids.offset, i))) mstore(add(o, i), sload(keccak256(0x00, 0x40))) } } } /// @dev Returns true if this contract implements the interface defined by `interfaceId`. /// See: https://eips.ethereum.org/EIPS/eip-165 /// This function call must use less than 30000 gas. function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { let s := shr(224, interfaceId) // ERC165: 0x01ffc9a7, ERC1155: 0xd9b67a26, ERC1155MetadataURI: 0x0e89341c. result := or(or(eq(s, 0x01ffc9a7), eq(s, 0xd9b67a26)), eq(s, 0x0e89341c)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL MINT FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Mints `amount` of `id` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155Reveived}, which is called upon a batch transfer. /// /// Emits a {Transfer} event. function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(address(0), to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Increase and store the updated balance of `to`. { mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, to) mstore(0x00, id) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } // Emit a {TransferSingle} event. mstore(0x00, id) mstore(0x20, amount) log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), 0, shr(96, to_)) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(address(0), to, _single(id), _single(amount), data); } if (_hasCode(to)) _checkOnERC1155Received(address(0), to, id, amount, data); } /// @dev Mints `amounts` of `ids` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `ids` and `amounts` must have the same length. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer. /// /// Emits a {TransferBatch} event. function _batchMint( address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(address(0), to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { if iszero(eq(mload(ids), mload(amounts))) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Loop through all the `ids` and update the balances. { mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_)) let end := shl(5, mload(ids)) for { let i := 0 } iszero(eq(i, end)) {} { i := add(i, 0x20) let amount := mload(add(amounts, i)) // Increase and store the updated balance of `to`. { mstore(0x00, mload(add(ids, i))) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0x40) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, returndatasize())) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) n := sub(add(o, returndatasize()), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), 0, shr(96, to_)) } } if (_useAfterTokenTransfer()) { _afterTokenTransfer(address(0), to, ids, amounts, data); } if (_hasCode(to)) _checkOnERC1155BatchReceived(address(0), to, ids, amounts, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL BURN FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_burn(address(0), from, id, amount)`. function _burn(address from, uint256 id, uint256 amount) internal virtual { _burn(address(0), from, id, amount); } /// @dev Destroys `amount` of `id` from `from`. /// /// Requirements: /// - `from` must have at least `amount` of `id`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// /// Emits a {Transfer} event. function _burn(address by, address from, uint256 id, uint256 amount) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, address(0), _single(id), _single(amount), ""); } /// @solidity memory-safe-assembly assembly { let from_ := shl(96, from) mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_)) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. if iszero(or(iszero(shl(96, by)), eq(shl(96, by), from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Decrease and store the updated balance of `from`. { mstore(0x00, id) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Emit a {TransferSingle} event. mstore(0x00, id) mstore(0x20, amount) log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), 0) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, address(0), _single(id), _single(amount), ""); } } /// @dev Equivalent to `_batchBurn(address(0), from, ids, amounts)`. function _batchBurn(address from, uint256[] memory ids, uint256[] memory amounts) internal virtual { _batchBurn(address(0), from, ids, amounts); } /// @dev Destroys `amounts` of `ids` from `from`. /// /// Requirements: /// - `ids` and `amounts` must have the same length. /// - `from` must have at least `amounts` of `ids`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// /// Emits a {TransferBatch} event. function _batchBurn(address by, address from, uint256[] memory ids, uint256[] memory amounts) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, address(0), ids, amounts, ""); } /// @solidity memory-safe-assembly assembly { if iszero(eq(mload(ids), mload(amounts))) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let from_ := shl(96, from) mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_)) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. let by_ := shl(96, by) if iszero(or(iszero(by_), eq(by_, from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Loop through all the `ids` and update the balances. { let end := shl(5, mload(ids)) for { let i := 0 } iszero(eq(i, end)) {} { i := add(i, 0x20) let amount := mload(add(amounts, i)) // Decrease and store the updated balance of `to`. { mstore(0x00, mload(add(ids, i))) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0x40) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, returndatasize())) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) n := sub(add(o, returndatasize()), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), 0) } } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, address(0), ids, amounts, ""); } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL APPROVAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Approve or remove the `operator` as an operator for `by`, /// without authorization checks. /// /// Emits a {ApprovalForAll} event. function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual { /// @solidity memory-safe-assembly assembly { // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`by`, `operator`). mstore(0x20, _ERC1155_MASTER_SLOT_SEED) mstore(0x14, by) mstore(0x00, operator) sstore(keccak256(0x0c, 0x34), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) let m := shr(96, not(0)) log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, and(m, by), and(m, operator)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL TRANSFER FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_safeTransfer(address(0), from, to, id, amount, data)`. function _safeTransfer(address from, address to, uint256 id, uint256 amount, bytes memory data) internal virtual { _safeTransfer(address(0), from, to, id, amount, data); } /// @dev Transfers `amount` of `id` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `from` must have at least `amount` of `id`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155Reveived}, which is called upon a batch transfer. /// /// Emits a {Transfer} event. function _safeTransfer( address by, address from, address to, uint256 id, uint256 amount, bytes memory data ) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, _single(id), _single(amount), data); } /// @solidity memory-safe-assembly assembly { let from_ := shl(96, from) let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_)) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. let by_ := shl(96, by) if iszero(or(iszero(by_), eq(by_, from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Subtract and store the updated balance of `from`. { mstore(0x00, id) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_)) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } // Emit a {TransferSingle} event. mstore(0x20, amount) // forgefmt: disable-next-line log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_)) } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, _single(id), _single(amount), data); } if (_hasCode(to)) _checkOnERC1155Received(from, to, id, amount, data); } /// @dev Equivalent to `_safeBatchTransfer(address(0), from, to, ids, amounts, data)`. function _safeBatchTransfer( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { _safeBatchTransfer(address(0), from, to, ids, amounts, data); } /// @dev Transfers `amounts` of `ids` from `from` to `to`. /// /// Requirements: /// - `to` cannot be the zero address. /// - `ids` and `amounts` must have the same length. /// - `from` must have at least `amounts` of `ids`. /// - If `by` is not the zero address, it must be either `from`, /// or approved to manage the tokens of `from`. /// - If `to` refers to a smart contract, it must implement /// {ERC1155-onERC1155BatchReveived}, which is called upon a batch transfer. /// /// Emits a {TransferBatch} event. function _safeBatchTransfer( address by, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { if (_useBeforeTokenTransfer()) { _beforeTokenTransfer(from, to, ids, amounts, data); } /// @solidity memory-safe-assembly assembly { if iszero(eq(mload(ids), mload(amounts))) { mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`. revert(0x1c, 0x04) } let from_ := shl(96, from) let to_ := shl(96, to) // Revert if `to` is the zero address. if iszero(to_) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, from_) let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, to_) mstore(0x20, fromSlotSeed) // If `by` is not the zero address, and not equal to `from`, // check if it is approved to manage all the tokens of `from`. let by_ := shl(96, by) if iszero(or(iszero(by_), eq(by_, from_))) { mstore(0x00, by) if iszero(sload(keccak256(0x0c, 0x34))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Loop through all the `ids` and update the balances. { let end := shl(5, mload(ids)) for { let i := 0 } iszero(eq(i, end)) {} { i := add(i, 0x20) let amount := mload(add(amounts, i)) // Subtract and store the updated balance of `from`. { mstore(0x20, fromSlotSeed) mstore(0x00, mload(add(ids, i))) let fromBalanceSlot := keccak256(0x00, 0x40) let fromBalance := sload(fromBalanceSlot) if gt(amount, fromBalance) { mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. revert(0x1c, 0x04) } sstore(fromBalanceSlot, sub(fromBalance, amount)) } // Increase and store the updated balance of `to`. { mstore(0x20, toSlotSeed) let toBalanceSlot := keccak256(0x00, 0x40) let toBalanceBefore := sload(toBalanceSlot) let toBalanceAfter := add(toBalanceBefore, amount) if lt(toBalanceAfter, toBalanceBefore) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceAfter) } } } // Emit a {TransferBatch} event. { let m := mload(0x40) // Copy the `ids`. mstore(m, 0x40) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0x40) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. mstore(add(m, 0x20), add(0x40, returndatasize())) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) n := sub(add(o, returndatasize()), m) // Do the emit. log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_)) } } if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, ids, amounts, data); } if (_hasCode(to)) _checkOnERC1155BatchReceived(from, to, ids, amounts, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HOOKS FOR OVERRIDING */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override this function to return true if `_beforeTokenTransfer` is used. /// The is to help the compiler avoid producing dead bytecode. function _useBeforeTokenTransfer() internal view virtual returns (bool) { return false; } /// @dev Hook that is called before any token transfer. /// This includes minting and burning, as well as batched variants. /// /// The same hook is called on both single and batched variants. /// For single transfers, the length of the `id` and `amount` arrays are 1. function _beforeTokenTransfer( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual {} /// @dev Override this function to return true if `_afterTokenTransfer` is used. /// The is to help the compiler avoid producing dead bytecode. function _useAfterTokenTransfer() internal view virtual returns (bool) { return false; } /// @dev Hook that is called after any token transfer. /// This includes minting and burning, as well as batched variants. /// /// The same hook is called on both single and batched variants. /// For single transfers, the length of the `id` and `amount` arrays are 1. function _afterTokenTransfer( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual {} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Helper for calling the `_afterTokenTransfer` hook. /// The is to help the compiler avoid producing dead bytecode. function _afterTokenTransferCalldata( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) private { if (_useAfterTokenTransfer()) { _afterTokenTransfer(from, to, ids, amounts, data); } } /// @dev Returns if `a` has bytecode of non-zero length. function _hasCode(address a) private view returns (bool result) { /// @solidity memory-safe-assembly assembly { result := extcodesize(a) // Can handle dirty upper bits. } } /// @dev Perform a call to invoke {IERC1155Receiver-onERC1155Received} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC1155Received( address from, address to, uint256 id, uint256 amount, bytes memory data ) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) // `onERC1155Received(address,address,uint256,uint256,bytes)`. mstore(m, 0xf23a6e61) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), shr(96, shl(96, from))) mstore(add(m, 0x60), id) mstore(add(m, 0x80), amount) mstore(add(m, 0xa0), 0xa0) let n := mload(data) mstore(add(m, 0xc0), n) if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xe0), n)) } // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, n), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } mstore(m, 0) } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xf23a6e61))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } /// @dev Perform a call to invoke {IERC1155Receiver-onERC1155BatchReceived} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC1155BatchReceived( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) // `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`. mstore(m, 0xbc197c81) mstore(add(m, 0x20), caller()) mstore(add(m, 0x40), shr(96, shl(96, from))) // Copy the `ids`. mstore(add(m, 0x60), 0xa0) let n := add(0x20, shl(5, mload(ids))) let o := add(m, 0xc0) pop(staticcall(gas(), 4, ids, n, o, n)) // Copy the `amounts`. let s := add(0xa0, returndatasize()) mstore(add(m, 0x80), s) o := add(o, returndatasize()) n := add(0x20, shl(5, mload(amounts))) pop(staticcall(gas(), 4, amounts, n, o, n)) // Copy the `data`. mstore(add(m, 0xa0), add(s, returndatasize())) o := add(o, returndatasize()) n := add(0x20, mload(data)) pop(staticcall(gas(), 4, data, n, o, n)) n := sub(add(o, returndatasize()), add(m, 0x1c)) // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), n, m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } mstore(m, 0) } // Load the returndata and compare it with the function selector. if iszero(eq(mload(m), shl(224, 0xbc197c81))) { mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`. revert(0x1c, 0x04) } } } /// @dev Returns `x` in an array with a single element. function _single(uint256 x) private pure returns (uint256[] memory result) { assembly { result := mload(0x40) mstore(0x40, add(result, 0x40)) mstore(result, 1) mstore(add(result, 0x20), x) } } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import { BasicOrderType, ItemType, OrderType, Side } from "./ConsiderationEnums.sol"; import { CalldataPointer, MemoryPointer } from "../helpers/PointerLibraries.sol"; /** * @dev An order contains eleven components: an offerer, a zone (or account that * can cancel the order or restrict who can fulfill the order depending on * the type), the order type (specifying partial fill support as well as * restricted order status), the start and end time, a hash that will be * provided to the zone when validating restricted orders, a salt, a key * corresponding to a given conduit, a counter, and an arbitrary number of * offer items that can be spent along with consideration items that must * be received by their respective recipient. */ struct OrderComponents { address offerer; address zone; OfferItem[] offer; ConsiderationItem[] consideration; OrderType orderType; uint256 startTime; uint256 endTime; bytes32 zoneHash; uint256 salt; bytes32 conduitKey; uint256 counter; } /** * @dev An offer item has five components: an item type (ETH or other native * tokens, ERC20, ERC721, and ERC1155, as well as criteria-based ERC721 and * ERC1155), a token address, a dual-purpose "identifierOrCriteria" * component that will either represent a tokenId or a merkle root * depending on the item type, and a start and end amount that support * increasing or decreasing amounts over the duration of the respective * order. */ struct OfferItem { ItemType itemType; address token; uint256 identifierOrCriteria; uint256 startAmount; uint256 endAmount; } /** * @dev A consideration item has the same five components as an offer item and * an additional sixth component designating the required recipient of the * item. */ struct ConsiderationItem { ItemType itemType; address token; uint256 identifierOrCriteria; uint256 startAmount; uint256 endAmount; address payable recipient; } /** * @dev A spent item is translated from a utilized offer item and has four * components: an item type (ETH or other native tokens, ERC20, ERC721, and * ERC1155), a token address, a tokenId, and an amount. */ struct SpentItem { ItemType itemType; address token; uint256 identifier; uint256 amount; } /** * @dev A received item is translated from a utilized consideration item and has * the same four components as a spent item, as well as an additional fifth * component designating the required recipient of the item. */ struct ReceivedItem { ItemType itemType; address token; uint256 identifier; uint256 amount; address payable recipient; } /** * @dev For basic orders involving ETH / native / ERC20 <=> ERC721 / ERC1155 * matching, a group of six functions may be called that only requires a * subset of the usual order arguments. Note the use of a "basicOrderType" * enum; this represents both the usual order type as well as the "route" * of the basic order (a simple derivation function for the basic order * type is `basicOrderType = orderType + (4 * basicOrderRoute)`.) */ struct BasicOrderParameters { // calldata offset address considerationToken; // 0x24 uint256 considerationIdentifier; // 0x44 uint256 considerationAmount; // 0x64 address payable offerer; // 0x84 address zone; // 0xa4 address offerToken; // 0xc4 uint256 offerIdentifier; // 0xe4 uint256 offerAmount; // 0x104 BasicOrderType basicOrderType; // 0x124 uint256 startTime; // 0x144 uint256 endTime; // 0x164 bytes32 zoneHash; // 0x184 uint256 salt; // 0x1a4 bytes32 offererConduitKey; // 0x1c4 bytes32 fulfillerConduitKey; // 0x1e4 uint256 totalOriginalAdditionalRecipients; // 0x204 AdditionalRecipient[] additionalRecipients; // 0x224 bytes signature; // 0x244 // Total length, excluding dynamic array data: 0x264 (580) } /** * @dev Basic orders can supply any number of additional recipients, with the * implied assumption that they are supplied from the offered ETH (or other * native token) or ERC20 token for the order. */ struct AdditionalRecipient { uint256 amount; address payable recipient; } /** * @dev The full set of order components, with the exception of the counter, * must be supplied when fulfilling more sophisticated orders or groups of * orders. The total number of original consideration items must also be * supplied, as the caller may specify additional consideration items. */ struct OrderParameters { address offerer; // 0x00 address zone; // 0x20 OfferItem[] offer; // 0x40 ConsiderationItem[] consideration; // 0x60 OrderType orderType; // 0x80 uint256 startTime; // 0xa0 uint256 endTime; // 0xc0 bytes32 zoneHash; // 0xe0 uint256 salt; // 0x100 bytes32 conduitKey; // 0x120 uint256 totalOriginalConsiderationItems; // 0x140 // offer.length // 0x160 } /** * @dev Orders require a signature in addition to the other order parameters. */ struct Order { OrderParameters parameters; bytes signature; } /** * @dev Advanced orders include a numerator (i.e. a fraction to attempt to fill) * and a denominator (the total size of the order) in addition to the * signature and other order parameters. It also supports an optional field * for supplying extra data; this data will be provided to the zone if the * order type is restricted and the zone is not the caller, or will be * provided to the offerer as context for contract order types. */ struct AdvancedOrder { OrderParameters parameters; uint120 numerator; uint120 denominator; bytes signature; bytes extraData; } /** * @dev Orders can be validated (either explicitly via `validate`, or as a * consequence of a full or partial fill), specifically cancelled (they can * also be cancelled in bulk via incrementing a per-zone counter), and * partially or fully filled (with the fraction filled represented by a * numerator and denominator). */ struct OrderStatus { bool isValidated; bool isCancelled; uint120 numerator; uint120 denominator; } /** * @dev A criteria resolver specifies an order, side (offer vs. consideration), * and item index. It then provides a chosen identifier (i.e. tokenId) * alongside a merkle proof demonstrating the identifier meets the required * criteria. */ struct CriteriaResolver { uint256 orderIndex; Side side; uint256 index; uint256 identifier; bytes32[] criteriaProof; } /** * @dev A fulfillment is applied to a group of orders. It decrements a series of * offer and consideration items, then generates a single execution * element. A given fulfillment can be applied to as many offer and * consideration items as desired, but must contain at least one offer and * at least one consideration that match. The fulfillment must also remain * consistent on all key parameters across all offer items (same offerer, * token, type, tokenId, and conduit preference) as well as across all * consideration items (token, type, tokenId, and recipient). */ struct Fulfillment { FulfillmentComponent[] offerComponents; FulfillmentComponent[] considerationComponents; } /** * @dev Each fulfillment component contains one index referencing a specific * order and another referencing a specific offer or consideration item. */ struct FulfillmentComponent { uint256 orderIndex; uint256 itemIndex; } /** * @dev An execution is triggered once all consideration items have been zeroed * out. It sends the item in question from the offerer to the item's * recipient, optionally sourcing approvals from either this contract * directly or from the offerer's chosen conduit if one is specified. An * execution is not provided as an argument, but rather is derived via * orders, criteria resolvers, and fulfillments (where the total number of * executions will be less than or equal to the total number of indicated * fulfillments) and returned as part of `matchOrders`. */ struct Execution { ReceivedItem item; address offerer; bytes32 conduitKey; } /** * @dev Restricted orders are validated post-execution by calling validateOrder * on the zone. This struct provides context about the order fulfillment * and any supplied extraData, as well as all order hashes fulfilled in a * call to a match or fulfillAvailable method. */ struct ZoneParameters { bytes32 orderHash; address fulfiller; address offerer; SpentItem[] offer; ReceivedItem[] consideration; bytes extraData; bytes32[] orderHashes; uint256 startTime; uint256 endTime; bytes32 zoneHash; } /** * @dev Zones and contract offerers can communicate which schemas they implement * along with any associated metadata related to each schema. */ struct Schema { uint256 id; bytes metadata; } using StructPointers for OrderComponents global; using StructPointers for OfferItem global; using StructPointers for ConsiderationItem global; using StructPointers for SpentItem global; using StructPointers for ReceivedItem global; using StructPointers for BasicOrderParameters global; using StructPointers for AdditionalRecipient global; using StructPointers for OrderParameters global; using StructPointers for Order global; using StructPointers for AdvancedOrder global; using StructPointers for OrderStatus global; using StructPointers for CriteriaResolver global; using StructPointers for Fulfillment global; using StructPointers for FulfillmentComponent global; using StructPointers for Execution global; using StructPointers for ZoneParameters global; /** * @dev This library provides a set of functions for converting structs to * pointers. */ library StructPointers { /** * @dev Get a MemoryPointer from OrderComponents. * * @param obj The OrderComponents object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( OrderComponents memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from OrderComponents. * * @param obj The OrderComponents object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( OrderComponents calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from OfferItem. * * @param obj The OfferItem object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( OfferItem memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from OfferItem. * * @param obj The OfferItem object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( OfferItem calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from ConsiderationItem. * * @param obj The ConsiderationItem object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( ConsiderationItem memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from ConsiderationItem. * * @param obj The ConsiderationItem object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( ConsiderationItem calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from SpentItem. * * @param obj The SpentItem object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( SpentItem memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from SpentItem. * * @param obj The SpentItem object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( SpentItem calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from ReceivedItem. * * @param obj The ReceivedItem object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( ReceivedItem memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from ReceivedItem. * * @param obj The ReceivedItem object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( ReceivedItem calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from BasicOrderParameters. * * @param obj The BasicOrderParameters object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( BasicOrderParameters memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from BasicOrderParameters. * * @param obj The BasicOrderParameters object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( BasicOrderParameters calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from AdditionalRecipient. * * @param obj The AdditionalRecipient object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( AdditionalRecipient memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from AdditionalRecipient. * * @param obj The AdditionalRecipient object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( AdditionalRecipient calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from OrderParameters. * * @param obj The OrderParameters object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( OrderParameters memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from OrderParameters. * * @param obj The OrderParameters object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( OrderParameters calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from Order. * * @param obj The Order object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( Order memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from Order. * * @param obj The Order object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( Order calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from AdvancedOrder. * * @param obj The AdvancedOrder object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( AdvancedOrder memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from AdvancedOrder. * * @param obj The AdvancedOrder object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( AdvancedOrder calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from OrderStatus. * * @param obj The OrderStatus object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( OrderStatus memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from OrderStatus. * * @param obj The OrderStatus object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( OrderStatus calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from CriteriaResolver. * * @param obj The CriteriaResolver object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( CriteriaResolver memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from CriteriaResolver. * * @param obj The CriteriaResolver object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( CriteriaResolver calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from Fulfillment. * * @param obj The Fulfillment object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( Fulfillment memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from Fulfillment. * * @param obj The Fulfillment object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( Fulfillment calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from FulfillmentComponent. * * @param obj The FulfillmentComponent object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( FulfillmentComponent memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from FulfillmentComponent. * * @param obj The FulfillmentComponent object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( FulfillmentComponent calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from Execution. * * @param obj The Execution object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( Execution memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from Execution. * * @param obj The Execution object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( Execution calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } /** * @dev Get a MemoryPointer from ZoneParameters. * * @param obj The ZoneParameters object. * * @return ptr The MemoryPointer. */ function toMemoryPointer( ZoneParameters memory obj ) internal pure returns (MemoryPointer ptr) { assembly { ptr := obj } } /** * @dev Get a CalldataPointer from ZoneParameters. * * @param obj The ZoneParameters object. * * @return ptr The CalldataPointer. */ function toCalldataPointer( ZoneParameters calldata obj ) internal pure returns (CalldataPointer ptr) { assembly { ptr := obj } } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {ReceivedItem, Schema, SpentItem} from "../lib/ConsiderationStructs.sol"; import {IERC165} from "../interfaces/IERC165.sol"; /** * @title ContractOffererInterface * @notice Contains the minimum interfaces needed to interact with a contract * offerer. */ interface ContractOffererInterface is IERC165 { /** * @dev Generates an order with the specified minimum and maximum spent * items, and optional context (supplied as extraData). * * @param fulfiller The address of the fulfiller. * @param minimumReceived The minimum items that the caller is willing to * receive. * @param maximumSpent The maximum items the caller is willing to spend. * @param context Additional context of the order. * * @return offer A tuple containing the offer items. * @return consideration A tuple containing the consideration items. */ function generateOrder( address fulfiller, SpentItem[] calldata minimumReceived, SpentItem[] calldata maximumSpent, bytes calldata context // encoded based on the schemaID ) external returns (SpentItem[] memory offer, ReceivedItem[] memory consideration); /** * @dev Ratifies an order with the specified offer, consideration, and * optional context (supplied as extraData). * * @param offer The offer items. * @param consideration The consideration items. * @param context Additional context of the order. * @param orderHashes The hashes to ratify. * @param contractNonce The nonce of the contract. * * @return ratifyOrderMagicValue The magic value returned by the contract * offerer. */ function ratifyOrder( SpentItem[] calldata offer, ReceivedItem[] calldata consideration, bytes calldata context, // encoded based on the schemaID bytes32[] calldata orderHashes, uint256 contractNonce ) external returns (bytes4 ratifyOrderMagicValue); /** * @dev View function to preview an order generated in response to a minimum * set of received items, maximum set of spent items, and context * (supplied as extraData). * * @param caller The address of the caller (e.g. Seaport). * @param fulfiller The address of the fulfiller (e.g. the account * calling Seaport). * @param minimumReceived The minimum items that the caller is willing to * receive. * @param maximumSpent The maximum items the caller is willing to spend. * @param context Additional context of the order. * * @return offer A tuple containing the offer items. * @return consideration A tuple containing the consideration items. */ function previewOrder( address caller, address fulfiller, SpentItem[] calldata minimumReceived, SpentItem[] calldata maximumSpent, bytes calldata context // encoded based on the schemaID ) external view returns (SpentItem[] memory offer, ReceivedItem[] memory consideration); /** * @dev Gets the metadata for this contract offerer. * * @return name The name of the contract offerer. * @return schemas The schemas supported by the contract offerer. */ function getSeaportMetadata() external view returns (string memory name, Schema[] memory schemas); // map to Seaport Improvement Proposal IDs function supportsInterface(bytes4 interfaceId) external view override returns (bool); // Additional functions and/or events based on implemented schemaIDs } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.19; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; interface ISeaDropTokenContractMetadata { /** * @dev Emit an event for token metadata reveals/updates, * according to EIP-4906. * * @param _fromTokenId The start token id. * @param _toTokenId The end token id. */ event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); /** * @dev Emit an event when the URI for the collection-level metadata * is updated. */ event ContractURIUpdated(string newContractURI); /** * @dev Emit an event with the previous and new provenance hash after * being updated. */ event ProvenanceHashUpdated(bytes32 previousHash, bytes32 newHash); /** * @dev Emit an event when the EIP-2981 royalty info is updated. */ event RoyaltyInfoUpdated(address receiver, uint256 basisPoints); /** * @notice Throw if the max supply exceeds uint64, a limit * due to the storage of bit-packed variables. */ error CannotExceedMaxSupplyOfUint64(uint256 got); /** * @dev Revert with an error when attempting to set the provenance * hash after the mint has started. */ error ProvenanceHashCannotBeSetAfterMintStarted(); /** * @dev Revert with an error when attempting to set the provenance * hash after it has already been set. */ error ProvenanceHashCannotBeSetAfterAlreadyBeingSet(); /** * @notice Sets the base URI for the token metadata and emits an event. * * @param tokenURI The new base URI to set. */ function setBaseURI(string calldata tokenURI) external; /** * @notice Sets the contract URI for contract metadata. * * @param newContractURI The new contract URI. */ function setContractURI(string calldata newContractURI) external; /** * @notice Sets the provenance hash and emits an event. * * The provenance hash is used for random reveals, which * is a hash of the ordered metadata to show it has not been * modified after mint started. * * This function will revert after the first item has been minted. * * @param newProvenanceHash The new provenance hash to set. */ function setProvenanceHash(bytes32 newProvenanceHash) external; /** * @notice Sets the default royalty information. * * Requirements: * * - `receiver` cannot be the zero address. * - `feeNumerator` cannot be greater than the fee denominator of * 10_000 basis points. */ function setDefaultRoyalty(address receiver, uint96 feeNumerator) external; /** * @notice Returns the base URI for token metadata. */ function baseURI() external view returns (string memory); /** * @notice Returns the contract URI. */ function contractURI() external view returns (string memory); /** * @notice Returns the provenance hash. * The provenance hash is used for random reveals, which * is a hash of the ordered metadata to show it is unmodified * after mint has started. */ function provenanceHash() external view returns (bytes32); } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { ISeaDropTokenContractMetadata } from "./ISeaDropTokenContractMetadata.sol"; interface IERC1155ContractMetadata is ISeaDropTokenContractMetadata { /** * @dev A struct representing the supply info for a token id, * packed into one storage slot. * * @param maxSupply The max supply for the token id. * @param totalSupply The total token supply for the token id. * Subtracted when an item is burned. * @param totalMinted The total number of tokens minted for the token id. */ struct TokenSupply { uint64 maxSupply; // 64/256 bits uint64 totalSupply; // 128/256 bits uint64 totalMinted; // 192/256 bits } /** * @dev Emit an event when the max token supply for a token id is updated. */ event MaxSupplyUpdated(uint256 tokenId, uint256 newMaxSupply); /** * @dev Revert with an error if the mint quantity exceeds the max token * supply. */ error MintExceedsMaxSupply(uint256 total, uint256 maxSupply); /** * @notice Sets the max supply for a token id and emits an event. * * @param tokenId The token id to set the max supply for. * @param newMaxSupply The new max supply to set. */ function setMaxSupply(uint256 tokenId, uint256 newMaxSupply) external; /** * @notice Returns the name of the token. */ function name() external view returns (string memory); /** * @notice Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @notice Returns the max token supply for a token id. */ function maxSupply(uint256 tokenId) external view returns (uint256); /** * @notice Returns the total supply for a token id. */ function totalSupply(uint256 tokenId) external view returns (uint256); /** * @notice Returns the total minted for a token id. */ function totalMinted(uint256 tokenId) external view returns (uint256); } // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface ICreatorToken { event TransferValidatorUpdated(address oldValidator, address newValidator); function getTransferValidator() external view returns (address validator); function getTransferValidationFunction() external view returns (bytes4 functionSignature, bool isViewFunction); function setTransferValidator(address validator) external; } interface ILegacyCreatorToken { event TransferValidatorUpdated(address oldValidator, address newValidator); function getTransferValidator() external view returns (address validator); function setTransferValidator(address validator) external; } // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; interface ITransferValidator721 { /// @notice Ensure that a transfer has been authorized for a specific tokenId function validateTransfer( address caller, address from, address to, uint256 tokenId ) external view; } interface ITransferValidator1155 { /// @notice Ensure that a transfer has been authorized for a specific amount of a specific tokenId, and reduce the transferable amount remaining function validateTransfer( address caller, address from, address to, uint256 tokenId, uint256 amount ) external; } // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import { ICreatorToken } from "../interfaces/ICreatorToken.sol"; /** * @title TokenTransferValidator * @notice Functionality to use a transfer validator. */ abstract contract TokenTransferValidator is ICreatorToken { /// @dev Store the transfer validator. The null address means no transfer validator is set. address internal _transferValidator; /// @notice Revert with an error if the transfer validator is being set to the same address. error SameTransferValidator(); /// @notice Returns the currently active transfer validator. /// The null address means no transfer validator is set. function getTransferValidator() external view returns (address) { return _transferValidator; } /// @notice Set the transfer validator. /// The external method that uses this must include access control. function _setTransferValidator(address newValidator) internal { address oldValidator = _transferValidator; if (oldValidator == newValidator) { revert SameTransferValidator(); } _transferValidator = newValidator; emit TransferValidatorUpdated(oldValidator, newValidator); } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC2981 NFT Royalty Standard implementation. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC2981.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/common/ERC2981.sol) abstract contract ERC2981 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The royalty fee numerator exceeds the fee denominator. error RoyaltyOverflow(); /// @dev The royalty receiver cannot be the zero address. error RoyaltyReceiverIsZeroAddress(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The default royalty info is given by: /// ``` /// let packed := sload(_ERC2981_MASTER_SLOT_SEED) /// let receiver := shr(96, packed) /// let royaltyFraction := xor(packed, shl(96, receiver)) /// ``` /// /// The per token royalty info is given by. /// ``` /// mstore(0x00, tokenId) /// mstore(0x20, _ERC2981_MASTER_SLOT_SEED) /// let packed := sload(keccak256(0x00, 0x40)) /// let receiver := shr(96, packed) /// let royaltyFraction := xor(packed, shl(96, receiver)) /// ``` uint256 private constant _ERC2981_MASTER_SLOT_SEED = 0xaa4ec00224afccfdb7; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC2981 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Checks that `_feeDenominator` is non-zero. constructor() { require(_feeDenominator() != 0, "Fee denominator cannot be zero."); } /// @dev Returns the denominator for the royalty amount. /// Defaults to 10000, which represents fees in basis points. /// Override this function to return a custom amount if needed. function _feeDenominator() internal pure virtual returns (uint96) { return 10000; } /// @dev Returns true if this contract implements the interface defined by `interfaceId`. /// See: https://eips.ethereum.org/EIPS/eip-165 /// This function call must use less than 30000 gas. function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { let s := shr(224, interfaceId) // ERC165: 0x01ffc9a7, ERC2981: 0x2a55205a. result := or(eq(s, 0x01ffc9a7), eq(s, 0x2a55205a)) } } /// @dev Returns the `receiver` and `royaltyAmount` for `tokenId` sold at `salePrice`. function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual returns (address receiver, uint256 royaltyAmount) { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) let packed := sload(keccak256(0x00, 0x40)) receiver := shr(96, packed) if iszero(receiver) { packed := sload(mload(0x20)) receiver := shr(96, packed) } let x := salePrice let y := xor(packed, shl(96, receiver)) // `feeNumerator`. // Overflow check, equivalent to `require(y == 0 || x <= type(uint256).max / y)`. // Out-of-gas revert. Should not be triggered in practice, but included for safety. returndatacopy(returndatasize(), returndatasize(), mul(y, gt(x, div(not(0), y)))) royaltyAmount := div(mul(x, y), feeDenominator) } } /// @dev Sets the default royalty `receiver` and `feeNumerator`. /// /// Requirements: /// - `receiver` must not be the zero address. /// - `feeNumerator` must not be greater than the fee denominator. function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { feeNumerator := shr(160, shl(160, feeNumerator)) if gt(feeNumerator, feeDenominator) { mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`. revert(0x1c, 0x04) } let packed := shl(96, receiver) if iszero(packed) { mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`. revert(0x1c, 0x04) } sstore(_ERC2981_MASTER_SLOT_SEED, or(packed, feeNumerator)) } } /// @dev Sets the default royalty `receiver` and `feeNumerator` to zero. function _deleteDefaultRoyalty() internal virtual { /// @solidity memory-safe-assembly assembly { sstore(_ERC2981_MASTER_SLOT_SEED, 0) } } /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId`. /// /// Requirements: /// - `receiver` must not be the zero address. /// - `feeNumerator` must not be greater than the fee denominator. function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { feeNumerator := shr(160, shl(160, feeNumerator)) if gt(feeNumerator, feeDenominator) { mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`. revert(0x1c, 0x04) } let packed := shl(96, receiver) if iszero(packed) { mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`. revert(0x1c, 0x04) } mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) sstore(keccak256(0x00, 0x40), or(packed, feeNumerator)) } } /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId` to zero. function _resetTokenRoyalty(uint256 tokenId) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) sstore(keccak256(0x00, 0x40), 0) } } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// @dev While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. /// It is intentionally chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(not(_OWNER_SLOT_NOT), newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { /// @solidity memory-safe-assembly assembly { let ownerSlot := not(_OWNER_SLOT_NOT) // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(not(_OWNER_SLOT_NOT)) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. function ownershipHandoverValidFor() public view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.19; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (address(this).code.length == 0 && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { CreatorPayout, PublicDrop } from "./ERC721SeaDropStructs.sol"; interface SeaDropErrorsAndEvents { /** * @notice The SeaDrop token types, emitted as part of * `event SeaDropTokenDeployed`. */ enum SEADROP_TOKEN_TYPE { ERC721_STANDARD, ERC721_CLONE, ERC721_UPGRADEABLE, ERC1155_STANDARD, ERC1155_CLONE, ERC1155_UPGRADEABLE } /** * @notice An event to signify that a SeaDrop token contract was deployed. */ event SeaDropTokenDeployed(SEADROP_TOKEN_TYPE tokenType); /** * @notice Revert with an error if the function selector is not supported. */ error UnsupportedFunctionSelector(bytes4 selector); /** * @dev Revert with an error if the drop stage is not active. */ error NotActive( uint256 currentTimestamp, uint256 startTimestamp, uint256 endTimestamp ); /** * @dev Revert with an error if the mint quantity exceeds the max allowed * to be minted per wallet. */ error MintQuantityExceedsMaxMintedPerWallet(uint256 total, uint256 allowed); /** * @dev Revert with an error if the mint quantity exceeds the max token * supply. */ error MintQuantityExceedsMaxSupply(uint256 total, uint256 maxSupply); /** * @dev Revert with an error if the mint quantity exceeds the max token * supply for the stage. * Note: The `maxTokenSupplyForStage` for public mint is * always `type(uint).max`. */ error MintQuantityExceedsMaxTokenSupplyForStage( uint256 total, uint256 maxTokenSupplyForStage ); /** * @dev Revert if the fee recipient is the zero address. */ error FeeRecipientCannotBeZeroAddress(); /** * @dev Revert if the fee recipient is not already included. */ error FeeRecipientNotPresent(); /** * @dev Revert if the fee basis points is greater than 10_000. */ error InvalidFeeBps(uint256 feeBps); /** * @dev Revert if the fee recipient is already included. */ error DuplicateFeeRecipient(); /** * @dev Revert if the fee recipient is restricted and not allowed. */ error FeeRecipientNotAllowed(address got); /** * @dev Revert if the creator payout address is the zero address. */ error CreatorPayoutAddressCannotBeZeroAddress(); /** * @dev Revert if the creator payouts are not set. */ error CreatorPayoutsNotSet(); /** * @dev Revert if the creator payout basis points are zero. */ error CreatorPayoutBasisPointsCannotBeZero(); /** * @dev Revert if the total basis points for the creator payouts * don't equal exactly 10_000. */ error InvalidCreatorPayoutTotalBasisPoints( uint256 totalReceivedBasisPoints ); /** * @dev Revert if the creator payout basis points don't add up to 10_000. */ error InvalidCreatorPayoutBasisPoints(uint256 totalReceivedBasisPoints); /** * @dev Revert with an error if the allow list proof is invalid. */ error InvalidProof(); /** * @dev Revert if a supplied signer address is the zero address. */ error SignerCannotBeZeroAddress(); /** * @dev Revert with an error if a signer is not included in * the enumeration when removing. */ error SignerNotPresent(); /** * @dev Revert with an error if a payer is not included in * the enumeration when removing. */ error PayerNotPresent(); /** * @dev Revert with an error if a payer is already included in mapping * when adding. */ error DuplicatePayer(); /** * @dev Revert with an error if a signer is already included in mapping * when adding. */ error DuplicateSigner(); /** * @dev Revert with an error if the payer is not allowed. The minter must * pay for their own mint. */ error PayerNotAllowed(address got); /** * @dev Revert if a supplied payer address is the zero address. */ error PayerCannotBeZeroAddress(); /** * @dev Revert if the start time is greater than the end time. */ error InvalidStartAndEndTime(uint256 startTime, uint256 endTime); /** * @dev Revert with an error if the signer payment token is not the same. */ error InvalidSignedPaymentToken(address got, address want); /** * @dev Revert with an error if supplied signed mint price is less than * the minimum specified. */ error InvalidSignedMintPrice( address paymentToken, uint256 got, uint256 minimum ); /** * @dev Revert with an error if supplied signed maxTotalMintableByWallet * is greater than the maximum specified. */ error InvalidSignedMaxTotalMintableByWallet(uint256 got, uint256 maximum); /** * @dev Revert with an error if supplied signed * maxTotalMintableByWalletPerToken is greater than the maximum * specified. */ error InvalidSignedMaxTotalMintableByWalletPerToken( uint256 got, uint256 maximum ); /** * @dev Revert with an error if the fromTokenId is not within range. */ error InvalidSignedFromTokenId(uint256 got, uint256 minimum); /** * @dev Revert with an error if the toTokenId is not within range. */ error InvalidSignedToTokenId(uint256 got, uint256 maximum); /** * @dev Revert with an error if supplied signed start time is less than * the minimum specified. */ error InvalidSignedStartTime(uint256 got, uint256 minimum); /** * @dev Revert with an error if supplied signed end time is greater than * the maximum specified. */ error InvalidSignedEndTime(uint256 got, uint256 maximum); /** * @dev Revert with an error if supplied signed maxTokenSupplyForStage * is greater than the maximum specified. */ error InvalidSignedMaxTokenSupplyForStage(uint256 got, uint256 maximum); /** * @dev Revert with an error if supplied signed feeBps is greater than * the maximum specified, or less than the minimum. */ error InvalidSignedFeeBps(uint256 got, uint256 minimumOrMaximum); /** * @dev Revert with an error if signed mint did not specify to restrict * fee recipients. */ error SignedMintsMustRestrictFeeRecipients(); /** * @dev Revert with an error if a signature for a signed mint has already * been used. */ error SignatureAlreadyUsed(); /** * @dev Revert with an error if the contract has no balance to withdraw. */ error NoBalanceToWithdraw(); /** * @dev Revert with an error if the caller is not an allowed Seaport. */ error InvalidCallerOnlyAllowedSeaport(address caller); /** * @dev Revert with an error if the order does not have the ERC1155 magic * consideration item to signify a consecutive mint. */ error MustSpecifyERC1155ConsiderationItemForSeaDropMint(); /** * @dev Revert with an error if the extra data version is not supported. */ error UnsupportedExtraDataVersion(uint8 version); /** * @dev Revert with an error if the extra data encoding is not supported. */ error InvalidExtraDataEncoding(uint8 version); /** * @dev Revert with an error if the provided substandard is not supported. */ error InvalidSubstandard(uint8 substandard); /** * @dev Revert with an error if the implementation contract is called without * delegatecall. */ error OnlyDelegateCalled(); /** * @dev Revert with an error if the provided allowed Seaport is the * zero address. */ error AllowedSeaportCannotBeZeroAddress(); /** * @dev Emit an event when allowed Seaport contracts are updated. */ event AllowedSeaportUpdated(address[] allowedSeaport); /** * @dev An event with details of a SeaDrop mint, for analytical purposes. * * @param payer The address who payed for the tx. * @param dropStageIndex The drop stage index. Items minted through * public mint have dropStageIndex of 0 */ event SeaDropMint(address payer, uint256 dropStageIndex); /** * @dev An event with updated allow list data. * * @param previousMerkleRoot The previous allow list merkle root. * @param newMerkleRoot The new allow list merkle root. * @param publicKeyURI If the allow list is encrypted, the public key * URIs that can decrypt the list. * Empty if unencrypted. * @param allowListURI The URI for the allow list. */ event AllowListUpdated( bytes32 indexed previousMerkleRoot, bytes32 indexed newMerkleRoot, string[] publicKeyURI, string allowListURI ); /** * @dev An event with updated drop URI. */ event DropURIUpdated(string newDropURI); /** * @dev An event with the updated creator payout address. */ event CreatorPayoutsUpdated(CreatorPayout[] creatorPayouts); /** * @dev An event with the updated allowed fee recipient. */ event AllowedFeeRecipientUpdated( address indexed feeRecipient, bool indexed allowed ); /** * @dev An event with the updated signer. */ event SignerUpdated(address indexed signer, bool indexed allowed); /** * @dev An event with the updated payer. */ event PayerUpdated(address indexed payer, bool indexed allowed); } // SPDX-License-Identifier: MIT pragma solidity ^0.8.13; enum OrderType { // 0: no partial fills, anyone can execute FULL_OPEN, // 1: partial fills supported, anyone can execute PARTIAL_OPEN, // 2: no partial fills, only offerer or zone can execute FULL_RESTRICTED, // 3: partial fills supported, only offerer or zone can execute PARTIAL_RESTRICTED, // 4: contract order type CONTRACT } enum BasicOrderType { // 0: no partial fills, anyone can execute ETH_TO_ERC721_FULL_OPEN, // 1: partial fills supported, anyone can execute ETH_TO_ERC721_PARTIAL_OPEN, // 2: no partial fills, only offerer or zone can execute ETH_TO_ERC721_FULL_RESTRICTED, // 3: partial fills supported, only offerer or zone can execute ETH_TO_ERC721_PARTIAL_RESTRICTED, // 4: no partial fills, anyone can execute ETH_TO_ERC1155_FULL_OPEN, // 5: partial fills supported, anyone can execute ETH_TO_ERC1155_PARTIAL_OPEN, // 6: no partial fills, only offerer or zone can execute ETH_TO_ERC1155_FULL_RESTRICTED, // 7: partial fills supported, only offerer or zone can execute ETH_TO_ERC1155_PARTIAL_RESTRICTED, // 8: no partial fills, anyone can execute ERC20_TO_ERC721_FULL_OPEN, // 9: partial fills supported, anyone can execute ERC20_TO_ERC721_PARTIAL_OPEN, // 10: no partial fills, only offerer or zone can execute ERC20_TO_ERC721_FULL_RESTRICTED, // 11: partial fills supported, only offerer or zone can execute ERC20_TO_ERC721_PARTIAL_RESTRICTED, // 12: no partial fills, anyone can execute ERC20_TO_ERC1155_FULL_OPEN, // 13: partial fills supported, anyone can execute ERC20_TO_ERC1155_PARTIAL_OPEN, // 14: no partial fills, only offerer or zone can execute ERC20_TO_ERC1155_FULL_RESTRICTED, // 15: partial fills supported, only offerer or zone can execute ERC20_TO_ERC1155_PARTIAL_RESTRICTED, // 16: no partial fills, anyone can execute ERC721_TO_ERC20_FULL_OPEN, // 17: partial fills supported, anyone can execute ERC721_TO_ERC20_PARTIAL_OPEN, // 18: no partial fills, only offerer or zone can execute ERC721_TO_ERC20_FULL_RESTRICTED, // 19: partial fills supported, only offerer or zone can execute ERC721_TO_ERC20_PARTIAL_RESTRICTED, // 20: no partial fills, anyone can execute ERC1155_TO_ERC20_FULL_OPEN, // 21: partial fills supported, anyone can execute ERC1155_TO_ERC20_PARTIAL_OPEN, // 22: no partial fills, only offerer or zone can execute ERC1155_TO_ERC20_FULL_RESTRICTED, // 23: partial fills supported, only offerer or zone can execute ERC1155_TO_ERC20_PARTIAL_RESTRICTED } enum BasicOrderRouteType { // 0: provide Ether (or other native token) to receive offered ERC721 item. ETH_TO_ERC721, // 1: provide Ether (or other native token) to receive offered ERC1155 item. ETH_TO_ERC1155, // 2: provide ERC20 item to receive offered ERC721 item. ERC20_TO_ERC721, // 3: provide ERC20 item to receive offered ERC1155 item. ERC20_TO_ERC1155, // 4: provide ERC721 item to receive offered ERC20 item. ERC721_TO_ERC20, // 5: provide ERC1155 item to receive offered ERC20 item. ERC1155_TO_ERC20 } enum ItemType { // 0: ETH on mainnet, MATIC on polygon, etc. NATIVE, // 1: ERC20 items (ERC777 and ERC20 analogues could also technically work) ERC20, // 2: ERC721 items ERC721, // 3: ERC1155 items ERC1155, // 4: ERC721 items where a number of tokenIds are supported ERC721_WITH_CRITERIA, // 5: ERC1155 items where a number of ids are supported ERC1155_WITH_CRITERIA } enum Side { // 0: Items that can be spent OFFER, // 1: Items that must be received CONSIDERATION } // SPDX-License-Identifier: MIT pragma solidity ^0.8.13; type CalldataPointer is uint256; type ReturndataPointer is uint256; type MemoryPointer is uint256; using CalldataPointerLib for CalldataPointer global; using MemoryPointerLib for MemoryPointer global; using ReturndataPointerLib for ReturndataPointer global; using CalldataReaders for CalldataPointer global; using ReturndataReaders for ReturndataPointer global; using MemoryReaders for MemoryPointer global; using MemoryWriters for MemoryPointer global; CalldataPointer constant CalldataStart = CalldataPointer.wrap(0x04); MemoryPointer constant FreeMemoryPPtr = MemoryPointer.wrap(0x40); uint256 constant IdentityPrecompileAddress = 0x4; uint256 constant OffsetOrLengthMask = 0xffffffff; uint256 constant _OneWord = 0x20; uint256 constant _FreeMemoryPointerSlot = 0x40; /// @dev Allocates `size` bytes in memory by increasing the free memory pointer /// and returns the memory pointer to the first byte of the allocated region. // (Free functions cannot have visibility.) // solhint-disable-next-line func-visibility function malloc(uint256 size) pure returns (MemoryPointer mPtr) { assembly { mPtr := mload(_FreeMemoryPointerSlot) mstore(_FreeMemoryPointerSlot, add(mPtr, size)) } } // (Free functions cannot have visibility.) // solhint-disable-next-line func-visibility function getFreeMemoryPointer() pure returns (MemoryPointer mPtr) { mPtr = FreeMemoryPPtr.readMemoryPointer(); } // (Free functions cannot have visibility.) // solhint-disable-next-line func-visibility function setFreeMemoryPointer(MemoryPointer mPtr) pure { FreeMemoryPPtr.write(mPtr); } library CalldataPointerLib { function lt( CalldataPointer a, CalldataPointer b ) internal pure returns (bool c) { assembly { c := lt(a, b) } } function gt( CalldataPointer a, CalldataPointer b ) internal pure returns (bool c) { assembly { c := gt(a, b) } } function eq( CalldataPointer a, CalldataPointer b ) internal pure returns (bool c) { assembly { c := eq(a, b) } } function isNull(CalldataPointer a) internal pure returns (bool b) { assembly { b := iszero(a) } } /// @dev Resolves an offset stored at `cdPtr + headOffset` to a calldata. /// pointer `cdPtr` must point to some parent object with a dynamic /// type's head stored at `cdPtr + headOffset`. function pptr( CalldataPointer cdPtr, uint256 headOffset ) internal pure returns (CalldataPointer cdPtrChild) { cdPtrChild = cdPtr.offset( cdPtr.offset(headOffset).readUint256() & OffsetOrLengthMask ); } /// @dev Resolves an offset stored at `cdPtr` to a calldata pointer. /// `cdPtr` must point to some parent object with a dynamic type as its /// first member, e.g. `struct { bytes data; }` function pptr( CalldataPointer cdPtr ) internal pure returns (CalldataPointer cdPtrChild) { cdPtrChild = cdPtr.offset(cdPtr.readUint256() & OffsetOrLengthMask); } /// @dev Returns the calldata pointer one word after `cdPtr`. function next( CalldataPointer cdPtr ) internal pure returns (CalldataPointer cdPtrNext) { assembly { cdPtrNext := add(cdPtr, _OneWord) } } /// @dev Returns the calldata pointer `_offset` bytes after `cdPtr`. function offset( CalldataPointer cdPtr, uint256 _offset ) internal pure returns (CalldataPointer cdPtrNext) { assembly { cdPtrNext := add(cdPtr, _offset) } } /// @dev Copies `size` bytes from calldata starting at `src` to memory at /// `dst`. function copy( CalldataPointer src, MemoryPointer dst, uint256 size ) internal pure { assembly { calldatacopy(dst, src, size) } } } library ReturndataPointerLib { function lt( ReturndataPointer a, ReturndataPointer b ) internal pure returns (bool c) { assembly { c := lt(a, b) } } function gt( ReturndataPointer a, ReturndataPointer b ) internal pure returns (bool c) { assembly { c := gt(a, b) } } function eq( ReturndataPointer a, ReturndataPointer b ) internal pure returns (bool c) { assembly { c := eq(a, b) } } function isNull(ReturndataPointer a) internal pure returns (bool b) { assembly { b := iszero(a) } } /// @dev Resolves an offset stored at `rdPtr + headOffset` to a returndata /// pointer. `rdPtr` must point to some parent object with a dynamic /// type's head stored at `rdPtr + headOffset`. function pptr( ReturndataPointer rdPtr, uint256 headOffset ) internal pure returns (ReturndataPointer rdPtrChild) { rdPtrChild = rdPtr.offset( rdPtr.offset(headOffset).readUint256() & OffsetOrLengthMask ); } /// @dev Resolves an offset stored at `rdPtr` to a returndata pointer. /// `rdPtr` must point to some parent object with a dynamic type as its /// first member, e.g. `struct { bytes data; }` function pptr( ReturndataPointer rdPtr ) internal pure returns (ReturndataPointer rdPtrChild) { rdPtrChild = rdPtr.offset(rdPtr.readUint256() & OffsetOrLengthMask); } /// @dev Returns the returndata pointer one word after `cdPtr`. function next( ReturndataPointer rdPtr ) internal pure returns (ReturndataPointer rdPtrNext) { assembly { rdPtrNext := add(rdPtr, _OneWord) } } /// @dev Returns the returndata pointer `_offset` bytes after `cdPtr`. function offset( ReturndataPointer rdPtr, uint256 _offset ) internal pure returns (ReturndataPointer rdPtrNext) { assembly { rdPtrNext := add(rdPtr, _offset) } } /// @dev Copies `size` bytes from returndata starting at `src` to memory at /// `dst`. function copy( ReturndataPointer src, MemoryPointer dst, uint256 size ) internal pure { assembly { returndatacopy(dst, src, size) } } } library MemoryPointerLib { function copy( MemoryPointer src, MemoryPointer dst, uint256 size ) internal view { assembly { let success := staticcall( gas(), IdentityPrecompileAddress, src, size, dst, size ) if or(iszero(returndatasize()), iszero(success)) { revert(0, 0) } } } function lt( MemoryPointer a, MemoryPointer b ) internal pure returns (bool c) { assembly { c := lt(a, b) } } function gt( MemoryPointer a, MemoryPointer b ) internal pure returns (bool c) { assembly { c := gt(a, b) } } function eq( MemoryPointer a, MemoryPointer b ) internal pure returns (bool c) { assembly { c := eq(a, b) } } function isNull(MemoryPointer a) internal pure returns (bool b) { assembly { b := iszero(a) } } function hash( MemoryPointer ptr, uint256 length ) internal pure returns (bytes32 _hash) { assembly { _hash := keccak256(ptr, length) } } /// @dev Returns the memory pointer one word after `mPtr`. function next( MemoryPointer mPtr ) internal pure returns (MemoryPointer mPtrNext) { assembly { mPtrNext := add(mPtr, _OneWord) } } /// @dev Returns the memory pointer `_offset` bytes after `mPtr`. function offset( MemoryPointer mPtr, uint256 _offset ) internal pure returns (MemoryPointer mPtrNext) { assembly { mPtrNext := add(mPtr, _offset) } } /// @dev Resolves a pointer at `mPtr + headOffset` to a memory /// pointer. `mPtr` must point to some parent object with a dynamic /// type's pointer stored at `mPtr + headOffset`. function pptr( MemoryPointer mPtr, uint256 headOffset ) internal pure returns (MemoryPointer mPtrChild) { mPtrChild = mPtr.offset(headOffset).readMemoryPointer(); } /// @dev Resolves a pointer stored at `mPtr` to a memory pointer. /// `mPtr` must point to some parent object with a dynamic type as its /// first member, e.g. `struct { bytes data; }` function pptr( MemoryPointer mPtr ) internal pure returns (MemoryPointer mPtrChild) { mPtrChild = mPtr.readMemoryPointer(); } } library CalldataReaders { /// @dev Reads the value at `cdPtr` and applies a mask to return only the /// last 4 bytes. function readMaskedUint256( CalldataPointer cdPtr ) internal pure returns (uint256 value) { value = cdPtr.readUint256() & OffsetOrLengthMask; } /// @dev Reads the bool at `cdPtr` in calldata. function readBool( CalldataPointer cdPtr ) internal pure returns (bool value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the address at `cdPtr` in calldata. function readAddress( CalldataPointer cdPtr ) internal pure returns (address value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes1 at `cdPtr` in calldata. function readBytes1( CalldataPointer cdPtr ) internal pure returns (bytes1 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes2 at `cdPtr` in calldata. function readBytes2( CalldataPointer cdPtr ) internal pure returns (bytes2 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes3 at `cdPtr` in calldata. function readBytes3( CalldataPointer cdPtr ) internal pure returns (bytes3 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes4 at `cdPtr` in calldata. function readBytes4( CalldataPointer cdPtr ) internal pure returns (bytes4 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes5 at `cdPtr` in calldata. function readBytes5( CalldataPointer cdPtr ) internal pure returns (bytes5 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes6 at `cdPtr` in calldata. function readBytes6( CalldataPointer cdPtr ) internal pure returns (bytes6 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes7 at `cdPtr` in calldata. function readBytes7( CalldataPointer cdPtr ) internal pure returns (bytes7 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes8 at `cdPtr` in calldata. function readBytes8( CalldataPointer cdPtr ) internal pure returns (bytes8 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes9 at `cdPtr` in calldata. function readBytes9( CalldataPointer cdPtr ) internal pure returns (bytes9 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes10 at `cdPtr` in calldata. function readBytes10( CalldataPointer cdPtr ) internal pure returns (bytes10 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes11 at `cdPtr` in calldata. function readBytes11( CalldataPointer cdPtr ) internal pure returns (bytes11 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes12 at `cdPtr` in calldata. function readBytes12( CalldataPointer cdPtr ) internal pure returns (bytes12 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes13 at `cdPtr` in calldata. function readBytes13( CalldataPointer cdPtr ) internal pure returns (bytes13 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes14 at `cdPtr` in calldata. function readBytes14( CalldataPointer cdPtr ) internal pure returns (bytes14 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes15 at `cdPtr` in calldata. function readBytes15( CalldataPointer cdPtr ) internal pure returns (bytes15 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes16 at `cdPtr` in calldata. function readBytes16( CalldataPointer cdPtr ) internal pure returns (bytes16 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes17 at `cdPtr` in calldata. function readBytes17( CalldataPointer cdPtr ) internal pure returns (bytes17 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes18 at `cdPtr` in calldata. function readBytes18( CalldataPointer cdPtr ) internal pure returns (bytes18 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes19 at `cdPtr` in calldata. function readBytes19( CalldataPointer cdPtr ) internal pure returns (bytes19 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes20 at `cdPtr` in calldata. function readBytes20( CalldataPointer cdPtr ) internal pure returns (bytes20 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes21 at `cdPtr` in calldata. function readBytes21( CalldataPointer cdPtr ) internal pure returns (bytes21 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes22 at `cdPtr` in calldata. function readBytes22( CalldataPointer cdPtr ) internal pure returns (bytes22 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes23 at `cdPtr` in calldata. function readBytes23( CalldataPointer cdPtr ) internal pure returns (bytes23 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes24 at `cdPtr` in calldata. function readBytes24( CalldataPointer cdPtr ) internal pure returns (bytes24 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes25 at `cdPtr` in calldata. function readBytes25( CalldataPointer cdPtr ) internal pure returns (bytes25 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes26 at `cdPtr` in calldata. function readBytes26( CalldataPointer cdPtr ) internal pure returns (bytes26 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes27 at `cdPtr` in calldata. function readBytes27( CalldataPointer cdPtr ) internal pure returns (bytes27 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes28 at `cdPtr` in calldata. function readBytes28( CalldataPointer cdPtr ) internal pure returns (bytes28 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes29 at `cdPtr` in calldata. function readBytes29( CalldataPointer cdPtr ) internal pure returns (bytes29 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes30 at `cdPtr` in calldata. function readBytes30( CalldataPointer cdPtr ) internal pure returns (bytes30 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes31 at `cdPtr` in calldata. function readBytes31( CalldataPointer cdPtr ) internal pure returns (bytes31 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the bytes32 at `cdPtr` in calldata. function readBytes32( CalldataPointer cdPtr ) internal pure returns (bytes32 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint8 at `cdPtr` in calldata. function readUint8( CalldataPointer cdPtr ) internal pure returns (uint8 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint16 at `cdPtr` in calldata. function readUint16( CalldataPointer cdPtr ) internal pure returns (uint16 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint24 at `cdPtr` in calldata. function readUint24( CalldataPointer cdPtr ) internal pure returns (uint24 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint32 at `cdPtr` in calldata. function readUint32( CalldataPointer cdPtr ) internal pure returns (uint32 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint40 at `cdPtr` in calldata. function readUint40( CalldataPointer cdPtr ) internal pure returns (uint40 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint48 at `cdPtr` in calldata. function readUint48( CalldataPointer cdPtr ) internal pure returns (uint48 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint56 at `cdPtr` in calldata. function readUint56( CalldataPointer cdPtr ) internal pure returns (uint56 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint64 at `cdPtr` in calldata. function readUint64( CalldataPointer cdPtr ) internal pure returns (uint64 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint72 at `cdPtr` in calldata. function readUint72( CalldataPointer cdPtr ) internal pure returns (uint72 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint80 at `cdPtr` in calldata. function readUint80( CalldataPointer cdPtr ) internal pure returns (uint80 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint88 at `cdPtr` in calldata. function readUint88( CalldataPointer cdPtr ) internal pure returns (uint88 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint96 at `cdPtr` in calldata. function readUint96( CalldataPointer cdPtr ) internal pure returns (uint96 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint104 at `cdPtr` in calldata. function readUint104( CalldataPointer cdPtr ) internal pure returns (uint104 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint112 at `cdPtr` in calldata. function readUint112( CalldataPointer cdPtr ) internal pure returns (uint112 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint120 at `cdPtr` in calldata. function readUint120( CalldataPointer cdPtr ) internal pure returns (uint120 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint128 at `cdPtr` in calldata. function readUint128( CalldataPointer cdPtr ) internal pure returns (uint128 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint136 at `cdPtr` in calldata. function readUint136( CalldataPointer cdPtr ) internal pure returns (uint136 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint144 at `cdPtr` in calldata. function readUint144( CalldataPointer cdPtr ) internal pure returns (uint144 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint152 at `cdPtr` in calldata. function readUint152( CalldataPointer cdPtr ) internal pure returns (uint152 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint160 at `cdPtr` in calldata. function readUint160( CalldataPointer cdPtr ) internal pure returns (uint160 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint168 at `cdPtr` in calldata. function readUint168( CalldataPointer cdPtr ) internal pure returns (uint168 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint176 at `cdPtr` in calldata. function readUint176( CalldataPointer cdPtr ) internal pure returns (uint176 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint184 at `cdPtr` in calldata. function readUint184( CalldataPointer cdPtr ) internal pure returns (uint184 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint192 at `cdPtr` in calldata. function readUint192( CalldataPointer cdPtr ) internal pure returns (uint192 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint200 at `cdPtr` in calldata. function readUint200( CalldataPointer cdPtr ) internal pure returns (uint200 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint208 at `cdPtr` in calldata. function readUint208( CalldataPointer cdPtr ) internal pure returns (uint208 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint216 at `cdPtr` in calldata. function readUint216( CalldataPointer cdPtr ) internal pure returns (uint216 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint224 at `cdPtr` in calldata. function readUint224( CalldataPointer cdPtr ) internal pure returns (uint224 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint232 at `cdPtr` in calldata. function readUint232( CalldataPointer cdPtr ) internal pure returns (uint232 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint240 at `cdPtr` in calldata. function readUint240( CalldataPointer cdPtr ) internal pure returns (uint240 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint248 at `cdPtr` in calldata. function readUint248( CalldataPointer cdPtr ) internal pure returns (uint248 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the uint256 at `cdPtr` in calldata. function readUint256( CalldataPointer cdPtr ) internal pure returns (uint256 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int8 at `cdPtr` in calldata. function readInt8( CalldataPointer cdPtr ) internal pure returns (int8 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int16 at `cdPtr` in calldata. function readInt16( CalldataPointer cdPtr ) internal pure returns (int16 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int24 at `cdPtr` in calldata. function readInt24( CalldataPointer cdPtr ) internal pure returns (int24 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int32 at `cdPtr` in calldata. function readInt32( CalldataPointer cdPtr ) internal pure returns (int32 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int40 at `cdPtr` in calldata. function readInt40( CalldataPointer cdPtr ) internal pure returns (int40 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int48 at `cdPtr` in calldata. function readInt48( CalldataPointer cdPtr ) internal pure returns (int48 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int56 at `cdPtr` in calldata. function readInt56( CalldataPointer cdPtr ) internal pure returns (int56 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int64 at `cdPtr` in calldata. function readInt64( CalldataPointer cdPtr ) internal pure returns (int64 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int72 at `cdPtr` in calldata. function readInt72( CalldataPointer cdPtr ) internal pure returns (int72 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int80 at `cdPtr` in calldata. function readInt80( CalldataPointer cdPtr ) internal pure returns (int80 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int88 at `cdPtr` in calldata. function readInt88( CalldataPointer cdPtr ) internal pure returns (int88 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int96 at `cdPtr` in calldata. function readInt96( CalldataPointer cdPtr ) internal pure returns (int96 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int104 at `cdPtr` in calldata. function readInt104( CalldataPointer cdPtr ) internal pure returns (int104 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int112 at `cdPtr` in calldata. function readInt112( CalldataPointer cdPtr ) internal pure returns (int112 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int120 at `cdPtr` in calldata. function readInt120( CalldataPointer cdPtr ) internal pure returns (int120 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int128 at `cdPtr` in calldata. function readInt128( CalldataPointer cdPtr ) internal pure returns (int128 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int136 at `cdPtr` in calldata. function readInt136( CalldataPointer cdPtr ) internal pure returns (int136 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int144 at `cdPtr` in calldata. function readInt144( CalldataPointer cdPtr ) internal pure returns (int144 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int152 at `cdPtr` in calldata. function readInt152( CalldataPointer cdPtr ) internal pure returns (int152 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int160 at `cdPtr` in calldata. function readInt160( CalldataPointer cdPtr ) internal pure returns (int160 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int168 at `cdPtr` in calldata. function readInt168( CalldataPointer cdPtr ) internal pure returns (int168 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int176 at `cdPtr` in calldata. function readInt176( CalldataPointer cdPtr ) internal pure returns (int176 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int184 at `cdPtr` in calldata. function readInt184( CalldataPointer cdPtr ) internal pure returns (int184 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int192 at `cdPtr` in calldata. function readInt192( CalldataPointer cdPtr ) internal pure returns (int192 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int200 at `cdPtr` in calldata. function readInt200( CalldataPointer cdPtr ) internal pure returns (int200 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int208 at `cdPtr` in calldata. function readInt208( CalldataPointer cdPtr ) internal pure returns (int208 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int216 at `cdPtr` in calldata. function readInt216( CalldataPointer cdPtr ) internal pure returns (int216 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int224 at `cdPtr` in calldata. function readInt224( CalldataPointer cdPtr ) internal pure returns (int224 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int232 at `cdPtr` in calldata. function readInt232( CalldataPointer cdPtr ) internal pure returns (int232 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int240 at `cdPtr` in calldata. function readInt240( CalldataPointer cdPtr ) internal pure returns (int240 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int248 at `cdPtr` in calldata. function readInt248( CalldataPointer cdPtr ) internal pure returns (int248 value) { assembly { value := calldataload(cdPtr) } } /// @dev Reads the int256 at `cdPtr` in calldata. function readInt256( CalldataPointer cdPtr ) internal pure returns (int256 value) { assembly { value := calldataload(cdPtr) } } } library ReturndataReaders { /// @dev Reads value at `rdPtr` & applies a mask to return only last 4 bytes function readMaskedUint256( ReturndataPointer rdPtr ) internal pure returns (uint256 value) { value = rdPtr.readUint256() & OffsetOrLengthMask; } /// @dev Reads the bool at `rdPtr` in returndata. function readBool( ReturndataPointer rdPtr ) internal pure returns (bool value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the address at `rdPtr` in returndata. function readAddress( ReturndataPointer rdPtr ) internal pure returns (address value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes1 at `rdPtr` in returndata. function readBytes1( ReturndataPointer rdPtr ) internal pure returns (bytes1 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes2 at `rdPtr` in returndata. function readBytes2( ReturndataPointer rdPtr ) internal pure returns (bytes2 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes3 at `rdPtr` in returndata. function readBytes3( ReturndataPointer rdPtr ) internal pure returns (bytes3 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes4 at `rdPtr` in returndata. function readBytes4( ReturndataPointer rdPtr ) internal pure returns (bytes4 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes5 at `rdPtr` in returndata. function readBytes5( ReturndataPointer rdPtr ) internal pure returns (bytes5 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes6 at `rdPtr` in returndata. function readBytes6( ReturndataPointer rdPtr ) internal pure returns (bytes6 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes7 at `rdPtr` in returndata. function readBytes7( ReturndataPointer rdPtr ) internal pure returns (bytes7 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes8 at `rdPtr` in returndata. function readBytes8( ReturndataPointer rdPtr ) internal pure returns (bytes8 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes9 at `rdPtr` in returndata. function readBytes9( ReturndataPointer rdPtr ) internal pure returns (bytes9 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes10 at `rdPtr` in returndata. function readBytes10( ReturndataPointer rdPtr ) internal pure returns (bytes10 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes11 at `rdPtr` in returndata. function readBytes11( ReturndataPointer rdPtr ) internal pure returns (bytes11 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes12 at `rdPtr` in returndata. function readBytes12( ReturndataPointer rdPtr ) internal pure returns (bytes12 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes13 at `rdPtr` in returndata. function readBytes13( ReturndataPointer rdPtr ) internal pure returns (bytes13 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes14 at `rdPtr` in returndata. function readBytes14( ReturndataPointer rdPtr ) internal pure returns (bytes14 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes15 at `rdPtr` in returndata. function readBytes15( ReturndataPointer rdPtr ) internal pure returns (bytes15 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes16 at `rdPtr` in returndata. function readBytes16( ReturndataPointer rdPtr ) internal pure returns (bytes16 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes17 at `rdPtr` in returndata. function readBytes17( ReturndataPointer rdPtr ) internal pure returns (bytes17 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes18 at `rdPtr` in returndata. function readBytes18( ReturndataPointer rdPtr ) internal pure returns (bytes18 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes19 at `rdPtr` in returndata. function readBytes19( ReturndataPointer rdPtr ) internal pure returns (bytes19 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes20 at `rdPtr` in returndata. function readBytes20( ReturndataPointer rdPtr ) internal pure returns (bytes20 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes21 at `rdPtr` in returndata. function readBytes21( ReturndataPointer rdPtr ) internal pure returns (bytes21 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes22 at `rdPtr` in returndata. function readBytes22( ReturndataPointer rdPtr ) internal pure returns (bytes22 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes23 at `rdPtr` in returndata. function readBytes23( ReturndataPointer rdPtr ) internal pure returns (bytes23 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes24 at `rdPtr` in returndata. function readBytes24( ReturndataPointer rdPtr ) internal pure returns (bytes24 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes25 at `rdPtr` in returndata. function readBytes25( ReturndataPointer rdPtr ) internal pure returns (bytes25 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes26 at `rdPtr` in returndata. function readBytes26( ReturndataPointer rdPtr ) internal pure returns (bytes26 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes27 at `rdPtr` in returndata. function readBytes27( ReturndataPointer rdPtr ) internal pure returns (bytes27 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes28 at `rdPtr` in returndata. function readBytes28( ReturndataPointer rdPtr ) internal pure returns (bytes28 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes29 at `rdPtr` in returndata. function readBytes29( ReturndataPointer rdPtr ) internal pure returns (bytes29 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes30 at `rdPtr` in returndata. function readBytes30( ReturndataPointer rdPtr ) internal pure returns (bytes30 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes31 at `rdPtr` in returndata. function readBytes31( ReturndataPointer rdPtr ) internal pure returns (bytes31 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the bytes32 at `rdPtr` in returndata. function readBytes32( ReturndataPointer rdPtr ) internal pure returns (bytes32 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint8 at `rdPtr` in returndata. function readUint8( ReturndataPointer rdPtr ) internal pure returns (uint8 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint16 at `rdPtr` in returndata. function readUint16( ReturndataPointer rdPtr ) internal pure returns (uint16 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint24 at `rdPtr` in returndata. function readUint24( ReturndataPointer rdPtr ) internal pure returns (uint24 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint32 at `rdPtr` in returndata. function readUint32( ReturndataPointer rdPtr ) internal pure returns (uint32 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint40 at `rdPtr` in returndata. function readUint40( ReturndataPointer rdPtr ) internal pure returns (uint40 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint48 at `rdPtr` in returndata. function readUint48( ReturndataPointer rdPtr ) internal pure returns (uint48 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint56 at `rdPtr` in returndata. function readUint56( ReturndataPointer rdPtr ) internal pure returns (uint56 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint64 at `rdPtr` in returndata. function readUint64( ReturndataPointer rdPtr ) internal pure returns (uint64 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint72 at `rdPtr` in returndata. function readUint72( ReturndataPointer rdPtr ) internal pure returns (uint72 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint80 at `rdPtr` in returndata. function readUint80( ReturndataPointer rdPtr ) internal pure returns (uint80 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint88 at `rdPtr` in returndata. function readUint88( ReturndataPointer rdPtr ) internal pure returns (uint88 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint96 at `rdPtr` in returndata. function readUint96( ReturndataPointer rdPtr ) internal pure returns (uint96 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint104 at `rdPtr` in returndata. function readUint104( ReturndataPointer rdPtr ) internal pure returns (uint104 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint112 at `rdPtr` in returndata. function readUint112( ReturndataPointer rdPtr ) internal pure returns (uint112 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint120 at `rdPtr` in returndata. function readUint120( ReturndataPointer rdPtr ) internal pure returns (uint120 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint128 at `rdPtr` in returndata. function readUint128( ReturndataPointer rdPtr ) internal pure returns (uint128 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint136 at `rdPtr` in returndata. function readUint136( ReturndataPointer rdPtr ) internal pure returns (uint136 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint144 at `rdPtr` in returndata. function readUint144( ReturndataPointer rdPtr ) internal pure returns (uint144 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint152 at `rdPtr` in returndata. function readUint152( ReturndataPointer rdPtr ) internal pure returns (uint152 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint160 at `rdPtr` in returndata. function readUint160( ReturndataPointer rdPtr ) internal pure returns (uint160 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint168 at `rdPtr` in returndata. function readUint168( ReturndataPointer rdPtr ) internal pure returns (uint168 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint176 at `rdPtr` in returndata. function readUint176( ReturndataPointer rdPtr ) internal pure returns (uint176 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint184 at `rdPtr` in returndata. function readUint184( ReturndataPointer rdPtr ) internal pure returns (uint184 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint192 at `rdPtr` in returndata. function readUint192( ReturndataPointer rdPtr ) internal pure returns (uint192 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint200 at `rdPtr` in returndata. function readUint200( ReturndataPointer rdPtr ) internal pure returns (uint200 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint208 at `rdPtr` in returndata. function readUint208( ReturndataPointer rdPtr ) internal pure returns (uint208 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint216 at `rdPtr` in returndata. function readUint216( ReturndataPointer rdPtr ) internal pure returns (uint216 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint224 at `rdPtr` in returndata. function readUint224( ReturndataPointer rdPtr ) internal pure returns (uint224 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint232 at `rdPtr` in returndata. function readUint232( ReturndataPointer rdPtr ) internal pure returns (uint232 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint240 at `rdPtr` in returndata. function readUint240( ReturndataPointer rdPtr ) internal pure returns (uint240 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint248 at `rdPtr` in returndata. function readUint248( ReturndataPointer rdPtr ) internal pure returns (uint248 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the uint256 at `rdPtr` in returndata. function readUint256( ReturndataPointer rdPtr ) internal pure returns (uint256 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int8 at `rdPtr` in returndata. function readInt8( ReturndataPointer rdPtr ) internal pure returns (int8 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int16 at `rdPtr` in returndata. function readInt16( ReturndataPointer rdPtr ) internal pure returns (int16 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int24 at `rdPtr` in returndata. function readInt24( ReturndataPointer rdPtr ) internal pure returns (int24 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int32 at `rdPtr` in returndata. function readInt32( ReturndataPointer rdPtr ) internal pure returns (int32 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int40 at `rdPtr` in returndata. function readInt40( ReturndataPointer rdPtr ) internal pure returns (int40 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int48 at `rdPtr` in returndata. function readInt48( ReturndataPointer rdPtr ) internal pure returns (int48 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int56 at `rdPtr` in returndata. function readInt56( ReturndataPointer rdPtr ) internal pure returns (int56 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int64 at `rdPtr` in returndata. function readInt64( ReturndataPointer rdPtr ) internal pure returns (int64 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int72 at `rdPtr` in returndata. function readInt72( ReturndataPointer rdPtr ) internal pure returns (int72 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int80 at `rdPtr` in returndata. function readInt80( ReturndataPointer rdPtr ) internal pure returns (int80 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int88 at `rdPtr` in returndata. function readInt88( ReturndataPointer rdPtr ) internal pure returns (int88 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int96 at `rdPtr` in returndata. function readInt96( ReturndataPointer rdPtr ) internal pure returns (int96 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int104 at `rdPtr` in returndata. function readInt104( ReturndataPointer rdPtr ) internal pure returns (int104 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int112 at `rdPtr` in returndata. function readInt112( ReturndataPointer rdPtr ) internal pure returns (int112 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int120 at `rdPtr` in returndata. function readInt120( ReturndataPointer rdPtr ) internal pure returns (int120 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int128 at `rdPtr` in returndata. function readInt128( ReturndataPointer rdPtr ) internal pure returns (int128 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int136 at `rdPtr` in returndata. function readInt136( ReturndataPointer rdPtr ) internal pure returns (int136 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int144 at `rdPtr` in returndata. function readInt144( ReturndataPointer rdPtr ) internal pure returns (int144 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int152 at `rdPtr` in returndata. function readInt152( ReturndataPointer rdPtr ) internal pure returns (int152 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int160 at `rdPtr` in returndata. function readInt160( ReturndataPointer rdPtr ) internal pure returns (int160 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int168 at `rdPtr` in returndata. function readInt168( ReturndataPointer rdPtr ) internal pure returns (int168 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int176 at `rdPtr` in returndata. function readInt176( ReturndataPointer rdPtr ) internal pure returns (int176 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int184 at `rdPtr` in returndata. function readInt184( ReturndataPointer rdPtr ) internal pure returns (int184 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int192 at `rdPtr` in returndata. function readInt192( ReturndataPointer rdPtr ) internal pure returns (int192 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int200 at `rdPtr` in returndata. function readInt200( ReturndataPointer rdPtr ) internal pure returns (int200 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int208 at `rdPtr` in returndata. function readInt208( ReturndataPointer rdPtr ) internal pure returns (int208 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int216 at `rdPtr` in returndata. function readInt216( ReturndataPointer rdPtr ) internal pure returns (int216 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int224 at `rdPtr` in returndata. function readInt224( ReturndataPointer rdPtr ) internal pure returns (int224 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int232 at `rdPtr` in returndata. function readInt232( ReturndataPointer rdPtr ) internal pure returns (int232 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int240 at `rdPtr` in returndata. function readInt240( ReturndataPointer rdPtr ) internal pure returns (int240 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int248 at `rdPtr` in returndata. function readInt248( ReturndataPointer rdPtr ) internal pure returns (int248 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } /// @dev Reads the int256 at `rdPtr` in returndata. function readInt256( ReturndataPointer rdPtr ) internal pure returns (int256 value) { assembly { returndatacopy(0, rdPtr, _OneWord) value := mload(0) } } } library MemoryReaders { /// @dev Reads the memory pointer at `mPtr` in memory. function readMemoryPointer( MemoryPointer mPtr ) internal pure returns (MemoryPointer value) { assembly { value := mload(mPtr) } } /// @dev Reads value at `mPtr` & applies a mask to return only last 4 bytes function readMaskedUint256( MemoryPointer mPtr ) internal pure returns (uint256 value) { value = mPtr.readUint256() & OffsetOrLengthMask; } /// @dev Reads the bool at `mPtr` in memory. function readBool(MemoryPointer mPtr) internal pure returns (bool value) { assembly { value := mload(mPtr) } } /// @dev Reads the address at `mPtr` in memory. function readAddress( MemoryPointer mPtr ) internal pure returns (address value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes1 at `mPtr` in memory. function readBytes1( MemoryPointer mPtr ) internal pure returns (bytes1 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes2 at `mPtr` in memory. function readBytes2( MemoryPointer mPtr ) internal pure returns (bytes2 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes3 at `mPtr` in memory. function readBytes3( MemoryPointer mPtr ) internal pure returns (bytes3 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes4 at `mPtr` in memory. function readBytes4( MemoryPointer mPtr ) internal pure returns (bytes4 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes5 at `mPtr` in memory. function readBytes5( MemoryPointer mPtr ) internal pure returns (bytes5 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes6 at `mPtr` in memory. function readBytes6( MemoryPointer mPtr ) internal pure returns (bytes6 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes7 at `mPtr` in memory. function readBytes7( MemoryPointer mPtr ) internal pure returns (bytes7 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes8 at `mPtr` in memory. function readBytes8( MemoryPointer mPtr ) internal pure returns (bytes8 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes9 at `mPtr` in memory. function readBytes9( MemoryPointer mPtr ) internal pure returns (bytes9 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes10 at `mPtr` in memory. function readBytes10( MemoryPointer mPtr ) internal pure returns (bytes10 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes11 at `mPtr` in memory. function readBytes11( MemoryPointer mPtr ) internal pure returns (bytes11 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes12 at `mPtr` in memory. function readBytes12( MemoryPointer mPtr ) internal pure returns (bytes12 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes13 at `mPtr` in memory. function readBytes13( MemoryPointer mPtr ) internal pure returns (bytes13 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes14 at `mPtr` in memory. function readBytes14( MemoryPointer mPtr ) internal pure returns (bytes14 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes15 at `mPtr` in memory. function readBytes15( MemoryPointer mPtr ) internal pure returns (bytes15 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes16 at `mPtr` in memory. function readBytes16( MemoryPointer mPtr ) internal pure returns (bytes16 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes17 at `mPtr` in memory. function readBytes17( MemoryPointer mPtr ) internal pure returns (bytes17 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes18 at `mPtr` in memory. function readBytes18( MemoryPointer mPtr ) internal pure returns (bytes18 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes19 at `mPtr` in memory. function readBytes19( MemoryPointer mPtr ) internal pure returns (bytes19 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes20 at `mPtr` in memory. function readBytes20( MemoryPointer mPtr ) internal pure returns (bytes20 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes21 at `mPtr` in memory. function readBytes21( MemoryPointer mPtr ) internal pure returns (bytes21 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes22 at `mPtr` in memory. function readBytes22( MemoryPointer mPtr ) internal pure returns (bytes22 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes23 at `mPtr` in memory. function readBytes23( MemoryPointer mPtr ) internal pure returns (bytes23 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes24 at `mPtr` in memory. function readBytes24( MemoryPointer mPtr ) internal pure returns (bytes24 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes25 at `mPtr` in memory. function readBytes25( MemoryPointer mPtr ) internal pure returns (bytes25 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes26 at `mPtr` in memory. function readBytes26( MemoryPointer mPtr ) internal pure returns (bytes26 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes27 at `mPtr` in memory. function readBytes27( MemoryPointer mPtr ) internal pure returns (bytes27 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes28 at `mPtr` in memory. function readBytes28( MemoryPointer mPtr ) internal pure returns (bytes28 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes29 at `mPtr` in memory. function readBytes29( MemoryPointer mPtr ) internal pure returns (bytes29 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes30 at `mPtr` in memory. function readBytes30( MemoryPointer mPtr ) internal pure returns (bytes30 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes31 at `mPtr` in memory. function readBytes31( MemoryPointer mPtr ) internal pure returns (bytes31 value) { assembly { value := mload(mPtr) } } /// @dev Reads the bytes32 at `mPtr` in memory. function readBytes32( MemoryPointer mPtr ) internal pure returns (bytes32 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint8 at `mPtr` in memory. function readUint8(MemoryPointer mPtr) internal pure returns (uint8 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint16 at `mPtr` in memory. function readUint16( MemoryPointer mPtr ) internal pure returns (uint16 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint24 at `mPtr` in memory. function readUint24( MemoryPointer mPtr ) internal pure returns (uint24 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint32 at `mPtr` in memory. function readUint32( MemoryPointer mPtr ) internal pure returns (uint32 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint40 at `mPtr` in memory. function readUint40( MemoryPointer mPtr ) internal pure returns (uint40 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint48 at `mPtr` in memory. function readUint48( MemoryPointer mPtr ) internal pure returns (uint48 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint56 at `mPtr` in memory. function readUint56( MemoryPointer mPtr ) internal pure returns (uint56 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint64 at `mPtr` in memory. function readUint64( MemoryPointer mPtr ) internal pure returns (uint64 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint72 at `mPtr` in memory. function readUint72( MemoryPointer mPtr ) internal pure returns (uint72 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint80 at `mPtr` in memory. function readUint80( MemoryPointer mPtr ) internal pure returns (uint80 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint88 at `mPtr` in memory. function readUint88( MemoryPointer mPtr ) internal pure returns (uint88 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint96 at `mPtr` in memory. function readUint96( MemoryPointer mPtr ) internal pure returns (uint96 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint104 at `mPtr` in memory. function readUint104( MemoryPointer mPtr ) internal pure returns (uint104 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint112 at `mPtr` in memory. function readUint112( MemoryPointer mPtr ) internal pure returns (uint112 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint120 at `mPtr` in memory. function readUint120( MemoryPointer mPtr ) internal pure returns (uint120 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint128 at `mPtr` in memory. function readUint128( MemoryPointer mPtr ) internal pure returns (uint128 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint136 at `mPtr` in memory. function readUint136( MemoryPointer mPtr ) internal pure returns (uint136 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint144 at `mPtr` in memory. function readUint144( MemoryPointer mPtr ) internal pure returns (uint144 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint152 at `mPtr` in memory. function readUint152( MemoryPointer mPtr ) internal pure returns (uint152 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint160 at `mPtr` in memory. function readUint160( MemoryPointer mPtr ) internal pure returns (uint160 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint168 at `mPtr` in memory. function readUint168( MemoryPointer mPtr ) internal pure returns (uint168 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint176 at `mPtr` in memory. function readUint176( MemoryPointer mPtr ) internal pure returns (uint176 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint184 at `mPtr` in memory. function readUint184( MemoryPointer mPtr ) internal pure returns (uint184 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint192 at `mPtr` in memory. function readUint192( MemoryPointer mPtr ) internal pure returns (uint192 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint200 at `mPtr` in memory. function readUint200( MemoryPointer mPtr ) internal pure returns (uint200 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint208 at `mPtr` in memory. function readUint208( MemoryPointer mPtr ) internal pure returns (uint208 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint216 at `mPtr` in memory. function readUint216( MemoryPointer mPtr ) internal pure returns (uint216 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint224 at `mPtr` in memory. function readUint224( MemoryPointer mPtr ) internal pure returns (uint224 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint232 at `mPtr` in memory. function readUint232( MemoryPointer mPtr ) internal pure returns (uint232 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint240 at `mPtr` in memory. function readUint240( MemoryPointer mPtr ) internal pure returns (uint240 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint248 at `mPtr` in memory. function readUint248( MemoryPointer mPtr ) internal pure returns (uint248 value) { assembly { value := mload(mPtr) } } /// @dev Reads the uint256 at `mPtr` in memory. function readUint256( MemoryPointer mPtr ) internal pure returns (uint256 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int8 at `mPtr` in memory. function readInt8(MemoryPointer mPtr) internal pure returns (int8 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int16 at `mPtr` in memory. function readInt16(MemoryPointer mPtr) internal pure returns (int16 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int24 at `mPtr` in memory. function readInt24(MemoryPointer mPtr) internal pure returns (int24 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int32 at `mPtr` in memory. function readInt32(MemoryPointer mPtr) internal pure returns (int32 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int40 at `mPtr` in memory. function readInt40(MemoryPointer mPtr) internal pure returns (int40 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int48 at `mPtr` in memory. function readInt48(MemoryPointer mPtr) internal pure returns (int48 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int56 at `mPtr` in memory. function readInt56(MemoryPointer mPtr) internal pure returns (int56 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int64 at `mPtr` in memory. function readInt64(MemoryPointer mPtr) internal pure returns (int64 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int72 at `mPtr` in memory. function readInt72(MemoryPointer mPtr) internal pure returns (int72 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int80 at `mPtr` in memory. function readInt80(MemoryPointer mPtr) internal pure returns (int80 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int88 at `mPtr` in memory. function readInt88(MemoryPointer mPtr) internal pure returns (int88 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int96 at `mPtr` in memory. function readInt96(MemoryPointer mPtr) internal pure returns (int96 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int104 at `mPtr` in memory. function readInt104( MemoryPointer mPtr ) internal pure returns (int104 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int112 at `mPtr` in memory. function readInt112( MemoryPointer mPtr ) internal pure returns (int112 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int120 at `mPtr` in memory. function readInt120( MemoryPointer mPtr ) internal pure returns (int120 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int128 at `mPtr` in memory. function readInt128( MemoryPointer mPtr ) internal pure returns (int128 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int136 at `mPtr` in memory. function readInt136( MemoryPointer mPtr ) internal pure returns (int136 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int144 at `mPtr` in memory. function readInt144( MemoryPointer mPtr ) internal pure returns (int144 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int152 at `mPtr` in memory. function readInt152( MemoryPointer mPtr ) internal pure returns (int152 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int160 at `mPtr` in memory. function readInt160( MemoryPointer mPtr ) internal pure returns (int160 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int168 at `mPtr` in memory. function readInt168( MemoryPointer mPtr ) internal pure returns (int168 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int176 at `mPtr` in memory. function readInt176( MemoryPointer mPtr ) internal pure returns (int176 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int184 at `mPtr` in memory. function readInt184( MemoryPointer mPtr ) internal pure returns (int184 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int192 at `mPtr` in memory. function readInt192( MemoryPointer mPtr ) internal pure returns (int192 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int200 at `mPtr` in memory. function readInt200( MemoryPointer mPtr ) internal pure returns (int200 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int208 at `mPtr` in memory. function readInt208( MemoryPointer mPtr ) internal pure returns (int208 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int216 at `mPtr` in memory. function readInt216( MemoryPointer mPtr ) internal pure returns (int216 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int224 at `mPtr` in memory. function readInt224( MemoryPointer mPtr ) internal pure returns (int224 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int232 at `mPtr` in memory. function readInt232( MemoryPointer mPtr ) internal pure returns (int232 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int240 at `mPtr` in memory. function readInt240( MemoryPointer mPtr ) internal pure returns (int240 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int248 at `mPtr` in memory. function readInt248( MemoryPointer mPtr ) internal pure returns (int248 value) { assembly { value := mload(mPtr) } } /// @dev Reads the int256 at `mPtr` in memory. function readInt256( MemoryPointer mPtr ) internal pure returns (int256 value) { assembly { value := mload(mPtr) } } } library MemoryWriters { /// @dev Writes `valuePtr` to memory at `mPtr`. function write(MemoryPointer mPtr, MemoryPointer valuePtr) internal pure { assembly { mstore(mPtr, valuePtr) } } /// @dev Writes a boolean `value` to `mPtr` in memory. function write(MemoryPointer mPtr, bool value) internal pure { assembly { mstore(mPtr, value) } } /// @dev Writes an address `value` to `mPtr` in memory. function write(MemoryPointer mPtr, address value) internal pure { assembly { mstore(mPtr, value) } } /// @dev Writes a bytes32 `value` to `mPtr` in memory. /// Separate name to disambiguate literal write parameters. function writeBytes32(MemoryPointer mPtr, bytes32 value) internal pure { assembly { mstore(mPtr, value) } } /// @dev Writes a uint256 `value` to `mPtr` in memory. function write(MemoryPointer mPtr, uint256 value) internal pure { assembly { mstore(mPtr, value) } } /// @dev Writes an int256 `value` to `mPtr` in memory. /// Separate name to disambiguate literal write parameters. function writeInt(MemoryPointer mPtr, int256 value) internal pure { assembly { mstore(mPtr, value) } } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.7; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.19; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @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, it is bubbled up by this * function (like regular Solidity function calls). * * 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. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @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`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(target.code.length > 0, "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { AllowListData, CreatorPayout } from "./SeaDropStructs.sol"; /** * @notice A struct defining public drop data. * Designed to fit efficiently in two storage slots. * * @param startPrice The start price per token. (Up to 1.2m * of native token, e.g. ETH, MATIC) * @param endPrice The end price per token. If this differs * from startPrice, the current price will * be calculated based on the current time. * @param startTime The start time, ensure this is not zero. * @param endTime The end time, ensure this is not zero. * @param paymentToken The payment token address. Null for * native token. * @param maxTotalMintableByWallet Maximum total number of mints a user is * allowed. (The limit for this field is * 2^16 - 1) * @param feeBps Fee out of 10_000 basis points to be * collected. * @param restrictFeeRecipients If false, allow any fee recipient; * if true, check fee recipient is allowed. */ struct PublicDrop { uint80 startPrice; // 80/512 bits uint80 endPrice; // 160/512 bits uint40 startTime; // 200/512 bits uint40 endTime; // 240/512 bits address paymentToken; // 400/512 bits uint16 maxTotalMintableByWallet; // 416/512 bits uint16 feeBps; // 432/512 bits bool restrictFeeRecipients; // 440/512 bits } /** * @notice A struct defining mint params for an allow list. * An allow list leaf will be composed of `msg.sender` and * the following params. * * Note: Since feeBps is encoded in the leaf, backend should ensure * that feeBps is acceptable before generating a proof. * * @param startPrice The start price per token. (Up to 1.2m * of native token, e.g. ETH, MATIC) * @param endPrice The end price per token. If this differs * from startPrice, the current price will * be calculated based on the current time. * @param startTime The start time, ensure this is not zero. * @param endTime The end time, ensure this is not zero. * @param paymentToken The payment token for the mint. Null for * native token. * @param maxTotalMintableByWallet Maximum total number of mints a user is * allowed. * @param maxTokenSupplyForStage The limit of token supply this stage can * mint within. * @param dropStageIndex The drop stage index to emit with the event * for analytical purposes. This should be * non-zero since the public mint emits with * index zero. * @param feeBps Fee out of 10_000 basis points to be * collected. * @param restrictFeeRecipients If false, allow any fee recipient; * if true, check fee recipient is allowed. */ struct MintParams { uint256 startPrice; uint256 endPrice; uint256 startTime; uint256 endTime; address paymentToken; uint256 maxTotalMintableByWallet; uint256 maxTokenSupplyForStage; uint256 dropStageIndex; // non-zero uint256 feeBps; bool restrictFeeRecipients; } /** * @dev Struct containing internal SeaDrop implementation logic * mint details to avoid stack too deep. * * @param feeRecipient The fee recipient. * @param payer The payer of the mint. * @param minter The mint recipient. * @param quantity The number of tokens to mint. * @param withEffects Whether to apply state changes of the mint. */ struct MintDetails { address feeRecipient; address payer; address minter; uint256 quantity; bool withEffects; } /** * @notice A struct to configure multiple contract options in one transaction. */ struct MultiConfigureStruct { uint256 maxSupply; string baseURI; string contractURI; PublicDrop publicDrop; string dropURI; AllowListData allowListData; CreatorPayout[] creatorPayouts; bytes32 provenanceHash; address[] allowedFeeRecipients; address[] disallowedFeeRecipients; address[] allowedPayers; address[] disallowedPayers; // Server-signed address[] allowedSigners; address[] disallowedSigners; // ERC-2981 address royaltyReceiver; uint96 royaltyBps; // Mint address mintRecipient; uint256 mintQuantity; }
File 3 of 3: CreatorTokenTransferValidator
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "../Constants.sol"; import "../interfaces/IEOARegistry.sol"; import "../interfaces/ITransferValidator.sol"; import "./TransferPolicy.sol"; import {CreatorTokenTransferValidatorConfiguration} from "./CreatorTokenTransferValidatorConfiguration.sol"; import "@limitbreak/permit-c/PermitC.sol"; import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "@opensea/tstorish/Tstorish.sol"; /** * @title CreatorTokenTransferValidator * @author Limit Break, Inc. * @notice The CreatorTokenTransferValidator contract is designed to provide a customizable and secure transfer * validation mechanism for NFT collections. This contract allows the owner of an NFT collection to configure * the transfer security level, blacklisted accounts and codehashes, whitelisted accounts and codehashes, and * authorized accounts and codehashes for each collection. * * @dev <h4>Features</h4> * - Transfer security levels: Provides different levels of transfer security, * from open transfers to completely restricted transfers. * - Blacklist: Allows the owner of a collection to blacklist specific operator addresses or codehashes * from executing transfers on behalf of others. * - Whitelist: Allows the owner of a collection to whitelist specific operator addresses or codehashes * permitted to execute transfers on behalf of others or send/receive tokens when otherwise disabled by * security policy. * - Authorizers: Allows the owner of a collection to enable authorizer contracts, that can perform * authorization-based filtering of transfers. * * @dev <h4>Benefits</h4> * - Enhanced security: Allows creators to have more control over their NFT collections, ensuring the safety * and integrity of their assets. * - Flexibility: Provides collection owners the ability to customize transfer rules as per their requirements. * - Compliance: Facilitates compliance with regulations by enabling creators to restrict transfers based on * specific criteria. * * @dev <h4>Intended Usage</h4> * - The CreatorTokenTransferValidatorV3 contract is intended to be used by NFT collection owners to manage and * enforce transfer policies. This contract is integrated with the following varations of creator token * NFT contracts to validate transfers according to the defined security policies. * * - ERC721-C: Creator token implenting OpenZeppelin's ERC-721 standard. * - ERC721-AC: Creator token implenting Azuki's ERC-721A standard. * - ERC721-CW: Creator token implementing OpenZeppelin's ERC-721 standard with opt-in staking to * wrap/upgrade a pre-existing ERC-721 collection. * - ERC721-ACW: Creator token implementing Azuki's ERC721-A standard with opt-in staking to * wrap/upgrade a pre-existing ERC-721 collection. * - ERC1155-C: Creator token implenting OpenZeppelin's ERC-1155 standard. * - ERC1155-CW: Creator token implementing OpenZeppelin's ERC-1155 standard with opt-in staking to * wrap/upgrade a pre-existing ERC-1155 collection. * * <h4>Transfer Security Levels</h4> * - Recommended: Recommended defaults are same as Level 3 (Whitelisting with OTC Enabled). * - Caller Constraints: OperatorWhitelistEnableOTC * - Receiver Constraints: None * - Level 1: No transfer restrictions. * - Caller Constraints: None * - Receiver Constraints: None * - Level 2: Only non-blacklisted operators can initiate transfers, over-the-counter (OTC) trading enabled. * - Caller Constraints: OperatorBlacklistEnableOTC * - Receiver Constraints: None * - Level 3: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading enabled. * - Caller Constraints: OperatorWhitelistEnableOTC * - Receiver Constraints: None * - Level 4: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading disabled. * - Caller Constraints: OperatorWhitelistDisableOTC * - Receiver Constraints: None * - Level 5: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading enabled. * Transfers to contracts with code are not allowed, unless present on the whitelist. * - Caller Constraints: OperatorWhitelistEnableOTC * - Receiver Constraints: NoCode * - Level 6: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading enabled. * Transfers are allowed only to Externally Owned Accounts (EOAs), unless present on the whitelist. * - Caller Constraints: OperatorWhitelistEnableOTC * - Receiver Constraints: EOA * - Level 7: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading disabled. * Transfers to contracts with code are not allowed, unless present on the whitelist. * - Caller Constraints: OperatorWhitelistDisableOTC * - Receiver Constraints: NoCode * - Level 8: Only whitelisted accounts can initiate transfers, over-the-counter (OTC) trading disabled. * Transfers are allowed only to Externally Owned Accounts (EOAs), unless present on the whitelist. * - Caller Constraints: OperatorWhitelistDisableOTC * - Receiver Constraints: EOA */ contract CreatorTokenTransferValidator is IEOARegistry, ITransferValidator, ERC165, Tstorish, PermitC { using EnumerableSet for EnumerableSet.AddressSet; using EnumerableSet for EnumerableSet.Bytes32Set; /*************************************************************************/ /* CUSTOM ERRORS */ /*************************************************************************/ /// @dev Thrown when attempting to set a list id that does not exist. error CreatorTokenTransferValidator__ListDoesNotExist(); /// @dev Thrown when attempting to transfer the ownership of a list to the zero address. error CreatorTokenTransferValidator__ListOwnershipCannotBeTransferredToZeroAddress(); /// @dev Thrown when attempting to call a function that requires the caller to be the list owner. error CreatorTokenTransferValidator__CallerDoesNotOwnList(); /// @dev Thrown when validating a transfer for a collection using whitelists and the operator is not on the whitelist. error CreatorTokenTransferValidator__CallerMustBeWhitelisted(); /// @dev Thrown when authorizing a transfer for a collection using authorizers and the msg.sender is not in the authorizer list. error CreatorTokenTransferValidator__CallerMustBeAnAuthorizer(); /// @dev Thrown when attempting to call a function that requires owner or default admin role for a collection that the caller does not have. error CreatorTokenTransferValidator__CallerMustHaveElevatedPermissionsForSpecifiedNFT(); /// @dev Thrown when constructor args are not valid error CreatorTokenTransferValidator__InvalidConstructorArgs(); /// @dev Thrown when setting the transfer security level to an invalid value. error CreatorTokenTransferValidator__InvalidTransferSecurityLevel(); /// @dev Thrown when validating a transfer for a collection using blacklists and the operator is on the blacklist. error CreatorTokenTransferValidator__OperatorIsBlacklisted(); /// @dev Thrown when validating a transfer for a collection that does not allow receiver to have code and the receiver has code. error CreatorTokenTransferValidator__ReceiverMustNotHaveDeployedCode(); /// @dev Thrown when validating a transfer for a collection that requires receivers be verified EOAs and the receiver is not verified. error CreatorTokenTransferValidator__ReceiverProofOfEOASignatureUnverified(); /// @dev Thrown when a frozen account is the receiver of a transfer error CreatorTokenTransferValidator__ReceiverAccountIsFrozen(); /// @dev Thrown when a frozen account is the sender of a transfer error CreatorTokenTransferValidator__SenderAccountIsFrozen(); /// @dev Thrown when validating a transfer for a collection that is in soulbound token mode. error CreatorTokenTransferValidator__TokenIsSoulbound(); /// @dev Thrown when an authorizer attempts to set a wildcard authorized operator on collections that don't allow wildcards error CreatorTokenTransferValidator__WildcardOperatorsCannotBeAuthorizedForCollection(); /// @dev Thrown when attempting to set a authorized operator when authorization mode is disabled. error CreatorTokenTransferValidator__AuthorizationDisabledForCollection(); /// @dev Thrown when attempting to validate a permitted transfer where the permit type does not match the collection-defined token type. error CreatorTokenTransferValidator__TokenTypesDoNotMatch(); /*************************************************************************/ /* EVENTS */ /*************************************************************************/ /// @dev Emitted when a new list is created. event CreatedList(uint256 indexed id, string name); /// @dev Emitted when a list is applied to a collection. event AppliedListToCollection(address indexed collection, uint120 indexed id); /// @dev Emitted when the ownership of a list is transferred to a new owner. event ReassignedListOwnership(uint256 indexed id, address indexed newOwner); /// @dev Emitted when an account is added to the list of frozen accounts for a collection. event AccountFrozenForCollection(address indexed collection, address indexed account); /// @dev Emitted when an account is removed from the list of frozen accounts for a collection. event AccountUnfrozenForCollection(address indexed collection, address indexed account); /// @dev Emitted when an address is added to a list. event AddedAccountToList(uint8 indexed kind, uint256 indexed id, address indexed account); /// @dev Emitted when a codehash is added to a list. event AddedCodeHashToList(uint8 indexed kind, uint256 indexed id, bytes32 indexed codehash); /// @dev Emitted when an address is removed from a list. event RemovedAccountFromList(uint8 indexed kind, uint256 indexed id, address indexed account); /// @dev Emitted when a codehash is removed from a list. event RemovedCodeHashFromList(uint8 indexed kind, uint256 indexed id, bytes32 indexed codehash); /// @dev Emitted when the security level for a collection is updated. event SetTransferSecurityLevel(address indexed collection, uint8 level); /// @dev Emitted when a collection updates its authorization mode. event SetAuthorizationModeEnabled(address indexed collection, bool disabled, bool authorizersCannotSetWildcardOperators); /// @dev Emitted when a collection turns account freezing on or off. event SetAccountFreezingModeEnabled(address indexed collection, bool enabled); /// @dev Emitted when a collection's token type is updated. event SetTokenType(address indexed collection, uint16 tokenType); /*************************************************************************/ /* STRUCTS */ /*************************************************************************/ /** * @dev This struct is internally for the storage of account and codehash lists. */ struct List { EnumerableSet.AddressSet enumerableAccounts; EnumerableSet.Bytes32Set enumerableCodehashes; mapping (address => bool) nonEnumerableAccounts; mapping (bytes32 => bool) nonEnumerableCodehashes; } /** * @dev This struct is internally for the storage of account lists. */ struct AccountList { EnumerableSet.AddressSet enumerableAccounts; mapping (address => bool) nonEnumerableAccounts; } /*************************************************************************/ /* CONSTANTS */ /*************************************************************************/ /// @dev Immutable lookup table for constant gas determination of caller constraints by security level. /// @dev Created during contract construction using defined constants. uint256 private immutable _callerConstraintsLookup; /// @dev Immutable lookup table for constant gas determination of receiver constraints by security level. /// @dev Created during contract construction using defined constants. uint256 private immutable _receiverConstraintsLookup; /// @dev The address of the EOA Registry to use to validate an account is a verified EOA. address private immutable _eoaRegistry; /// @dev The legacy Creator Token Transfer Validator Interface bytes4 private constant LEGACY_TRANSFER_VALIDATOR_INTERFACE_ID = 0x00000000; /// @dev The default admin role value for contracts that implement access control. bytes32 private constant DEFAULT_ACCESS_CONTROL_ADMIN_ROLE = 0x00; /// @dev Value representing a zero value code hash. bytes32 private constant BYTES32_ZERO = 0x0000000000000000000000000000000000000000000000000000000000000000; address private constant WILDCARD_OPERATOR_ADDRESS = address(0x01); uint16 private constant DEFAULT_TOKEN_TYPE = 0; /*************************************************************************/ /* STORAGE */ /*************************************************************************/ /// @notice Keeps track of the most recently created list id. uint120 public lastListId; /// @notice Mapping of list ids to list owners mapping (uint120 => address) public listOwners; /// @dev Mapping of collection addresses to their security policy settings mapping (address => CollectionSecurityPolicyV3) internal collectionSecurityPolicies; /// @dev Mapping of list ids to blacklist settings mapping (uint120 => List) internal blacklists; /// @dev Mapping of list ids to whitelist settings mapping (uint120 => List) internal whitelists; /// @dev Mapping of list ids to authorizers mapping (uint120 => List) internal authorizers; /// @dev Mapping of collections to accounts that are frozen for those collections mapping (address => AccountList) internal frozenAccounts; constructor( address defaultOwner, address eoaRegistry_, string memory name, string memory version, address validatorConfiguration ) Tstorish() PermitC( name, version, defaultOwner, CreatorTokenTransferValidatorConfiguration(validatorConfiguration).getNativeValueToCheckPauseState() ) { if (defaultOwner == address(0) || eoaRegistry_ == address(0)) { revert CreatorTokenTransferValidator__InvalidConstructorArgs(); } _createDefaultList(defaultOwner); _eoaRegistry = eoaRegistry_; _callerConstraintsLookup = _constructCallerConstraintsTable(); _receiverConstraintsLookup = _constructReceiverConstraintsTable(); } /** * @dev This function is only called during contract construction to create the default list. */ function _createDefaultList(address defaultOwner) internal { uint120 id = 0; listOwners[id] = defaultOwner; emit CreatedList(id, "DEFAULT LIST"); emit ReassignedListOwnership(id, defaultOwner); } /** * @dev This function is only called during contract construction to create the caller constraints * @dev lookup table. */ function _constructCallerConstraintsTable() internal pure returns (uint256) { return (CALLER_CONSTRAINTS_OPERATOR_WHITELIST_ENABLE_OTC << (TRANSFER_SECURITY_LEVEL_RECOMMENDED << 3)) | (CALLER_CONSTRAINTS_NONE << (TRANSFER_SECURITY_LEVEL_ONE << 3)) | (CALLER_CONSTRAINTS_OPERATOR_BLACKLIST_ENABLE_OTC << (TRANSFER_SECURITY_LEVEL_TWO << 3)) | (CALLER_CONSTRAINTS_OPERATOR_WHITELIST_ENABLE_OTC << (TRANSFER_SECURITY_LEVEL_THREE << 3)) | (CALLER_CONSTRAINTS_OPERATOR_WHITELIST_DISABLE_OTC << (TRANSFER_SECURITY_LEVEL_FOUR << 3)) | (CALLER_CONSTRAINTS_OPERATOR_WHITELIST_ENABLE_OTC << (TRANSFER_SECURITY_LEVEL_FIVE << 3)) | (CALLER_CONSTRAINTS_OPERATOR_WHITELIST_ENABLE_OTC << (TRANSFER_SECURITY_LEVEL_SIX << 3)) | (CALLER_CONSTRAINTS_OPERATOR_WHITELIST_DISABLE_OTC << (TRANSFER_SECURITY_LEVEL_SEVEN << 3)) | (CALLER_CONSTRAINTS_OPERATOR_WHITELIST_DISABLE_OTC << (TRANSFER_SECURITY_LEVEL_EIGHT << 3)) | (CALLER_CONSTRAINTS_SBT << (TRANSFER_SECURITY_LEVEL_NINE << 3)); } /** * @dev This function is only called during contract construction to create the receiver constraints * @dev lookup table. */ function _constructReceiverConstraintsTable() internal pure returns (uint256) { return (RECEIVER_CONSTRAINTS_NONE << (TRANSFER_SECURITY_LEVEL_RECOMMENDED << 3)) | (RECEIVER_CONSTRAINTS_NONE << (TRANSFER_SECURITY_LEVEL_ONE << 3)) | (RECEIVER_CONSTRAINTS_NONE << (TRANSFER_SECURITY_LEVEL_TWO << 3)) | (RECEIVER_CONSTRAINTS_NONE << (TRANSFER_SECURITY_LEVEL_THREE << 3)) | (RECEIVER_CONSTRAINTS_NONE << (TRANSFER_SECURITY_LEVEL_FOUR << 3)) | (RECEIVER_CONSTRAINTS_NO_CODE << (TRANSFER_SECURITY_LEVEL_FIVE << 3)) | (RECEIVER_CONSTRAINTS_EOA << (TRANSFER_SECURITY_LEVEL_SIX << 3)) | (RECEIVER_CONSTRAINTS_NO_CODE << (TRANSFER_SECURITY_LEVEL_SEVEN << 3)) | (RECEIVER_CONSTRAINTS_EOA << (TRANSFER_SECURITY_LEVEL_EIGHT << 3)) | (RECEIVER_CONSTRAINTS_SBT << (TRANSFER_SECURITY_LEVEL_NINE << 3)); } /*************************************************************************/ /* MODIFIERS */ /*************************************************************************/ /** * @dev This modifier restricts a function call to the owner of the list `id`. * @dev Throws when the caller is not the list owner. */ modifier onlyListOwner(uint120 id) { _requireCallerOwnsList(id); _; } /*************************************************************************/ /* APPLY TRANSFER POLICIES */ /*************************************************************************/ /** * @notice Apply the collection transfer policy to a transfer operation of a creator token. * * @dev If the caller is self (Permit-C Processor) it means we have already applied operator validation in the * _beforeTransferFrom callback. In this case, the security policy was already applied and the operator * that used the Permit-C processor passed the security policy check and transfer can be safely allowed. * * @dev The order of checking whitelisted accounts, authorized operator check and whitelisted codehashes * is very deliberate. The order of operations is determined by the most frequently used settings that are * expected in the wild. * * @dev Throws when the collection has enabled account freezing mode and either the `from` or `to` addresses * are on the list of frozen accounts for the collection. * @dev Throws when the collection is set to Level 9 - Soulbound Token. * @dev Throws when the receiver has deployed code and isn't whitelisted, if ReceiverConstraints.NoCode is set * and the transfer is not approved by an authorizer for the collection. * @dev Throws when the receiver has never verified a signature to prove they are an EOA and the receiver * isn't whitelisted, if the ReceiverConstraints.EOA is set and the transfer is not approved by an * authorizer for the collection.. * @dev Throws when `msg.sender` is blacklisted, if CallerConstraints.OperatorBlacklistEnableOTC is set, unless * `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection. * @dev Throws when `msg.sender` isn't whitelisted, if CallerConstraints.OperatorWhitelistEnableOTC is set, unless * `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection. * @dev Throws when neither `msg.sender` nor `from` are whitelisted, if * CallerConstraints.OperatorWhitelistDisableOTC is set and the transfer * is not approved by an authorizer for the collection. * * @dev <h4>Postconditions:</h4> * 1. Transfer is allowed or denied based on the applied transfer policy. * * @param caller The address initiating the transfer. * @param from The address of the token owner. * @param to The address of the token receiver. */ function validateTransfer(address caller, address from, address to) public view { (bytes4 errorSelector,) = _validateTransfer(_callerAuthorizedCheckCollection, msg.sender, caller, from, to, 0); if (errorSelector != SELECTOR_NO_ERROR) { _revertCustomErrorSelectorAsm(errorSelector); } } /** * @notice Apply the collection transfer policy to a transfer operation of a creator token. * * @dev If the caller is self (Permit-C Processor) it means we have already applied operator validation in the * _beforeTransferFrom callback. In this case, the security policy was already applied and the operator * that used the Permit-C processor passed the security policy check and transfer can be safely allowed. * * @dev The order of checking whitelisted accounts, authorized operator check and whitelisted codehashes * is very deliberate. The order of operations is determined by the most frequently used settings that are * expected in the wild. * * @dev Throws when the collection has enabled account freezing mode and either the `from` or `to` addresses * are on the list of frozen accounts for the collection. * @dev Throws when the collection is set to Level 9 - Soulbound Token. * @dev Throws when the receiver has deployed code and isn't whitelisted, if ReceiverConstraints.NoCode is set * and the transfer is not approved by an authorizer for the collection. * @dev Throws when the receiver has never verified a signature to prove they are an EOA and the receiver * isn't whitelisted, if the ReceiverConstraints.EOA is set and the transfer is not approved by an * authorizer for the collection.. * @dev Throws when `msg.sender` is blacklisted, if CallerConstraints.OperatorBlacklistEnableOTC is set, unless * `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection. * @dev Throws when `msg.sender` isn't whitelisted, if CallerConstraints.OperatorWhitelistEnableOTC is set, unless * `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection. * @dev Throws when neither `msg.sender` nor `from` are whitelisted, if * CallerConstraints.OperatorWhitelistDisableOTC is set and the transfer * is not approved by an authorizer for the collection. * * @dev <h4>Postconditions:</h4> * 1. Transfer is allowed or denied based on the applied transfer policy. * * @param caller The address initiating the transfer. * @param from The address of the token owner. * @param to The address of the token receiver. * @param tokenId The token id being transferred. */ function validateTransfer(address caller, address from, address to, uint256 tokenId) public view { (bytes4 errorSelector,) = _validateTransfer(_callerAuthorizedCheckToken, msg.sender, caller, from, to, tokenId); if (errorSelector != SELECTOR_NO_ERROR) { _revertCustomErrorSelectorAsm(errorSelector); } } /** * @notice Apply the collection transfer policy to a transfer operation of a creator token. * * @dev If the caller is self (Permit-C Processor) it means we have already applied operator validation in the * _beforeTransferFrom callback. In this case, the security policy was already applied and the operator * that used the Permit-C processor passed the security policy check and transfer can be safely allowed. * * @dev The order of checking whitelisted accounts, authorized operator check and whitelisted codehashes * is very deliberate. The order of operations is determined by the most frequently used settings that are * expected in the wild. * * @dev Throws when the collection has enabled account freezing mode and either the `from` or `to` addresses * are on the list of frozen accounts for the collection. * @dev Throws when the collection is set to Level 9 - Soulbound Token. * @dev Throws when the receiver has deployed code and isn't whitelisted, if ReceiverConstraints.NoCode is set * and the transfer is not approved by an authorizer for the collection. * @dev Throws when the receiver has never verified a signature to prove they are an EOA and the receiver * isn't whitelisted, if the ReceiverConstraints.EOA is set and the transfer is not approved by an * authorizer for the collection.. * @dev Throws when `msg.sender` is blacklisted, if CallerConstraints.OperatorBlacklistEnableOTC is set, unless * `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection. * @dev Throws when `msg.sender` isn't whitelisted, if CallerConstraints.OperatorWhitelistEnableOTC is set, unless * `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection. * @dev Throws when neither `msg.sender` nor `from` are whitelisted, if * CallerConstraints.OperatorWhitelistDisableOTC is set and the transfer * is not approved by an authorizer for the collection. * * @dev <h4>Postconditions:</h4> * 1. Transfer is allowed or denied based on the applied transfer policy. * * @param caller The address initiating the transfer. * @param from The address of the token owner. * @param to The address of the token receiver. * @param tokenId The token id being transferred. */ function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 /*amount*/) external { validateTransfer(caller, from, to, tokenId); } /** * @notice Apply the collection transfer policy to a transfer operation of a creator token. * * @dev If the caller is self (Permit-C Processor) it means we have already applied operator validation in the * _beforeTransferFrom callback. In this case, the security policy was already applied and the operator * that used the Permit-C processor passed the security policy check and transfer can be safely allowed. * * @dev The order of checking whitelisted accounts, authorized operator check and whitelisted codehashes * is very deliberate. The order of operations is determined by the most frequently used settings that are * expected in the wild. * * @dev Throws when the collection has enabled account freezing mode and either the `from` or `to` addresses * are on the list of frozen accounts for the collection. * @dev Throws when the collection is set to Level 9 - Soulbound Token. * @dev Throws when the receiver has deployed code and isn't whitelisted, if ReceiverConstraints.NoCode is set * and the transfer is not approved by an authorizer for the collection. * @dev Throws when the receiver has never verified a signature to prove they are an EOA and the receiver * isn't whitelisted, if the ReceiverConstraints.EOA is set and the transfer is not approved by an * authorizer for the collection.. * @dev Throws when `msg.sender` is blacklisted, if CallerConstraints.OperatorBlacklistEnableOTC is set, unless * `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection. * @dev Throws when `msg.sender` isn't whitelisted, if CallerConstraints.OperatorWhitelistEnableOTC is set, unless * `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection. * @dev Throws when neither `msg.sender` nor `from` are whitelisted, if * CallerConstraints.OperatorWhitelistDisableOTC is set and the transfer * is not approved by an authorizer for the collection. * * @dev <h4>Postconditions:</h4> * 1. Transfer is allowed or denied based on the applied transfer policy. * * @param caller The address initiating the transfer. * @param from The address of the token owner. * @param to The address of the token receiver. */ function applyCollectionTransferPolicy(address caller, address from, address to) external view { validateTransfer(caller, from, to); } /** * @notice Returns the caller and receiver constraints for the specified transfer security level. * * @param level The transfer security level to return the caller and receiver constraints for. * * @return callerConstraints The `CallerConstraints` value for the level. * @return receiverConstraints The `ReceiverConstraints` value for the level. */ function transferSecurityPolicies( uint256 level ) public view returns (uint256 callerConstraints, uint256 receiverConstraints) { callerConstraints = uint8((_callerConstraintsLookup >> (level << 3))); receiverConstraints = uint8((_receiverConstraintsLookup >> (level << 3))); } /** * @notice Sets an operator for an authorized transfer that skips transfer security level * validation for caller and receiver constraints. * * @dev An authorizer *MUST* clear the authorization with a call to `afterAuthorizedTransfer` * to prevent unauthorized transfers of the token. * * @dev Throws when authorization mode is disabled for the collection. * @dev Throws when using the wildcard operator address and the collection does not allow * for wildcard authorized operators. * @dev Throws when the caller is not an allowed authorizer for the collection. * * @dev <h4>Postconditions:</h4> * 1. The `operator` is stored as an authorized operator for transfers. * * @param operator The address of the operator to set as authorized for transfers. * @param token The address of the token to authorize. * @param tokenId The token id to set the authorized operator for. */ function beforeAuthorizedTransfer(address operator, address token, uint256 tokenId) external { _setOperatorInTransientStorage(operator, token, tokenId, false); } /** * @notice Clears the authorized operator for a token to prevent additional transfers that * do not conform to the transfer security level for the token. * * @dev Throws when authorization mode is disabled for the collection. * @dev Throws when using the wildcard operator address and the collection does not allow * for wildcard authorized operators. * @dev Throws when the caller is not an allowed authorizer for the collection. * * @dev <h4>Postconditions:</h4> * 1. The authorized operator for the token is cleared from storage. * * @param token The address of the token to authorize. * @param tokenId The token id to set the authorized operator for. */ function afterAuthorizedTransfer(address token, uint256 tokenId) public { _setOperatorInTransientStorage(address(uint160(uint256(BYTES32_ZERO))), token, tokenId, false); } /** * @notice Sets an operator for an authorized transfer that skips transfer security level * validation for caller and receiver constraints. * @notice This overload of `beforeAuthorizedTransfer` defaults to a tokenId of 0. * * @dev An authorizer *MUST* clear the authorization with a call to `afterAuthorizedTransfer` * to prevent unauthorized transfers of the token. * * @dev Throws when authorization mode is disabled for the collection. * @dev Throws when using the wildcard operator address and the collection does not allow * for wildcard authorized operators. * @dev Throws when the caller is not an allowed authorizer for the collection. * * @dev <h4>Postconditions:</h4> * 1. The `operator` is stored as an authorized operator for transfers. * * @param operator The address of the operator to set as authorized for transfers. * @param token The address of the token to authorize. */ function beforeAuthorizedTransfer(address operator, address token) external { _setOperatorInTransientStorage(operator, token, 0, true); } /** * @notice Clears the authorized operator for a token to prevent additional transfers that * do not conform to the transfer security level for the token. * @notice This overload of `afterAuthorizedTransfer` defaults to a tokenId of 0. * * @dev Throws when authorization mode is disabled for the collection. * @dev Throws when using the wildcard operator address and the collection does not allow * for wildcard authorized operators. * @dev Throws when the caller is not an allowed authorizer for the collection. * * @dev <h4>Postconditions:</h4> * 1. The authorized operator for the token is cleared from storage. * * @param token The address of the token to authorize. */ function afterAuthorizedTransfer(address token) external { afterAuthorizedTransfer(token, 0); } /** * @notice Sets the wildcard operator to authorize any operator to transfer a token while * skipping transfer security level validation for caller and receiver constraints. * * @dev An authorizer *MUST* clear the authorization with a call to `afterAuthorizedTransfer` * to prevent unauthorized transfers of the token. * * @dev Throws when authorization mode is disabled for the collection. * @dev Throws when the collection does not allow for wildcard authorized operators. * @dev Throws when the caller is not an allowed authorizer for the collection. * * @dev <h4>Postconditions:</h4> * 1. The wildcard operator is stored as an authorized operator for transfers. * * @param token The address of the token to authorize. * @param tokenId The token id to set the authorized operator for. */ function beforeAuthorizedTransfer(address token, uint256 tokenId) external { _setOperatorInTransientStorage(WILDCARD_OPERATOR_ADDRESS, token, tokenId, false); } /** * @notice Sets the wildcard operator to authorize any operator to transfer a token while * skipping transfer security level validation for caller and receiver constraints. * * @dev An authorizer *MUST* clear the authorization with a call to `afterAuthorizedTransfer` * to prevent unauthorized transfers of the token. * * @dev Throws when authorization mode is disabled for the collection. * @dev Throws when the collection does not allow for wildcard authorized operators. * @dev Throws when the caller is not an allowed authorizer for the collection. * * @dev <h4>Postconditions:</h4> * 1. The wildcard operator is stored as an authorized operator for transfers. * * @param token The address of the token to authorize. * @param tokenId The token id to set the authorized operator for. */ function beforeAuthorizedTransferWithAmount(address token, uint256 tokenId, uint256 /*amount*/) external { _setOperatorInTransientStorage(WILDCARD_OPERATOR_ADDRESS, token, tokenId, false); } /** * @notice Clears the authorized operator for a token to prevent additional transfers that * do not conform to the transfer security level for the token. * * @dev Throws when authorization mode is disabled for the collection. * @dev Throws when using the wildcard operator address and the collection does not allow * for wildcard authorized operators. * @dev Throws when the caller is not an allowed authorizer for the collection. * * @dev <h4>Postconditions:</h4> * 1. The authorized operator for the token is cleared from storage. * * @param token The address of the token to authorize. * @param tokenId The token id to set the authorized operator for. */ function afterAuthorizedTransferWithAmount(address token, uint256 tokenId) external { afterAuthorizedTransfer(token, tokenId); } /*************************************************************************/ /* LIST MANAGEMENT */ /*************************************************************************/ /** * @notice Creates a new list id. The list id is a handle to allow editing of blacklisted and whitelisted accounts * and codehashes. * * @dev <h4>Postconditions:</h4> * 1. A new list with the specified name is created. * 2. The caller is set as the owner of the new list. * 3. A `CreatedList` event is emitted. * 4. A `ReassignedListOwnership` event is emitted. * * @param name The name of the new list. * @return id The id of the new list. */ function createList(string calldata name) public returns (uint120 id) { unchecked { id = ++lastListId; } listOwners[id] = msg.sender; emit CreatedList(id, name); emit ReassignedListOwnership(id, msg.sender); } /** * @notice Creates a new list id, and copies all blacklisted and whitelisted accounts and codehashes from the * specified source list. * * @dev <h4>Postconditions:</h4> * 1. A new list with the specified name is created. * 2. The caller is set as the owner of the new list. * 3. A `CreatedList` event is emitted. * 4. A `ReassignedListOwnership` event is emitted. * 5. All blacklisted and whitelisted accounts and codehashes from the specified source list are copied * to the new list. * 6. An `AddedAccountToList` event is emitted for each blacklisted and whitelisted account copied. * 7. An `AddedCodeHashToList` event is emitted for each blacklisted and whitelisted codehash copied. * * @param name The name of the new list. * @param sourceListId The id of the source list to copy from. * @return id The id of the new list. */ function createListCopy(string calldata name, uint120 sourceListId) external returns (uint120 id) { unchecked { id = ++lastListId; } unchecked { if (sourceListId > id - 1) { revert CreatorTokenTransferValidator__ListDoesNotExist(); } } listOwners[id] = msg.sender; emit CreatedList(id, name); emit ReassignedListOwnership(id, msg.sender); List storage sourceBlacklist = blacklists[sourceListId]; List storage sourceWhitelist = whitelists[sourceListId]; List storage sourceAuthorizers = authorizers[sourceListId]; List storage targetBlacklist = blacklists[id]; List storage targetWhitelist = whitelists[id]; List storage targetAuthorizers = authorizers[id]; _copyAddressSet(LIST_TYPE_BLACKLIST, id, sourceBlacklist, targetBlacklist); _copyBytes32Set(LIST_TYPE_BLACKLIST, id, sourceBlacklist, targetBlacklist); _copyAddressSet(LIST_TYPE_WHITELIST, id, sourceWhitelist, targetWhitelist); _copyBytes32Set(LIST_TYPE_WHITELIST, id, sourceWhitelist, targetWhitelist); _copyAddressSet(LIST_TYPE_AUTHORIZERS, id, sourceAuthorizers, targetAuthorizers); _copyBytes32Set(LIST_TYPE_AUTHORIZERS, id, sourceAuthorizers, targetAuthorizers); } /** * @notice Transfer ownership of a list to a new owner. * * @dev Throws when the new owner is the zero address. * @dev Throws when the caller does not own the specified list. * * @dev <h4>Postconditions:</h4> * 1. The list ownership is transferred to the new owner. * 2. A `ReassignedListOwnership` event is emitted. * * @param id The id of the list. * @param newOwner The address of the new owner. */ function reassignOwnershipOfList(uint120 id, address newOwner) public { if(newOwner == address(0)) { revert CreatorTokenTransferValidator__ListOwnershipCannotBeTransferredToZeroAddress(); } _reassignOwnershipOfList(id, newOwner); } /** * @notice Renounce the ownership of a list, rendering the list immutable. * * @dev Throws when the caller does not own the specified list. * * @dev <h4>Postconditions:</h4> * 1. The ownership of the specified list is renounced. * 2. A `ReassignedListOwnership` event is emitted. * * @param id The id of the list. */ function renounceOwnershipOfList(uint120 id) public { _reassignOwnershipOfList(id, address(0)); } /** * @notice Set the transfer security level, authorization mode and account freezing mode settings of a collection. * * @dev Throws when the caller is neither collection contract, nor the owner or admin of the specified collection. * * @dev <h4>Postconditions:</h4> * 1. The transfer security level of the specified collection is set to the new value. * 2. The authorization mode setting of the specified collection is set to the new value. * 3. The authorization wildcard operator mode setting of the specified collection is set to the new value. * 4. The account freezing mode setting of the specified collection is set to the new value. * 5. A `SetTransferSecurityLevel` event is emitted. * 6. A `SetAuthorizationModeEnabled` event is emitted. * 7. A `SetAccountFreezingModeEnabled` event is emitted. * * @param collection The address of the collection. * @param level The new transfer security level to apply. * @param disableAuthorizationMode Flag if the collection allows for authorizer mode. * @param disableWildcardOperators Flag if the authorizer can set wildcard operators. * @param enableAccountFreezingMode Flag if the collection is using account freezing. */ function setTransferSecurityLevelOfCollection( address collection, uint8 level, bool disableAuthorizationMode, bool disableWildcardOperators, bool enableAccountFreezingMode) external { if (level > TRANSFER_SECURITY_LEVEL_NINE) { revert CreatorTokenTransferValidator__InvalidTransferSecurityLevel(); } _requireCallerIsNFTOrContractOwnerOrAdmin(collection); collectionSecurityPolicies[collection].transferSecurityLevel = level; collectionSecurityPolicies[collection].disableAuthorizationMode = disableAuthorizationMode; collectionSecurityPolicies[collection].authorizersCannotSetWildcardOperators = disableWildcardOperators; collectionSecurityPolicies[collection].enableAccountFreezingMode = enableAccountFreezingMode; emit SetTransferSecurityLevel(collection, level); emit SetAuthorizationModeEnabled(collection, disableAuthorizationMode, disableWildcardOperators); emit SetAccountFreezingModeEnabled(collection, enableAccountFreezingMode); } /** * @notice Set the token type setting of a collection. * * @dev Throws when the caller is neither collection contract, nor the owner or admin of the specified collection. * * @dev <h4>Postconditions:</h4> * 1. The token type of the specified collection is set to the new value. * 2. A `SetTokenType` event is emitted. * * @param collection The address of the collection. * @param tokenType The new transfer security level to apply. */ function setTokenTypeOfCollection( address collection, uint16 tokenType ) external { _requireCallerIsNFTOrContractOwnerOrAdmin(collection); collectionSecurityPolicies[collection].tokenType = tokenType; emit SetTokenType(collection, tokenType); } /** * @notice Applies the specified list to a collection. * * @dev Throws when the caller is neither collection contract, nor the owner or admin of the specified collection. * @dev Throws when the specified list id does not exist. * * @dev <h4>Postconditions:</h4> * 1. The list of the specified collection is set to the new value. * 2. An `AppliedListToCollection` event is emitted. * * @param collection The address of the collection. * @param id The id of the operator whitelist. */ function applyListToCollection(address collection, uint120 id) public { _requireCallerIsNFTOrContractOwnerOrAdmin(collection); if (id > lastListId) { revert CreatorTokenTransferValidator__ListDoesNotExist(); } collectionSecurityPolicies[collection].listId = id; emit AppliedListToCollection(collection, id); } /** * @notice Adds accounts to the frozen accounts list of a collection. * * @dev Throws when the caller is neither collection contract, nor the owner or admin of the specified collection. * * @dev <h4>Postconditions:</h4> * 1. The accounts are added to the list of frozen accounts for a collection. * 2. A `AccountFrozenForCollection` event is emitted for each account added to the list. * * @param collection The address of the collection. * @param accountsToFreeze The list of accounts to added to frozen accounts. */ function freezeAccountsForCollection(address collection, address[] calldata accountsToFreeze) external { _requireCallerIsNFTOrContractOwnerOrAdmin(collection); AccountList storage accounts = frozenAccounts[collection]; for (uint256 i = 0; i < accountsToFreeze.length;) { address accountToFreeze = accountsToFreeze[i]; if (accounts.enumerableAccounts.add(accountToFreeze)) { emit AccountFrozenForCollection(collection, accountToFreeze); accounts.nonEnumerableAccounts[accountToFreeze] = true; } unchecked { ++i; } } } /** * @notice Removes accounts to the frozen accounts list of a collection. * * @dev Throws when the caller is neither collection contract, nor the owner or admin of the specified collection. * * @dev <h4>Postconditions:</h4> * 1. The accounts are removed from the list of frozen accounts for a collection. * 2. A `AccountUnfrozenForCollection` event is emitted for each account removed from the list. * * @param collection The address of the collection. * @param accountsToUnfreeze The list of accounts to remove from frozen accounts. */ function unfreezeAccountsForCollection(address collection, address[] calldata accountsToUnfreeze) external { _requireCallerIsNFTOrContractOwnerOrAdmin(collection); AccountList storage accounts = frozenAccounts[collection]; for (uint256 i = 0; i < accountsToUnfreeze.length;) { address accountToUnfreeze = accountsToUnfreeze[i]; if (accounts.enumerableAccounts.remove(accountToUnfreeze)) { emit AccountUnfrozenForCollection(collection, accountToUnfreeze); accounts.nonEnumerableAccounts[accountToUnfreeze] = false; } unchecked { ++i; } } } /** * @notice Get the security policy of the specified collection. * @param collection The address of the collection. * @return The security policy of the specified collection, which includes: * Transfer security level, operator whitelist id, permitted contract receiver allowlist id, * authorizer mode, if authorizer can set a wildcard operator, and if account freezing is * enabled. */ function getCollectionSecurityPolicy( address collection ) external view returns (CollectionSecurityPolicyV3 memory) { return collectionSecurityPolicies[collection]; } /** * @notice Adds one or more accounts to a blacklist. * * @dev Throws when the caller does not own the specified list. * @dev Throws when the accounts array is empty. * * @dev <h4>Postconditions:</h4> * 1. Accounts not previously in the list are added. * 2. An `AddedAccountToList` event is emitted for each account that is newly added to the list. * * @param id The id of the list. * @param accounts The addresses of the accounts to add. */ function addAccountsToBlacklist( uint120 id, address[] calldata accounts ) external { _addAccountsToList(blacklists[id], LIST_TYPE_BLACKLIST, id, accounts); } /** * @notice Adds one or more accounts to a whitelist. * * @dev Throws when the caller does not own the specified list. * @dev Throws when the accounts array is empty. * * @dev <h4>Postconditions:</h4> * 1. Accounts not previously in the list are added. * 2. An `AddedAccountToList` event is emitted for each account that is newly added to the list. * * @param id The id of the list. * @param accounts The addresses of the accounts to add. */ function addAccountsToWhitelist( uint120 id, address[] calldata accounts ) external { _addAccountsToList(whitelists[id], LIST_TYPE_WHITELIST, id, accounts); } /** * @notice Adds one or more accounts to authorizers. * * @dev Throws when the caller does not own the specified list. * @dev Throws when the accounts array is empty. * * @dev <h4>Postconditions:</h4> * 1. Accounts not previously in the list are added. * 2. An `AddedAccountToList` event is emitted for each account that is newly added to the list. * * @param id The id of the list. * @param accounts The addresses of the accounts to add. */ function addAccountsToAuthorizers( uint120 id, address[] calldata accounts ) external { _addAccountsToList(authorizers[id], LIST_TYPE_AUTHORIZERS, id, accounts); } /** * @notice Adds one or more codehashes to a blacklist. * * @dev Throws when the caller does not own the specified list. * @dev Throws when the codehashes array is empty. * @dev Throws when a codehash is zero. * * @dev <h4>Postconditions:</h4> * 1. Codehashes not previously in the list are added. * 2. An `AddedCodeHashToList` event is emitted for each codehash that is newly added to the list. * * @param id The id of the list. * @param codehashes The codehashes to add. */ function addCodeHashesToBlacklist( uint120 id, bytes32[] calldata codehashes ) external { _addCodeHashesToList(blacklists[id], LIST_TYPE_BLACKLIST, id, codehashes); } /** * @notice Adds one or more codehashes to a whitelist. * * @dev Throws when the caller does not own the specified list. * @dev Throws when the codehashes array is empty. * @dev Throws when a codehash is zero. * * @dev <h4>Postconditions:</h4> * 1. Codehashes not previously in the list are added. * 2. An `AddedCodeHashToList` event is emitted for each codehash that is newly added to the list. * * @param id The id of the list. * @param codehashes The codehashes to add. */ function addCodeHashesToWhitelist( uint120 id, bytes32[] calldata codehashes ) external { _addCodeHashesToList(whitelists[id], LIST_TYPE_WHITELIST, id, codehashes); } /** * @notice Removes one or more accounts from a blacklist. * * @dev Throws when the caller does not own the specified list. * @dev Throws when the accounts array is empty. * * @dev <h4>Postconditions:</h4> * 1. Accounts previously in the list are removed. * 2. A `RemovedAccountFromList` event is emitted for each account that is removed from the list. * * @param id The id of the list. * @param accounts The addresses of the accounts to remove. */ function removeAccountsFromBlacklist( uint120 id, address[] calldata accounts ) external { _removeAccountsFromList(blacklists[id], LIST_TYPE_BLACKLIST, id, accounts); } /** * @notice Removes one or more accounts from a whitelist. * * @dev Throws when the caller does not own the specified list. * @dev Throws when the accounts array is empty. * * @dev <h4>Postconditions:</h4> * 1. Accounts previously in the list are removed. * 2. A `RemovedAccountFromList` event is emitted for each account that is removed from the list. * * @param id The id of the list. * @param accounts The addresses of the accounts to remove. */ function removeAccountsFromWhitelist( uint120 id, address[] calldata accounts ) external { _removeAccountsFromList(whitelists[id], LIST_TYPE_WHITELIST, id, accounts); } /** * @notice Removes one or more accounts from authorizers. * * @dev Throws when the caller does not own the specified list. * @dev Throws when the accounts array is empty. * * @dev <h4>Postconditions:</h4> * 1. Accounts previously in the list are removed. * 2. A `RemovedAccountFromList` event is emitted for each account that is removed from the list. * * @param id The id of the list. * @param accounts The addresses of the accounts to remove. */ function removeAccountsFromAuthorizers( uint120 id, address[] calldata accounts ) external { _removeAccountsFromList(authorizers[id], LIST_TYPE_AUTHORIZERS, id, accounts); } /** * @notice Removes one or more codehashes from a blacklist. * * @dev Throws when the caller does not own the specified list. * @dev Throws when the codehashes array is empty. * * @dev <h4>Postconditions:</h4> * 1. Codehashes previously in the list are removed. * 2. A `RemovedCodeHashFromList` event is emitted for each codehash that is removed from the list. * * @param id The id of the list. * @param codehashes The codehashes to remove. */ function removeCodeHashesFromBlacklist( uint120 id, bytes32[] calldata codehashes ) external { _removeCodeHashesFromList(blacklists[id], LIST_TYPE_BLACKLIST, id, codehashes); } /** * @notice Removes one or more codehashes from a whitelist. * * @dev Throws when the caller does not own the specified list. * @dev Throws when the codehashes array is empty. * * @dev <h4>Postconditions:</h4> * 1. Codehashes previously in the list are removed. * 2. A `RemovedCodeHashFromList` event is emitted for each codehash that is removed from the list. * * @param id The id of the list. * @param codehashes The codehashes to remove. */ function removeCodeHashesFromWhitelist( uint120 id, bytes32[] calldata codehashes ) external { _removeCodeHashesFromList(whitelists[id], LIST_TYPE_WHITELIST, id, codehashes); } /** * @notice Get blacklisted accounts by list id. * @param id The id of the list. * @return An array of blacklisted accounts. */ function getBlacklistedAccounts(uint120 id) public view returns (address[] memory) { return blacklists[id].enumerableAccounts.values(); } /** * @notice Get whitelisted accounts by list id. * @param id The id of the list. * @return An array of whitelisted accounts. */ function getWhitelistedAccounts(uint120 id) public view returns (address[] memory) { return whitelists[id].enumerableAccounts.values(); } /** * @notice Get authorizor accounts by list id. * @param id The id of the list. * @return An array of authorizer accounts. */ function getAuthorizerAccounts(uint120 id) public view returns (address[] memory) { return authorizers[id].enumerableAccounts.values(); } /** * @notice Get blacklisted codehashes by list id. * @param id The id of the list. * @return An array of blacklisted codehashes. */ function getBlacklistedCodeHashes(uint120 id) public view returns (bytes32[] memory) { return blacklists[id].enumerableCodehashes.values(); } /** * @notice Get whitelisted codehashes by list id. * @param id The id of the list. * @return An array of whitelisted codehashes. */ function getWhitelistedCodeHashes(uint120 id) public view returns (bytes32[] memory) { return whitelists[id].enumerableCodehashes.values(); } /** * @notice Check if an account is blacklisted in a specified list. * @param id The id of the list. * @param account The address of the account to check. * @return True if the account is blacklisted in the specified list, false otherwise. */ function isAccountBlacklisted(uint120 id, address account) public view returns (bool) { return blacklists[id].nonEnumerableAccounts[account]; } /** * @notice Check if an account is whitelisted in a specified list. * @param id The id of the list. * @param account The address of the account to check. * @return True if the account is whitelisted in the specified list, false otherwise. */ function isAccountWhitelisted(uint120 id, address account) public view returns (bool) { return whitelists[id].nonEnumerableAccounts[account]; } /** * @notice Check if an account is an authorizer in a specified list. * @param id The id of the list. * @param account The address of the account to check. * @return True if the account is an authorizer in the specified list, false otherwise. */ function isAccountAuthorizer(uint120 id, address account) public view returns (bool) { return authorizers[id].nonEnumerableAccounts[account]; } /** * @notice Check if a codehash is blacklisted in a specified list. * @param id The id of the list. * @param codehash The codehash to check. * @return True if the codehash is blacklisted in the specified list, false otherwise. */ function isCodeHashBlacklisted(uint120 id, bytes32 codehash) public view returns (bool) { return blacklists[id].nonEnumerableCodehashes[codehash]; } /** * @notice Check if a codehash is whitelisted in a specified list. * @param id The id of the list. * @param codehash The codehash to check. * @return True if the codehash is whitelisted in the specified list, false otherwise. */ function isCodeHashWhitelisted(uint120 id, bytes32 codehash) public view returns (bool) { return whitelists[id].nonEnumerableCodehashes[codehash]; } /** * @notice Get blacklisted accounts by collection. * @param collection The address of the collection. * @return An array of blacklisted accounts. */ function getBlacklistedAccountsByCollection(address collection) external view returns (address[] memory) { return getBlacklistedAccounts(collectionSecurityPolicies[collection].listId); } /** * @notice Get whitelisted accounts by collection. * @param collection The address of the collection. * @return An array of whitelisted accounts. */ function getWhitelistedAccountsByCollection(address collection) external view returns (address[] memory) { return getWhitelistedAccounts(collectionSecurityPolicies[collection].listId); } /** * @notice Get authorizer accounts by collection. * @param collection The address of the collection. * @return An array of authorizer accounts. */ function getAuthorizerAccountsByCollection(address collection) external view returns (address[] memory) { return getAuthorizerAccounts(collectionSecurityPolicies[collection].listId); } /** * @notice Get frozen accounts by collection. * @param collection The address of the collection. * @return An array of frozen accounts. */ function getFrozenAccountsByCollection(address collection) external view returns (address[] memory) { return frozenAccounts[collection].enumerableAccounts.values(); } /** * @notice Get blacklisted codehashes by collection. * @param collection The address of the collection. * @return An array of blacklisted codehashes. */ function getBlacklistedCodeHashesByCollection(address collection) external view returns (bytes32[] memory) { return getBlacklistedCodeHashes(collectionSecurityPolicies[collection].listId); } /** * @notice Get whitelisted codehashes by collection. * @param collection The address of the collection. * @return An array of whitelisted codehashes. */ function getWhitelistedCodeHashesByCollection(address collection) external view returns (bytes32[] memory) { return getWhitelistedCodeHashes(collectionSecurityPolicies[collection].listId); } /** * @notice Check if an account is blacklisted by a specified collection. * @param collection The address of the collection. * @param account The address of the account to check. * @return True if the account is blacklisted by the specified collection, false otherwise. */ function isAccountBlacklistedByCollection(address collection, address account) external view returns (bool) { return isAccountBlacklisted(collectionSecurityPolicies[collection].listId, account); } /** * @notice Check if an account is whitelisted by a specified collection. * @param collection The address of the collection. * @param account The address of the account to check. * @return True if the account is whitelisted by the specified collection, false otherwise. */ function isAccountWhitelistedByCollection(address collection, address account) external view returns (bool) { return isAccountWhitelisted(collectionSecurityPolicies[collection].listId, account); } /** * @notice Check if an account is an authorizer of a specified collection. * @param collection The address of the collection. * @param account The address of the account to check. * @return True if the account is an authorizer by the specified collection, false otherwise. */ function isAccountAuthorizerOfCollection(address collection, address account) external view returns (bool) { return isAccountAuthorizer(collectionSecurityPolicies[collection].listId, account); } /** * @notice Check if an account is frozen for a specified collection. * @param collection The address of the collection. * @param account The address of the account to check. * @return True if the account is frozen by the specified collection, false otherwise. */ function isAccountFrozenForCollection(address collection, address account) external view returns (bool) { return frozenAccounts[collection].nonEnumerableAccounts[account]; } /** * @notice Check if a codehash is blacklisted by a specified collection. * @param collection The address of the collection. * @param codehash The codehash to check. * @return True if the codehash is blacklisted by the specified collection, false otherwise. */ function isCodeHashBlacklistedByCollection(address collection, bytes32 codehash) external view returns (bool) { return isCodeHashBlacklisted(collectionSecurityPolicies[collection].listId, codehash); } /** * @notice Check if a codehash is whitelisted by a specified collection. * @param collection The address of the collection. * @param codehash The codehash to check. * @return True if the codehash is whitelisted by the specified collection, false otherwise. */ function isCodeHashWhitelistedByCollection(address collection, bytes32 codehash) external view returns (bool) { return isCodeHashWhitelisted(collectionSecurityPolicies[collection].listId, codehash); } /// @notice Returns true if the specified account has verified a signature on the registry, false otherwise. function isVerifiedEOA(address account) public view returns (bool) { return IEOARegistry(_eoaRegistry).isVerifiedEOA(account); } /// @notice ERC-165 Interface Support /// @dev Do not remove LEGACY from this contract or future contracts. /// Doing so will break backwards compatibility with V1 and V2 creator tokens. function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == LEGACY_TRANSFER_VALIDATOR_INTERFACE_ID || interfaceId == type(ITransferValidator).interfaceId || interfaceId == type(IPermitC).interfaceId || interfaceId == type(IEOARegistry).interfaceId || super.supportsInterface(interfaceId); } /*************************************************************************/ /* HELPERS */ /*************************************************************************/ /** * @notice Reverts the transaction if the caller is not the owner or assigned the default * @notice admin role of the contract at `tokenAddress`. * * @dev Throws when the caller is neither owner nor assigned the default admin role. * * @param tokenAddress The contract address of the token to check permissions for. */ function _requireCallerIsNFTOrContractOwnerOrAdmin(address tokenAddress) internal view { address caller = msg.sender; if(caller == tokenAddress) { return; } (address contractOwner,) = _safeOwner(tokenAddress); if(caller == contractOwner) { return; } (bool callerIsContractAdmin,) = _safeHasRole(tokenAddress, DEFAULT_ACCESS_CONTROL_ADMIN_ROLE, caller); if(callerIsContractAdmin) { return; } revert CreatorTokenTransferValidator__CallerMustHaveElevatedPermissionsForSpecifiedNFT(); } /** * @notice Copies all addresses in `ptrFromList` to `ptrToList`. * * @dev This function will copy all addresses from one list to another list. * @dev Note: If used to copy adddresses to an existing list the current list contents will not be * @dev deleted before copying. New addresses will be appeneded to the end of the list and the * @dev non-enumerable mapping key value will be set to true. * * @dev <h4>Postconditions:</h4> * 1. Addresses in from list that are not already present in to list are added to the to list. * 2. Emits an `AddedAccountToList` event for each address copied to the list. * * @param listType The type of list addresses are being copied from and to. * @param destinationListId The id of the list being copied to. * @param ptrFromList The storage pointer for the list being copied from. * @param ptrToList The storage pointer for the list being copied to. */ function _copyAddressSet( uint8 listType, uint120 destinationListId, List storage ptrFromList, List storage ptrToList ) private { EnumerableSet.AddressSet storage ptrFromSet = ptrFromList.enumerableAccounts; EnumerableSet.AddressSet storage ptrToSet = ptrToList.enumerableAccounts; mapping (address => bool) storage ptrToNonEnumerableSet = ptrToList.nonEnumerableAccounts; uint256 sourceLength = ptrFromSet.length(); address account; for (uint256 i = 0; i < sourceLength;) { account = ptrFromSet.at(i); if (ptrToSet.add(account)) { emit AddedAccountToList(listType, destinationListId, account); ptrToNonEnumerableSet[account] = true; } unchecked { ++i; } } } /** * @notice Copies all codehashes in `ptrFromList` to `ptrToList`. * * @dev This function will copy all codehashes from one list to another list. * @dev Note: If used to copy codehashes to an existing list the current list contents will not be * @dev deleted before copying. New codehashes will be appeneded to the end of the list and the * @dev non-enumerable mapping key value will be set to true. * * @dev <h4>Postconditions:</h4> * 1. Codehashes in from list that are not already present in to list are added to the to list. * 2. Emits an `AddedCodeHashToList` event for each codehash copied to the list. * * @param listType The type of list codehashes are being copied from and to. * @param destinationListId The id of the list being copied to. * @param ptrFromList The storage pointer for the list being copied from. * @param ptrToList The storage pointer for the list being copied to. */ function _copyBytes32Set( uint8 listType, uint120 destinationListId, List storage ptrFromList, List storage ptrToList ) private { EnumerableSet.Bytes32Set storage ptrFromSet = ptrFromList.enumerableCodehashes; EnumerableSet.Bytes32Set storage ptrToSet = ptrToList.enumerableCodehashes; mapping (bytes32 => bool) storage ptrToNonEnumerableSet = ptrToList.nonEnumerableCodehashes; uint256 sourceLength = ptrFromSet.length(); bytes32 codehash; for (uint256 i = 0; i < sourceLength;) { codehash = ptrFromSet.at(i); if (ptrToSet.add(codehash)) { emit AddedCodeHashToList(listType, destinationListId, codehash); ptrToNonEnumerableSet[codehash] = true; } unchecked { ++i; } } } /** * @notice Adds one or more accounts to a list. * * @dev <h4>Postconditions:</h4> * 1. Accounts that were not previously in the list are added to the list. * 2. An `AddedAccountToList` event is emitted for each account that was not * previously on the list. * * @param list The storage pointer for the list to add accounts to. * @param listType The type of list the accounts are being added to. * @param id The id of the list the accounts are being added to. * @param accounts An array of accounts to add to the list. */ function _addAccountsToList( List storage list, uint8 listType, uint120 id, address[] calldata accounts ) internal onlyListOwner(id) { address account; for (uint256 i = 0; i < accounts.length;) { account = accounts[i]; if (list.enumerableAccounts.add(account)) { emit AddedAccountToList(listType, id, account); list.nonEnumerableAccounts[account] = true; } unchecked { ++i; } } } /** * @notice Adds one or more codehashes to a list. * * @dev <h4>Postconditions:</h4> * 1. Codehashes that were not previously in the list are added to the list. * 2. An `AddedCodeHashToList` event is emitted for each codehash that was not * previously on the list. * * @param list The storage pointer for the list to add codehashes to. * @param listType The type of list the codehashes are being added to. * @param id The id of the list the codehashes are being added to. * @param codehashes An array of codehashes to add to the list. */ function _addCodeHashesToList( List storage list, uint8 listType, uint120 id, bytes32[] calldata codehashes ) internal onlyListOwner(id) { bytes32 codehash; for (uint256 i = 0; i < codehashes.length;) { codehash = codehashes[i]; if (list.enumerableCodehashes.add(codehash)) { emit AddedCodeHashToList(listType, id, codehash); list.nonEnumerableCodehashes[codehash] = true; } unchecked { ++i; } } } /** * @notice Removes one or more accounts from a list. * * @dev <h4>Postconditions:</h4> * 1. Accounts that were previously in the list are removed from the list. * 2. An `RemovedAccountFromList` event is emitted for each account that was * previously on the list. * * @param list The storage pointer for the list to remove accounts from. * @param listType The type of list the accounts are being removed from. * @param id The id of the list the accounts are being removed from. * @param accounts An array of accounts to remove from the list. */ function _removeAccountsFromList( List storage list, uint8 listType, uint120 id, address[] memory accounts ) internal onlyListOwner(id) { address account; for (uint256 i = 0; i < accounts.length;) { account = accounts[i]; if (list.enumerableAccounts.remove(account)) { emit RemovedAccountFromList(listType, id, account); delete list.nonEnumerableAccounts[account]; } unchecked { ++i; } } } /** * @notice Removes one or more codehashes from a list. * * @dev <h4>Postconditions:</h4> * 1. Codehashes that were previously in the list are removed from the list. * 2. An `RemovedCodeHashFromList` event is emitted for each codehash that was * previously on the list. * * @param list The storage pointer for the list to remove codehashes from. * @param listType The type of list the codehashes are being removed from. * @param id The id of the list the codehashes are being removed from. * @param codehashes An array of codehashes to remove from the list. */ function _removeCodeHashesFromList( List storage list, uint8 listType, uint120 id, bytes32[] calldata codehashes ) internal onlyListOwner(id) { bytes32 codehash; for (uint256 i = 0; i < codehashes.length;) { codehash = codehashes[i]; if (list.enumerableCodehashes.remove(codehash)) { emit RemovedCodeHashFromList(listType, id, codehash); delete list.nonEnumerableCodehashes[codehash]; } unchecked { ++i; } } } /** * @notice Sets the owner of list `id` to `newOwner`. * * @dev Throws when the caller is not the owner of the list. * * @dev <h4>Postconditions:</h4> * 1. The owner of list `id` is set to `newOwner`. * 2. Emits a `ReassignedListOwnership` event. * * @param id The id of the list to reassign ownership of. * @param newOwner The account to assign ownership of the list to. */ function _reassignOwnershipOfList(uint120 id, address newOwner) private { _requireCallerOwnsList(id); listOwners[id] = newOwner; emit ReassignedListOwnership(id, newOwner); } /** * @notice Requires the caller to be the owner of list `id`. * * @dev Throws when the caller is not the owner of the list. * * @param id The id of the list to check ownership of. */ function _requireCallerOwnsList(uint120 id) private view { if (msg.sender != listOwners[id]) { revert CreatorTokenTransferValidator__CallerDoesNotOwnList(); } } /** * @dev Internal function used to efficiently retrieve the code length of `account`. * * @param account The address to get the deployed code length for. * * @return length The length of deployed code at the address. */ function _getCodeLengthAsm(address account) internal view returns (uint256 length) { assembly { length := extcodesize(account) } } /** * @dev Internal function used to efficiently retrieve the codehash of `account`. * * @param account The address to get the deployed codehash for. * * @return codehash The codehash of the deployed code at the address. */ function _getCodeHashAsm(address account) internal view returns (bytes32 codehash) { assembly { codehash := extcodehash(account) } } /** * @dev Hook that is called before any permitted token transfer that goes through Permit-C. * Applies the collection transfer policy, using the operator that called Permit-C as the caller. * This allows creator token standard protections to extend to permitted transfers. * * @param token The collection address of the token being transferred. * @param from The address of the token owner. * @param to The address of the token receiver. * @param id The token id being transferred. */ function _beforeTransferFrom( uint256 tokenType, address token, address from, address to, uint256 id, uint256 /*amount*/ ) internal override returns (bool isError) { (bytes4 selector, uint16 collectionTokenType) = _validateTransfer(_callerAuthorizedCheckToken, token, msg.sender, from, to, id); if (collectionTokenType == DEFAULT_TOKEN_TYPE || collectionTokenType == tokenType) { isError = SELECTOR_NO_ERROR != selector; } else { revert CreatorTokenTransferValidator__TokenTypesDoNotMatch(); } } /** * @notice Apply the collection transfer policy to a transfer operation of a creator token. * * @dev If the caller is self (Permit-C Processor) it means we have already applied operator validation in the * _beforeTransferFrom callback. In this case, the security policy was already applied and the operator * that used the Permit-C processor passed the security policy check and transfer can be safely allowed. * * @dev The order of checking whitelisted accounts, authorized operator check and whitelisted codehashes * is very deliberate. The order of operations is determined by the most frequently used settings that are * expected in the wild. * * @dev Throws when the collection has enabled account freezing mode and either the `from` or `to` addresses * are on the list of frozen accounts for the collection. * @dev Throws when the collection is set to Level 9 - Soulbound Token. * @dev Throws when the receiver has deployed code and isn't whitelisted, if ReceiverConstraints.NoCode is set * and the transfer is not approved by an authorizer for the collection. * @dev Throws when the receiver has never verified a signature to prove they are an EOA and the receiver * isn't whitelisted, if the ReceiverConstraints.EOA is set and the transfer is not approved by an * authorizer for the collection.. * @dev Throws when `msg.sender` is blacklisted, if CallerConstraints.OperatorBlacklistEnableOTC is set, unless * `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection. * @dev Throws when `msg.sender` isn't whitelisted, if CallerConstraints.OperatorWhitelistEnableOTC is set, unless * `msg.sender` is also the `from` address or the transfer is approved by an authorizer for the collection. * @dev Throws when neither `msg.sender` nor `from` are whitelisted, if * CallerConstraints.OperatorWhitelistDisableOTC is set and the transfer * is not approved by an authorizer for the collection. * * @dev <h4>Postconditions:</h4> * 1. Transfer is allowed or denied based on the applied transfer policy. * * @param collection The collection address of the token being transferred. * @param caller The address initiating the transfer. * @param from The address of the token owner. * @param to The address of the token receiver. * @param tokenId The token id being transferred. * * @return The selector value for an error if the transfer is not allowed, `SELECTOR_NO_ERROR` if the transfer is allowed. */ function _validateTransfer( function(address,address,uint256) internal view returns(bool) _callerAuthorizedParam, address collection, address caller, address from, address to, uint256 tokenId ) internal view returns (bytes4,uint16) { if (caller == address(this)) { // If the caller is self (Permit-C Processor) it means we have already applied operator validation in the // _beforeTransferFrom callback. In this case, the security policy was already applied and the operator // that used the Permit-C processor passed the security policy check and transfer can be safely allowed. return (SELECTOR_NO_ERROR, DEFAULT_TOKEN_TYPE); } CollectionSecurityPolicyV3 storage collectionSecurityPolicy = collectionSecurityPolicies[collection]; uint120 listId = collectionSecurityPolicy.listId; (uint256 callerConstraints, uint256 receiverConstraints) = transferSecurityPolicies(collectionSecurityPolicy.transferSecurityLevel); if (collectionSecurityPolicy.enableAccountFreezingMode) { AccountList storage frozenAccountList = frozenAccounts[collection]; if (frozenAccountList.nonEnumerableAccounts[from]) { return (CreatorTokenTransferValidator__SenderAccountIsFrozen.selector, DEFAULT_TOKEN_TYPE); } if (frozenAccountList.nonEnumerableAccounts[to]) { return (CreatorTokenTransferValidator__ReceiverAccountIsFrozen.selector, DEFAULT_TOKEN_TYPE); } } if (callerConstraints == CALLER_CONSTRAINTS_SBT) { return (CreatorTokenTransferValidator__TokenIsSoulbound.selector, DEFAULT_TOKEN_TYPE); } List storage whitelist = whitelists[listId]; if (receiverConstraints == RECEIVER_CONSTRAINTS_NO_CODE) { if (_getCodeLengthAsm(to) > 0) { if (!whitelist.nonEnumerableAccounts[to]) { // Cache _callerAuthorizedParam on stack to avoid stack too deep function(address,address,uint256) internal view returns(bool) _callerAuthorized = _callerAuthorizedParam; if(!_callerAuthorized(collection, caller, tokenId)) { if (!whitelist.nonEnumerableCodehashes[_getCodeHashAsm(to)]) { return (CreatorTokenTransferValidator__ReceiverMustNotHaveDeployedCode.selector, DEFAULT_TOKEN_TYPE); } } } } } else if (receiverConstraints == RECEIVER_CONSTRAINTS_EOA) { if (!isVerifiedEOA(to)) { if (!whitelist.nonEnumerableAccounts[to]) { // Cache _callerAuthorizedParam on stack to avoid stack too deep function(address,address,uint256) internal view returns(bool) _callerAuthorized = _callerAuthorizedParam; if(!_callerAuthorized(collection, caller, tokenId)) { if (!whitelist.nonEnumerableCodehashes[_getCodeHashAsm(to)]) { return (CreatorTokenTransferValidator__ReceiverProofOfEOASignatureUnverified.selector, DEFAULT_TOKEN_TYPE); } } } } } if (caller == from) { if (callerConstraints != CALLER_CONSTRAINTS_OPERATOR_WHITELIST_DISABLE_OTC) { return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType); } } if (callerConstraints == CALLER_CONSTRAINTS_OPERATOR_BLACKLIST_ENABLE_OTC) { // Cache _callerAuthorizedParam on stack to avoid stack too deep function(address,address,uint256) internal view returns(bool) _callerAuthorized = _callerAuthorizedParam; if(_callerAuthorized(collection, caller, tokenId)) { return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType); } List storage blacklist = blacklists[listId]; if (blacklist.nonEnumerableAccounts[caller]) { return (CreatorTokenTransferValidator__OperatorIsBlacklisted.selector, DEFAULT_TOKEN_TYPE); } if (blacklist.nonEnumerableCodehashes[_getCodeHashAsm(caller)]) { return (CreatorTokenTransferValidator__OperatorIsBlacklisted.selector, DEFAULT_TOKEN_TYPE); } } else if (callerConstraints == CALLER_CONSTRAINTS_OPERATOR_WHITELIST_ENABLE_OTC) { if (whitelist.nonEnumerableAccounts[caller]) { return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType); } // Cache _callerAuthorizedParam on stack to avoid stack too deep function(address,address,uint256) internal view returns(bool) _callerAuthorized = _callerAuthorizedParam; if( _callerAuthorized(collection, caller, tokenId)) { return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType); } if (whitelist.nonEnumerableCodehashes[_getCodeHashAsm(caller)]) { return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType); } return (CreatorTokenTransferValidator__CallerMustBeWhitelisted.selector, DEFAULT_TOKEN_TYPE); } else if (callerConstraints == CALLER_CONSTRAINTS_OPERATOR_WHITELIST_DISABLE_OTC) { mapping(address => bool) storage accountWhitelist = whitelist.nonEnumerableAccounts; if (accountWhitelist[caller]) { return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType); } if (accountWhitelist[from]) { return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType); } // Cache _callerAuthorizedParam on stack to avoid stack too deep function(address,address,uint256) internal view returns(bool) _callerAuthorized = _callerAuthorizedParam; if(_callerAuthorized(collection, caller, tokenId)) { return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType); } mapping(bytes32 => bool) storage codehashWhitelist = whitelist.nonEnumerableCodehashes; // Cache caller on stack to avoid stack too deep address tmpAddress = caller; if (codehashWhitelist[_getCodeHashAsm(tmpAddress)]) { return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType); } // Cache from on stack to avoid stack too deep tmpAddress = from; if (codehashWhitelist[_getCodeHashAsm(tmpAddress)]) { return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType); } return (CreatorTokenTransferValidator__CallerMustBeWhitelisted.selector, DEFAULT_TOKEN_TYPE); } return (SELECTOR_NO_ERROR, collectionSecurityPolicy.tokenType); } /** * @dev Internal function used to efficiently revert with a custom error selector. * * @param errorSelector The error selector to revert with. */ function _revertCustomErrorSelectorAsm(bytes4 errorSelector) internal pure { assembly { mstore(0x00, errorSelector) revert(0x00, 0x04) } } /** * @dev Internal function used to check if authorization mode can be activated for a transfer. * * @dev Throws when the collection has not enabled authorization mode. * @dev Throws when the wildcard operator is being set for a collection that does not * allow wildcard operators. * @dev Throws when the authorizer is not in the list of approved authorizers for * the collection. * * @param collection The collection address to activate authorization mode for a transfer. * @param operator The operator specified by the authorizer to allow transfers. * @param authorizer The address of the authorizer making the call. */ function _checkCollectionAllowsAuthorizerAndOperator( address collection, address operator, address authorizer ) internal view { CollectionSecurityPolicyV3 storage collectionSecurityPolicy = collectionSecurityPolicies[collection]; if (collectionSecurityPolicy.disableAuthorizationMode) { revert CreatorTokenTransferValidator__AuthorizationDisabledForCollection(); } if (collectionSecurityPolicy.authorizersCannotSetWildcardOperators) { if (operator == WILDCARD_OPERATOR_ADDRESS) { revert CreatorTokenTransferValidator__WildcardOperatorsCannotBeAuthorizedForCollection(); } } if (!authorizers[collectionSecurityPolicy.listId].nonEnumerableAccounts[authorizer]) { revert CreatorTokenTransferValidator__CallerMustBeAnAuthorizer(); } } /** * @dev Modifier to apply the allowed authorizer and operator for collection checks. * * @dev Throws when the collection has not enabled authorization mode. * @dev Throws when the wildcard operator is being set for a collection that does not * allow wildcard operators. * @dev Throws when the authorizer is not in the list of approved authorizers for * the collection. * * @param collection The collection address to activate authorization mode for a transfer. * @param operator The operator specified by the authorizer to allow transfers. * @param authorizer The address of the authorizer making the call. */ modifier whenAuthorizerAndOperatorEnabledForCollection( address collection, address operator, address authorizer ) { _checkCollectionAllowsAuthorizerAndOperator(collection, operator, authorizer); _; } /** * @dev Internal function for setting the authorized operator in storage for a token and collection. * * @param operator The allowed operator for an authorized transfer. * @param collection The address of the collection that the operator is authorized for. * @param tokenId The id of the token that is authorized. * @param allowAnyTokenId Flag if the authorizer is enabling transfers for any token id */ function _setOperatorInTransientStorage( address operator, address collection, uint256 tokenId, bool allowAnyTokenId ) internal whenAuthorizerAndOperatorEnabledForCollection(collection, operator, msg.sender) { _setTstorish(_getTransientOperatorSlot(collection), (allowAnyTokenId ? 1 << 255 : 0) | uint256(uint160(operator))); _setTstorish(_getTransientOperatorSlot(collection, tokenId), uint256(uint160(operator))); } /** * @dev Internal function to check if a caller is an authorized operator for the token being transferred. * * @param caller The caller of the token transfer. * @param collection The collection address of the token being transferred. * @param tokenId The id of the token being transferred. * * @return isAuthorized True if the caller is authorized to transfer the token, false otherwise. */ function _callerAuthorizedCheckToken( address collection, address caller, uint256 tokenId ) internal view returns (bool isAuthorized) { uint256 slotValue; (isAuthorized, ) = _callerAuthorized(caller, _getTransientOperatorSlot(collection, tokenId)); if (isAuthorized) return true; (isAuthorized, slotValue) = _callerAuthorized(caller, _getTransientOperatorSlot(collection)); isAuthorized = isAuthorized && slotValue >> 255 == 1; } /** * @dev Internal function to check if a caller is an authorized operator for the collection being transferred. * * @param caller The caller of the token transfer. * @param collection The collection address of the token being transferred. * * @return isAuthorized True if the caller is authorized to transfer the collection, false otherwise. */ function _callerAuthorizedCheckCollection( address collection, address caller, uint256 /*tokenId*/ ) internal view returns (bool isAuthorized) { (isAuthorized, ) = _callerAuthorized(caller, _getTransientOperatorSlot(collection)); } /** * @dev Internal function to check if a caller is an authorized operator. * @dev This overload of `_callerAuthorized` checks a specific storage slot for the caller address. * * @param caller The caller of the token transfer. * @param slot The storage slot to check for the caller address. * * @return isAuthorized True if the caller is authorized to transfer the token, false otherwise. * @return slotValue The transient storage value in `slot`, used to check for allow any token id flag if necessary. */ function _callerAuthorized(address caller, uint256 slot) internal view returns (bool isAuthorized, uint256 slotValue) { slotValue = _getTstorish(slot); address authorizedOperator = address(uint160(slotValue)); isAuthorized = authorizedOperator == WILDCARD_OPERATOR_ADDRESS || authorizedOperator == caller; } /** * @dev Internal function used to compute the transient storage slot for the authorized * operator of a token in a collection. * * @param collection The collection address of the token being transferred. * @param tokenId The id of the token being transferred. * * @return operatorSlot The storage slot location for the authorized operator value. */ function _getTransientOperatorSlot( address collection, uint256 tokenId ) internal pure returns (uint256 operatorSlot) { assembly { mstore(0x00, collection) mstore(0x20, tokenId) operatorSlot := shr(4, keccak256(0x00, 0x40)) } } /** * @dev Internal function used to compute the transient storage slot for the authorized operator of a collection. * * @param collection The collection address of the token being transferred. * * @return operatorSlot The storage slot location for the authorized operator value. */ function _getTransientOperatorSlot(address collection) internal pure returns (uint256 operatorSlot) { return uint256(uint160(collection)); } /** * @dev A gas efficient, and fallback-safe way to call the owner function on a token contract. * This will get the owner if it exists - and when the function is unimplemented, the * presence of a fallback function will not result in halted execution. * * @param tokenAddress The address of the token collection to get the owner of. * * @return owner The owner of the token collection contract. * @return isError True if there was an error in retrieving the owner, false if the call was successful. */ function _safeOwner( address tokenAddress ) internal view returns(address owner, bool isError) { assembly { function _callOwner(_tokenAddress) -> _owner, _isError { mstore(0x00, 0x8da5cb5b) if and(iszero(lt(returndatasize(), 0x20)), staticcall(gas(), _tokenAddress, 0x1C, 0x04, 0x00, 0x20)) { _owner := mload(0x00) leave } _isError := true } owner, isError := _callOwner(tokenAddress) } } /** * @dev A gas efficient, and fallback-safe way to call the hasRole function on a token contract. * This will check if the account `hasRole` if `hasRole` exists - and when the function is unimplemented, the * presence of a fallback function will not result in halted execution. * * @param tokenAddress The address of the token collection to call hasRole on. * @param role The role to check if the account has on the collection. * @param account The address of the account to check if they have a specified role. * * @return hasRole The owner of the token collection contract. * @return isError True if there was an error in retrieving the owner, false if the call was successful. */ function _safeHasRole( address tokenAddress, bytes32 role, address account ) internal view returns(bool hasRole, bool isError) { assembly { function _callHasRole(_tokenAddress, _role, _account) -> _hasRole, _isError { let ptr := mload(0x40) mstore(0x40, add(ptr, 0x60)) mstore(ptr, 0x91d14854) mstore(add(0x20, ptr), _role) mstore(add(0x40, ptr), _account) if and(iszero(lt(returndatasize(), 0x20)), staticcall(gas(), _tokenAddress, add(ptr, 0x1C), 0x44, 0x00, 0x20)) { _hasRole := mload(0x00) leave } _isError := true } hasRole, isError := _callHasRole(tokenAddress, role, account) } } }// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /** * @dev Constant definitions for receiver constraints used by the transfer validator. */ /// @dev No constraints on the receiver of a token. uint256 constant RECEIVER_CONSTRAINTS_NONE = 0; /// @dev Token receiver cannot have deployed code. uint256 constant RECEIVER_CONSTRAINTS_NO_CODE = 1; /// @dev Token receiver must be a verified EOA with the EOA Registry. uint256 constant RECEIVER_CONSTRAINTS_EOA = 2; /// @dev Token is a soulbound token and cannot be transferred. uint256 constant RECEIVER_CONSTRAINTS_SBT = 3; /** * @dev Constant definitions for caller constraints used by the transfer validator. */ /// @dev No constraints on the caller of a token transfer. uint256 constant CALLER_CONSTRAINTS_NONE = 0; /// @dev Caller of a token transfer must not be on the blacklist unless it is an OTC transfer. uint256 constant CALLER_CONSTRAINTS_OPERATOR_BLACKLIST_ENABLE_OTC = 1; /// @dev Caller of a token transfer must be on the whitelist unless it is an OTC transfer. uint256 constant CALLER_CONSTRAINTS_OPERATOR_WHITELIST_ENABLE_OTC = 2; /// @dev Caller of a token transfer must be on the whitelist. uint256 constant CALLER_CONSTRAINTS_OPERATOR_WHITELIST_DISABLE_OTC = 3; /// @dev Token is a soulbound token and cannot be transferred. uint256 constant CALLER_CONSTRAINTS_SBT = 4; /** * @dev Constant definitions for transfer security levels used by the transfer validator * to define what receiver and caller constraints are applied to a transfer. */ /// @dev Recommend Security Level - /// Caller Constraints: Operator Whitelist /// Receiver Constraints: None /// OTC: Allowed uint8 constant TRANSFER_SECURITY_LEVEL_RECOMMENDED = 0; /// @dev Security Level One - /// Caller Constraints: None /// Receiver Constraints: None /// OTC: Allowed uint8 constant TRANSFER_SECURITY_LEVEL_ONE = 1; /// @dev Security Level Two - /// Caller Constraints: Operator Blacklist /// Receiver Constraints: None /// OTC: Allowed uint8 constant TRANSFER_SECURITY_LEVEL_TWO = 2; /// @dev Security Level Three - /// Caller Constraints: Operator Whitelist /// Receiver Constraints: None /// OTC: Allowed uint8 constant TRANSFER_SECURITY_LEVEL_THREE = 3; /// @dev Security Level Four - /// Caller Constraints: Operator Whitelist /// Receiver Constraints: None /// OTC: Not Allowed uint8 constant TRANSFER_SECURITY_LEVEL_FOUR = 4; /// @dev Security Level Five - /// Caller Constraints: Operator Whitelist /// Receiver Constraints: No Code /// OTC: Allowed uint8 constant TRANSFER_SECURITY_LEVEL_FIVE = 5; /// @dev Security Level Six - /// Caller Constraints: Operator Whitelist /// Receiver Constraints: Verified EOA /// OTC: Allowed uint8 constant TRANSFER_SECURITY_LEVEL_SIX = 6; /// @dev Security Level Seven - /// Caller Constraints: Operator Whitelist /// Receiver Constraints: No Code /// OTC: Not Allowed uint8 constant TRANSFER_SECURITY_LEVEL_SEVEN = 7; /// @dev Security Level Eight - /// Caller Constraints: Operator Whitelist /// Receiver Constraints: Verified EOA /// OTC: Not Allowed uint8 constant TRANSFER_SECURITY_LEVEL_EIGHT = 8; /// @dev Security Level Nine - /// Soulbound Token, No Transfers Allowed uint8 constant TRANSFER_SECURITY_LEVEL_NINE = 9; /// @dev List type is a blacklist. uint8 constant LIST_TYPE_BLACKLIST = 0; /// @dev List type is a whitelist. uint8 constant LIST_TYPE_WHITELIST = 1; /// @dev List type is authorizers. uint8 constant LIST_TYPE_AUTHORIZERS = 2; /// @dev Constant value for the no error selector. bytes4 constant SELECTOR_NO_ERROR = bytes4(0x00000000);// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; interface IEOARegistry is IERC165 { function isVerifiedEOA(address account) external view returns (bool); }// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; interface ITransferValidator { function applyCollectionTransferPolicy(address caller, address from, address to) external view; function validateTransfer(address caller, address from, address to) external view; function validateTransfer(address caller, address from, address to, uint256 tokenId) external view; function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount) external; function beforeAuthorizedTransfer(address operator, address token, uint256 tokenId) external; function afterAuthorizedTransfer(address token, uint256 tokenId) external; function beforeAuthorizedTransfer(address operator, address token) external; function afterAuthorizedTransfer(address token) external; function beforeAuthorizedTransfer(address token, uint256 tokenId) external; function beforeAuthorizedTransferWithAmount(address token, uint256 tokenId, uint256 amount) external; function afterAuthorizedTransferWithAmount(address token, uint256 tokenId) external; }// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /** * @dev Defines constraints for staking tokens in token wrapper contracts. */ enum StakerConstraints { // 0: No constraints applied to staker. None, // 1: Transaction originator must be the address that will receive the wrapped tokens. CallerIsTxOrigin, // 2: Address that will receive the wrapped tokens must be a verified EOA. EOA } /** * @dev Defines the security policy for a token collection in Creator Token Standards V2. * * @dev **transferSecurityLevel**: The transfer security level set for the collection. * @dev **listId**: The list id that contains the blacklist and whitelist to apply to the collection. * @dev **enableGraylisting**: If true, graylisting will be enabled for the collection. */ struct CollectionSecurityPolicyV3 { bool disableAuthorizationMode; bool authorizersCannotSetWildcardOperators; uint8 transferSecurityLevel; uint120 listId; bool enableAccountFreezingMode; uint16 tokenType; }// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "@openzeppelin/contracts/access/Ownable.sol"; contract CreatorTokenTransferValidatorConfiguration is Ownable { error CreatorTokenTransferValidatorConfiguration__ConfigurationNotInitialized(); bool configurationInitialized; uint256 private nativeValueToCheckPauseState; constructor(address defaultOwner) { _transferOwnership(defaultOwner); } function setNativeValueToCheckPauseState(uint256 _nativeValueToCheckPauseState) external onlyOwner { nativeValueToCheckPauseState = _nativeValueToCheckPauseState; configurationInitialized = true; } function getNativeValueToCheckPauseState() external view returns(uint256 _nativeValueToCheckPauseState) { if (!configurationInitialized) { revert CreatorTokenTransferValidatorConfiguration__ConfigurationNotInitialized(); } _nativeValueToCheckPauseState = nativeValueToCheckPauseState; } }// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "./Errors.sol"; import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; import {IERC721} from "@openzeppelin/contracts/interfaces/IERC721.sol"; import {IERC1155} from "@openzeppelin/contracts/interfaces/IERC1155.sol"; import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol"; import {Ownable} from "./openzeppelin-optimized/Ownable.sol"; import {EIP712} from "./openzeppelin-optimized/EIP712.sol"; import { ZERO_BYTES32, ZERO, ONE, ORDER_STATE_OPEN, ORDER_STATE_FILLED, ORDER_STATE_CANCELLED, SINGLE_USE_PERMIT_TRANSFER_ADVANCED_TYPEHASH_STUB, PERMIT_ORDER_ADVANCED_TYPEHASH_STUB, UPPER_BIT_MASK, TOKEN_TYPE_ERC1155, TOKEN_TYPE_ERC20, TOKEN_TYPE_ERC721, PAUSABLE_APPROVAL_TRANSFER_FROM_ERC721, PAUSABLE_APPROVAL_TRANSFER_FROM_ERC1155, PAUSABLE_APPROVAL_TRANSFER_FROM_ERC20, PAUSABLE_PERMITTED_TRANSFER_FROM_ERC721, PAUSABLE_PERMITTED_TRANSFER_FROM_ERC1155, PAUSABLE_PERMITTED_TRANSFER_FROM_ERC20, PAUSABLE_ORDER_TRANSFER_FROM_ERC1155, PAUSABLE_ORDER_TRANSFER_FROM_ERC20 } from "./Constants.sol"; import {PackedApproval, OrderFillAmounts} from "./DataTypes.sol"; import {PermitHash} from './libraries/PermitHash.sol'; import {IPermitC} from './interfaces/IPermitC.sol'; import {CollateralizedPausableFlags} from './CollateralizedPausableFlags.sol'; /* @@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@( @@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@ #@@@@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@@@@* @@@@@@@@@@@@ @@@@@@@@@@@@@@@ @ @@@@@@@@@@@@ @@@@@@@@@@@@@@@ @ @@@@@@@@@@@ @@@@@@@@@@@@@@@ @@ @@@@@@@@@@@@ @@@@@@@@@@@@@@@ #@@ @@@@@@@@@@@@/ @@@@@@@@@@@@@@. @@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@&%%%%%%%%&&@@@@@@@@@@@@@@ @@@@@@@@@@@@@@ @@@@@ @@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@ @@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@ @@@@@@@@@@@& @@@@@@@@@@@@@@ *@@@@@@@ (@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@@ @@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ .@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@% @@@@@@@@@@@@@@@@@@@@@@@@( @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@& @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ * @title PermitC * @custom:version 1.0.0 * @author Limit Break, Inc. * @description Advanced approval management for ERC20, ERC721 and ERC1155 tokens * allowing for single use permit transfers, time-bound approvals * and order ID based transfers. */ contract PermitC is Ownable, CollateralizedPausableFlags, EIP712, IPermitC { /** * @notice Map of approval details for the provided bytes32 hash to allow for multiple accessors * * @dev keccak256(abi.encode(owner, tokenType, token, id, orderId, masterNonce)) => * @dev operator => (state, amount, expiration) * @dev Utilized for stored approvals by an owner's direct call to `approve` and * @dev approvals by signature in `updateApprovalBySignature`. Both methods use a * @dev bytes32(0) value for the `orderId`. */ mapping(bytes32 => mapping(address => PackedApproval)) private _transferApprovals; /** * @notice Map of approval details for the provided bytes32 hash to allow for multiple accessors * * @dev keccak256(abi.encode(owner, tokenType, token, id, orderId, masterNonce)) => * @dev operator => (state, amount, expiration) * @dev Utilized for order approvals by `fillPermittedOrderERC20` and `fillPermittedOrderERC1155` * @dev with the `orderId` provided by the sender. */ mapping(bytes32 => mapping(address => PackedApproval)) private _orderApprovals; /** * @notice Map of registered additional data hashes for transfer permits. * * @dev This is used to prevent someone from providing an invalid EIP712 envelope label * @dev and tricking a user into signing a different message than they expect. */ mapping(bytes32 => bool) private _registeredTransferHashes; /** * @notice Map of registered additional data hashes for order permits. * * @dev This is used to prevent someone from providing an invalid EIP712 envelope label * @dev and tricking a user into signing a different message than they expect. */ mapping(bytes32 => bool) private _registeredOrderHashes; /// @dev Map of an address to a bitmap (slot => status) mapping(address => mapping(uint256 => uint256)) private _unorderedNonces; /** * @notice Master nonce used to invalidate all outstanding approvals for an owner * * @dev owner => masterNonce * @dev This is incremented when the owner calls lockdown() */ mapping(address => uint256) private _masterNonces; constructor( string memory name, string memory version, address _defaultContractOwner, uint256 _nativeValueToCheckPauseState ) CollateralizedPausableFlags(_nativeValueToCheckPauseState) EIP712(name, version) { _transferOwnership(_defaultContractOwner); } /** * ================================================= * ================= Modifiers ===================== * ================================================= */ modifier onlyRegisteredTransferAdvancedTypeHash(bytes32 advancedPermitHash) { _requireTransferAdvancedPermitHashIsRegistered(advancedPermitHash); _; } modifier onlyRegisteredOrderAdvancedTypeHash(bytes32 advancedPermitHash) { _requireOrderAdvancedPermitHashIsRegistered(advancedPermitHash); _; } /** * ================================================= * ============== Approval Transfers =============== * ================================================= */ /** * @notice Approve an operator to spend a specific token / ID combination * @notice This function is compatible with ERC20, ERC721 and ERC1155 * @notice To give unlimited approval for ERC20 and ERC1155, set amount to type(uint200).max * @notice When approving an ERC721, you MUST set amount to `1` * @notice When approving an ERC20, you MUST set id to `0` * * @dev <h4>Postconditions:</h4> * @dev 1. Updates the approval for an operator to use an amount of a specific token / ID combination * @dev 2. If the expiration is 0, the approval is valid only in the context of the current block * @dev 3. If the expiration is not 0, the approval is valid until the expiration timestamp * @dev 4. If the provided amount is type(uint200).max, the approval is unlimited * * @param tokenType The type of token being approved - must be 20, 721 or 1155. * @param token The address of the token contract * @param id The token ID * @param operator The address of the operator * @param amount The amount of tokens to approve * @param expiration The expiration timestamp of the approval */ function approve( uint256 tokenType, address token, uint256 id, address operator, uint200 amount, uint48 expiration ) external { _requireValidTokenType(tokenType); _storeApproval(tokenType, token, id, amount, expiration, msg.sender, operator); } /** * @notice Use a signed permit to increase the allowance for a provided operator * @notice This function is compatible with ERC20, ERC721 and ERC1155 * @notice To give unlimited approval for ERC20 and ERC1155, set amount to type(uint200).max * @notice When approving an ERC721, you MUST set amount to `1` * @notice When approving an ERC20, you MUST set id to `0` * @notice An `approvalExpiration` of zero is considered an atomic permit which will use the * @notice current block time as the expiration time when storing the permit data. * * @dev - Throws if the permit has expired * @dev - Throws if the permit's nonce has already been used * @dev - Throws if the permit signature is does not recover to the provided owner * * @dev <h4>Postconditions:</h4> * @dev 1. Updates the approval for an operator to use an amount of a specific token / ID combination * @dev 3. Sets the expiration of the approval to the expiration timestamp of the permit * @dev 4. If the provided amount is type(uint200).max, the approval is unlimited * * @param tokenType The type of token being approved - must be 20, 721 or 1155. * @param token Address of the token to approve * @param id The token ID * @param nonce The nonce of the permit * @param amount The amount of tokens to approve * @param operator The address of the operator * @param approvalExpiration The expiration timestamp of the approval * @param sigDeadline The deadline timestamp for the permit signature * @param owner The owner of the tokens * @param signedPermit The permit signature, signed by the owner */ function updateApprovalBySignature( uint256 tokenType, address token, uint256 id, uint256 nonce, uint200 amount, address operator, uint48 approvalExpiration, uint48 sigDeadline, address owner, bytes calldata signedPermit ) external { if (block.timestamp > sigDeadline) { revert PermitC__ApprovalTransferPermitExpiredOrUnset(); } _requireValidTokenType(tokenType); _checkAndInvalidateNonce(owner, nonce); _verifyPermitSignature( _hashTypedDataV4( PermitHash.hashOnChainApproval( tokenType, token, id, amount, nonce, operator, approvalExpiration, sigDeadline, _masterNonces[owner] ) ), signedPermit, owner ); // Expiration of zero is considered an atomic permit which is only valid in the // current block. approvalExpiration = approvalExpiration == 0 ? uint48(block.timestamp) : approvalExpiration; _storeApproval(tokenType, token, id, amount, approvalExpiration, owner, operator); } /** * @notice Returns the amount of allowance an operator has and it's expiration for a specific token and id * @notice If the expiration on the allowance has expired, returns 0 * @notice To retrieve allowance for ERC20, set id to `0` * * @param owner The owner of the token * @param operator The operator of the token * @param tokenType The type of token the allowance is for * @param token The address of the token contract * @param id The token ID * * @return allowedAmount The amount of allowance the operator has * @return expiration The expiration timestamp of the allowance */ function allowance( address owner, address operator, uint256 tokenType, address token, uint256 id ) external view returns (uint256 allowedAmount, uint256 expiration) { return _allowance(_transferApprovals, owner, operator, tokenType, token, id, ZERO_BYTES32); } /** * ================================================= * ================ Signed Transfers =============== * ================================================= */ /** * @notice Registers the combination of a provided string with the `SINGLE_USE_PERMIT_TRANSFER_ADVANCED_TYPEHASH_STUB` * @notice and `PERMIT_ORDER_ADVANCED_TYPEHASH_STUB` to create valid additional data hashes * * @dev This function prevents malicious actors from changing the label of the EIP712 hash * @dev to a value that would fool an external user into signing a different message. * * @dev <h4>Postconditions:</h4> * @dev 1. The provided string is combined with the `SINGLE_USE_PERMIT_TRANSFER_ADVANCED_TYPEHASH_STUB` string * @dev 2. The combined string is hashed using keccak256 * @dev 3. The resulting hash is added to the `_registeredTransferHashes` mapping * @dev 4. The provided string is combined with the `PERMIT_ORDER_ADVANCED_TYPEHASH_STUB` string * @dev 5. The combined string is hashed using keccak256 * @dev 6. The resulting hash is added to the `_registeredOrderHashes` mapping * * @param additionalDataTypeString The string to register as a valid additional data hash */ function registerAdditionalDataHash(string calldata additionalDataTypeString) external { _registeredTransferHashes[ keccak256( bytes( string.concat( SINGLE_USE_PERMIT_TRANSFER_ADVANCED_TYPEHASH_STUB, additionalDataTypeString ) ) ) ] = true; _registeredOrderHashes[ keccak256( bytes( string.concat( PERMIT_ORDER_ADVANCED_TYPEHASH_STUB, additionalDataTypeString ) ) ) ] = true; } /** * @notice Transfer an ERC721 token from the owner to the recipient using a permit signature. * * @dev Be advised that the permitted amount for ERC721 is always inferred to be 1, so signed permitted amount * @dev MUST always be set to 1. * * @dev - Throws if the permit is expired * @dev - Throws if the nonce has already been used * @dev - Throws if the permit is not signed by the owner * @dev - Throws if the requested amount exceeds the permitted amount * @dev - Throws if the provided token address does not implement ERC721 transferFrom function * @dev - Returns `false` if the transfer fails * * @dev <h4>Postconditions:</h4> * @dev 1. Transfers the token from the owner to the recipient * @dev 2. The nonce of the permit is marked as used * @dev 3. Performs any additional checks in the before and after hooks * * @param token The address of the token * @param id The ID of the token * @param nonce The nonce of the permit * @param expiration The expiration timestamp of the permit * @param owner The owner of the token * @param to The address to transfer the tokens to * @param signedPermit The permit signature, signed by the owner * * @return isError True if the transfer failed, false otherwise */ function permitTransferFromERC721( address token, uint256 id, uint256 nonce, uint256 expiration, address owner, address to, bytes calldata signedPermit ) external returns (bool isError) { _requireNotPaused(PAUSABLE_PERMITTED_TRANSFER_FROM_ERC721); _checkPermitApproval(TOKEN_TYPE_ERC721, token, id, ONE, nonce, expiration, owner, ONE, signedPermit); isError = _transferFromERC721(owner, to, token, id); if (isError) { _restoreNonce(owner, nonce); } } /** * @notice Transfers an ERC721 token from the owner to the recipient using a permit signature * @notice This function includes additional data to verify on the signature, allowing * @notice protocols to extend the validation in one function call. NOTE: before calling this * @notice function you MUST register the stub end of the additional data typestring using * @notice the `registerAdditionalDataHash` function. * * @dev Be advised that the permitted amount for ERC721 is always inferred to be 1, so signed permitted amount * @dev MUST always be set to 1. * * @dev - Throws for any reason permitTransferFromERC721 would. * @dev - Throws if the additional data does not match the signature * @dev - Throws if the provided hash has not been registered as a valid additional data hash * @dev - Throws if the provided hash does not match the provided additional data * * @dev <h4>Postconditions:</h4> * @dev 1. Transfers the token from the owner to the recipient * @dev 2. Performs any additional checks in the before and after hooks * @dev 3. The nonce of the permit is marked as used * * @param token The address of the token * @param id The ID of the token * @param nonce The nonce of the permit * @param expiration The expiration timestamp of the permit * @param owner The owner of the token * @param to The address to transfer the tokens to * @param additionalData The additional data to verify on the signature * @param advancedPermitHash The hash of the additional data * @param signedPermit The permit signature, signed by the owner * * @return isError True if the transfer failed, false otherwise */ function permitTransferFromWithAdditionalDataERC721( address token, uint256 id, uint256 nonce, uint256 expiration, address owner, address to, bytes32 additionalData, bytes32 advancedPermitHash, bytes calldata signedPermit ) external onlyRegisteredTransferAdvancedTypeHash(advancedPermitHash) returns (bool isError) { _requireNotPaused(PAUSABLE_PERMITTED_TRANSFER_FROM_ERC721); _checkPermitApprovalWithAdditionalDataERC721( token, id, ONE, nonce, expiration, owner, ONE, signedPermit, additionalData, advancedPermitHash ); isError = _transferFromERC721(owner, to, token, id); if (isError) { _restoreNonce(owner, nonce); } } /** * @notice Transfer an ERC1155 token from the owner to the recipient using a permit signature * * @dev - Throws if the permit is expired * @dev - Throws if the nonce has already been used * @dev - Throws if the permit is not signed by the owner * @dev - Throws if the requested amount exceeds the permitted amount * @dev - Throws if the provided token address does not implement ERC1155 safeTransferFrom function * @dev - Returns `false` if the transfer fails * * @dev <h4>Postconditions:</h4> * @dev 1. Transfers the token (in the requested amount) from the owner to the recipient * @dev 2. The nonce of the permit is marked as used * @dev 3. Performs any additional checks in the before and after hooks * * @param token The address of the token * @param id The ID of the token * @param nonce The nonce of the permit * @param permitAmount The amount of tokens permitted by the owner * @param expiration The expiration timestamp of the permit * @param owner The owner of the token * @param to The address to transfer the tokens to * @param transferAmount The amount of tokens to transfer * @param signedPermit The permit signature, signed by the owner * * @return isError True if the transfer failed, false otherwise */ function permitTransferFromERC1155( address token, uint256 id, uint256 nonce, uint256 permitAmount, uint256 expiration, address owner, address to, uint256 transferAmount, bytes calldata signedPermit ) external returns (bool isError) { _requireNotPaused(PAUSABLE_PERMITTED_TRANSFER_FROM_ERC1155); _checkPermitApproval(TOKEN_TYPE_ERC1155, token, id, permitAmount, nonce, expiration, owner, transferAmount, signedPermit); isError = _transferFromERC1155(token, owner, to, id, transferAmount); if (isError) { _restoreNonce(owner, nonce); } } /** * @notice Transfers a token from the owner to the recipient using a permit signature * @notice This function includes additional data to verify on the signature, allowing * @notice protocols to extend the validation in one function call. NOTE: before calling this * @notice function you MUST register the stub end of the additional data typestring using * @notice the `registerAdditionalDataHash` function. * * @dev - Throws for any reason permitTransferFrom would. * @dev - Throws if the additional data does not match the signature * @dev - Throws if the provided hash has not been registered as a valid additional data hash * @dev - Throws if the provided hash does not match the provided additional data * @dev - Throws if the provided hash has not been registered as a valid additional data hash * @dev - Returns `false` if the transfer fails * * @dev <h4>Postconditions:</h4> * @dev 1. Transfers the token (in the requested amount) from the owner to the recipient * @dev 2. Performs any additional checks in the before and after hooks * @dev 3. The nonce of the permit is marked as used * * @param token The address of the token * @param id The ID of the token * @param nonce The nonce of the permit * @param permitAmount The amount of tokens permitted by the owner * @param expiration The expiration timestamp of the permit * @param owner The owner of the token * @param to The address to transfer the tokens to * @param transferAmount The amount of tokens to transfer * @param additionalData The additional data to verify on the signature * @param advancedPermitHash The hash of the additional data * @param signedPermit The permit signature, signed by the owner * * @return isError True if the transfer failed, false otherwise */ function permitTransferFromWithAdditionalDataERC1155( address token, uint256 id, uint256 nonce, uint256 permitAmount, uint256 expiration, address owner, address to, uint256 transferAmount, bytes32 additionalData, bytes32 advancedPermitHash, bytes calldata signedPermit ) external onlyRegisteredTransferAdvancedTypeHash(advancedPermitHash) returns (bool isError) { _requireNotPaused(PAUSABLE_PERMITTED_TRANSFER_FROM_ERC1155); _checkPermitApprovalWithAdditionalDataERC1155( token, id, permitAmount, nonce, expiration, owner, transferAmount, signedPermit, additionalData, advancedPermitHash ); // copy id to top of stack to avoid stack too deep uint256 tmpId = id; isError = _transferFromERC1155(token, owner, to, tmpId, transferAmount); if (isError) { _restoreNonce(owner, nonce); } } /** * @notice Transfer an ERC20 token from the owner to the recipient using a permit signature. * * @dev Be advised that the token ID for ERC20 is always inferred to be 0, so signed token ID * @dev MUST always be set to 0. * * @dev - Throws if the permit is expired * @dev - Throws if the nonce has already been used * @dev - Throws if the permit is not signed by the owner * @dev - Throws if the requested amount exceeds the permitted amount * @dev - Throws if the provided token address does not implement ERC20 transferFrom function * @dev - Returns `false` if the transfer fails * * @dev <h4>Postconditions:</h4> * @dev 1. Transfers the token in the requested amount from the owner to the recipient * @dev 2. The nonce of the permit is marked as used * @dev 3. Performs any additional checks in the before and after hooks * * @param token The address of the token * @param nonce The nonce of the permit * @param permitAmount The amount of tokens permitted by the owner * @param expiration The expiration timestamp of the permit * @param owner The owner of the token * @param to The address to transfer the tokens to * @param signedPermit The permit signature, signed by the owner * * @return isError True if the transfer failed, false otherwise */ function permitTransferFromERC20( address token, uint256 nonce, uint256 permitAmount, uint256 expiration, address owner, address to, uint256 transferAmount, bytes calldata signedPermit ) external returns (bool isError) { _requireNotPaused(PAUSABLE_PERMITTED_TRANSFER_FROM_ERC20); _checkPermitApproval(TOKEN_TYPE_ERC20, token, ZERO, permitAmount, nonce, expiration, owner, transferAmount, signedPermit); isError = _transferFromERC20(token, owner, to, ZERO, transferAmount); if (isError) { _restoreNonce(owner, nonce); } } /** * @notice Transfers an ERC20 token from the owner to the recipient using a permit signature * @notice This function includes additional data to verify on the signature, allowing * @notice protocols to extend the validation in one function call. NOTE: before calling this * @notice function you MUST register the stub end of the additional data typestring using * @notice the `registerAdditionalDataHash` function. * * @dev Be advised that the token ID for ERC20 is always inferred to be 0, so signed token ID * @dev MUST always be set to 0. * * @dev - Throws for any reason permitTransferFromERC20 would. * @dev - Throws if the additional data does not match the signature * @dev - Throws if the provided hash has not been registered as a valid additional data hash * @dev - Throws if the provided hash does not match the provided additional data * @dev - Returns `false` if the transfer fails * * @dev <h4>Postconditions:</h4> * @dev 1. Transfers the token (in the requested amount) from the owner to the recipient * @dev 2. Performs any additional checks in the before and after hooks * @dev 3. The nonce of the permit is marked as used * * @param token The address of the token * @param nonce The nonce of the permit * @param permitAmount The amount of tokens permitted by the owner * @param expiration The expiration timestamp of the permit * @param owner The owner of the token * @param to The address to transfer the tokens to * @param transferAmount The amount of tokens to transfer * @param additionalData The additional data to verify on the signature * @param advancedPermitHash The hash of the additional data * @param signedPermit The permit signature, signed by the owner * * @return isError True if the transfer failed, false otherwise */ function permitTransferFromWithAdditionalDataERC20( address token, uint256 nonce, uint256 permitAmount, uint256 expiration, address owner, address to, uint256 transferAmount, bytes32 additionalData, bytes32 advancedPermitHash, bytes calldata signedPermit ) external onlyRegisteredTransferAdvancedTypeHash(advancedPermitHash) returns (bool isError) { _requireNotPaused(PAUSABLE_PERMITTED_TRANSFER_FROM_ERC20); _checkPermitApprovalWithAdditionalDataERC20( token, ZERO, permitAmount, nonce, expiration, owner, transferAmount, signedPermit, additionalData, advancedPermitHash ); isError = _transferFromERC20(token, owner, to, ZERO, transferAmount); if (isError) { _restoreNonce(owner, nonce); } } /** * @notice Returns true if the provided hash has been registered as a valid additional data hash for transfers. * * @param hash The hash to check * * @return isRegistered true if the hash is valid, false otherwise */ function isRegisteredTransferAdditionalDataHash(bytes32 hash) external view returns (bool isRegistered) { isRegistered = _registeredTransferHashes[hash]; } /** * @notice Returns true if the provided hash has been registered as a valid additional data hash for orders. * * @param hash The hash to check * * @return isRegistered true if the hash is valid, false otherwise */ function isRegisteredOrderAdditionalDataHash(bytes32 hash) external view returns (bool isRegistered) { isRegistered = _registeredOrderHashes[hash]; } /** * ================================================= * =============== Order Transfers ================= * ================================================= */ /** * @notice Transfers an ERC1155 token from the owner to the recipient using a permit signature * @notice Order transfers are used to transfer a specific amount of a token from a specific order * @notice and allow for multiple uses of the same permit up to the allocated amount. NOTE: before calling this * @notice function you MUST register the stub end of the additional data typestring using * @notice the `registerAdditionalDataHash` function. * * @dev - Throws if the permit is expired * @dev - Throws if the permit is not signed by the owner * @dev - Throws if the requested amount + amount already filled exceeds the permitted amount * @dev - Throws if the requested amount is less than the minimum fill amount * @dev - Throws if the provided token address does not implement ERC1155 safeTransferFrom function * @dev - Throws if the provided advanced permit hash has not been registered * @dev - Returns `false` if the transfer fails * * @dev <h4>Postconditions:</h4> * @dev 1. Transfers the token (in the requested amount) from the owner to the recipient * @dev 2. Updates the amount filled for the order ID * @dev 3. If completely filled, marks the order as filled * * @param signedPermit The permit signature, signed by the owner * @param orderFillAmounts The amount of tokens to transfer * @param token The address of the token * @param id The ID of the token * @param owner The owner of the token * @param to The address to transfer the tokens to * @param salt The salt of the permit * @param expiration The expiration timestamp of the permit * @param orderId The order ID * @param advancedPermitHash The hash of the additional data * * @return quantityFilled The amount of tokens filled * @return isError True if the transfer failed, false otherwise */ function fillPermittedOrderERC1155( bytes calldata signedPermit, OrderFillAmounts calldata orderFillAmounts, address token, uint256 id, address owner, address to, uint256 salt, uint48 expiration, bytes32 orderId, bytes32 advancedPermitHash ) external onlyRegisteredOrderAdvancedTypeHash(advancedPermitHash) returns (uint256 quantityFilled, bool isError) { _requireNotPaused(PAUSABLE_ORDER_TRANSFER_FROM_ERC1155); PackedApproval storage orderStatus = _checkOrderTransferERC1155( signedPermit, orderFillAmounts, token, id, owner, salt, expiration, orderId, advancedPermitHash ); ( quantityFilled, isError ) = _orderTransfer( orderStatus, orderFillAmounts, token, id, owner, to, orderId, _transferFromERC1155 ); if (isError) { _restoreFillableItems(orderStatus, owner, orderId, quantityFilled, true); } } /** * @notice Transfers an ERC20 token from the owner to the recipient using a permit signature * @notice Order transfers are used to transfer a specific amount of a token from a specific order * @notice and allow for multiple uses of the same permit up to the allocated amount. NOTE: before calling this * @notice function you MUST register the stub end of the additional data typestring using * @notice the `registerAdditionalDataHash` function. * * @dev - Throws if the permit is expired * @dev - Throws if the permit is not signed by the owner * @dev - Throws if the requested amount + amount already filled exceeds the permitted amount * @dev - Throws if the requested amount is less than the minimum fill amount * @dev - Throws if the provided token address does not implement ERC20 transferFrom function * @dev - Throws if the provided advanced permit hash has not been registered * @dev - Returns `false` if the transfer fails * * @dev <h4>Postconditions:</h4> * @dev 1. Transfers the token (in the requested amount) from the owner to the recipient * @dev 2. Updates the amount filled for the order ID * @dev 3. If completely filled, marks the order as filled * * @param signedPermit The permit signature, signed by the owner * @param orderFillAmounts The amount of tokens to transfer * @param token The address of the token * @param owner The owner of the token * @param to The address to transfer the tokens to * @param salt The salt of the permit * @param expiration The expiration timestamp of the permit * @param orderId The order ID * @param advancedPermitHash The hash of the additional data * * @return quantityFilled The amount of tokens filled * @return isError True if the transfer failed, false otherwise */ function fillPermittedOrderERC20( bytes calldata signedPermit, OrderFillAmounts calldata orderFillAmounts, address token, address owner, address to, uint256 salt, uint48 expiration, bytes32 orderId, bytes32 advancedPermitHash ) external onlyRegisteredOrderAdvancedTypeHash(advancedPermitHash) returns (uint256 quantityFilled, bool isError) { _requireNotPaused(PAUSABLE_ORDER_TRANSFER_FROM_ERC20); PackedApproval storage orderStatus = _checkOrderTransferERC20( signedPermit, orderFillAmounts, token, ZERO, owner, salt, expiration, orderId, advancedPermitHash ); ( quantityFilled, isError ) = _orderTransfer( orderStatus, orderFillAmounts, token, ZERO, owner, to, orderId, _transferFromERC20 ); if (isError) { _restoreFillableItems(orderStatus, owner, orderId, quantityFilled, true); } } /** * @notice Closes an outstanding order to prevent further execution of transfers. * * @dev - Throws if the order is not in the open state * * @dev <h4>Postconditions:</h4> * @dev 1. Marks the order as cancelled * @dev 2. Sets the order amount to 0 * @dev 3. Sets the order expiration to 0 * @dev 4. Emits a OrderClosed event * * @param owner The owner of the token * @param operator The operator allowed to transfer the token * @param tokenType The type of token the order is for - must be 20, 721 or 1155. * @param token The address of the token contract * @param id The token ID * @param orderId The order ID */ function closePermittedOrder( address owner, address operator, uint256 tokenType, address token, uint256 id, bytes32 orderId ) external { if(!(msg.sender == owner || msg.sender == operator)) { revert PermitC__CallerMustBeOwnerOrOperator(); } _requireValidTokenType(tokenType); PackedApproval storage orderStatus = _getPackedApprovalPtr(_orderApprovals, owner, tokenType, token, id, orderId, operator); if (orderStatus.state == ORDER_STATE_OPEN) { orderStatus.state = ORDER_STATE_CANCELLED; orderStatus.amount = 0; orderStatus.expiration = 0; emit OrderClosed(orderId, owner, operator, true); } else { revert PermitC__OrderIsEitherCancelledOrFilled(); } } /** * @notice Returns the amount of allowance an operator has for a specific token and id * @notice If the expiration on the allowance has expired, returns 0 * * @dev Overload of the on chain allowance function for approvals with a specified order ID * * @param owner The owner of the token * @param operator The operator of the token * @param token The address of the token contract * @param id The token ID * * @return allowedAmount The amount of allowance the operator has */ function allowance( address owner, address operator, uint256 tokenType, address token, uint256 id, bytes32 orderId ) external view returns (uint256 allowedAmount, uint256 expiration) { return _allowance(_orderApprovals, owner, operator, tokenType, token, id, orderId); } /** * ================================================= * ================ Nonce Management =============== * ================================================= */ /** * @notice Invalidates the provided nonce * * @dev - Throws if the provided nonce has already been used * * @dev <h4>Postconditions:</h4> * @dev 1. Sets the provided nonce as used for the sender * * @param nonce Nonce to invalidate */ function invalidateUnorderedNonce(uint256 nonce) external { _checkAndInvalidateNonce(msg.sender, nonce); } /** * @notice Returns if the provided nonce has been used * * @param owner The owner of the token * @param nonce The nonce to check * * @return isValid true if the nonce is valid, false otherwise */ function isValidUnorderedNonce(address owner, uint256 nonce) external view returns (bool isValid) { isValid = ((_unorderedNonces[owner][uint248(nonce >> 8)] >> uint8(nonce)) & ONE) == ZERO; } /** * @notice Revokes all outstanding approvals for the sender * * @dev <h4>Postconditions:</h4> * @dev 1. Increments the master nonce for the sender * @dev 2. All outstanding approvals for the sender are invalidated */ function lockdown() external { unchecked { _masterNonces[msg.sender]++; } emit Lockdown(msg.sender); } /** * @notice Returns the master nonce for the provided owner address * * @param owner The owner address * * @return The master nonce */ function masterNonce(address owner) external view returns (uint256) { return _masterNonces[owner]; } /** * ================================================= * ============== Transfer Functions =============== * ================================================= */ /** * @notice Transfer an ERC721 token from the owner to the recipient using on chain approvals * * @dev Public transfer function overload for approval transfers * @dev - Throws if the provided token address does not implement ERC721 transferFrom function * @dev - Throws if the requested amount exceeds the approved amount * @dev - Throws if the approval is expired * @dev - Returns `false` if the transfer fails * * @dev <h4>Postconditions:</h4> * @dev 1. Transfers the token (in the requested amount) from the owner to the recipient * @dev 2. Decrements the approval amount by the requested amount * @dev 3. Performs any additional checks in the before and after hooks * * @param owner The owner of the token * @param to The recipient of the token * @param token The address of the token * @param id The id of the token * * @return isError True if the transfer failed, false otherwise */ function transferFromERC721( address owner, address to, address token, uint256 id ) external returns (bool isError) { _requireNotPaused(PAUSABLE_APPROVAL_TRANSFER_FROM_ERC721); PackedApproval storage approval = _checkAndUpdateApproval(owner, TOKEN_TYPE_ERC721, token, id, ONE, true); isError = _transferFromERC721(owner, to, token, id); if (isError) { _restoreFillableItems(approval, owner, ZERO_BYTES32, ONE, false); } } /** * @notice Transfer an ERC1155 token from the owner to the recipient using on chain approvals * * @dev Public transfer function overload for approval transfers * @dev - Throws if the provided token address does not implement ERC1155 safeTransferFrom function * @dev - Throws if the requested amount exceeds the approved amount * @dev - Throws if the approval is expired * @dev - Returns `false` if the transfer fails * * @dev <h4>Postconditions:</h4> * @dev 1. Transfers the token (in the requested amount) from the owner to the recipient * @dev 2. Decrements the approval amount by the requested amount * @dev 3. Performs any additional checks in the before and after hooks * * @param owner The owner of the token * @param to The recipient of the token * @param amount The amount of the token to transfer * @param token The address of the token * @param id The id of the token * * @return isError True if the transfer failed, false otherwise */ function transferFromERC1155( address owner, address to, address token, uint256 id, uint256 amount ) external returns (bool isError) { _requireNotPaused(PAUSABLE_APPROVAL_TRANSFER_FROM_ERC1155); PackedApproval storage approval = _checkAndUpdateApproval(owner, TOKEN_TYPE_ERC1155, token, id, amount, false); isError = _transferFromERC1155(token, owner, to, id, amount); if (isError) { _restoreFillableItems(approval, owner, ZERO_BYTES32, amount, false); } } /** * @notice Transfer an ERC20 token from the owner to the recipient using on chain approvals * * @dev Public transfer function overload for approval transfers * @dev - Throws if the provided token address does not implement ERC20 transferFrom function * @dev - Throws if the requested amount exceeds the approved amount * @dev - Throws if the approval is expired * @dev - Returns `false` if the transfer fails * * @dev <h4>Postconditions:</h4> * @dev 1. Transfers the token (in the requested amount) from the owner to the recipient * @dev 2. Decrements the approval amount by the requested amount * @dev 3. Performs any additional checks in the before and after hooks * * @param owner The owner of the token * @param to The recipient of the token * @param amount The amount of the token to transfer * @param token The address of the token * * @return isError True if the transfer failed, false otherwise */ function transferFromERC20( address owner, address to, address token, uint256 amount ) external returns (bool isError) { _requireNotPaused(PAUSABLE_APPROVAL_TRANSFER_FROM_ERC20); PackedApproval storage approval = _checkAndUpdateApproval(owner, TOKEN_TYPE_ERC20, token, ZERO, amount, false); isError = _transferFromERC20(token, owner, to, ZERO, amount); if (isError) { _restoreFillableItems(approval, owner, ZERO_BYTES32, amount, false); } } /** * @notice Performs a transfer of an ERC721 token. * * @dev Will **NOT** attempt transfer if `_beforeTransferFrom` hook returns false. * @dev Will **NOT** revert if the transfer is unsucessful. * @dev Invokers **MUST** check `isError` return value to determine success. * * @param owner The owner of the token being transferred * @param to The address to transfer the token to * @param token The token address of the token being transferred * @param id The token id being transferred * * @return isError True if the token was not transferred, false if token was transferred */ function _transferFromERC721( address owner, address to, address token, uint256 id ) private returns (bool isError) { isError = _beforeTransferFrom(TOKEN_TYPE_ERC721, token, owner, to, id, ONE); if (!isError) { try IERC721(token).transferFrom(owner, to, id) { } catch { isError = true; } } } /** * @notice Performs a transfer of an ERC1155 token. * * @dev Will **NOT** attempt transfer if `_beforeTransferFrom` hook returns false. * @dev Will **NOT** revert if the transfer is unsucessful. * @dev Invokers **MUST** check `isError` return value to determine success. * * @param token The token address of the token being transferred * @param owner The owner of the token being transferred * @param to The address to transfer the token to * @param id The token id being transferred * @param amount The quantity of token id to transfer * * @return isError True if the token was not transferred, false if token was transferred */ function _transferFromERC1155( address token, address owner, address to, uint256 id, uint256 amount ) private returns (bool isError) { isError = _beforeTransferFrom(TOKEN_TYPE_ERC1155, token, owner, to, id, amount); if (!isError) { try IERC1155(token).safeTransferFrom(owner, to, id, amount, "") { } catch { isError = true; } } } /** * @notice Performs a transfer of an ERC20 token. * * @dev Will **NOT** attempt transfer if `_beforeTransferFrom` hook returns false. * @dev Will **NOT** revert if the transfer is unsucessful. * @dev Invokers **MUST** check `isError` return value to determine success. * * @param token The token address of the token being transferred * @param owner The owner of the token being transferred * @param to The address to transfer the token to * @param amount The quantity of token id to transfer * * @return isError True if the token was not transferred, false if token was transferred */ function _transferFromERC20( address token, address owner, address to, uint256 /*id*/, uint256 amount ) private returns (bool isError) { isError = _beforeTransferFrom(TOKEN_TYPE_ERC20, token, owner, to, ZERO, amount); if (!isError) { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, owner, to, amount)); if (!success) { isError = true; } else if (data.length > 0) { isError = !abi.decode(data, (bool)); } } } /** * ================================================= * ============ Signature Verification ============= * ================================================= */ /** * @notice Returns the domain separator used in the permit signature * * @return domainSeparator The domain separator */ function domainSeparatorV4() external view returns (bytes32 domainSeparator) { domainSeparator = _domainSeparatorV4(); } /** * @notice Verifies a permit signature based on the bytes length of the signature provided. * * @dev Throws when - * @dev The bytes signature length is 64 or 65 bytes AND * @dev The ECDSA recovered signer is not the owner AND * @dev The owner's code length is zero OR the owner does not return a valid EIP-1271 response * @dev * @dev OR * @dev * @dev The bytes signature length is not 64 or 65 bytes AND * @dev The owner's code length is zero OR the owner does not return a valid EIP-1271 response */ function _verifyPermitSignature(bytes32 digest, bytes calldata signature, address owner) private view { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // Divide the signature in r, s and v variables /// @solidity memory-safe-assembly assembly { r := calldataload(signature.offset) s := calldataload(add(signature.offset, 32)) v := byte(0, calldataload(add(signature.offset, 64))) } (bool isError, address signer) = _ecdsaRecover(digest, v, r, s); if (owner != signer || isError) { _verifyEIP1271Signature(owner, digest, signature); } } else if (signature.length == 64) { bytes32 r; bytes32 vs; // Divide the signature in r and vs variables /// @solidity memory-safe-assembly assembly { r := calldataload(signature.offset) vs := calldataload(add(signature.offset, 32)) } (bool isError, address signer) = _ecdsaRecover(digest, r, vs); if (owner != signer || isError) { _verifyEIP1271Signature(owner, digest, signature); } } else { _verifyEIP1271Signature(owner, digest, signature); } } /** * @notice Verifies an EIP-1271 signature. * * @dev Throws when `signer` code length is zero OR the EIP-1271 call does not * @dev return the correct magic value. * * @param signer The signer address to verify a signature with * @param hash The hash digest to verify with the signer * @param signature The signature to verify */ function _verifyEIP1271Signature(address signer, bytes32 hash, bytes calldata signature) private view { if(signer.code.length == 0) { revert PermitC__SignatureTransferInvalidSignature(); } if (!_safeIsValidSignature(signer, hash, signature)) { revert PermitC__SignatureTransferInvalidSignature(); } } /** * @notice Overload of the `_ecdsaRecover` function to unpack the `v` and `s` values * * @param digest The hash digest that was signed * @param r The `r` value of the signature * @param vs The packed `v` and `s` values of the signature * * @return isError True if the ECDSA function is provided invalid inputs * @return signer The recovered address from ECDSA */ function _ecdsaRecover(bytes32 digest, bytes32 r, bytes32 vs) private pure returns (bool isError, address signer) { unchecked { bytes32 s = vs & UPPER_BIT_MASK; uint8 v = uint8(uint256(vs >> 255)) + 27; (isError, signer) = _ecdsaRecover(digest, v, r, s); } } /** * @notice Recovers the signer address using ECDSA * * @dev Does **NOT** revert if invalid input values are provided or `signer` is recovered as address(0) * @dev Returns an `isError` value in those conditions that is handled upstream * * @param digest The hash digest that was signed * @param v The `v` value of the signature * @param r The `r` value of the signature * @param s The `s` value of the signature * * @return isError True if the ECDSA function is provided invalid inputs * @return signer The recovered address from ECDSA */ function _ecdsaRecover(bytes32 digest, uint8 v, bytes32 r, bytes32 s) private pure returns (bool isError, address signer) { if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { // Invalid signature `s` value - return isError = true and signer = address(0) to check EIP-1271 return (true, address(0)); } signer = ecrecover(digest, v, r, s); isError = (signer == address(0)); } /** * @notice A gas efficient, and fallback-safe way to call the isValidSignature function for EIP-1271. * * @param signer The EIP-1271 signer to call to check for a valid signature. * @param hash The hash digest to verify with the EIP-1271 signer. * @param signature The supplied signature to verify. * * @return isValid True if the EIP-1271 signer returns the EIP-1271 magic value. */ function _safeIsValidSignature( address signer, bytes32 hash, bytes calldata signature ) private view returns(bool isValid) { assembly { function _callIsValidSignature(_signer, _hash, _signatureOffset, _signatureLength) -> _isValid { let ptr := mload(0x40) // store isValidSignature(bytes32,bytes) selector mstore(ptr, hex"1626ba7e") // store bytes32 hash value in abi encoded location mstore(add(ptr, 0x04), _hash) // store abi encoded location of the bytes signature data mstore(add(ptr, 0x24), 0x40) // store bytes signature length mstore(add(ptr, 0x44), _signatureLength) // copy calldata bytes signature to memory calldatacopy(add(ptr, 0x64), _signatureOffset, _signatureLength) // calculate data length based on abi encoded data with rounded up signature length let dataLength := add(0x64, and(add(_signatureLength, 0x1F), not(0x1F))) // update free memory pointer mstore(0x40, add(ptr, dataLength)) // static call _signer with abi encoded data // skip return data check if call failed or return data size is not at least 32 bytes if and(iszero(lt(returndatasize(), 0x20)), staticcall(gas(), _signer, ptr, dataLength, 0x00, 0x20)) { // check if return data is equal to isValidSignature magic value _isValid := eq(mload(0x00), hex"1626ba7e") leave } } isValid := _callIsValidSignature(signer, hash, signature.offset, signature.length) } } /** * ================================================= * ===================== Hooks ===================== * ================================================= */ /** * @dev This function is empty by default. Override it to add additional logic after the approval transfer. * @dev The function returns a boolean value instead of reverting to indicate if there is an error for more granular control in inheriting protocols. */ function _beforeTransferFrom(uint256 tokenType, address token, address owner, address to, uint256 id, uint256 amount) internal virtual returns (bool isError) {} /** * ================================================= * ==================== Internal =================== * ================================================= */ /** * @notice Checks if an advanced permit typehash has been registered with PermitC * * @dev Throws when the typehash has not been registered * * @param advancedPermitHash The permit typehash to check */ function _requireTransferAdvancedPermitHashIsRegistered(bytes32 advancedPermitHash) private view { if (!_registeredTransferHashes[advancedPermitHash]) { revert PermitC__SignatureTransferPermitHashNotRegistered(); } } /** * @notice Checks if an advanced permit typehash has been registered with PermitC * * @dev Throws when the typehash has not been registered * * @param advancedPermitHash The permit typehash to check */ function _requireOrderAdvancedPermitHashIsRegistered(bytes32 advancedPermitHash) private view { if (!_registeredOrderHashes[advancedPermitHash]) { revert PermitC__SignatureTransferPermitHashNotRegistered(); } } /** * @notice Invalidates an account nonce if it has not been previously used * * @dev Throws when the nonce was previously used * * @param account The account to invalidate the nonce of * @param nonce The nonce to invalidate */ function _checkAndInvalidateNonce(address account, uint256 nonce) private { unchecked { if (uint256(_unorderedNonces[account][uint248(nonce >> 8)] ^= (ONE << uint8(nonce))) & (ONE << uint8(nonce)) == ZERO) { revert PermitC__NonceAlreadyUsedOrRevoked(); } } } /** * @notice Checks an approval to ensure it is sufficient for the `amount` to send * * @dev Throws when the approval is expired * @dev Throws when the approved amount is insufficient * * @param owner The owner of the token * @param tokenType The type of token * @param token The address of the token * @param id The id of the token * @param amount The amount to deduct from the approval * @param zeroOutApproval True if the approval should be set to zero * * @return approval Storage pointer for the approval data */ function _checkAndUpdateApproval( address owner, uint256 tokenType, address token, uint256 id, uint256 amount, bool zeroOutApproval ) private returns (PackedApproval storage approval) { approval = _getPackedApprovalPtr(_transferApprovals, owner, tokenType, token, id, ZERO_BYTES32, msg.sender); if (approval.expiration < block.timestamp) { revert PermitC__ApprovalTransferPermitExpiredOrUnset(); } if (approval.amount < amount) { revert PermitC__ApprovalTransferExceededPermittedAmount(); } if(zeroOutApproval) { approval.amount = 0; } else if (approval.amount < type(uint200).max) { unchecked { approval.amount -= uint200(amount); } } } /** * @notice Gets the storage pointer for an approval * * @param _approvals The mapping to retrieve the approval from * @param account The account the approval is from * @param tokenType The type of token the approval is for * @param token The address of the token * @param id The id of the token * @param orderId The order id for the approval * @param operator The operator for the approval * * @return approval Storage pointer for the approval data */ function _getPackedApprovalPtr( mapping(bytes32 => mapping(address => PackedApproval)) storage _approvals, address account, uint256 tokenType, address token, uint256 id, bytes32 orderId, address operator ) private view returns (PackedApproval storage approval) { approval = _approvals[_getPackedApprovalKey(account, tokenType, token, id, orderId)][operator]; } /** * @notice Gets the storage key for the mapping for a specific approval * * @param owner The owner of the token * @param tokenType The type of token * @param token The address of the token * @param id The id of the token * @param orderId The order id of the approval * * @return key The key value to use to access the approval in the mapping */ function _getPackedApprovalKey(address owner, uint256 tokenType, address token, uint256 id, bytes32 orderId) private view returns (bytes32 key) { key = keccak256(abi.encode(owner, tokenType, token, id, orderId, _masterNonces[owner])); } /** * @notice Checks the permit approval for a single use permit without additional data * * @dev Throws when the `nonce` has already been consumed * @dev Throws when the permit amount is less than the transfer amount * @dev Throws when the permit is expired * @dev Throws when the signature is invalid * * @param tokenType The type of token * @param token The address of the token * @param id The id of the token * @param permitAmount The amount authorized by the owner signature * @param nonce The nonce of the permit * @param expiration The time the permit expires * @param owner The owner of the token * @param transferAmount The amount of tokens requested to transfer * @param signedPermit The signature for the permit */ function _checkPermitApproval( uint256 tokenType, address token, uint256 id, uint256 permitAmount, uint256 nonce, uint256 expiration, address owner, uint256 transferAmount, bytes calldata signedPermit ) private { bytes32 digest = _hashTypedDataV4( PermitHash.hashSingleUsePermit( tokenType, token, id, permitAmount, nonce, expiration, _masterNonces[owner] ) ); _checkPermitData( nonce, expiration, transferAmount, permitAmount, owner, digest, signedPermit ); } /** * @notice Overload of `_checkPermitApprovalWithAdditionalData` to supply TOKEN_TYPE_ERC1155 * * @dev Prevents stack too deep in `permitTransferFromWithAdditionalDataERC1155` * @dev Throws when the `nonce` has already been consumed * @dev Throws when the permit amount is less than the transfer amount * @dev Throws when the permit is expired * @dev Throws when the signature is invalid * * @param token The address of the token * @param id The id of the token * @param permitAmount The amount authorized by the owner signature * @param nonce The nonce of the permit * @param expiration The time the permit expires * @param owner The owner of the token * @param transferAmount The amount of tokens requested to transfer * @param signedPermit The signature for the permit * @param additionalData The additional data to validate with the permit signature * @param advancedPermitHash The typehash of the permit to use for validating the signature */ function _checkPermitApprovalWithAdditionalDataERC1155( address token, uint256 id, uint256 permitAmount, uint256 nonce, uint256 expiration, address owner, uint256 transferAmount, bytes calldata signedPermit, bytes32 additionalData, bytes32 advancedPermitHash ) private { _checkPermitApprovalWithAdditionalData( TOKEN_TYPE_ERC1155, token, id, permitAmount, nonce, expiration, owner, transferAmount, signedPermit, additionalData, advancedPermitHash ); } /** * @notice Overload of `_checkPermitApprovalWithAdditionalData` to supply TOKEN_TYPE_ERC20 * * @dev Prevents stack too deep in `permitTransferFromWithAdditionalDataERC220` * @dev Throws when the `nonce` has already been consumed * @dev Throws when the permit amount is less than the transfer amount * @dev Throws when the permit is expired * @dev Throws when the signature is invalid * * @param token The address of the token * @param id The id of the token * @param permitAmount The amount authorized by the owner signature * @param nonce The nonce of the permit * @param expiration The time the permit expires * @param owner The owner of the token * @param transferAmount The amount of tokens requested to transfer * @param signedPermit The signature for the permit * @param additionalData The additional data to validate with the permit signature * @param advancedPermitHash The typehash of the permit to use for validating the signature */ function _checkPermitApprovalWithAdditionalDataERC20( address token, uint256 id, uint256 permitAmount, uint256 nonce, uint256 expiration, address owner, uint256 transferAmount, bytes calldata signedPermit, bytes32 additionalData, bytes32 advancedPermitHash ) private { _checkPermitApprovalWithAdditionalData( TOKEN_TYPE_ERC20, token, id, permitAmount, nonce, expiration, owner, transferAmount, signedPermit, additionalData, advancedPermitHash ); } /** * @notice Overload of `_checkPermitApprovalWithAdditionalData` to supply TOKEN_TYPE_ERC721 * * @dev Prevents stack too deep in `permitTransferFromWithAdditionalDataERC721` * @dev Throws when the `nonce` has already been consumed * @dev Throws when the permit amount is less than the transfer amount * @dev Throws when the permit is expired * @dev Throws when the signature is invalid * * @param token The address of the token * @param id The id of the token * @param permitAmount The amount authorized by the owner signature * @param nonce The nonce of the permit * @param expiration The time the permit expires * @param owner The owner of the token * @param transferAmount The amount of tokens requested to transfer * @param signedPermit The signature for the permit * @param additionalData The additional data to validate with the permit signature * @param advancedPermitHash The typehash of the permit to use for validating the signature */ function _checkPermitApprovalWithAdditionalDataERC721( address token, uint256 id, uint256 permitAmount, uint256 nonce, uint256 expiration, address owner, uint256 transferAmount, bytes calldata signedPermit, bytes32 additionalData, bytes32 advancedPermitHash ) private { _checkPermitApprovalWithAdditionalData( TOKEN_TYPE_ERC721, token, id, permitAmount, nonce, expiration, owner, transferAmount, signedPermit, additionalData, advancedPermitHash ); } /** * @notice Checks the permit approval for a single use permit with additional data * * @dev Throws when the `nonce` has already been consumed * @dev Throws when the permit amount is less than the transfer amount * @dev Throws when the permit is expired * @dev Throws when the signature is invalid * * @param tokenType The type of token * @param token The address of the token * @param id The id of the token * @param permitAmount The amount authorized by the owner signature * @param nonce The nonce of the permit * @param expiration The time the permit expires * @param owner The owner of the token * @param transferAmount The amount of tokens requested to transfer * @param signedPermit The signature for the permit * @param additionalData The additional data to validate with the permit signature * @param advancedPermitHash The typehash of the permit to use for validating the signature */ function _checkPermitApprovalWithAdditionalData( uint256 tokenType, address token, uint256 id, uint256 permitAmount, uint256 nonce, uint256 expiration, address owner, uint256 transferAmount, bytes calldata signedPermit, bytes32 additionalData, bytes32 advancedPermitHash ) private { bytes32 digest = _getAdvancedTypedDataV4PermitHash( tokenType, token, id, permitAmount, owner, nonce, expiration, additionalData, advancedPermitHash ); _checkPermitData( nonce, expiration, transferAmount, permitAmount, owner, digest, signedPermit ); } /** * @notice Checks that a single use permit has not expired, was authorized for the amount * @notice being transferred, has a valid nonce and has a valid signature. * * @dev Throws when the `nonce` has already been consumed * @dev Throws when the permit amount is less than the transfer amount * @dev Throws when the permit is expired * @dev Throws when the signature is invalid * * @param nonce The nonce of the permit * @param expiration The time the permit expires * @param transferAmount The amount of tokens requested to transfer * @param permitAmount The amount authorized by the owner signature * @param owner The owner of the token * @param digest The digest that was signed by the owner * @param signedPermit The signature for the permit */ function _checkPermitData( uint256 nonce, uint256 expiration, uint256 transferAmount, uint256 permitAmount, address owner, bytes32 digest, bytes calldata signedPermit ) private { if (block.timestamp > expiration) { revert PermitC__SignatureTransferExceededPermitExpired(); } if (transferAmount > permitAmount) { revert PermitC__SignatureTransferExceededPermittedAmount(); } _checkAndInvalidateNonce(owner, nonce); _verifyPermitSignature(digest, signedPermit, owner); } /** * @notice Stores an approval for future use by `operator` to move tokens on behalf of `owner` * * @param tokenType The type of token * @param token The address of the token * @param id The id of the token * @param amount The amount authorized by the owner * @param expiration The time the permit expires * @param owner The owner of the token * @param operator The account allowed to transfer the tokens */ function _storeApproval( uint256 tokenType, address token, uint256 id, uint200 amount, uint48 expiration, address owner, address operator ) private { PackedApproval storage approval = _getPackedApprovalPtr(_transferApprovals, owner, tokenType, token, id, ZERO_BYTES32, operator); approval.expiration = expiration; approval.amount = amount; emit Approval(owner, token, operator, id, amount, expiration); } /** * @notice Overload of `_checkOrderTransfer` to supply TOKEN_TYPE_ERC1155 * * @dev Prevents stack too deep in `fillPermittedOrderERC1155` * @dev Throws when the order start amount is greater than type(uint200).max * @dev Throws when the order status is not open * @dev Throws when the signature is invalid * @dev Throws when the permit is expired * * @param signedPermit The signature for the permit * @param orderFillAmounts A struct containing the order start, requested fill and minimum fill amounts * @param token The address of the token * @param id The id of the token * @param owner The owner of the token * @param salt The salt value for the permit * @param expiration The time the permit expires * @param orderId The order id for the permit * @param advancedPermitHash The typehash of the permit to use for validating the signature * * @return orderStatus Storage pointer for the approval data */ function _checkOrderTransferERC1155( bytes calldata signedPermit, OrderFillAmounts calldata orderFillAmounts, address token, uint256 id, address owner, uint256 salt, uint48 expiration, bytes32 orderId, bytes32 advancedPermitHash ) private returns (PackedApproval storage orderStatus) { orderStatus = _checkOrderTransfer( signedPermit, orderFillAmounts, TOKEN_TYPE_ERC1155, token, id, owner, salt, expiration, orderId, advancedPermitHash ); } /** * @notice Overload of `_checkOrderTransfer` to supply TOKEN_TYPE_ERC20 * * @dev Prevents stack too deep in `fillPermittedOrderERC20` * @dev Throws when the order start amount is greater than type(uint200).max * @dev Throws when the order status is not open * @dev Throws when the signature is invalid * @dev Throws when the permit is expired * * @param signedPermit The signature for the permit * @param orderFillAmounts A struct containing the order start, requested fill and minimum fill amounts * @param token The address of the token * @param id The id of the token * @param owner The owner of the token * @param salt The salt value for the permit * @param expiration The time the permit expires * @param orderId The order id for the permit * @param advancedPermitHash The typehash of the permit to use for validating the signature * * @return orderStatus Storage pointer for the approval data */ function _checkOrderTransferERC20( bytes calldata signedPermit, OrderFillAmounts calldata orderFillAmounts, address token, uint256 id, address owner, uint256 salt, uint48 expiration, bytes32 orderId, bytes32 advancedPermitHash ) private returns (PackedApproval storage orderStatus) { orderStatus = _checkOrderTransfer( signedPermit, orderFillAmounts, TOKEN_TYPE_ERC20, token, id, owner, salt, expiration, orderId, advancedPermitHash ); } /** * @notice Validates an order transfer to check order start amount, status, signature if not previously * @notice opened, and expiration. * * @dev Throws when the order start amount is greater than type(uint200).max * @dev Throws when the order status is not open * @dev Throws when the signature is invalid * @dev Throws when the permit is expired * * @param signedPermit The signature for the permit * @param orderFillAmounts A struct containing the order start, requested fill and minimum fill amounts * @param tokenType The type of token * @param token The address of the token * @param id The id of the token * @param owner The owner of the token * @param salt The salt value for the permit * @param expiration The time the permit expires * @param orderId The order id for the permit * @param advancedPermitHash The typehash of the permit to use for validating the signature * * @return orderStatus Storage pointer for the approval data */ function _checkOrderTransfer( bytes calldata signedPermit, OrderFillAmounts calldata orderFillAmounts, uint256 tokenType, address token, uint256 id, address owner, uint256 salt, uint48 expiration, bytes32 orderId, bytes32 advancedPermitHash ) private returns (PackedApproval storage orderStatus) { if (orderFillAmounts.orderStartAmount > type(uint200).max) { revert PermitC__AmountExceedsStorageMaximum(); } orderStatus = _getPackedApprovalPtr(_orderApprovals, owner, tokenType, token, id, orderId, msg.sender); if (orderStatus.state == ORDER_STATE_OPEN) { if (orderStatus.amount == 0) { _verifyPermitSignature( _getAdvancedTypedDataV4PermitHash( tokenType, token, id, orderFillAmounts.orderStartAmount, owner, salt, expiration, orderId, advancedPermitHash ), signedPermit, owner ); orderStatus.amount = uint200(orderFillAmounts.orderStartAmount); orderStatus.expiration = expiration; emit OrderOpened(orderId, owner, msg.sender, orderFillAmounts.orderStartAmount); } if (block.timestamp > orderStatus.expiration) { revert PermitC__SignatureTransferExceededPermitExpired(); } } else { revert PermitC__OrderIsEitherCancelledOrFilled(); } } /** * @notice Checks the order fill amounts against approval data and transfers tokens, updates * @notice approval if the fill results in the order being closed. * * @dev Throws when the amount to fill is less than the minimum fill amount * * @param orderStatus Storage pointer for the approval data * @param orderFillAmounts A struct containing the order start, requested fill and minimum fill amounts * @param token The address of the token * @param id The id of the token * @param owner The owner of the token * @param to The address to send the tokens to * @param orderId The order id for the permit * @param _transferFrom Function pointer of the transfer function to send tokens with * * @return quantityFilled The number of tokens filled in the order * @return isError True if there was an error transferring tokens, false otherwise */ function _orderTransfer( PackedApproval storage orderStatus, OrderFillAmounts calldata orderFillAmounts, address token, uint256 id, address owner, address to, bytes32 orderId, function (address, address, address, uint256, uint256) internal returns (bool) _transferFrom ) private returns (uint256 quantityFilled, bool isError) { quantityFilled = orderFillAmounts.requestedFillAmount; if (quantityFilled > orderStatus.amount) { quantityFilled = orderStatus.amount; } if (quantityFilled < orderFillAmounts.minimumFillAmount) { revert PermitC__UnableToFillMinimumRequestedQuantity(); } unchecked { orderStatus.amount -= uint200(quantityFilled); emit OrderFilled(orderId, owner, msg.sender, quantityFilled); } if (orderStatus.amount == 0) { orderStatus.state = ORDER_STATE_FILLED; emit OrderClosed(orderId, owner, msg.sender, false); } isError = _transferFrom(token, owner, to, id, quantityFilled); } /** * @notice Restores an account's nonce when a transfer was not successful * * @dev Throws when the nonce was not already consumed * * @param account The account to restore the nonce of * @param nonce The nonce to restore */ function _restoreNonce(address account, uint256 nonce) private { unchecked { if (uint256(_unorderedNonces[account][uint248(nonce >> 8)] ^= (ONE << uint8(nonce))) & (ONE << uint8(nonce)) != ZERO) { revert PermitC__NonceNotUsedOrRevoked(); } } } /** * @notice Restores an approval amount when a transfer was not successful * * @param approval Storage pointer for the approval data * @param owner The owner of the tokens * @param orderId The order id to restore approval amount on * @param unfilledAmount The amount that was not filled on the order * @param isOrderPermit True if the fill restoration is for an permit order */ function _restoreFillableItems( PackedApproval storage approval, address owner, bytes32 orderId, uint256 unfilledAmount, bool isOrderPermit ) private { if (unfilledAmount > 0) { if (isOrderPermit) { // Order permits always deduct amount and must be restored unchecked { approval.amount += uint200(unfilledAmount); } approval.state = ORDER_STATE_OPEN; emit OrderRestored(orderId, owner, unfilledAmount); } else if (approval.amount < type(uint200).max) { // Stored approvals only deduct amount unchecked { approval.amount += uint200(unfilledAmount); } } } } function _requireValidTokenType(uint256 tokenType) private pure { if(!( tokenType == TOKEN_TYPE_ERC721 || tokenType == TOKEN_TYPE_ERC1155 || tokenType == TOKEN_TYPE_ERC20 ) ) { revert PermitC__InvalidTokenType(); } } /** * @notice Generates an EIP-712 digest for a permit * * @param tokenType The type of token * @param token The address of the token * @param id The id of the token * @param amount The amount authorized by the owner signature * @param owner The owner of the token * @param nonce The nonce for the permit * @param expiration The time the permit expires * @param additionalData The additional data to validate with the permit signature * @param advancedPermitHash The typehash of the permit to use for validating the signature * * @return digest The EIP-712 digest of the permit data */ function _getAdvancedTypedDataV4PermitHash( uint256 tokenType, address token, uint256 id, uint256 amount, address owner, uint256 nonce, uint256 expiration, bytes32 additionalData, bytes32 advancedPermitHash ) private view returns (bytes32 digest) { // cache masterNonce on stack to avoid stack too deep uint256 masterNonce_ = _masterNonces[owner]; digest = _hashTypedDataV4( PermitHash.hashSingleUsePermitWithAdditionalData( tokenType, token, id, amount, nonce, expiration, additionalData, advancedPermitHash, masterNonce_ ) ); } /** * @notice Returns the current allowed amount and expiration for a stored permit * * @dev Returns zero allowed if the permit has expired * * @param _approvals The mapping to retrieve the approval from * @param owner The account the approval is from * @param operator The operator for the approval * @param tokenType The type of token the approval is for * @param token The address of the token * @param id The id of the token * @param orderId The order id for the approval * * @return allowedAmount The amount authorized by the approval, zero if the permit has expired * @return expiration The expiration of the approval */ function _allowance( mapping(bytes32 => mapping(address => PackedApproval)) storage _approvals, address owner, address operator, uint256 tokenType, address token, uint256 id, bytes32 orderId ) private view returns (uint256 allowedAmount, uint256 expiration) { PackedApproval storage allowed = _getPackedApprovalPtr(_approvals, owner, tokenType, token, id, orderId, operator); allowedAmount = allowed.expiration < block.timestamp ? 0 : allowed.amount; expiration = allowed.expiration; } /** * @notice Allows the owner of the PermitC contract to access pausable admin functions * * @dev May be overriden by an inheriting contract to provide alternative permission structure */ function _requireCallerHasPausePermissions() internal view virtual override { _checkOwner(); } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @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. * * ``` * 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. * ==== */ library EnumerableSet { // 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. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @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) private returns (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._indexes[value] = set._values.length; return true; } else { return false; } } /** * @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) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 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 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (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) private view returns (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) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { 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. */ function add(Bytes32Set storage set, bytes32 value) internal returns (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. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (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}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (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. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { 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. */ function add(AddressSet storage set, address value) internal returns (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. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (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}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(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. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { 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. */ function add(UintSet storage set, uint256 value) internal returns (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. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (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}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return 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. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; contract Tstorish { // Declare a storage variable indicating if TSTORE support has been // activated post-deployment. bool private _tstoreSupport; /* * ------------------------------------------------------------------------+ * Opcode | Mnemonic | Stack | Memory | * ------------------------------------------------------------------------| * 60 0x02 | PUSH1 0x02 | 0x02 | | * 60 0x1e | PUSH1 0x1e | 0x1e 0x02 | | * 61 0x3d5c | PUSH2 0x3d5c | 0x3d5c 0x1e 0x02 | | * 3d | RETURNDATASIZE | 0 0x3d5c 0x1e 0x02 | | * | * :: store deployed bytecode in memory: (3d) RETURNDATASIZE (5c) TLOAD :: | * 52 | MSTORE | 0x1e 0x02 | [0..0x20): 0x3d5c | * f3 | RETURN | | [0..0x20): 0x3d5c | * ------------------------------------------------------------------------+ */ uint256 constant _TLOAD_TEST_PAYLOAD = 0x6002_601e_613d5c_3d_52_f3; uint256 constant _TLOAD_TEST_PAYLOAD_LENGTH = 0x0a; uint256 constant _TLOAD_TEST_PAYLOAD_OFFSET = 0x16; // Declare an immutable variable to store the initial TSTORE support status. bool private immutable _tstoreInitialSupport; // Declare an immutable variable to store the tstore test contract address. address private immutable _tloadTestContract; // Declare a few custom revert error types. error TStoreAlreadyActivated(); error TStoreNotSupported(); error TloadTestContractDeploymentFailed(); error OnlyDirectCalls(); /** * @dev Determine TSTORE availability during deployment. This involves * attempting to deploy a contract that utilizes TLOAD as part of the * contract construction bytecode, and configuring initial support for * using TSTORE in place of SSTORE based on the result. */ constructor() { // Deploy the contract testing TLOAD support and store the address. address tloadTestContract = _prepareTloadTest(); // Ensure the deployment was successful. if (tloadTestContract == address(0)) { revert TloadTestContractDeploymentFailed(); } // Determine if TSTORE is supported. bool tstoreInitialSupport = _testTload(tloadTestContract); // Store the result as an immutable. _tstoreInitialSupport = tstoreInitialSupport; // Set the address of the deployed TLOAD test contract as an immutable. _tloadTestContract = tloadTestContract; } /** * @dev External function to activate TSTORE usage. Does not need to be * called if TSTORE is supported from deployment, and only needs to be * called once. Reverts if TSTORE has already been activated or if the * opcode is not available. Note that this must be called directly from * an externally-owned account to avoid potential reentrancy issues. */ function __activateTstore() external { // Ensure this function is triggered from an externally-owned account. if (msg.sender != tx.origin) { revert OnlyDirectCalls(); } // Determine if TSTORE can potentially be activated. if (_tstoreInitialSupport || _tstoreSupport) { revert TStoreAlreadyActivated(); } // Determine if TSTORE can be activated and revert if not. if (!_testTload(_tloadTestContract)) { revert TStoreNotSupported(); } // Mark TSTORE as activated. _tstoreSupport = true; } /** * @dev Internal function to set a TSTORISH value. * * @param storageSlot The slot to write the TSTORISH value to. * @param value The value to write to the given storage slot. */ function _setTstorish(uint256 storageSlot, uint256 value) internal { if (_tstoreInitialSupport) { assembly { tstore(storageSlot, value) } } else if (_tstoreSupport) { assembly { tstore(storageSlot, value) } } else { assembly { sstore(storageSlot, value) } } } /** * @dev Internal function to read a TSTORISH value. * * @param storageSlot The slot to read the TSTORISH value from. * * @return value The TSTORISH value at the given storage slot. */ function _getTstorish( uint256 storageSlot ) internal view returns (uint256 value) { if (_tstoreInitialSupport) { assembly { value := tload(storageSlot) } } else if (_tstoreSupport) { assembly { value := tload(storageSlot) } } else { assembly { value := sload(storageSlot) } } } /** * @dev Internal function to clear a TSTORISH value. * * @param storageSlot The slot to clear the TSTORISH value for. */ function _clearTstorish(uint256 storageSlot) internal { if (_tstoreInitialSupport) { assembly { tstore(storageSlot, 0) } } else if (_tstoreSupport) { assembly { tstore(storageSlot, 0) } } else { assembly { sstore(storageSlot, 0) } } } /** * @dev Private function to deploy a test contract that utilizes TLOAD as * part of its fallback logic. */ function _prepareTloadTest() private returns (address contractAddress) { // Utilize assembly to deploy a contract testing TLOAD support. assembly { // Write the contract deployment code payload to scratch space. mstore(0, _TLOAD_TEST_PAYLOAD) // Deploy the contract. contractAddress := create( 0, _TLOAD_TEST_PAYLOAD_OFFSET, _TLOAD_TEST_PAYLOAD_LENGTH ) } } /** * @dev Private view function to determine if TSTORE/TLOAD are supported by * the current EVM implementation by attempting to call the test * contract, which utilizes TLOAD as part of its fallback logic. */ function _testTload( address tloadTestContract ) private view returns (bool ok) { // Call the test contract, which will perform a TLOAD test. If the call // does not revert, then TLOAD/TSTORE is supported. Do not forward all // available gas, as all forwarded gas will be consumed on revert. (ok, ) = tloadTestContract.staticcall{ gas: gasleft() / 10 }(""); } }// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../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. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @dev Thrown when a stored approval exceeds type(uint200).max error PermitC__AmountExceedsStorageMaximum(); /// @dev Thrown when a transfer amount requested exceeds the permitted amount error PermitC__ApprovalTransferExceededPermittedAmount(); /// @dev Thrown when a transfer is requested after the permit has expired error PermitC__ApprovalTransferPermitExpiredOrUnset(); /// @dev Thrown when attempting to close an order by an account that is not the owner or operator error PermitC__CallerMustBeOwnerOrOperator(); /// @dev Thrown when attempting to approve a token type that is not valid for PermitC error PermitC__InvalidTokenType(); /// @dev Thrown when attempting to invalidate a nonce that has already been used error PermitC__NonceAlreadyUsedOrRevoked(); /// @dev Thrown when attempting to restore a nonce that has not been used error PermitC__NonceNotUsedOrRevoked(); /// @dev Thrown when attempting to fill an order that has already been filled or cancelled error PermitC__OrderIsEitherCancelledOrFilled(); /// @dev Thrown when a transfer amount requested exceeds the permitted amount error PermitC__SignatureTransferExceededPermittedAmount(); /// @dev Thrown when a transfer is requested after the permit has expired error PermitC__SignatureTransferExceededPermitExpired(); /// @dev Thrown when attempting to use an advanced permit typehash that is not registered error PermitC__SignatureTransferPermitHashNotRegistered(); /// @dev Thrown when a permit signature is invalid error PermitC__SignatureTransferInvalidSignature(); /// @dev Thrown when the remaining fill amount is less than the requested minimum fill error PermitC__UnableToFillMinimumRequestedQuantity();// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol"; // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC721.sol) pragma solidity ^0.8.0; import "../token/ERC721/IERC721.sol"; // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC1155.sol) pragma solidity ^0.8.0; import "../token/ERC1155/IERC1155.sol"; // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. * * _Available since v4.1._ */ interface IERC1271 { /** * @dev Should return whether the signature provided is valid for the provided data * @param hash Hash of the data to be signed * @param signature Signature byte array associated with _data */ function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import {Context} from "@openzeppelin/contracts/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. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { error Ownable__CallerIsNotOwner(); error Ownable__NewOwnerIsZeroAddress(); address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if(owner() != _msgSender()) revert Ownable__CallerIsNotOwner(); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if(newOwner == address(0)) revert Ownable__NewOwnerIsZeroAddress(); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.8; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. * * _Available since v3.4._ * * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment */ abstract contract EIP712 { bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _cachedDomainSeparator; uint256 private immutable _cachedChainId; bytes32 private immutable _hashedName; bytes32 private immutable _hashedVersion; /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { _hashedName = keccak256(bytes(name)); _hashedVersion = keccak256(bytes(version)); _cachedChainId = block.chainid; _cachedDomainSeparator = _buildDomainSeparator(); } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { if (block.chainid == _cachedChainId) { return _cachedDomainSeparator; } else { return _buildDomainSeparator(); } } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash); } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @dev Constant bytes32 value of 0x000...000 bytes32 constant ZERO_BYTES32 = bytes32(0); /// @dev Constant value of 0 uint256 constant ZERO = 0; /// @dev Constant value of 1 uint256 constant ONE = 1; /// @dev Constant value representing an open order in storage uint8 constant ORDER_STATE_OPEN = 0; /// @dev Constant value representing a filled order in storage uint8 constant ORDER_STATE_FILLED = 1; /// @dev Constant value representing a cancelled order in storage uint8 constant ORDER_STATE_CANCELLED = 2; /// @dev Constant value representing the ERC721 token type for signatures and transfer hooks uint256 constant TOKEN_TYPE_ERC721 = 721; /// @dev Constant value representing the ERC1155 token type for signatures and transfer hooks uint256 constant TOKEN_TYPE_ERC1155 = 1155; /// @dev Constant value representing the ERC20 token type for signatures and transfer hooks uint256 constant TOKEN_TYPE_ERC20 = 20; /// @dev Constant value to mask the upper bits of a signature that uses a packed `vs` value to extract `s` bytes32 constant UPPER_BIT_MASK = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; /// @dev EIP-712 typehash used for validating signature based stored approvals bytes32 constant UPDATE_APPROVAL_TYPEHASH = keccak256("UpdateApprovalBySignature(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 approvalExpiration,uint256 sigDeadline,uint256 masterNonce)"); /// @dev EIP-712 typehash used for validating a single use permit without additional data bytes32 constant SINGLE_USE_PERMIT_TYPEHASH = keccak256("PermitTransferFrom(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 expiration,uint256 masterNonce)"); /// @dev EIP-712 typehash used for validating a single use permit with additional data string constant SINGLE_USE_PERMIT_TRANSFER_ADVANCED_TYPEHASH_STUB = "PermitTransferFromWithAdditionalData(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 expiration,uint256 masterNonce,"; /// @dev EIP-712 typehash used for validating an order permit that updates storage as it fills string constant PERMIT_ORDER_ADVANCED_TYPEHASH_STUB = "PermitOrderWithAdditionalData(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 salt,address operator,uint256 expiration,uint256 masterNonce,"; /// @dev Pausable flag for stored approval transfers of ERC721 assets uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC721 = 1 << 0; /// @dev Pausable flag for stored approval transfers of ERC1155 assets uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC1155 = 1 << 1; /// @dev Pausable flag for stored approval transfers of ERC20 assets uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC20 = 1 << 2; /// @dev Pausable flag for single use permit transfers of ERC721 assets uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC721 = 1 << 3; /// @dev Pausable flag for single use permit transfers of ERC1155 assets uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC1155 = 1 << 4; /// @dev Pausable flag for single use permit transfers of ERC20 assets uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC20 = 1 << 5; /// @dev Pausable flag for order fill transfers of ERC1155 assets uint256 constant PAUSABLE_ORDER_TRANSFER_FROM_ERC1155 = 1 << 6; /// @dev Pausable flag for order fill transfers of ERC20 assets uint256 constant PAUSABLE_ORDER_TRANSFER_FROM_ERC20 = 1 << 7;// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @dev Storage data struct for stored approvals and order approvals struct PackedApproval { // Only used for partial fill position 1155 transfers uint8 state; // Amount allowed uint200 amount; // Permission expiry uint48 expiration; } /// @dev Calldata data struct for order fill amounts struct OrderFillAmounts { uint256 orderStartAmount; uint256 requestedFillAmount; uint256 minimumFillAmount; }// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {SINGLE_USE_PERMIT_TYPEHASH, UPDATE_APPROVAL_TYPEHASH} from "../Constants.sol"; library PermitHash { /** * @notice Hashes the permit data for a stored approval * * @param tokenType The type of token * @param token The address of the token * @param id The id of the token * @param amount The amount authorized by the owner signature * @param nonce The nonce for the permit * @param operator The account that is allowed to use the permit * @param approvalExpiration The time the permit approval expires * @param sigDeadline The deadline for submitting the permit onchain * @param masterNonce The signers master nonce * * @return hash The hash of the permit data */ function hashOnChainApproval( uint256 tokenType, address token, uint256 id, uint256 amount, uint256 nonce, address operator, uint256 approvalExpiration, uint256 sigDeadline, uint256 masterNonce ) internal pure returns (bytes32 hash) { hash = keccak256( abi.encode( UPDATE_APPROVAL_TYPEHASH, tokenType, token, id, amount, nonce, operator, approvalExpiration, sigDeadline, masterNonce ) ); } /** * @notice Hashes the permit data with the single user permit without additional data typehash * * @param tokenType The type of token * @param token The address of the token * @param id The id of the token * @param amount The amount authorized by the owner signature * @param nonce The nonce for the permit * @param expiration The time the permit expires * @param masterNonce The signers master nonce * * @return hash The hash of the permit data */ function hashSingleUsePermit( uint256 tokenType, address token, uint256 id, uint256 amount, uint256 nonce, uint256 expiration, uint256 masterNonce ) internal view returns (bytes32 hash) { hash = keccak256( abi.encode( SINGLE_USE_PERMIT_TYPEHASH, tokenType, token, id, amount, nonce, msg.sender, expiration, masterNonce ) ); } /** * @notice Hashes the permit data with the supplied typehash * * @param tokenType The type of token * @param token The address of the token * @param id The id of the token * @param amount The amount authorized by the owner signature * @param nonce The nonce for the permit * @param expiration The time the permit expires * @param additionalData The additional data to validate with the permit signature * @param additionalDataTypeHash The typehash of the permit to use for validating the signature * @param masterNonce The signers master nonce * * @return hash The hash of the permit data with the supplied typehash */ function hashSingleUsePermitWithAdditionalData( uint256 tokenType, address token, uint256 id, uint256 amount, uint256 nonce, uint256 expiration, bytes32 additionalData, bytes32 additionalDataTypeHash, uint256 masterNonce ) internal view returns (bytes32 hash) { hash = keccak256( abi.encode( additionalDataTypeHash, tokenType, token, id, amount, nonce, msg.sender, expiration, masterNonce, additionalData ) ); } } // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import {OrderFillAmounts} from "../DataTypes.sol"; interface IPermitC { /** * ================================================= * ==================== Events ===================== * ================================================= */ /// @dev Emitted when an approval is stored event Approval( address indexed owner, address indexed token, address indexed operator, uint256 id, uint200 amount, uint48 expiration ); /// @dev Emitted when a user increases their master nonce event Lockdown(address indexed owner); /// @dev Emitted when an order is opened event OrderOpened( bytes32 indexed orderId, address indexed owner, address indexed operator, uint256 fillableQuantity ); /// @dev Emitted when an order has a fill event OrderFilled( bytes32 indexed orderId, address indexed owner, address indexed operator, uint256 amount ); /// @dev Emitted when an order has been fully filled or cancelled event OrderClosed( bytes32 indexed orderId, address indexed owner, address indexed operator, bool wasCancellation); /// @dev Emitted when an order has an amount restored due to a failed transfer event OrderRestored( bytes32 indexed orderId, address indexed owner, uint256 amountRestoredToOrder ); /** * ================================================= * ============== Approval Transfers =============== * ================================================= */ function approve(uint256 tokenType, address token, uint256 id, address operator, uint200 amount, uint48 expiration) external; function updateApprovalBySignature( uint256 tokenType, address token, uint256 id, uint256 nonce, uint200 amount, address operator, uint48 approvalExpiration, uint48 sigDeadline, address owner, bytes calldata signedPermit ) external; function allowance( address owner, address operator, uint256 tokenType, address token, uint256 id ) external view returns (uint256 amount, uint256 expiration); /** * ================================================= * ================ Signed Transfers =============== * ================================================= */ function registerAdditionalDataHash(string memory additionalDataTypeString) external; function permitTransferFromERC721( address token, uint256 id, uint256 nonce, uint256 expiration, address owner, address to, bytes calldata signedPermit ) external returns (bool isError); function permitTransferFromWithAdditionalDataERC721( address token, uint256 id, uint256 nonce, uint256 expiration, address owner, address to, bytes32 additionalData, bytes32 advancedPermitHash, bytes calldata signedPermit ) external returns (bool isError); function permitTransferFromERC1155( address token, uint256 id, uint256 nonce, uint256 permitAmount, uint256 expiration, address owner, address to, uint256 transferAmount, bytes calldata signedPermit ) external returns (bool isError); function permitTransferFromWithAdditionalDataERC1155( address token, uint256 id, uint256 nonce, uint256 permitAmount, uint256 expiration, address owner, address to, uint256 transferAmount, bytes32 additionalData, bytes32 advancedPermitHash, bytes calldata signedPermit ) external returns (bool isError); function permitTransferFromERC20( address token, uint256 nonce, uint256 permitAmount, uint256 expiration, address owner, address to, uint256 transferAmount, bytes calldata signedPermit ) external returns (bool isError); function permitTransferFromWithAdditionalDataERC20( address token, uint256 nonce, uint256 permitAmount, uint256 expiration, address owner, address to, uint256 transferAmount, bytes32 additionalData, bytes32 advancedPermitHash, bytes calldata signedPermit ) external returns (bool isError); function isRegisteredTransferAdditionalDataHash(bytes32 hash) external view returns (bool isRegistered); function isRegisteredOrderAdditionalDataHash(bytes32 hash) external view returns (bool isRegistered); /** * ================================================= * =============== Order Transfers ================= * ================================================= */ function fillPermittedOrderERC1155( bytes calldata signedPermit, OrderFillAmounts calldata orderFillAmounts, address token, uint256 id, address owner, address to, uint256 nonce, uint48 expiration, bytes32 orderId, bytes32 advancedPermitHash ) external returns (uint256 quantityFilled, bool isError); function fillPermittedOrderERC20( bytes calldata signedPermit, OrderFillAmounts calldata orderFillAmounts, address token, address owner, address to, uint256 nonce, uint48 expiration, bytes32 orderId, bytes32 advancedPermitHash ) external returns (uint256 quantityFilled, bool isError); function closePermittedOrder( address owner, address operator, uint256 tokenType, address token, uint256 id, bytes32 orderId ) external; function allowance( address owner, address operator, uint256 tokenType, address token, uint256 id, bytes32 orderId ) external view returns (uint256 amount, uint256 expiration); /** * ================================================= * ================ Nonce Management =============== * ================================================= */ function invalidateUnorderedNonce(uint256 nonce) external; function isValidUnorderedNonce(address owner, uint256 nonce) external view returns (bool isValid); function lockdown() external; function masterNonce(address owner) external view returns (uint256); /** * ================================================= * ============== Transfer Functions =============== * ================================================= */ function transferFromERC721( address from, address to, address token, uint256 id ) external returns (bool isError); function transferFromERC1155( address from, address to, address token, uint256 id, uint256 amount ) external returns (bool isError); function transferFromERC20( address from, address to, address token, uint256 amount ) external returns (bool isError); /** * ================================================= * ============ Signature Verification ============= * ================================================= */ function domainSeparatorV4() external view returns (bytes32); } //SPDX-License-Identifier: MIT pragma solidity ^0.8.24; /* @@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@( @@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@ #@@@@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@@@@* @@@@@@@@@@@@ @@@@@@@@@@@@@@@ @ @@@@@@@@@@@@ @@@@@@@@@@@@@@@ @ @@@@@@@@@@@ @@@@@@@@@@@@@@@ @@ @@@@@@@@@@@@ @@@@@@@@@@@@@@@ #@@ @@@@@@@@@@@@/ @@@@@@@@@@@@@@. @@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@&%%%%%%%%&&@@@@@@@@@@@@@@ @@@@@@@@@@@@@@ @@@@@ @@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@ @@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@ @@@@@@@@@@@& @@@@@@@@@@@@@@ *@@@@@@@ (@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@@ @@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ .@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@% @@@@@@@@@@@@@@@@@@@@@@@@( @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@& @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ * @title CollateralizedPausableFlags * @custom:version 1.0.0 * @author Limit Break, Inc. * @description Collateralized Pausable Flags is an extension for contracts * that require features to be pausable in the event of potential * or actual threats without incurring a storage read overhead cost * during normal operations by using contract starting balance as * a signal for checking the paused state. * * Using contract balance to enable checking paused state creates an * economic penalty for developers that deploy code that can be * exploited as well as an economic incentive (recovery of collateral) * for them to mitigate the threat. * * Developers implementing Collateralized Pausable Flags should consider * their risk mitigation strategy and ensure funds are readily available * for pausing if ever necessary by setting an appropriate threshold * value and considering use of an escrow contract that can initiate the * pause with funds. * * There is no restriction on the depositor as this can be easily * circumvented through a `SELFDESTRUCT` opcode. * * Developers must be aware of potential outflows from the contract that * could reduce collateral below the pausable check threshold and protect * against those methods when pausing is required. */ abstract contract CollateralizedPausableFlags { /// @dev Emitted when the pausable flags are updated event PausableFlagsUpdated(uint256 previousFlags, uint256 newFlags); /// @dev Thrown when an execution path requires a flag to not be paused but it is paused error CollateralizedPausableFlags__Paused(); /// @dev Thrown when an executin path requires a flag to be paused but it is not paused error CollateralizedPausableFlags__NotPaused(); /// @dev Thrown when a call to withdraw funds fails error CollateralizedPausableFlags__WithdrawFailed(); /// @dev Immutable variable that defines the native funds threshold before flags are checked uint256 private immutable nativeValueToCheckPauseState; /// @dev Flags for current pausable state, each bit is considered a separate flag uint256 private pausableFlags; /// @dev Immutable pointer for the _requireNotPaused function to use based on value threshold function(uint256) internal view immutable _requireNotPaused; /// @dev Immutable pointer for the _requirePaused function to use based on value threshold function(uint256) internal view immutable _requirePaused; /// @dev Immutable pointer for the _getPausableFlags function to use based on value threshold function() internal view returns (uint256) immutable _getPausableFlags; constructor(uint256 _nativeValueToCheckPauseState) { // Optimizes value check at runtime by reducing the stored immutable // value by 1 so that greater than can be used instead of greater // than or equal while allowing the deployment parameter to reflect // the value at which the deployer wants to trigger pause checking. // Example: // Constructed with a value of 1000 // Immutable value stored is 999 // State checking enabled at 1000 units deposited because // 1000 > 999 evaluates true if (_nativeValueToCheckPauseState > 0) { unchecked { _nativeValueToCheckPauseState -= 1; } _requireNotPaused = _requireNotPausedWithCollateralCheck; _requirePaused = _requirePausedWithCollateralCheck; _getPausableFlags = _getPausableFlagsWithCollateralCheck; } else { _requireNotPaused = _requireNotPausedWithoutCollateralCheck; _requirePaused = _requirePausedWithoutCollateralCheck; _getPausableFlags = _getPausableFlagsWithoutCollateralCheck; } nativeValueToCheckPauseState = _nativeValueToCheckPauseState; } /** * @dev Modifier to make a function callable only when the specified flags are not paused * @dev Throws when any of the flags specified are paused * * @param _flags The flags to check for pause state */ modifier whenNotPaused(uint256 _flags) { _requireNotPaused(_flags); _; } /** * @dev Modifier to make a function callable only when the specified flags are paused * @dev Throws when any of the flags specified are not paused * * @param _flags The flags to check for pause state */ modifier whenPaused(uint256 _flags) { _requirePaused(_flags); _; } /** * @dev Modifier to make a function callable only by a permissioned account * @dev Throws when the caller does not have permission */ modifier onlyPausePermissionedCaller() { _requireCallerHasPausePermissions(); _; } /** * @notice Updates the pausable flags settings * * @dev Throws when the caller does not have permission * @dev **NOTE:** Pausable flag settings will only take effect if contract balance exceeds * @dev `nativeValueToPause` * * @dev <h4>Postconditions:</h4> * @dev 1. address(this).balance increases by msg.value * @dev 2. `pausableFlags` is set to the new value * @dev 3. Emits a PausableFlagsUpdated event * * @param _pausableFlags The new pausable flags to set */ function pause(uint256 _pausableFlags) external payable onlyPausePermissionedCaller { _setPausableFlags(_pausableFlags); } /** * @notice Allows any account to supply funds for enabling the pausable checks * * @dev **NOTE:** The threshold check for pausable collateral does not pause * @dev any functions unless the associated pausable flag is set. */ function pausableDepositCollateral() external payable { // thank you for your contribution to safety } /** * @notice Resets all pausable flags to unpaused and withdraws funds * * @dev Throws when the caller does not have permission * * @dev <h4>Postconditions:</h4> * @dev 1. `pausableFlags` is set to zero * @dev 2. Emits a PausableFlagsUpdated event * @dev 3. Transfers `withdrawAmount` of native funds to `withdrawTo` if non-zero * * @param withdrawTo The address to withdraw the collateral to * @param withdrawAmount The amount of collateral to withdraw */ function unpause(address withdrawTo, uint256 withdrawAmount) external onlyPausePermissionedCaller { _setPausableFlags(0); if (withdrawAmount > 0) { (bool success, ) = withdrawTo.call{value: withdrawAmount}(""); if(!success) revert CollateralizedPausableFlags__WithdrawFailed(); } } /** * @notice Returns collateralized pausable configuration information * * @return _nativeValueToCheckPauseState The collateral required to enable pause state checking * @return _pausableFlags The current pausable flags set, only checked when collateral met */ function pausableConfigurationSettings() external view returns( uint256 _nativeValueToCheckPauseState, uint256 _pausableFlags ) { unchecked { _nativeValueToCheckPauseState = nativeValueToCheckPauseState + 1; _pausableFlags = pausableFlags; } } /** * @notice Updates the `pausableFlags` variable and emits a PausableFlagsUpdated event * * @param _pausableFlags The new pausable flags to set */ function _setPausableFlags(uint256 _pausableFlags) internal { uint256 previousFlags = pausableFlags; pausableFlags = _pausableFlags; emit PausableFlagsUpdated(previousFlags, _pausableFlags); } /** * @notice Checks the current pause state of the supplied flags and reverts if any are paused * * @dev *Should* be called prior to any transfers of native funds out of the contract for efficiency * @dev Throws when the native funds balance is greater than the value to enable pausing AND * @dev one or more of the supplied `_flags` is paused. * * @param _flags The flags to check for pause state */ function _requireNotPausedWithCollateralCheck(uint256 _flags) private view { if (_nativeBalanceSubMsgValue() > nativeValueToCheckPauseState) { if (pausableFlags & _flags > 0) { revert CollateralizedPausableFlags__Paused(); } } } /** * @notice Checks the current pause state of the supplied flags and reverts if any are paused * * @dev Throws when one or more of the supplied `_flags` is paused. * * @param _flags The flags to check for pause state */ function _requireNotPausedWithoutCollateralCheck(uint256 _flags) private view { if (pausableFlags & _flags > 0) { revert CollateralizedPausableFlags__Paused(); } } /** * @notice Checks the current pause state of the supplied flags and reverts if none are paused * * @dev *Should* be called prior to any transfers of native funds out of the contract for efficiency * @dev Throws when the native funds balance is not greater than the value to enable pausing OR * @dev none of the supplied `_flags` are paused. * * @param _flags The flags to check for pause state */ function _requirePausedWithCollateralCheck(uint256 _flags) private view { if (_nativeBalanceSubMsgValue() <= nativeValueToCheckPauseState) { revert CollateralizedPausableFlags__NotPaused(); } else if (pausableFlags & _flags == 0) { revert CollateralizedPausableFlags__NotPaused(); } } /** * @notice Checks the current pause state of the supplied flags and reverts if none are paused * * @dev Throws when none of the supplied `_flags` are paused. * * @param _flags The flags to check for pause state */ function _requirePausedWithoutCollateralCheck(uint256 _flags) private view { if (pausableFlags & _flags == 0) { revert CollateralizedPausableFlags__NotPaused(); } } /** * @notice Returns the current state of the pausable flags * * @dev Will return zero if the native funds balance is not greater than the value to enable pausing * * @return _pausableFlags The current state of the pausable flags */ function _getPausableFlagsWithCollateralCheck() private view returns(uint256 _pausableFlags) { if (_nativeBalanceSubMsgValue() > nativeValueToCheckPauseState) { _pausableFlags = pausableFlags; } } /** * @notice Returns the current state of the pausable flags * * @return _pausableFlags The current state of the pausable flags */ function _getPausableFlagsWithoutCollateralCheck() private view returns(uint256 _pausableFlags) { _pausableFlags = pausableFlags; } /** * @notice Returns the current contract balance minus the value sent with the call * * @dev This is expected to be the contract balance at the beginning of a function call * @dev to efficiently determine whether a contract has the necessary collateral to enable * @dev the pausable flags checking for contracts that hold native token funds. * @dev This should **NOT** be used in any way to determine current balance for contract logic * @dev other than its intended purpose for pause state checking activation. */ function _nativeBalanceSubMsgValue() private view returns (uint256 _value) { unchecked { _value = address(this).balance - msg.value; } } /** * @dev To be implemented by an inheriting contract for authorization to `pause` and `unpause` * @dev functions as well as any functions in the inheriting contract that utilize the * @dev `onlyPausePermissionedCaller` modifier. * * @dev Implementing contract function **MUST** throw when the caller is not permissioned */ function _requireCallerHasPausePermissions() internal view virtual; }// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the 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 have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[EIP]. * * _Available since v3.1._ */ interface IERC1155 is IERC165 { /** * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the amount of tokens of token type `id` owned by `account`. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the caller. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\ 32", hash)); } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\ ", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\\x19\\x01", domainSeparator, structHash)); } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (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 up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (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. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (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; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 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. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); 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. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && 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 down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // 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. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (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. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (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. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * 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. */ function log256(uint256 value) internal pure returns (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 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }