More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 950 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Withdraw For Aff... | 18199022 | 456 days ago | IN | 0 ETH | 0.00024605 | ||||
Withdraw For Aff... | 18188077 | 458 days ago | IN | 0 ETH | 0.00025999 | ||||
Withdraw For Aff... | 17711788 | 524 days ago | IN | 0 ETH | 0.00058236 | ||||
Mint | 17680058 | 529 days ago | IN | 0.003 ETH | 0.00372595 | ||||
Mint To | 17675467 | 530 days ago | IN | 0.003 ETH | 0.00221912 | ||||
Mint | 17675241 | 530 days ago | IN | 0.001 ETH | 0.00208841 | ||||
Mint | 17668654 | 531 days ago | IN | 0.001 ETH | 0.00233675 | ||||
Withdraw For Aff... | 17664514 | 531 days ago | IN | 0 ETH | 0.00085379 | ||||
Mint | 17663618 | 531 days ago | IN | 0.001 ETH | 0.00421725 | ||||
Mint | 17661732 | 532 days ago | IN | 0.001 ETH | 0.00279998 | ||||
Mint | 17661021 | 532 days ago | IN | 0.002 ETH | 0.00179579 | ||||
Mint | 17659286 | 532 days ago | IN | 0.001 ETH | 0.00205523 | ||||
Mint | 17657145 | 532 days ago | IN | 0.001 ETH | 0.00342677 | ||||
Mint | 17654041 | 533 days ago | IN | 0.001 ETH | 0.00212379 | ||||
Mint | 17653558 | 533 days ago | IN | 0.002 ETH | 0.00209758 | ||||
Mint | 17648533 | 533 days ago | IN | 0.001 ETH | 0.00200718 | ||||
Mint | 17648441 | 533 days ago | IN | 0.001 ETH | 0.00226864 | ||||
Mint | 17648324 | 533 days ago | IN | 0.0045 ETH | 0.00317878 | ||||
Mint | 17647138 | 534 days ago | IN | 0.001 ETH | 0.00219119 | ||||
Mint | 17646883 | 534 days ago | IN | 0.001 ETH | 0.00242133 | ||||
Mint | 17646548 | 534 days ago | IN | 0.002 ETH | 0.00234863 | ||||
Mint | 17645715 | 534 days ago | IN | 0.002 ETH | 0.00305964 | ||||
Mint | 17645543 | 534 days ago | IN | 0.003 ETH | 0.00296869 | ||||
Mint | 17644901 | 534 days ago | IN | 0.002 ETH | 0.00342601 | ||||
Mint | 17643650 | 534 days ago | IN | 0.0015 ETH | 0.00829665 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
20586265 | 122 days ago | 0.00075 ETH | ||||
20511257 | 132 days ago | 0.0008 ETH | ||||
20242799 | 170 days ago | 0.00215 ETH | ||||
19072222 | 334 days ago | 0.0002 ETH | ||||
19072218 | 334 days ago | 0.0008 ETH | ||||
18199022 | 456 days ago | 0.00635 ETH | ||||
18188077 | 458 days ago | 0.01925 ETH | ||||
17746227 | 520 days ago | 0.00235 ETH | ||||
17711788 | 524 days ago | 0.00385 ETH | ||||
17680058 | 529 days ago | 0.00285 ETH | ||||
17675467 | 530 days ago | 0.00285 ETH | ||||
17675241 | 530 days ago | 0.00095 ETH | ||||
17668654 | 531 days ago | 0.00095 ETH | ||||
17664514 | 531 days ago | 0.01155 ETH | ||||
17663618 | 531 days ago | 0.00095 ETH | ||||
17661732 | 532 days ago | 0.00095 ETH | ||||
17661021 | 532 days ago | 0.0019 ETH | ||||
17659286 | 532 days ago | 0.00095 ETH | ||||
17657145 | 532 days ago | 0.00095 ETH | ||||
17654041 | 533 days ago | 0.00095 ETH | ||||
17653558 | 533 days ago | 0.0019 ETH | ||||
17648533 | 533 days ago | 0.00095 ETH | ||||
17648441 | 533 days ago | 0.00095 ETH | ||||
17648324 | 533 days ago | 0.004275 ETH | ||||
17647138 | 534 days ago | 0.00095 ETH |
Loading...
Loading
Contract Name:
MerkleDropMinterV2
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 1000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import { MerkleProofLib } from "solady/utils/MerkleProofLib.sol"; import { IERC165 } from "openzeppelin/utils/introspection/IERC165.sol"; import { BaseMinterV2 } from "@modules/BaseMinterV2.sol"; import { DelegateCashLib } from "@modules/utils/DelegateCashLib.sol"; import { IMerkleDropMinterV2, EditionMintData, MintInfo } from "./interfaces/IMerkleDropMinterV2.sol"; import { IMinterModuleV2 } from "@core/interfaces/IMinterModuleV2.sol"; import { ISoundEditionV1 } from "@core/interfaces/ISoundEditionV1.sol"; /** * @title MerkleDropMinterV2 * @dev Module for minting Sound editions using a merkle tree of approved accounts. * @author Sound.xyz */ contract MerkleDropMinterV2 is IMerkleDropMinterV2, BaseMinterV2 { // ============================================================= // STORAGE // ============================================================= /** * @dev Edition mint data. * `_baseDataSlot(_getBaseData(edition, mintId))` => value. */ mapping(bytes32 => EditionMintData) internal _editionMintData; /** * @dev The number of mints for each account. * `_baseDataSlot(_getBaseData(edition, mintId))` => `address` => value. * We will simply store a uint256 for every account, to keep the Merkle tree * simple, so that it is compatible with 3rd party allowlist services like Lanyard. */ mapping(bytes32 => mapping(address => uint256)) internal _mintCounts; // ============================================================= // PUBLIC / EXTERNAL WRITE FUNCTIONS // ============================================================= /** * @inheritdoc IMerkleDropMinterV2 */ function createEditionMint( address edition, bytes32 merkleRootHash, uint96 price, uint32 startTime, uint32 endTime, uint16 affiliateFeeBPS, uint32 maxMintable, uint32 maxMintablePerAccount ) public returns (uint128 mintId) { if (merkleRootHash == bytes32(0)) revert MerkleRootHashIsEmpty(); if (maxMintablePerAccount == 0) revert MaxMintablePerAccountIsZero(); mintId = _createEditionMint(edition, startTime, endTime, affiliateFeeBPS); BaseData storage baseData = _getBaseDataUnchecked(edition, mintId); baseData.price = price; baseData.maxMintablePerAccount = maxMintablePerAccount; EditionMintData storage data = _editionMintData[_baseDataSlot(baseData)]; data.merkleRootHash = merkleRootHash; data.maxMintable = maxMintable; // prettier-ignore emit MerkleDropMintCreated( edition, mintId, merkleRootHash, price, startTime, endTime, affiliateFeeBPS, maxMintable, maxMintablePerAccount ); } /** * @inheritdoc IMerkleDropMinterV2 */ function mintTo( address edition, uint128 mintId, address to, uint32 quantity, address allowlisted, bytes32[] calldata proof, address affiliate, bytes32[] calldata affiliateProof, uint256 attributionId ) public payable { BaseData storage baseData = _getBaseData(edition, mintId); EditionMintData storage data = _editionMintData[_baseDataSlot(baseData)]; // Increase `totalMinted` by `quantity`. // Require that the increased value does not exceed `maxMintable`. data.totalMinted = _incrementTotalMinted(data.totalMinted, quantity, data.maxMintable); // Verify that `allowlisted` is in the Merkle tree with the `proof`. // We also revert if `allowlisted` is the zero address to prevent libraries // that fill up partial Merkle trees with empty leafs from screwing things up. if ( allowlisted == address(0) || !MerkleProofLib.verifyCalldata(proof, data.merkleRootHash, _keccak256EncodePacked(allowlisted)) ) revert InvalidMerkleProof(); // To mint, either `msg.sender` or `to` must be equal to `allowlisted`, // or `msg.sender` must be a delegate of `allowlisted`. if (msg.sender != allowlisted && to != allowlisted) if (!DelegateCashLib.checkDelegateForAll(msg.sender, allowlisted)) revert CallerNotDelegated(); unchecked { // Check that the additional `quantity` does not exceed the maximum mintable per account. // Won't overflow, as `maxMintablePerAccount` and `quantity` are 32 bits. if ((_mintCounts[_baseDataSlot(baseData)][allowlisted] += quantity) > baseData.maxMintablePerAccount) revert ExceedsMaxPerAccount(); } _mintTo(edition, mintId, to, quantity, affiliate, affiliateProof, attributionId); emit DropClaimed(allowlisted, quantity); } /** * @inheritdoc IMerkleDropMinterV2 */ function mint( address edition, uint128 mintId, uint32 quantity, bytes32[] calldata proof, address affiliate ) public payable { mintTo(edition, mintId, msg.sender, quantity, msg.sender, proof, affiliate, MerkleProofLib.emptyProof(), 0); } /** * @inheritdoc IMerkleDropMinterV2 */ function setPrice( address edition, uint128 mintId, uint96 price ) public onlyEditionOwnerOrAdmin(edition) { _getBaseData(edition, mintId).price = price; emit PriceSet(edition, mintId, price); } /** * @inheritdoc IMerkleDropMinterV2 */ function setMaxMintablePerAccount( address edition, uint128 mintId, uint32 maxMintablePerAccount ) public onlyEditionOwnerOrAdmin(edition) { if (maxMintablePerAccount == 0) revert MaxMintablePerAccountIsZero(); _getBaseData(edition, mintId).maxMintablePerAccount = maxMintablePerAccount; emit MaxMintablePerAccountSet(edition, mintId, maxMintablePerAccount); } /** * @inheritdoc IMerkleDropMinterV2 */ function setMaxMintable( address edition, uint128 mintId, uint32 maxMintable ) public onlyEditionOwnerOrAdmin(edition) { _editionMintData[_baseDataSlot(_getBaseData(edition, mintId))].maxMintable = maxMintable; emit MaxMintableSet(edition, mintId, maxMintable); } /* * @inheritdoc IMerkleDropMinterV2 */ function setMerkleRootHash( address edition, uint128 mintId, bytes32 merkleRootHash ) public onlyEditionOwnerOrAdmin(edition) { if (merkleRootHash == bytes32(0)) revert MerkleRootHashIsEmpty(); _editionMintData[_baseDataSlot(_getBaseData(edition, mintId))].merkleRootHash = merkleRootHash; emit MerkleRootHashSet(edition, mintId, merkleRootHash); } // ============================================================= // PUBLIC / EXTERNAL VIEW FUNCTIONS // ============================================================= /** * @inheritdoc IMerkleDropMinterV2 */ function mintCount( address edition, uint128 mintId, address to ) public view virtual returns (uint256) { return _mintCounts[_baseDataSlot(_getBaseData(edition, mintId))][to]; } /** * @inheritdoc IMerkleDropMinterV2 */ function mintInfo(address edition, uint128 mintId) external view returns (MintInfo memory info) { BaseData storage baseData = _getBaseData(edition, mintId); EditionMintData storage mintData = _editionMintData[_baseDataSlot(baseData)]; info.startTime = baseData.startTime; info.endTime = baseData.endTime; info.affiliateFeeBPS = baseData.affiliateFeeBPS; info.mintPaused = baseData.mintPaused; info.price = baseData.price; info.maxMintable = mintData.maxMintable; info.maxMintablePerAccount = baseData.maxMintablePerAccount; info.totalMinted = mintData.totalMinted; info.merkleRootHash = mintData.merkleRootHash; info.affiliateMerkleRoot = baseData.affiliateMerkleRoot; } /** * @inheritdoc IERC165 */ function supportsInterface(bytes4 interfaceId) public view override(IERC165, BaseMinterV2) returns (bool) { return BaseMinterV2.supportsInterface(interfaceId) || interfaceId == type(IMerkleDropMinterV2).interfaceId; } /** * @inheritdoc IMinterModuleV2 */ function moduleInterfaceId() public pure returns (bytes4) { return type(IMerkleDropMinterV2).interfaceId; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; /** * @title IMetadataModule * @notice The interface for custom metadata modules. */ interface IMetadataModule { /** * @dev When implemented, SoundEdition's `tokenURI` redirects execution to this `tokenURI`. * @param tokenId The token ID to retrieve the token URI for. * @return The token URI string. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import { IERC165 } from "openzeppelin/utils/introspection/IERC165.sol"; /** * @title IMinterModuleV2 * @notice The interface for Sound protocol minter modules. */ interface IMinterModuleV2 is IERC165 { // ============================================================= // STRUCTS // ============================================================= struct BaseData { // Auxillary variable for storing the price. // May or may not be used. uint96 price; // Auxillary variable for storing the max amount mintable by an account. // May or may not be used. uint32 maxMintablePerAccount; // The start unix timestamp of the mint. uint32 startTime; // The end unix timestamp of the mint. uint32 endTime; // The affiliate fee in basis points. uint16 affiliateFeeBPS; // Whether the mint is paused. bool mintPaused; // Whether the mint has been created. bool created; // The Merkle root of the affiliate allow list, if any. bytes32 affiliateMerkleRoot; } // ============================================================= // EVENTS // ============================================================= /** * @dev Emitted when the mint instance for an `edition` is created. * @param edition The edition address. * @param mintId The mint ID, a global incrementing identifier used within the minter * @param startTime The start time of the mint. * @param endTime The end time of the mint. * @param affiliateFeeBPS The affiliate fee in basis points. */ event MintConfigCreated( address indexed edition, address indexed creator, uint128 mintId, uint32 startTime, uint32 endTime, uint16 affiliateFeeBPS ); /** * @dev Emitted when the `paused` status of `edition` is updated. * @param edition The edition address. * @param mintId The mint ID, to distinguish between multiple mints for the same edition. * @param paused The new paused status. */ event MintPausedSet(address indexed edition, uint128 mintId, bool paused); /** * @dev Emitted when the `paused` status of `edition` is updated. * @param edition The edition address. * @param mintId The mint ID, to distinguish between multiple mints for the same edition. * @param startTime The start time of the mint. * @param endTime The end time of the mint. */ event TimeRangeSet(address indexed edition, uint128 mintId, uint32 startTime, uint32 endTime); /** * @notice Emitted when the `affiliateFeeBPS` is updated. * @param edition The edition address. * @param mintId The mint ID, to distinguish between multiple mints for the same edition. * @param bps The affiliate fee basis points. */ event AffiliateFeeSet(address indexed edition, uint128 mintId, uint16 bps); /** * @dev Emitted when the Merkle root for an affiliate allow list is set. * @param edition The edition address. * @param mintId The mint ID, to distinguish between multiple mints for the same edition. * @param root The Merkle root for the affiliate allow list. */ event AffiliateMerkleRootSet(address indexed edition, uint128 mintId, bytes32 root); /** * @notice Emitted when a mint happens. * @param edition The edition address. * @param mintId The mint ID, to distinguish between multiple mints for * the same edition. * @param buyer The buyer address. * @param fromTokenId The first token ID of the batch. * @param quantity The size of the batch. * @param requiredEtherValue Total amount of Ether required for payment. * @param platformFee The cut paid to the platform. * @param affiliateFee The cut paid to the affiliate. * @param affiliate The affiliate's address. * @param affiliated Whether the affiliate is affiliated. * @param attributionId The attribution ID. */ event Minted( address indexed edition, uint128 mintId, address indexed buyer, uint32 fromTokenId, uint32 quantity, uint128 requiredEtherValue, uint128 platformFee, uint128 affiliateFee, address affiliate, bool affiliated, uint256 indexed attributionId ); /** * @dev Emitted when the `platformFeeBPS` is updated. * @param bps The platform fee basis points. */ event PlatformFeeSet(uint16 bps); /** * @dev Emitted when the `platformFlatFee` is updated. * @param flatFee The amount of platform flat fee per token. */ event PlatformFlatFeeSet(uint96 flatFee); /** * @dev Emitted when the `platformFeeAddress` is updated. * @param addr The platform fee address. */ event PlatformFeeAddressSet(address addr); /** * @dev Emitted when the accrued fees for `affiliate` are withdrawn. * @param affiliate The affiliate address. * @param accrued The amount of fees withdrawn. */ event AffiliateFeesWithdrawn(address indexed affiliate, uint256 accrued); /** * @dev Emitted when the accrued fees for the platform are withdrawn. * @param accrued The amount of fees withdrawn. */ event PlatformFeesWithdrawn(uint128 accrued); // ============================================================= // ERRORS // ============================================================= /** * @dev The Ether value paid is below the value required. * @param paid The amount sent to the contract. * @param required The amount required to mint. */ error Underpaid(uint256 paid, uint256 required); /** * @dev The Ether value paid is not exact. * @param paid The amount sent to the contract. * @param required The amount required to mint. */ error WrongPayment(uint256 paid, uint256 required); /** * @dev The number minted has exceeded the max mintable amount. * @param available The number of tokens remaining available for mint. */ error ExceedsAvailableSupply(uint32 available); /** * @dev The mint is not opened. * @param blockTimestamp The current block timestamp. * @param startTime The start time of the mint. * @param endTime The end time of the mint. */ error MintNotOpen(uint256 blockTimestamp, uint32 startTime, uint32 endTime); /** * @dev The mint is paused. */ error MintPaused(); /** * @dev The `startTime` is not less than the `endTime`. */ error InvalidTimeRange(); /** * @dev The affiliate fee BPS must not exceed `MAX_AFFILIATE_FEE_BPS`. */ error InvalidAffiliateFeeBPS(); /** * @dev The platform fee BPS must not exceed `MAX_PLATFORM_FEE_BPS`. */ error InvalidPlatformFeeBPS(); /** * @dev The platform flat fee must not exceed `MAX_PLATFORM_FLAT_FEE`. */ error InvalidPlatformFlatFee(); /** * @dev The platform fee address cannot be zero. */ error PlatformFeeAddressIsZero(); /** * @dev The mint does not exist. */ error MintDoesNotExist(); /** * @dev The `affiliate` provided is invalid for the given `affiliateProof`. */ error InvalidAffiliate(); // ============================================================= // PUBLIC / EXTERNAL WRITE FUNCTIONS // ============================================================= /** * @dev Sets the paused status for (`edition`, `mintId`). * * Calling conditions: * - The caller must be the edition's owner or admin. */ function setEditionMintPaused( address edition, uint128 mintId, bool paused ) external; /** * @dev Sets the time range for an edition mint. * * Calling conditions: * - The caller must be the edition's owner or admin. * * @param edition The edition address. * @param mintId The mint ID, a global incrementing identifier used within the minter * @param startTime The start time of the mint. * @param endTime The end time of the mint. */ function setTimeRange( address edition, uint128 mintId, uint32 startTime, uint32 endTime ) external; /** * @dev Sets the affiliate fee for (`edition`, `mintId`). * * Calling conditions: * - The caller must be the edition's owner or admin. * * @param edition The edition address. * @param mintId The mint ID, a global incrementing identifier used within the minter * @param affiliateFeeBPS The affiliate fee in basis points. */ function setAffiliateFee( address edition, uint128 mintId, uint16 affiliateFeeBPS ) external; /** * @dev Sets the affiliate Merkle root for (`edition`, `mintId`). * * Calling conditions: * - The caller must be the edition's owner or admin. * * @param edition The edition address. * @param mintId The mint ID, a global incrementing identifier used within the minter * @param root The affiliate Merkle root, if any. */ function setAffiliateMerkleRoot( address edition, uint128 mintId, bytes32 root ) external; /** * @dev Sets the platform fee bps. * * Calling conditions: * - The caller must be the owner of the contract. * * @param bps The platform fee in basis points. */ function setPlatformFee(uint16 bps) external; /** * @dev Sets the platform flat fee. * * Calling conditions: * - The caller must be the owner of the contract. * * @param flatFee The platform flat fee. */ function setPlatformFlatFee(uint96 flatFee) external; /** * @dev Sets the platform fee address. * * Calling conditions: * - The caller must be the owner of the contract. * * @param addr The platform fee address. */ function setPlatformFeeAddress(address addr) external; /** * @dev Withdraws all the accrued fees for `affiliate`. */ function withdrawForAffiliate(address affiliate) external; /** * @dev Withdraws all the accrued fees for the platform. */ function withdrawForPlatform() external; // ============================================================= // PUBLIC / EXTERNAL VIEW FUNCTIONS // ============================================================= /** * @dev This is the denominator, in basis points (BPS), for any of the fees. * @return The constant value. */ function BPS_DENOMINATOR() external pure returns (uint16); /** * @dev The maximum basis points (BPS) limit allowed for the affiliate fees. * @return The constant value. */ function MAX_AFFILIATE_FEE_BPS() external pure returns (uint16); /** * @dev The maximum basis points (BPS) limit allowed for the platform fees. * @return The constant value. */ function MAX_PLATFORM_FEE_BPS() external pure returns (uint16); /** * @dev The maximum value for platform flat fee per NFT. * @return The constant value. */ function MAX_PLATFORM_FLAT_FEE() external pure returns (uint96); /** * @dev The total fees accrued for `affiliate`. * @param affiliate The affiliate's address. * @return The latest value. */ function affiliateFeesAccrued(address affiliate) external view returns (uint128); /** * @dev The total fees accrued for the platform. * @return The latest value. */ function platformFeesAccrued() external view returns (uint128); /** * @dev Whether `affiliate` is affiliated for (`edition`, `mintId`). * @param edition The edition's address. * @param mintId The mint ID. * @param affiliate The affiliate's address. * @param affiliateProof The Merkle proof needed for verifying the affiliate, if any. * @return The computed value. */ function isAffiliatedWithProof( address edition, uint128 mintId, address affiliate, bytes32[] calldata affiliateProof ) external view returns (bool); /** * @dev Whether `affiliate` is affiliated for (`edition`, `mintId`). * @param edition The edition's address. * @param mintId The mint ID. * @param affiliate The affiliate's address. * @return The computed value. */ function isAffiliated( address edition, uint128 mintId, address affiliate ) external view returns (bool); /** * @dev Returns the affiliate Merkle root. * @param edition The edition's address. * @param mintId The mint ID. * @return The latest value. */ function affiliateMerkleRoot(address edition, uint128 mintId) external view returns (bytes32); /** * @dev The total price for `quantity` tokens for (`edition`, `mintId`). * This does NOT include any additional platform flat fees. * @param edition The edition's address. * @param mintId The mint ID. * @param to The address to mint to. * @param quantity The number of tokens to mint. * @return The computed value. */ function totalPrice( address edition, uint128 mintId, address to, uint32 quantity ) external view returns (uint128); /** * @dev Returns the platform fee basis points. * @return The configured value. */ function platformFeeBPS() external returns (uint16); /** * @dev Returns the platform flat fee. * @return The configured value. */ function platformFlatFee() external returns (uint96); /** * @dev Returns the platform fee address. * @return The configured value. */ function platformFeeAddress() external returns (address); /** * @dev The next mint ID. * A mint ID is assigned sequentially starting from (0, 1, 2, ...), * and is shared amongst all editions connected to the minter contract. * @return The latest value. */ function nextMintId() external view returns (uint128); /** * @dev The interface ID of the minter. * @return The constant value. */ function moduleInterfaceId() external view returns (bytes4); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import { IERC721AUpgradeable } from "chiru-labs/ERC721A-Upgradeable/IERC721AUpgradeable.sol"; import { IERC2981Upgradeable } from "openzeppelin-upgradeable/interfaces/IERC2981Upgradeable.sol"; import { IERC165Upgradeable } from "openzeppelin-upgradeable/utils/introspection/IERC165Upgradeable.sol"; import { IMetadataModule } from "./IMetadataModule.sol"; /** * @dev The information pertaining to this edition. */ struct EditionInfo { // Base URI for the tokenId. string baseURI; // Contract URI for OpenSea storefront. string contractURI; // Name of the collection. string name; // Symbol of the collection. string symbol; // Address that receives primary and secondary royalties. address fundingRecipient; // The current max mintable amount; uint32 editionMaxMintable; // The lower limit of the maximum number of tokens that can be minted. uint32 editionMaxMintableUpper; // The upper limit of the maximum number of tokens that can be minted. uint32 editionMaxMintableLower; // The timestamp (in seconds since unix epoch) after which the // max amount of tokens mintable will drop from // `maxMintableUpper` to `maxMintableLower`. uint32 editionCutoffTime; // Address of metadata module, address(0x00) if not used. address metadataModule; // The current mint randomness value. uint256 mintRandomness; // The royalty BPS (basis points). uint16 royaltyBPS; // Whether the mint randomness is enabled. bool mintRandomnessEnabled; // Whether the mint has concluded. bool mintConcluded; // Whether the metadata has been frozen. bool isMetadataFrozen; // Next token ID to be minted. uint256 nextTokenId; // Total number of tokens burned. uint256 totalBurned; // Total number of tokens minted. uint256 totalMinted; // Total number of tokens currently in existence. uint256 totalSupply; } /** * @title ISoundEditionV1 * @notice The interface for Sound edition contracts. */ interface ISoundEditionV1 is IERC721AUpgradeable, IERC2981Upgradeable { // ============================================================= // EVENTS // ============================================================= /** * @dev Emitted when the metadata module is set. * @param metadataModule the address of the metadata module. */ event MetadataModuleSet(address metadataModule); /** * @dev Emitted when the `baseURI` is set. * @param baseURI the base URI of the edition. */ event BaseURISet(string baseURI); /** * @dev Emitted when the `contractURI` is set. * @param contractURI The contract URI of the edition. */ event ContractURISet(string contractURI); /** * @dev Emitted when the metadata is frozen (e.g.: `baseURI` can no longer be changed). * @param metadataModule The address of the metadata module. * @param baseURI The base URI of the edition. * @param contractURI The contract URI of the edition. */ event MetadataFrozen(address metadataModule, string baseURI, string contractURI); /** * @dev Emitted when the `fundingRecipient` is set. * @param fundingRecipient The address of the funding recipient. */ event FundingRecipientSet(address fundingRecipient); /** * @dev Emitted when the `royaltyBPS` is set. * @param bps The new royalty, measured in basis points. */ event RoyaltySet(uint16 bps); /** * @dev Emitted when the edition's maximum mintable token quantity range is set. * @param editionMaxMintableLower_ The lower limit of the maximum number of tokens that can be minted. * @param editionMaxMintableUpper_ The upper limit of the maximum number of tokens that can be minted. */ event EditionMaxMintableRangeSet(uint32 editionMaxMintableLower_, uint32 editionMaxMintableUpper_); /** * @dev Emitted when the edition's cutoff time set. * @param editionCutoffTime_ The timestamp. */ event EditionCutoffTimeSet(uint32 editionCutoffTime_); /** * @dev Emitted when the `mintRandomnessEnabled` is set. * @param mintRandomnessEnabled_ The boolean value. */ event MintRandomnessEnabledSet(bool mintRandomnessEnabled_); /** * @dev Emitted upon initialization. * @param edition_ The address of the edition. * @param name_ Name of the collection. * @param symbol_ Symbol of the collection. * @param metadataModule_ Address of metadata module, address(0x00) if not used. * @param baseURI_ Base URI. * @param contractURI_ Contract URI for OpenSea storefront. * @param fundingRecipient_ Address that receives primary and secondary royalties. * @param royaltyBPS_ Royalty amount in bps (basis points). * @param editionMaxMintableLower_ The lower bound of the max mintable quantity for the edition. * @param editionMaxMintableUpper_ The upper bound of the max mintable quantity for the edition. * @param editionCutoffTime_ The timestamp after which `editionMaxMintable` drops from * `editionMaxMintableUpper` to * `max(_totalMinted(), editionMaxMintableLower)`. * @param flags_ The bitwise OR result of the initialization flags. * See: {METADATA_IS_FROZEN_FLAG} * See: {MINT_RANDOMNESS_ENABLED_FLAG} */ event SoundEditionInitialized( address indexed edition_, string name_, string symbol_, address metadataModule_, string baseURI_, string contractURI_, address fundingRecipient_, uint16 royaltyBPS_, uint32 editionMaxMintableLower_, uint32 editionMaxMintableUpper_, uint32 editionCutoffTime_, uint8 flags_ ); /** * @dev Emitted upon ETH withdrawal. * @param recipient The recipient of the withdrawal. * @param amount The amount withdrawn. * @param caller The account that initiated the withdrawal. */ event ETHWithdrawn(address recipient, uint256 amount, address caller); /** * @dev Emitted upon ERC20 withdrawal. * @param recipient The recipient of the withdrawal. * @param tokens The addresses of the ERC20 tokens. * @param amounts The amount of each token withdrawn. * @param caller The account that initiated the withdrawal. */ event ERC20Withdrawn(address recipient, address[] tokens, uint256[] amounts, address caller); /** * @dev Emitted upon a mint. * @param to The address to mint to. * @param quantity The number of minted. * @param fromTokenId The first token ID minted. */ event Minted(address to, uint256 quantity, uint256 fromTokenId); /** * @dev Emitted upon an airdrop. * @param to The recipients of the airdrop. * @param quantity The number of tokens airdropped to each address in `to`. * @param fromTokenId The first token ID minted to the first address in `to`. */ event Airdropped(address[] to, uint256 quantity, uint256 fromTokenId); // ============================================================= // ERRORS // ============================================================= /** * @dev The edition's metadata is frozen (e.g.: `baseURI` can no longer be changed). */ error MetadataIsFrozen(); /** * @dev The given `royaltyBPS` is invalid. */ error InvalidRoyaltyBPS(); /** * @dev The given `randomnessLockedAfterMinted` value is invalid. */ error InvalidRandomnessLock(); /** * @dev The requested quantity exceeds the edition's remaining mintable token quantity. * @param available The number of tokens remaining available for mint. */ error ExceedsEditionAvailableSupply(uint32 available); /** * @dev The given amount is invalid. */ error InvalidAmount(); /** * @dev The given `fundingRecipient` address is invalid. */ error InvalidFundingRecipient(); /** * @dev The `editionMaxMintableLower` must not be greater than `editionMaxMintableUpper`. */ error InvalidEditionMaxMintableRange(); /** * @dev The `editionMaxMintable` has already been reached. */ error MaximumHasAlreadyBeenReached(); /** * @dev The mint `quantity` cannot exceed `ADDRESS_BATCH_MINT_LIMIT` tokens. */ error ExceedsAddressBatchMintLimit(); /** * @dev The mint randomness has already been revealed. */ error MintRandomnessAlreadyRevealed(); /** * @dev No addresses to airdrop. */ error NoAddressesToAirdrop(); /** * @dev The mint has already concluded. */ error MintHasConcluded(); /** * @dev Cannot perform the operation after a token has been minted. */ error MintsAlreadyExist(); // ============================================================= // PUBLIC / EXTERNAL WRITE FUNCTIONS // ============================================================= /** * @dev Initializes the contract. * @param name_ Name of the collection. * @param symbol_ Symbol of the collection. * @param metadataModule_ Address of metadata module, address(0x00) if not used. * @param baseURI_ Base URI. * @param contractURI_ Contract URI for OpenSea storefront. * @param fundingRecipient_ Address that receives primary and secondary royalties. * @param royaltyBPS_ Royalty amount in bps (basis points). * @param editionMaxMintableLower_ The lower bound of the max mintable quantity for the edition. * @param editionMaxMintableUpper_ The upper bound of the max mintable quantity for the edition. * @param editionCutoffTime_ The timestamp after which `editionMaxMintable` drops from * `editionMaxMintableUpper` to * `max(_totalMinted(), editionMaxMintableLower)`. * @param flags_ The bitwise OR result of the initialization flags. * See: {METADATA_IS_FROZEN_FLAG} * See: {MINT_RANDOMNESS_ENABLED_FLAG} */ function initialize( string memory name_, string memory symbol_, address metadataModule_, string memory baseURI_, string memory contractURI_, address fundingRecipient_, uint16 royaltyBPS_, uint32 editionMaxMintableLower_, uint32 editionMaxMintableUpper_, uint32 editionCutoffTime_, uint8 flags_ ) external; /** * @dev Mints `quantity` tokens to addrress `to` * Each token will be assigned a token ID that is consecutively increasing. * * Calling conditions: * - The caller must be the owner of the contract, or have either the * `ADMIN_ROLE`, `MINTER_ROLE`, which can be granted via {grantRole}. * Multiple minters, such as different minter contracts, * can be authorized simultaneously. * * @param to Address to mint to. * @param quantity Number of tokens to mint. * @return fromTokenId The first token ID minted. */ function mint(address to, uint256 quantity) external payable returns (uint256 fromTokenId); /** * @dev Mints `quantity` tokens to each of the addresses in `to`. * * Calling conditions: * - The caller must be the owner of the contract, or have the * `ADMIN_ROLE`, which can be granted via {grantRole}. * * @param to Address to mint to. * @param quantity Number of tokens to mint. * @return fromTokenId The first token ID minted. */ function airdrop(address[] calldata to, uint256 quantity) external returns (uint256 fromTokenId); /** * @dev Withdraws collected ETH royalties to the fundingRecipient. */ function withdrawETH() external; /** * @dev Withdraws collected ERC20 royalties to the fundingRecipient. * @param tokens array of ERC20 tokens to withdraw */ function withdrawERC20(address[] calldata tokens) external; /** * @dev Sets metadata module. * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param metadataModule Address of metadata module. */ function setMetadataModule(address metadataModule) external; /** * @dev Sets global base URI. * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param baseURI The base URI to be set. */ function setBaseURI(string memory baseURI) external; /** * @dev Sets contract URI. * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param contractURI The contract URI to be set. */ function setContractURI(string memory contractURI) external; /** * @dev Freezes metadata by preventing any more changes to base URI. * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. */ function freezeMetadata() external; /** * @dev Sets funding recipient address. * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param fundingRecipient Address to be set as the new funding recipient. */ function setFundingRecipient(address fundingRecipient) external; /** * @dev Sets royalty amount in bps (basis points). * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param bps The new royalty basis points to be set. */ function setRoyalty(uint16 bps) external; /** * @dev Sets the edition max mintable range. * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param editionMaxMintableLower_ The lower limit of the maximum number of tokens that can be minted. * @param editionMaxMintableUpper_ The upper limit of the maximum number of tokens that can be minted. */ function setEditionMaxMintableRange(uint32 editionMaxMintableLower_, uint32 editionMaxMintableUpper_) external; /** * @dev Sets the timestamp after which, the `editionMaxMintable` drops * from `editionMaxMintableUpper` to `editionMaxMintableLower. * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param editionCutoffTime_ The timestamp. */ function setEditionCutoffTime(uint32 editionCutoffTime_) external; /** * @dev Sets whether the `mintRandomness` is enabled. * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param mintRandomnessEnabled_ The boolean value. */ function setMintRandomnessEnabled(bool mintRandomnessEnabled_) external; // ============================================================= // PUBLIC / EXTERNAL VIEW FUNCTIONS // ============================================================= /** * @dev Returns the edition info. * @return editionInfo The latest value. */ function editionInfo() external view returns (EditionInfo memory editionInfo); /** * @dev Returns the minter role flag. * @return The constant value. */ function MINTER_ROLE() external view returns (uint256); /** * @dev Returns the admin role flag. * @return The constant value. */ function ADMIN_ROLE() external view returns (uint256); /** * @dev Returns the maximum limit for the mint or airdrop `quantity`. * Prevents the first-time transfer costs for tokens near the end of large mint batches * via ERC721A from becoming too expensive due to the need to scan many storage slots. * See: https://chiru-labs.github.io/ERC721A/#/tips?id=batch-size * @return The constant value. */ function ADDRESS_BATCH_MINT_LIMIT() external pure returns (uint256); /** * @dev Returns the bit flag to freeze the metadata on initialization. * @return The constant value. */ function METADATA_IS_FROZEN_FLAG() external pure returns (uint8); /** * @dev Returns the bit flag to enable the mint randomness feature on initialization. * @return The constant value. */ function MINT_RANDOMNESS_ENABLED_FLAG() external pure returns (uint8); /** * @dev Returns the base token URI for the collection. * @return The configured value. */ function baseURI() external view returns (string memory); /** * @dev Returns the contract URI to be used by Opensea. * See: https://docs.opensea.io/docs/contract-level-metadata * @return The configured value. */ function contractURI() external view returns (string memory); /** * @dev Returns the address of the funding recipient. * @return The configured value. */ function fundingRecipient() external view returns (address); /** * @dev Returns the maximum amount of tokens mintable for this edition. * @return The configured value. */ function editionMaxMintable() external view returns (uint32); /** * @dev Returns the upper bound for the maximum tokens that can be minted for this edition. * @return The configured value. */ function editionMaxMintableUpper() external view returns (uint32); /** * @dev Returns the lower bound for the maximum tokens that can be minted for this edition. * @return The configured value. */ function editionMaxMintableLower() external view returns (uint32); /** * @dev Returns the timestamp after which `editionMaxMintable` drops from * `editionMaxMintableUpper` to `editionMaxMintableLower`. * @return The configured value. */ function editionCutoffTime() external view returns (uint32); /** * @dev Returns the address of the metadata module. * @return The configured value. */ function metadataModule() external view returns (address); /** * @dev Returns the randomness based on latest block hash, which is stored upon each mint. * unless {mintConcluded} is true. * Used for game mechanics like the Sound Golden Egg. * Returns 0 before revealed. * WARNING: This value should NOT be used for any reward of significant monetary * value, due to it being computed via a purely on-chain psuedorandom mechanism. * @return The latest value. */ function mintRandomness() external view returns (uint256); /** * @dev Returns whether the `mintRandomness` has been enabled. * @return The configured value. */ function mintRandomnessEnabled() external view returns (bool); /** * @dev Returns whether the mint has been concluded. * @return The latest value. */ function mintConcluded() external view returns (bool); /** * @dev Returns the royalty basis points. * @return The configured value. */ function royaltyBPS() external view returns (uint16); /** * @dev Returns whether the metadata module is frozen. * @return The configured value. */ function isMetadataFrozen() external view returns (bool); /** * @dev Returns the next token ID to be minted. * @return The latest value. */ function nextTokenId() external view returns (uint256); /** * @dev Returns the number of tokens minted by `owner`. * @param owner Address to query for number minted. * @return The latest value. */ function numberMinted(address owner) external view returns (uint256); /** * @dev Returns the number of tokens burned by `owner`. * @param owner Address to query for number burned. * @return The latest value. */ function numberBurned(address owner) external view returns (uint256); /** * @dev Returns the total amount of tokens minted. * @return The latest value. */ function totalMinted() external view returns (uint256); /** * @dev Returns the total amount of tokens burned. * @return The latest value. */ function totalBurned() external view returns (uint256); /** * @dev Informs other contracts which interfaces this contract supports. * Required by https://eips.ethereum.org/EIPS/eip-165 * @param interfaceId The interface id to check. * @return Whether the `interfaceId` is supported. */ function supportsInterface(bytes4 interfaceId) external view override(IERC721AUpgradeable, IERC165Upgradeable) returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import { IERC721AUpgradeable } from "chiru-labs/ERC721A-Upgradeable/IERC721AUpgradeable.sol"; import { IERC2981Upgradeable } from "openzeppelin-upgradeable/interfaces/IERC2981Upgradeable.sol"; import { IERC165Upgradeable } from "openzeppelin-upgradeable/utils/introspection/IERC165Upgradeable.sol"; import { IMetadataModule } from "./IMetadataModule.sol"; /** * @dev The information pertaining to this edition. */ struct EditionInfo { // Base URI for the tokenId. string baseURI; // Contract URI for OpenSea storefront. string contractURI; // Name of the collection. string name; // Symbol of the collection. string symbol; // Address that receives primary and secondary royalties. address fundingRecipient; // The current max mintable amount; uint32 editionMaxMintable; // The lower limit of the maximum number of tokens that can be minted. uint32 editionMaxMintableUpper; // The upper limit of the maximum number of tokens that can be minted. uint32 editionMaxMintableLower; // The timestamp (in seconds since unix epoch) after which the // max amount of tokens mintable will drop from // `maxMintableUpper` to `maxMintableLower`. uint32 editionCutoffTime; // Address of metadata module, address(0x00) if not used. address metadataModule; // The current mint randomness value. uint256 mintRandomness; // The royalty BPS (basis points). uint16 royaltyBPS; // Whether the mint randomness is enabled. bool mintRandomnessEnabled; // Whether the mint has concluded. bool mintConcluded; // Whether the metadata has been frozen. bool isMetadataFrozen; // Next token ID to be minted. uint256 nextTokenId; // Total number of tokens burned. uint256 totalBurned; // Total number of tokens minted. uint256 totalMinted; // Total number of tokens currently in existence. uint256 totalSupply; } /** * @title ISoundEditionV1_2 * @notice The interface for Sound edition contracts. */ interface ISoundEditionV1_2 is IERC721AUpgradeable, IERC2981Upgradeable { // ============================================================= // EVENTS // ============================================================= /** * @dev Emitted when the metadata module is set. * @param metadataModule the address of the metadata module. */ event MetadataModuleSet(address metadataModule); /** * @dev Emitted when the `baseURI` is set. * @param baseURI the base URI of the edition. */ event BaseURISet(string baseURI); /** * @dev Emitted when the `contractURI` is set. * @param contractURI The contract URI of the edition. */ event ContractURISet(string contractURI); /** * @dev Emitted when the metadata is frozen (e.g.: `baseURI` can no longer be changed). * @param metadataModule The address of the metadata module. * @param baseURI The base URI of the edition. * @param contractURI The contract URI of the edition. */ event MetadataFrozen(address metadataModule, string baseURI, string contractURI); /** * @dev Emitted when the `fundingRecipient` is set. * @param fundingRecipient The address of the funding recipient. */ event FundingRecipientSet(address fundingRecipient); /** * @dev Emitted when the `royaltyBPS` is set. * @param bps The new royalty, measured in basis points. */ event RoyaltySet(uint16 bps); /** * @dev Emitted when the edition's maximum mintable token quantity range is set. * @param editionMaxMintableLower_ The lower limit of the maximum number of tokens that can be minted. * @param editionMaxMintableUpper_ The upper limit of the maximum number of tokens that can be minted. */ event EditionMaxMintableRangeSet(uint32 editionMaxMintableLower_, uint32 editionMaxMintableUpper_); /** * @dev Emitted when the edition's cutoff time set. * @param editionCutoffTime_ The timestamp. */ event EditionCutoffTimeSet(uint32 editionCutoffTime_); /** * @dev Emitted when the `mintRandomnessEnabled` is set. * @param mintRandomnessEnabled_ The boolean value. */ event MintRandomnessEnabledSet(bool mintRandomnessEnabled_); /** * @dev Emitted when the `operatorFilteringEnabled` is set. * @param operatorFilteringEnabled_ The boolean value. */ event OperatorFilteringEnablededSet(bool operatorFilteringEnabled_); /** * @dev Emitted upon initialization. * @param edition_ The address of the edition. * @param name_ Name of the collection. * @param symbol_ Symbol of the collection. * @param metadataModule_ Address of metadata module, address(0x00) if not used. * @param baseURI_ Base URI. * @param contractURI_ Contract URI for OpenSea storefront. * @param fundingRecipient_ Address that receives primary and secondary royalties. * @param royaltyBPS_ Royalty amount in bps (basis points). * @param editionMaxMintableLower_ The lower bound of the max mintable quantity for the edition. * @param editionMaxMintableUpper_ The upper bound of the max mintable quantity for the edition. * @param editionCutoffTime_ The timestamp after which `editionMaxMintable` drops from * `editionMaxMintableUpper` to * `max(_totalMinted(), editionMaxMintableLower)`. * @param flags_ The bitwise OR result of the initialization flags. * See: {METADATA_IS_FROZEN_FLAG} * See: {MINT_RANDOMNESS_ENABLED_FLAG} */ event SoundEditionInitialized( address indexed edition_, string name_, string symbol_, address metadataModule_, string baseURI_, string contractURI_, address fundingRecipient_, uint16 royaltyBPS_, uint32 editionMaxMintableLower_, uint32 editionMaxMintableUpper_, uint32 editionCutoffTime_, uint8 flags_ ); /** * @dev Emitted upon ETH withdrawal. * @param recipient The recipient of the withdrawal. * @param amount The amount withdrawn. * @param caller The account that initiated the withdrawal. */ event ETHWithdrawn(address recipient, uint256 amount, address caller); /** * @dev Emitted upon ERC20 withdrawal. * @param recipient The recipient of the withdrawal. * @param tokens The addresses of the ERC20 tokens. * @param amounts The amount of each token withdrawn. * @param caller The account that initiated the withdrawal. */ event ERC20Withdrawn(address recipient, address[] tokens, uint256[] amounts, address caller); /** * @dev Emitted upon a mint. * @param to The address to mint to. * @param quantity The number of minted. * @param fromTokenId The first token ID minted. */ event Minted(address to, uint256 quantity, uint256 fromTokenId); /** * @dev Emitted upon an airdrop. * @param to The recipients of the airdrop. * @param quantity The number of tokens airdropped to each address in `to`. * @param fromTokenId The first token ID minted to the first address in `to`. */ event Airdropped(address[] to, uint256 quantity, uint256 fromTokenId); /** * @dev EIP-4906 event to signal marketplaces to refresh the metadata. * @param fromTokenId The starting token ID. * @param toTokenId The ending token ID. */ event BatchMetadataUpdate(uint256 fromTokenId, uint256 toTokenId); /** * @dev Emiited when the Sound Automated Market (i.e. bonding curve minter) is set. * @param sam_ The Sound Automated Market. */ event SAMSet(address sam_); // ============================================================= // ERRORS // ============================================================= /** * @dev The edition's metadata is frozen (e.g.: `baseURI` can no longer be changed). */ error MetadataIsFrozen(); /** * @dev The given `royaltyBPS` is invalid. */ error InvalidRoyaltyBPS(); /** * @dev The given `randomnessLockedAfterMinted` value is invalid. */ error InvalidRandomnessLock(); /** * @dev The requested quantity exceeds the edition's remaining mintable token quantity. * @param available The number of tokens remaining available for mint. */ error ExceedsEditionAvailableSupply(uint32 available); /** * @dev The given amount is invalid. */ error InvalidAmount(); /** * @dev The given `fundingRecipient` address is invalid. */ error InvalidFundingRecipient(); /** * @dev The `editionMaxMintableLower` must not be greater than `editionMaxMintableUpper`. */ error InvalidEditionMaxMintableRange(); /** * @dev The `editionMaxMintable` has already been reached. */ error MaximumHasAlreadyBeenReached(); /** * @dev The mint `quantity` cannot exceed `ADDRESS_BATCH_MINT_LIMIT` tokens. */ error ExceedsAddressBatchMintLimit(); /** * @dev The mint randomness has already been revealed. */ error MintRandomnessAlreadyRevealed(); /** * @dev No addresses to airdrop. */ error NoAddressesToAirdrop(); /** * @dev The mint has already concluded. */ error MintHasConcluded(); /** * @dev The mint has not concluded. */ error MintNotConcluded(); /** * @dev Cannot perform the operation after a token has been minted. */ error MintsAlreadyExist(); /** * @dev The token IDs must be in strictly ascending order. */ error TokenIdsNotStrictlyAscending(); /** * @dev Please wait for a while before you burn. */ error CannotBurnImmediately(); // ============================================================= // PUBLIC / EXTERNAL WRITE FUNCTIONS // ============================================================= /** * @dev Initializes the contract. * @param name_ Name of the collection. * @param symbol_ Symbol of the collection. * @param metadataModule_ Address of metadata module, address(0x00) if not used. * @param baseURI_ Base URI. * @param contractURI_ Contract URI for OpenSea storefront. * @param fundingRecipient_ Address that receives primary and secondary royalties. * @param royaltyBPS_ Royalty amount in bps (basis points). * @param editionMaxMintableLower_ The lower bound of the max mintable quantity for the edition. * @param editionMaxMintableUpper_ The upper bound of the max mintable quantity for the edition. * @param editionCutoffTime_ The timestamp after which `editionMaxMintable` drops from * `editionMaxMintableUpper` to * `max(_totalMinted(), editionMaxMintableLower)`. * @param flags_ The bitwise OR result of the initialization flags. * See: {METADATA_IS_FROZEN_FLAG} * See: {MINT_RANDOMNESS_ENABLED_FLAG} */ function initialize( string memory name_, string memory symbol_, address metadataModule_, string memory baseURI_, string memory contractURI_, address fundingRecipient_, uint16 royaltyBPS_, uint32 editionMaxMintableLower_, uint32 editionMaxMintableUpper_, uint32 editionCutoffTime_, uint8 flags_ ) external; /** * @dev Mints `quantity` tokens to addrress `to` * Each token will be assigned a token ID that is consecutively increasing. * * Calling conditions: * - The caller must be the owner of the contract, or have either the * `ADMIN_ROLE`, `MINTER_ROLE`, which can be granted via {grantRole}. * Multiple minters, such as different minter contracts, * can be authorized simultaneously. * * @param to Address to mint to. * @param quantity Number of tokens to mint. * @return fromTokenId The first token ID minted. */ function mint(address to, uint256 quantity) external payable returns (uint256 fromTokenId); /** * @dev Mints `quantity` tokens to each of the addresses in `to`. * * Calling conditions: * - The caller must be the owner of the contract, or have the * `ADMIN_ROLE`, which can be granted via {grantRole}. * * @param to Address to mint to. * @param quantity Number of tokens to mint. * @return fromTokenId The first token ID minted. */ function airdrop(address[] calldata to, uint256 quantity) external returns (uint256 fromTokenId); /** * @dev Mints `quantity` tokens to addrress `to` * Each token will be assigned a token ID that is consecutively increasing. * * Calling conditions: * - The caller must be the bonding curve contract. * * @param to Address to mint to. * @param quantity Number of tokens to mint. * @return fromTokenId The first token ID minted. */ function samMint(address to, uint256 quantity) external payable returns (uint256 fromTokenId); /** * @dev Burns the `tokenIds`. * * Calling conditions: * - The caller must be the bonding curve contract. * * @param burner The initiator of the burn. * @param tokenIds The list of token IDs to burn. */ function samBurn(address burner, uint256[] calldata tokenIds) external; /** * @dev Withdraws collected ETH royalties to the fundingRecipient. */ function withdrawETH() external; /** * @dev Withdraws collected ERC20 royalties to the fundingRecipient. * @param tokens array of ERC20 tokens to withdraw */ function withdrawERC20(address[] calldata tokens) external; /** * @dev Sets metadata module. * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param metadataModule Address of metadata module. */ function setMetadataModule(address metadataModule) external; /** * @dev Sets global base URI. * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param baseURI The base URI to be set. */ function setBaseURI(string memory baseURI) external; /** * @dev Sets contract URI. * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param contractURI The contract URI to be set. */ function setContractURI(string memory contractURI) external; /** * @dev Freezes metadata by preventing any more changes to base URI. * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. */ function freezeMetadata() external; /** * @dev Sets funding recipient address. * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param fundingRecipient Address to be set as the new funding recipient. */ function setFundingRecipient(address fundingRecipient) external; /** * @dev Sets royalty amount in bps (basis points). * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param bps The new royalty basis points to be set. */ function setRoyalty(uint16 bps) external; /** * @dev Sets the edition max mintable range. * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param editionMaxMintableLower_ The lower limit of the maximum number of tokens that can be minted. * @param editionMaxMintableUpper_ The upper limit of the maximum number of tokens that can be minted. */ function setEditionMaxMintableRange(uint32 editionMaxMintableLower_, uint32 editionMaxMintableUpper_) external; /** * @dev Sets the timestamp after which, the `editionMaxMintable` drops * from `editionMaxMintableUpper` to `editionMaxMintableLower. * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param editionCutoffTime_ The timestamp. */ function setEditionCutoffTime(uint32 editionCutoffTime_) external; /** * @dev Sets whether the `mintRandomness` is enabled. * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param mintRandomnessEnabled_ The boolean value. */ function setMintRandomnessEnabled(bool mintRandomnessEnabled_) external; /** * @dev Sets whether OpenSea operator filtering is enabled. * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param operatorFilteringEnabled_ The boolean value. */ function setOperatorFilteringEnabled(bool operatorFilteringEnabled_) external; /** * @dev Emits an event to signal to marketplaces to refresh all the metadata. */ function emitAllMetadataUpdate() external; /** * @dev Sets the Sound Automated Market (i.e. bonding curve minter). * * Calling conditions: * - The caller must be the owner of the contract, or have the `ADMIN_ROLE`. * * @param sam_ The Sound Automated Market. */ function setSAM(address sam_) external; // ============================================================= // PUBLIC / EXTERNAL VIEW FUNCTIONS // ============================================================= /** * @dev Returns the edition info. * @return editionInfo The latest value. */ function editionInfo() external view returns (EditionInfo memory editionInfo); /** * @dev Returns the minter role flag. * @return The constant value. */ function MINTER_ROLE() external view returns (uint256); /** * @dev Returns the admin role flag. * @return The constant value. */ function ADMIN_ROLE() external view returns (uint256); /** * @dev Returns the bit flag to freeze the metadata on initialization. * @return The constant value. */ function METADATA_IS_FROZEN_FLAG() external pure returns (uint8); /** * @dev Returns the bit flag to enable the mint randomness feature on initialization. * @return The constant value. */ function MINT_RANDOMNESS_ENABLED_FLAG() external pure returns (uint8); /** * @dev Returns the bit flag to enable OpenSea operator filtering. * @return The constant value. */ function OPERATOR_FILTERING_ENABLED_FLAG() external pure returns (uint8); /** * @dev Returns the base token URI for the collection. * @return The configured value. */ function baseURI() external view returns (string memory); /** * @dev Returns the contract URI to be used by Opensea. * See: https://docs.opensea.io/docs/contract-level-metadata * @return The configured value. */ function contractURI() external view returns (string memory); /** * @dev Returns the address of the funding recipient. * @return The configured value. */ function fundingRecipient() external view returns (address); /** * @dev Returns the maximum amount of tokens mintable for this edition. * @return The configured value. */ function editionMaxMintable() external view returns (uint32); /** * @dev Returns the upper bound for the maximum tokens that can be minted for this edition. * @return The configured value. */ function editionMaxMintableUpper() external view returns (uint32); /** * @dev Returns the lower bound for the maximum tokens that can be minted for this edition. * @return The configured value. */ function editionMaxMintableLower() external view returns (uint32); /** * @dev Returns the timestamp after which `editionMaxMintable` drops from * `editionMaxMintableUpper` to `editionMaxMintableLower`. * @return The configured value. */ function editionCutoffTime() external view returns (uint32); /** * @dev Returns the address of the metadata module. * @return The configured value. */ function metadataModule() external view returns (address); /** * @dev Returns the randomness based on latest block hash, which is stored upon each mint. * unless {mintConcluded} is true. * Used for game mechanics like the Sound Golden Egg. * Returns 0 before revealed. * WARNING: This value should NOT be used for any reward of significant monetary * value, due to it being computed via a purely on-chain psuedorandom mechanism. * @return The latest value. */ function mintRandomness() external view returns (uint256); /** * @dev Returns whether the `mintRandomness` has been enabled. * @return The configured value. */ function mintRandomnessEnabled() external view returns (bool); /** * @dev Returns whether the `operatorFilteringEnabled` has been enabled. * @return The configured value. */ function operatorFilteringEnabled() external view returns (bool); /** * @dev Returns whether the mint has been concluded. * @return The latest value. */ function mintConcluded() external view returns (bool); /** * @dev Returns the royalty basis points. * @return The configured value. */ function royaltyBPS() external view returns (uint16); /** * @dev Returns whether the metadata module is frozen. * @return The configured value. */ function isMetadataFrozen() external view returns (bool); /** * @dev Returns the sound automated market, if any. * @return The configured value. */ function sam() external view returns (address); /** * @dev Returns the next token ID to be minted. * @return The latest value. */ function nextTokenId() external view returns (uint256); /** * @dev Returns the number of tokens minted by `owner`. * @param owner Address to query for number minted. * @return The latest value. */ function numberMinted(address owner) external view returns (uint256); /** * @dev Returns the number of tokens burned by `owner`. * @param owner Address to query for number burned. * @return The latest value. */ function numberBurned(address owner) external view returns (uint256); /** * @dev Returns the total amount of tokens minted. * @return The latest value. */ function totalMinted() external view returns (uint256); /** * @dev Returns the total amount of tokens burned. * @return The latest value. */ function totalBurned() external view returns (uint256); /** * @dev Informs other contracts which interfaces this contract supports. * Required by https://eips.ethereum.org/EIPS/eip-165 * @param interfaceId The interface id to check. * @return Whether the `interfaceId` is supported. */ function supportsInterface(bytes4 interfaceId) external view override(IERC721AUpgradeable, IERC165Upgradeable) returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import { Ownable, OwnableRoles } from "solady/auth/OwnableRoles.sol"; import { ISoundEditionV1_2 } from "@core/interfaces/ISoundEditionV1_2.sol"; import { IMinterModuleV2 } from "@core/interfaces/IMinterModuleV2.sol"; import { IERC165 } from "openzeppelin/utils/introspection/IERC165.sol"; import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; import { FixedPointMathLib } from "solady/utils/FixedPointMathLib.sol"; import { SafeCastLib } from "solady/utils/SafeCastLib.sol"; import { MerkleProofLib } from "solady/utils/MerkleProofLib.sol"; import { LibMulticaller } from "multicaller/LibMulticaller.sol"; /** * @title Minter Base * @dev The `BaseMinterV2` class maintains a central storage record of edition mint instances. */ abstract contract BaseMinterV2 is IMinterModuleV2, Ownable { // ============================================================= // CONSTANTS // ============================================================= /** * @dev This is the denominator, in basis points (BPS), for any of the fees. */ uint16 public constant BPS_DENOMINATOR = 10_000; /** * @dev The maximum basis points (BPS) limit allowed for the affiliate fees. */ uint16 public constant MAX_AFFILIATE_FEE_BPS = 1000; /** * @dev The maximum basis points (BPS) limit allowed for the platform fees. */ uint16 public constant MAX_PLATFORM_FEE_BPS = 1000; /** * @dev The maximum platform flat fee per NFT. */ uint96 public constant MAX_PLATFORM_FLAT_FEE = 0.1 ether; // ============================================================= // STORAGE // ============================================================= /** * @dev The platform fee address. */ address public platformFeeAddress; /** * @dev The next mint ID. Shared amongst all editions connected. */ uint96 private _nextMintId; /** * @dev How much platform fees have been accrued. */ uint128 public platformFeesAccrued; /** * @dev The amount of platform flat fees per token. */ uint96 public platformFlatFee; /** * @dev The platform fee in basis points. */ uint16 public platformFeeBPS; /** * @dev Maps an edition and the mint ID to a mint instance. */ mapping(address => mapping(uint256 => BaseData)) private _baseData; /** * @dev Maps an address to how much affiliate fees have they accrued. */ mapping(address => uint128) public affiliateFeesAccrued; // ============================================================= // CONSTRUCTOR // ============================================================= constructor() payable { _initializeOwner(msg.sender); } // ============================================================= // PUBLIC / EXTERNAL WRITE FUNCTIONS // ============================================================= // Per edition mint parameter setters: // ----------------------------------- // These functions can only be called by the owner or admin of the edition. /** * @inheritdoc IMinterModuleV2 */ function setEditionMintPaused( address edition, uint128 mintId, bool paused ) public virtual onlyEditionOwnerOrAdmin(edition) { _getBaseData(edition, mintId).mintPaused = paused; emit MintPausedSet(edition, mintId, paused); } /** * @inheritdoc IMinterModuleV2 */ function setTimeRange( address edition, uint128 mintId, uint32 startTime, uint32 endTime ) public virtual onlyEditionOwnerOrAdmin(edition) { if (startTime >= endTime) revert InvalidTimeRange(); BaseData storage baseData = _getBaseData(edition, mintId); baseData.startTime = startTime; baseData.endTime = endTime; emit TimeRangeSet(edition, mintId, startTime, endTime); } /** * @inheritdoc IMinterModuleV2 */ function setAffiliateFee( address edition, uint128 mintId, uint16 bps ) public virtual override onlyEditionOwnerOrAdmin(edition) { if (bps > MAX_AFFILIATE_FEE_BPS) revert InvalidAffiliateFeeBPS(); _getBaseData(edition, mintId).affiliateFeeBPS = bps; emit AffiliateFeeSet(edition, mintId, bps); } /** * @inheritdoc IMinterModuleV2 */ function setAffiliateMerkleRoot( address edition, uint128 mintId, bytes32 root ) public virtual override onlyEditionOwnerOrAdmin(edition) { _getBaseData(edition, mintId).affiliateMerkleRoot = root; emit AffiliateMerkleRootSet(edition, mintId, root); } // Withdrawal functions: // --------------------- // These functions can be called by anyone. /** * @inheritdoc IMinterModuleV2 */ function withdrawForAffiliate(address affiliate) public override { uint128 accrued = affiliateFeesAccrued[affiliate]; if (accrued != 0) { affiliateFeesAccrued[affiliate] = 0; SafeTransferLib.forceSafeTransferETH(affiliate, accrued); emit AffiliateFeesWithdrawn(affiliate, accrued); } } /** * @inheritdoc IMinterModuleV2 */ function withdrawForPlatform() public override { address to = platformFeeAddress; if (to == address(0)) revert PlatformFeeAddressIsZero(); uint128 accrued = platformFeesAccrued; if (accrued != 0) { platformFeesAccrued = 0; SafeTransferLib.forceSafeTransferETH(to, accrued); emit PlatformFeesWithdrawn(accrued); } } // Only owner setters: // ------------------- // These functions can only be called by the owner of the minter contract. /** * @inheritdoc IMinterModuleV2 */ function setPlatformFee(uint16 bps) public onlyOwner { if (bps > MAX_PLATFORM_FEE_BPS) revert InvalidPlatformFeeBPS(); platformFeeBPS = bps; emit PlatformFeeSet(bps); } /** * @inheritdoc IMinterModuleV2 */ function setPlatformFlatFee(uint96 flatFee) public onlyOwner { if (flatFee > MAX_PLATFORM_FLAT_FEE) revert InvalidPlatformFlatFee(); platformFlatFee = flatFee; emit PlatformFlatFeeSet(flatFee); } /** * @inheritdoc IMinterModuleV2 */ function setPlatformFeeAddress(address addr) public onlyOwner { if (addr == address(0)) revert PlatformFeeAddressIsZero(); platformFeeAddress = addr; emit PlatformFeeAddressSet(addr); } // ============================================================= // PUBLIC / EXTERNAL VIEW FUNCTIONS // ============================================================= /** * @inheritdoc IMinterModuleV2 */ function nextMintId() external view returns (uint128) { return _nextMintId; } /** * @inheritdoc IMinterModuleV2 */ function isAffiliatedWithProof( address edition, uint128 mintId, address affiliate, bytes32[] calldata affiliateProof ) public view virtual override returns (bool) { bytes32 root = _getBaseData(edition, mintId).affiliateMerkleRoot; // If the root is empty, then use the default logic. if (root == bytes32(0)) { return affiliate != address(0); } // Otherwise, check if the affiliate is in the Merkle tree. // The check that that affiliate is not a zero address is to prevent libraries // that fill up partial Merkle trees with empty leafs from screwing things up. return affiliate != address(0) && MerkleProofLib.verifyCalldata(affiliateProof, root, _keccak256EncodePacked(affiliate)); } /** * @inheritdoc IMinterModuleV2 */ function isAffiliated( address edition, uint128 mintId, address affiliate ) public view virtual override returns (bool) { return isAffiliatedWithProof(edition, mintId, affiliate, MerkleProofLib.emptyProof()); } /** * @inheritdoc IMinterModuleV2 */ function affiliateMerkleRoot(address edition, uint128 mintId) external view returns (bytes32) { return _getBaseData(edition, mintId).affiliateMerkleRoot; } /** * @inheritdoc IERC165 */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IMinterModuleV2).interfaceId || interfaceId == this.supportsInterface.selector; } /** * @inheritdoc IMinterModuleV2 */ function totalPrice( address edition, uint128 mintId, address, /* to */ uint32 quantity ) public view virtual override returns (uint128) { unchecked { // Will not overflow, as `price` is 96 bits, and `quantity` is 32 bits. 96 + 32 = 128. return uint128(uint256(_getBaseData(edition, mintId).price) * uint256(quantity)); } } // ============================================================= // INTERNAL / PRIVATE HELPERS // ============================================================= /** * @dev Requires that the caller is the owner or admin of `edition`. * @param edition The edition address. */ modifier onlyEditionOwnerOrAdmin(address edition) { _requireOnlyEditionOwnerOrAdmin(edition); _; } /** * @dev Requires that the caller is the owner or admin of `edition`. * @param edition The edition address. */ function _requireOnlyEditionOwnerOrAdmin(address edition) internal view { address sender = LibMulticaller.sender(); if (sender != OwnableRoles(edition).owner()) if (!OwnableRoles(edition).hasAnyRole(sender, ISoundEditionV1_2(edition).ADMIN_ROLE())) revert Unauthorized(); } /** * @dev If overriden to return true, the amount of ETH paid must be exact. * @return The constant value. */ function _useExactPayment() internal view virtual returns (bool) { return true; } /** * @dev Creates an edition mint instance. * @param edition The edition address. * @param startTime The start time of the mint. * @param endTime The end time of the mint. * @param affiliateFeeBPS The affiliate fee in basis points. * @return mintId The ID for the mint instance. * Calling conditions: * - Must be owner or admin of the edition. */ function _createEditionMint( address edition, uint32 startTime, uint32 endTime, uint16 affiliateFeeBPS ) internal onlyEditionOwnerOrAdmin(edition) returns (uint128 mintId) { if (startTime >= endTime) revert InvalidTimeRange(); if (affiliateFeeBPS > MAX_AFFILIATE_FEE_BPS) revert InvalidAffiliateFeeBPS(); mintId = _nextMintId; BaseData storage data = _getBaseDataUnchecked(edition, mintId); data.startTime = startTime; data.endTime = endTime; data.affiliateFeeBPS = affiliateFeeBPS; data.created = true; unchecked { _nextMintId = SafeCastLib.toUint96(mintId + 1); } emit MintConfigCreated(edition, msg.sender, mintId, startTime, endTime, affiliateFeeBPS); } /** * For avoiding stack too deep. */ struct _MintTemps { bool affiliated; uint256 affiliateFee; uint256 remainingPayment; uint256 platformFlatFee; uint256 platformFee; uint256 totalPrice; uint256 requiredEtherValue; } /** * @dev Mints `quantity` of `edition` to `to` with a required payment of `requiredEtherValue`. * Note: this function should be called at the end of a function due to it refunding any * excess ether paid, to adhere to the checks-effects-interactions pattern. * Otherwise, a reentrancy guard must be used. * @param edition The edition address. * @param mintId The ID for the mint instance. * @param to The address to mint to. * @param quantity The quantity of tokens to mint. * @param affiliate The affiliate (referral) address. * @param affiliateProof The Merkle proof needed for verifying the affiliate, if any. * @param attributionId The attribution ID. */ function _mintTo( address edition, uint128 mintId, address to, uint32 quantity, address affiliate, bytes32[] calldata affiliateProof, uint256 attributionId ) internal { BaseData storage baseData = _getBaseData(edition, mintId); _MintTemps memory t; /* --------------------- GENERAL CHECKS --------------------- */ { uint32 startTime = baseData.startTime; uint32 endTime = baseData.endTime; if (block.timestamp < startTime) revert MintNotOpen(block.timestamp, startTime, endTime); if (block.timestamp > endTime) revert MintNotOpen(block.timestamp, startTime, endTime); if (baseData.mintPaused) revert MintPaused(); } /* ----------- AFFILIATE AND PLATFORM FEES LOGIC ------------ */ unchecked { t.platformFlatFee = uint256(quantity) * uint256(platformFlatFee); t.totalPrice = totalPrice(edition, mintId, to, quantity); t.requiredEtherValue = t.totalPrice + t.platformFlatFee; // Reverts if the payment is not exact, or not enough. if (_useExactPayment()) { if (msg.value != t.requiredEtherValue) revert WrongPayment(msg.value, t.requiredEtherValue); } else { if (msg.value < t.requiredEtherValue) revert Underpaid(msg.value, t.requiredEtherValue); } // Compute the platform fee. t.platformFee = (t.totalPrice * uint256(platformFeeBPS)) / uint256(BPS_DENOMINATOR) + t.platformFlatFee; // Increment the platform fees accrued. platformFeesAccrued = SafeCastLib.toUint128(uint256(platformFeesAccrued) + t.platformFee); // Deduct the platform fee. // Won't underflow as `platformFee <= requiredEtherValue`; t.remainingPayment = t.requiredEtherValue - t.platformFee; } // Check if the mint is an affiliated mint. t.affiliated = isAffiliatedWithProof(edition, mintId, affiliate, affiliateProof); unchecked { if (t.affiliated) { // Compute the affiliate fee. t.affiliateFee = (t.totalPrice * uint256(baseData.affiliateFeeBPS)) / uint256(BPS_DENOMINATOR); // Deduct the affiliate fee from the remaining payment. // Won't underflow as `affiliateFee <= remainingPayment`. t.remainingPayment -= t.affiliateFee; // Increment the affiliate fees accrued. affiliateFeesAccrued[affiliate] = SafeCastLib.toUint128( uint256(affiliateFeesAccrued[affiliate]) + t.affiliateFee ); } else { // If the affiliate is not the zero address despite not being // affiliated, it might be due to an invalid affiliate proof. // Revert to prevent unintended skipping of affiliate payment. if (affiliate != address(0)) { revert InvalidAffiliate(); } } } /* ------------------------- MINT --------------------------- */ // Emit the event. emit Minted( edition, mintId, to, // Need to put this call here to avoid stack-too-deep error (it returns `fromTokenId`). uint32(ISoundEditionV1_2(edition).mint{ value: t.remainingPayment }(to, quantity)), quantity, uint128(t.requiredEtherValue), uint128(t.platformFee), uint128(t.affiliateFee), affiliate, t.affiliated, attributionId ); /* ------------------------- REFUND ------------------------- */ unchecked { if (!_useExactPayment()) { // Note: We do this at the end to avoid creating a reentrancy vector. // Refund the user any ETH they spent over the current total price of the NFTs. if (msg.value > t.requiredEtherValue) { SafeTransferLib.forceSafeTransferETH(msg.sender, msg.value - t.requiredEtherValue); } } } } /** * @dev Increments `totalMinted` with `quantity`, reverting if `totalMinted + quantity > maxMintable`. * @param totalMinted The current total number of minted tokens. * @param maxMintable The maximum number of mintable tokens. * @return `totalMinted` + `quantity`. */ function _incrementTotalMinted( uint32 totalMinted, uint32 quantity, uint32 maxMintable ) internal pure returns (uint32) { unchecked { // Won't overflow as both are 32 bits. uint256 sum = uint256(totalMinted) + uint256(quantity); if (sum > maxMintable) { // Note that the `maxMintable` may vary and drop over time // and cause `totalMinted` to be greater than `maxMintable`. // The `zeroFloorSub` is equivalent to `max(0, x - y)`. uint32 available = uint32(FixedPointMathLib.zeroFloorSub(maxMintable, totalMinted)); revert ExceedsAvailableSupply(available); } return uint32(sum); } } /** * @dev Returns the storage pointer to the BaseData for (`edition`, `mintId`). * @param edition The edition address. * @param mintId The mint ID. * @return data Storage pointer to a BaseData. */ function _getBaseDataUnchecked(address edition, uint128 mintId) internal view returns (BaseData storage data) { data = _baseData[edition][mintId]; } /** * @dev Returns the storage pointer to the BaseData for (`edition`, `mintId`). * Reverts if the mint does not exist. * @param edition The edition address. * @param mintId The mint ID. * @return data Storage pointer to a BaseData. */ function _getBaseData(address edition, uint128 mintId) internal view returns (BaseData storage data) { data = _getBaseDataUnchecked(edition, mintId); if (!data.created) revert MintDoesNotExist(); } /** * @dev Casts the storage pointer to the BaseData to a bytes32. * @param data Storage pointer to a BaseData. * @return result The casted value of the slot. */ function _baseDataSlot(BaseData storage data) internal pure returns (bytes32 result) { assembly { result := data.slot } } /** * @dev Equivalent to `keccak256(abi.encodePacked(addr))`. * @param addr The address to hash. * @return result The hash of the address. */ function _keccak256EncodePacked(address addr) internal pure returns (bytes32 result) { assembly { mstore(0x00, addr) result := keccak256(0x0c, 0x14) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import { IMinterModuleV2 } from "@core/interfaces/IMinterModuleV2.sol"; /** * @dev Data unique to a Merkle drop mint. */ struct EditionMintData { // Hash of the root node for the Merkle tree drop bytes32 merkleRootHash; // The maximum number of tokens that can can be minted for this sale. uint32 maxMintable; // The total number of tokens minted so far for this sale. uint32 totalMinted; } /** * @dev All the information about a Merkle drop mint (combines EditionMintData with BaseData). */ struct MintInfo { uint32 startTime; uint32 endTime; uint16 affiliateFeeBPS; bool mintPaused; uint96 price; uint32 maxMintable; uint32 maxMintablePerAccount; uint32 totalMinted; bytes32 merkleRootHash; bytes32 affiliateMerkleRoot; } /** * @title IMerkleDropMinterV2 * @dev Interface for the `MerkleDropMinterV2` module. * @author Sound.xyz */ interface IMerkleDropMinterV2 is IMinterModuleV2 { // ============================================================= // EVENTS // ============================================================= /** * @dev Emitted when a new Merkle drop mint is created. * @param edition The edition address. * @param mintId The mint ID. * @param merkleRootHash The root of the Merkle tree of the approved addresses. * @param price The price at which each token will be sold, in ETH. * @param startTime The time minting can begin. * @param endTime The time minting will end. * @param affiliateFeeBPS The affiliate fee in basis points. * @param maxMintable The maximum number of tokens that can be minted. * @param maxMintablePerAccount The maximum number of tokens that an account can mint. */ event MerkleDropMintCreated( address indexed edition, uint128 mintId, bytes32 merkleRootHash, uint96 price, uint32 startTime, uint32 endTime, uint16 affiliateFeeBPS, uint32 maxMintable, uint32 maxMintablePerAccount ); /** * @dev Emitted when tokens are claimed by an account. * @param allowlisted The address in the allowlist. * @param quantity The quantity of tokens claimed. */ event DropClaimed(address allowlisted, uint32 quantity); /** * @dev Emitted when the `price` is changed for (`edition`, `mintId`). * @param edition Address of the song edition contract we are minting for. * @param mintId The mint ID. * @param price Sale price in ETH for minting a single token in `edition`. */ event PriceSet(address indexed edition, uint128 mintId, uint96 price); /** * @dev Emitted when the `maxMintable` is changed for (`edition`, `mintId`). * @param edition Address of the song edition contract we are minting for. * @param mintId The mint ID. * @param maxMintable The maximum number of tokens that can be minted on this schedule. */ event MaxMintableSet(address indexed edition, uint128 mintId, uint32 maxMintable); /** * @dev Emitted when the `maxMintablePerAccount` is changed for (`edition`, `mintId`). * @param edition Address of the song edition contract we are minting for. * @param mintId The mint ID. * @param maxMintablePerAccount The maximum number of tokens that can be minted per account. */ event MaxMintablePerAccountSet(address indexed edition, uint128 mintId, uint32 maxMintablePerAccount); /** * @dev Emitted when the `merkleRootHash` is changed for (`edition`, `mintId`). * @param edition Address of the song edition contract we are minting for. * @param mintId The mint ID. * @param merkleRootHash The merkle root hash of the entries. */ event MerkleRootHashSet(address indexed edition, uint128 mintId, bytes32 merkleRootHash); // ============================================================= // ERRORS // ============================================================= /** * @dev The merkle proof is invalid. */ error InvalidMerkleProof(); /** * @dev The caller must be delegated by the allowlisted. */ error CallerNotDelegated(); /** * @dev The number of tokens minted has exceeded the number allowed for each account. */ error ExceedsMaxPerAccount(); /** * @dev The merkle root hash is empty. */ error MerkleRootHashIsEmpty(); /** * @dev The max mintable per account cannot be zero. */ error MaxMintablePerAccountIsZero(); // ============================================================= // PUBLIC / EXTERNAL WRITE FUNCTIONS // ============================================================= /** * @dev Initializes Merkle drop mint instance. * @param edition Address of the song edition contract we are minting for. * @param merkleRootHash bytes32 hash of the Merkle tree representing eligible mints. * @param price Sale price in ETH for minting a single token in `edition`. * @param startTime Start timestamp of sale (in seconds since unix epoch). * @param endTime End timestamp of sale (in seconds since unix epoch). * @param affiliateFeeBPS The affiliate fee in basis points. * @param maxMintable_ The maximum number of tokens that can can be minted for this sale. * @param maxMintablePerAccount_ The maximum number of tokens that a single account can mint. * @return mintId The ID of the new mint instance. */ function createEditionMint( address edition, bytes32 merkleRootHash, uint96 price, uint32 startTime, uint32 endTime, uint16 affiliateFeeBPS, uint32 maxMintable_, uint32 maxMintablePerAccount_ ) external returns (uint128 mintId); /** * @dev Mints a token for a particular mint instance. * @param edition Address of the song edition contract we are minting for. * @param mintId The mint ID. * @param to The address to mint to. * @param quantity The quantity of tokens to mint. * @param allowlisted The address authorized to mint the tokens. * @param proof The Merkle proof. * @param affiliate The affiliate address. * @param affiliateProof The Merkle proof needed for verifying the affiliate, if any. * @param attributionId The attribution ID. */ function mintTo( address edition, uint128 mintId, address to, uint32 quantity, address allowlisted, bytes32[] calldata proof, address affiliate, bytes32[] calldata affiliateProof, uint256 attributionId ) external payable; /** * @dev Mints a token for a particular mint instance. * @param edition Address of the song edition contract we are minting for. * @param mintId The mint ID.. * @param quantity The quantity of tokens to mint. * @param proof The Merkle proof. * @param affiliate The affiliate address. */ function mint( address edition, uint128 mintId, uint32 quantity, bytes32[] calldata proof, address affiliate ) external payable; /** * @dev Sets the `price` for (`edition`, `mintId`). * @param edition Address of the song edition contract we are minting for. * @param mintId The mint ID. * @param price Sale price in ETH for minting a single token in `edition`. */ function setPrice( address edition, uint128 mintId, uint96 price ) external; /** * @dev Sets the `maxMintablePerAccount` for (`edition`, `mintId`). * @param edition Address of the song edition contract we are minting for. * @param mintId The mint ID. * @param maxMintablePerAccount The maximum number of tokens that can be minted by an account. */ function setMaxMintablePerAccount( address edition, uint128 mintId, uint32 maxMintablePerAccount ) external; /** * @dev Sets the `maxMintable` for (`edition`, `mintId`). * @param edition Address of the song edition contract we are minting for. * @param mintId The mint ID. * @param maxMintable The maximum number of tokens that can be minted on this schedule. */ function setMaxMintable( address edition, uint128 mintId, uint32 maxMintable ) external; /** * @dev Sets the `merkleRootHash` for (`edition`, `mintId`). * @param edition Address of the song edition contract we are minting for. * @param mintId The mint ID. * @param merkleRootHash The Merkle root hash of the entries. */ function setMerkleRootHash( address edition, uint128 mintId, bytes32 merkleRootHash ) external; // ============================================================= // PUBLIC / EXTERNAL VIEW FUNCTIONS // ============================================================= /** * @dev Returns the number of tokens minted to address `to`, for (`edition`, `mintId`). * @param edition Address of the song edition contract we are minting for. * @param mintId The mint ID. * @param to The address to mint to. * @return count The number of tokens minted. */ function mintCount( address edition, uint128 mintId, address to ) external view returns (uint256 count); /** * @dev Returns IMerkleDropMinterV2.MintInfo instance containing the full minter parameter set. * @param edition The edition to get the mint instance for. * @param mintId The ID of the mint instance. * @return mintInfo Information about this mint. */ function mintInfo(address edition, uint128 mintId) external view returns (MintInfo memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; library DelegateCashLib { address internal constant REGISTRY = 0x00000000000076A84feF008CDAbe6409d2FE638B; function checkDelegateForAll(address delegate, address vault) internal view returns (bool result) { assembly { // Cache the free memory pointer. let m := mload(0x40) // Store the function selector of `checkDelegateForAll(address,address)`. mstore(0x00, 0x9c395bc2) // Store the `delegate`. mstore(0x20, delegate) // Store the `vault`. mstore(0x40, vault) // Arguments are evaulated last to first. result := and( // The returndata is 1, which represents a bool true. eq(mload(0x00), 1), // The staticcall is successful. staticcall(gas(), REGISTRY, 0x1c, 0x44, 0x00, 0x20) ) // Restore the free memory pointer. mstore(0x40, m) } } }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.2.3 // Creator: Chiru Labs pragma solidity ^0.8.4; /** * @dev Interface of ERC721A. */ interface IERC721AUpgradeable { /** * The caller must own the token or be an approved operator. */ error ApprovalCallerNotOwnerNorApproved(); /** * The token does not exist. */ error ApprovalQueryForNonexistentToken(); /** * Cannot query the balance for the zero address. */ error BalanceQueryForZeroAddress(); /** * Cannot mint to the zero address. */ error MintToZeroAddress(); /** * The quantity of tokens minted must be more than zero. */ error MintZeroQuantity(); /** * The token does not exist. */ error OwnerQueryForNonexistentToken(); /** * The caller must own the token or be an approved operator. */ error TransferCallerNotOwnerNorApproved(); /** * The token must be owned by `from`. */ error TransferFromIncorrectOwner(); /** * Cannot safely transfer to a contract that does not implement the * ERC721Receiver interface. */ error TransferToNonERC721ReceiverImplementer(); /** * Cannot transfer to the zero address. */ error TransferToZeroAddress(); /** * The token does not exist. */ error URIQueryForNonexistentToken(); /** * The `quantity` minted with ERC2309 exceeds the safety limit. */ error MintERC2309QuantityExceedsLimit(); /** * The `extraData` cannot be set on an unintialized ownership slot. */ error OwnershipNotInitializedForExtraData(); // ============================================================= // STRUCTS // ============================================================= struct TokenOwnership { // The address of the owner. address addr; // Stores the start time of ownership with minimal overhead for tokenomics. uint64 startTimestamp; // Whether the token has been burned. bool burned; // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}. uint24 extraData; } // ============================================================= // TOKEN COUNTERS // ============================================================= /** * @dev Returns the total number of tokens in existence. * Burned tokens will reduce the count. * To get the total number of tokens minted, please see {_totalMinted}. */ function totalSupply() external view returns (uint256); // ============================================================= // IERC165 // ============================================================= /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified) * to learn more about how these ids are created. * * This function call must use less than 30000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); // ============================================================= // IERC721 // ============================================================= /** * @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`, * checking first that contract recipients are aware of the ERC721 protocol * to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move * this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external payable; /** * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external payable; /** * @dev Transfers `tokenId` from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} * whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token * by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external payable; /** * @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 payable; /** * @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); // ============================================================= // IERC721Metadata // ============================================================= /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); // ============================================================= // IERC2309 // ============================================================= /** * @dev Emitted when tokens in `fromTokenId` to `toTokenId` * (inclusive) is transferred from `from` to `to`, as defined in the * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard. * * See {_mintERC2309} for more details. */ event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /** * @title LibMulticaller * @author vectorized.eth * @notice Library to read the `msg.sender` of the multicaller with sender contract. */ library LibMulticaller { /** * @dev The address of the multicaller contract. */ address internal constant MULTICALLER = 0x000000000088228fCF7b8af41Faf3955bD0B3A41; /** * @dev The address of the multicaller with sender contract. */ address internal constant MULTICALLER_WITH_SENDER = 0x00000000002Fd5Aeb385D324B580FCa7c83823A0; /** * @dev Returns the caller of `aggregateWithSender` on `MULTICALLER_WITH_SENDER`. */ function multicallerSender() internal view returns (address result) { /// @solidity memory-safe-assembly assembly { if iszero( staticcall( gas(), // Remaining gas. MULTICALLER_WITH_SENDER, // The multicaller. 0x00, // Start of calldata in memory. 0x00, // Length of calldata. 0x00, // Start of returndata in memory. 0x20 // Length of returndata. ) ) { revert(0, 0) } // For better gas estimation. result := mul(mload(0x00), eq(returndatasize(), 0x20)) } } /** * @dev Returns the caller of `aggregateWithSender` on `MULTICALLER_WITH_SENDER`, * if the current context's `msg.sender` is `MULTICALLER_WITH_SENDER`. * Otherwise, returns `msg.sender`. */ function sender() internal view returns (address result) { /// @solidity memory-safe-assembly assembly { result := caller() if eq(result, MULTICALLER_WITH_SENDER) { if iszero( staticcall( gas(), // Remaining gas. MULTICALLER_WITH_SENDER, // The multicaller with sender. 0x00, // Start of calldata in memory. 0x00, // Length of calldata. 0x00, // Start of returndata in memory. 0x20 // Length of returndata. ) ) { revert(0, 0) } // For better gas estimation. result := mul(mload(0x00), eq(returndatasize(), 0x20)) } } } }
// 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.6.0) (interfaces/IERC2981.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165Upgradeable.sol"; /** * @dev Interface for the NFT Royalty Standard. * * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal * support for royalty payments across all NFT marketplaces and ecosystem participants. * * _Available since v4.5._ */ interface IERC2981Upgradeable is IERC165Upgradeable { /** * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. */ function royaltyInfo(uint256 tokenId, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount); }
// 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 IERC165Upgradeable { /** * @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.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(); /// @dev `bytes4(keccak256(bytes("Unauthorized()")))`. uint256 private constant _UNAUTHORIZED_ERROR_SELECTOR = 0x82b42900; /// @dev `bytes4(keccak256(bytes("NewOwnerIsZeroAddress()")))`. uint256 private constant _NEW_OWNER_IS_ZERO_ADDRESS_ERROR_SELECTOR = 0x7448fbae; /// @dev `bytes4(keccak256(bytes("NoHandoverRequest()")))`. uint256 private constant _NO_HANDOVER_REQUEST_ERROR_SELECTOR = 0x6f5e8818; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 choosen 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, _UNAUTHORIZED_ERROR_SELECTOR) 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, _NEW_OWNER_IS_ZERO_ADDRESS_ERROR_SELECTOR) 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 be 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, _NO_HANDOVER_REQUEST_ERROR_SELECTOR) 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 pragma solidity ^0.8.4; import "./Ownable.sol"; /// @notice Simple single owner and multiroles 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 and roles /// may be unique to this codebase. abstract contract OwnableRoles is Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev `bytes4(keccak256(bytes("Unauthorized()")))`. uint256 private constant _UNAUTHORIZED_ERROR_SELECTOR = 0x82b42900; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `user`'s roles is updated to `roles`. /// Each bit of `roles` represents whether the role is set. event RolesUpdated(address indexed user, uint256 indexed roles); /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The role slot of `user` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) /// let roleSlot := keccak256(0x00, 0x20) /// ``` /// This automatically ignores the upper bits of the `user` in case /// they are not clean, as well as keep the `keccak256` under 32-bytes. /// /// Note: This is equal to `_OWNER_SLOT_NOT` in for gas efficiency. uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Grants the roles directly without authorization guard. /// Each bit of `roles` represents the role to turn on. function _grantRoles(address user, uint256 roles) internal virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) let roleSlot := keccak256(0x0c, 0x20) // Load the current value and `or` it with `roles`. roles := or(sload(roleSlot), roles) // Store the new value. sstore(roleSlot, roles) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) } } /// @dev Removes the roles directly without authorization guard. /// Each bit of `roles` represents the role to turn off. function _removeRoles(address user, uint256 roles) internal virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) let roleSlot := keccak256(0x0c, 0x20) // Load the current value. let currentRoles := sload(roleSlot) // Use `and` to compute the intersection of `currentRoles` and `roles`, // `xor` it with `currentRoles` to flip the bits in the intersection. roles := xor(currentRoles, and(currentRoles, roles)) // Then, store the new value. sstore(roleSlot, roles) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) } } /// @dev Throws if the sender does not have any of the `roles`. function _checkRoles(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { mstore(0x00, _UNAUTHORIZED_ERROR_SELECTOR) revert(0x1c, 0x04) } } } /// @dev Throws if the sender is not the owner, /// and does not have any of the `roles`. /// Checks for ownership first, then lazily checks for roles. function _checkOwnerOrRoles(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner. // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { mstore(0x00, _UNAUTHORIZED_ERROR_SELECTOR) revert(0x1c, 0x04) } } } } /// @dev Throws if the sender does not have any of the `roles`, /// and is not the owner. /// Checks for roles first, then lazily checks for ownership. function _checkRolesOrOwner(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { // If the caller is not the stored owner. // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { mstore(0x00, _UNAUTHORIZED_ERROR_SELECTOR) revert(0x1c, 0x04) } } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to grant `user` `roles`. /// If the `user` already has a role, then it will be an no-op for the role. function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { _grantRoles(user, roles); } /// @dev Allows the owner to remove `user` `roles`. /// If the `user` does not have a role, then it will be an no-op for the role. function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { _removeRoles(user, roles); } /// @dev Allow the caller to remove their own roles. /// If the caller does not have a role, then it will be an no-op for the role. function renounceRoles(uint256 roles) public payable virtual { _removeRoles(msg.sender, roles); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `user` has any of `roles`. function hasAnyRole(address user, uint256 roles) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) // Load the stored value, and set the result to whether the // `and` intersection of the value and `roles` is not zero. result := iszero(iszero(and(sload(keccak256(0x0c, 0x20)), roles))) } } /// @dev Returns whether `user` has all of `roles`. function hasAllRoles(address user, uint256 roles) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) // Whether the stored value is contains all the set bits in `roles`. result := eq(and(sload(keccak256(0x0c, 0x20)), roles), roles) } } /// @dev Returns the roles of `user`. function rolesOf(address user) public view virtual returns (uint256 roles) { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) // Load the stored value. roles := sload(keccak256(0x0c, 0x20)) } } /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. /// This is meant for frontends like Etherscan, and is therefore not fully optimized. /// Not recommended to be called on-chain. function rolesFromOrdinals(uint8[] memory ordinals) public pure returns (uint256 roles) { /// @solidity memory-safe-assembly assembly { for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } { // We don't need to mask the values of `ordinals`, as Solidity // cleans dirty upper bits when storing variables into memory. roles := or(shl(mload(add(ordinals, i)), 1), roles) } } } /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. /// This is meant for frontends like Etherscan, and is therefore not fully optimized. /// Not recommended to be called on-chain. function ordinalsFromRoles(uint256 roles) public pure returns (uint8[] memory ordinals) { /// @solidity memory-safe-assembly assembly { // Grab the pointer to the free memory. ordinals := mload(0x40) let ptr := add(ordinals, 0x20) let o := 0 // The absence of lookup tables, De Bruijn, etc., here is intentional for // smaller bytecode, as this function is not meant to be called on-chain. for { let t := roles } 1 {} { mstore(ptr, o) // `shr` 5 is equivalent to multiplying by 0x20. // Push back into the ordinals array if the bit is set. ptr := add(ptr, shl(5, and(t, 1))) o := add(o, 1) t := shr(o, roles) if iszero(t) { break } } // Store the length of `ordinals`. mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) // Allocate the memory. mstore(0x40, ptr) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by an account with `roles`. modifier onlyRoles(uint256 roles) virtual { _checkRoles(roles); _; } /// @dev Marks a function as only callable by the owner or by an account /// with `roles`. Checks for ownership first, then lazily checks for roles. modifier onlyOwnerOrRoles(uint256 roles) virtual { _checkOwnerOrRoles(roles); _; } /// @dev Marks a function as only callable by an account with `roles` /// or the owner. Checks for roles first, then lazily checks for ownership. modifier onlyRolesOrOwner(uint256 roles) virtual { _checkRolesOrOwner(roles); _; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ROLE CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // IYKYK uint256 internal constant _ROLE_0 = 1 << 0; uint256 internal constant _ROLE_1 = 1 << 1; uint256 internal constant _ROLE_2 = 1 << 2; uint256 internal constant _ROLE_3 = 1 << 3; uint256 internal constant _ROLE_4 = 1 << 4; uint256 internal constant _ROLE_5 = 1 << 5; uint256 internal constant _ROLE_6 = 1 << 6; uint256 internal constant _ROLE_7 = 1 << 7; uint256 internal constant _ROLE_8 = 1 << 8; uint256 internal constant _ROLE_9 = 1 << 9; uint256 internal constant _ROLE_10 = 1 << 10; uint256 internal constant _ROLE_11 = 1 << 11; uint256 internal constant _ROLE_12 = 1 << 12; uint256 internal constant _ROLE_13 = 1 << 13; uint256 internal constant _ROLE_14 = 1 << 14; uint256 internal constant _ROLE_15 = 1 << 15; uint256 internal constant _ROLE_16 = 1 << 16; uint256 internal constant _ROLE_17 = 1 << 17; uint256 internal constant _ROLE_18 = 1 << 18; uint256 internal constant _ROLE_19 = 1 << 19; uint256 internal constant _ROLE_20 = 1 << 20; uint256 internal constant _ROLE_21 = 1 << 21; uint256 internal constant _ROLE_22 = 1 << 22; uint256 internal constant _ROLE_23 = 1 << 23; uint256 internal constant _ROLE_24 = 1 << 24; uint256 internal constant _ROLE_25 = 1 << 25; uint256 internal constant _ROLE_26 = 1 << 26; uint256 internal constant _ROLE_27 = 1 << 27; uint256 internal constant _ROLE_28 = 1 << 28; uint256 internal constant _ROLE_29 = 1 << 29; uint256 internal constant _ROLE_30 = 1 << 30; uint256 internal constant _ROLE_31 = 1 << 31; uint256 internal constant _ROLE_32 = 1 << 32; uint256 internal constant _ROLE_33 = 1 << 33; uint256 internal constant _ROLE_34 = 1 << 34; uint256 internal constant _ROLE_35 = 1 << 35; uint256 internal constant _ROLE_36 = 1 << 36; uint256 internal constant _ROLE_37 = 1 << 37; uint256 internal constant _ROLE_38 = 1 << 38; uint256 internal constant _ROLE_39 = 1 << 39; uint256 internal constant _ROLE_40 = 1 << 40; uint256 internal constant _ROLE_41 = 1 << 41; uint256 internal constant _ROLE_42 = 1 << 42; uint256 internal constant _ROLE_43 = 1 << 43; uint256 internal constant _ROLE_44 = 1 << 44; uint256 internal constant _ROLE_45 = 1 << 45; uint256 internal constant _ROLE_46 = 1 << 46; uint256 internal constant _ROLE_47 = 1 << 47; uint256 internal constant _ROLE_48 = 1 << 48; uint256 internal constant _ROLE_49 = 1 << 49; uint256 internal constant _ROLE_50 = 1 << 50; uint256 internal constant _ROLE_51 = 1 << 51; uint256 internal constant _ROLE_52 = 1 << 52; uint256 internal constant _ROLE_53 = 1 << 53; uint256 internal constant _ROLE_54 = 1 << 54; uint256 internal constant _ROLE_55 = 1 << 55; uint256 internal constant _ROLE_56 = 1 << 56; uint256 internal constant _ROLE_57 = 1 << 57; uint256 internal constant _ROLE_58 = 1 << 58; uint256 internal constant _ROLE_59 = 1 << 59; uint256 internal constant _ROLE_60 = 1 << 60; uint256 internal constant _ROLE_61 = 1 << 61; uint256 internal constant _ROLE_62 = 1 << 62; uint256 internal constant _ROLE_63 = 1 << 63; uint256 internal constant _ROLE_64 = 1 << 64; uint256 internal constant _ROLE_65 = 1 << 65; uint256 internal constant _ROLE_66 = 1 << 66; uint256 internal constant _ROLE_67 = 1 << 67; uint256 internal constant _ROLE_68 = 1 << 68; uint256 internal constant _ROLE_69 = 1 << 69; uint256 internal constant _ROLE_70 = 1 << 70; uint256 internal constant _ROLE_71 = 1 << 71; uint256 internal constant _ROLE_72 = 1 << 72; uint256 internal constant _ROLE_73 = 1 << 73; uint256 internal constant _ROLE_74 = 1 << 74; uint256 internal constant _ROLE_75 = 1 << 75; uint256 internal constant _ROLE_76 = 1 << 76; uint256 internal constant _ROLE_77 = 1 << 77; uint256 internal constant _ROLE_78 = 1 << 78; uint256 internal constant _ROLE_79 = 1 << 79; uint256 internal constant _ROLE_80 = 1 << 80; uint256 internal constant _ROLE_81 = 1 << 81; uint256 internal constant _ROLE_82 = 1 << 82; uint256 internal constant _ROLE_83 = 1 << 83; uint256 internal constant _ROLE_84 = 1 << 84; uint256 internal constant _ROLE_85 = 1 << 85; uint256 internal constant _ROLE_86 = 1 << 86; uint256 internal constant _ROLE_87 = 1 << 87; uint256 internal constant _ROLE_88 = 1 << 88; uint256 internal constant _ROLE_89 = 1 << 89; uint256 internal constant _ROLE_90 = 1 << 90; uint256 internal constant _ROLE_91 = 1 << 91; uint256 internal constant _ROLE_92 = 1 << 92; uint256 internal constant _ROLE_93 = 1 << 93; uint256 internal constant _ROLE_94 = 1 << 94; uint256 internal constant _ROLE_95 = 1 << 95; uint256 internal constant _ROLE_96 = 1 << 96; uint256 internal constant _ROLE_97 = 1 << 97; uint256 internal constant _ROLE_98 = 1 << 98; uint256 internal constant _ROLE_99 = 1 << 99; uint256 internal constant _ROLE_100 = 1 << 100; uint256 internal constant _ROLE_101 = 1 << 101; uint256 internal constant _ROLE_102 = 1 << 102; uint256 internal constant _ROLE_103 = 1 << 103; uint256 internal constant _ROLE_104 = 1 << 104; uint256 internal constant _ROLE_105 = 1 << 105; uint256 internal constant _ROLE_106 = 1 << 106; uint256 internal constant _ROLE_107 = 1 << 107; uint256 internal constant _ROLE_108 = 1 << 108; uint256 internal constant _ROLE_109 = 1 << 109; uint256 internal constant _ROLE_110 = 1 << 110; uint256 internal constant _ROLE_111 = 1 << 111; uint256 internal constant _ROLE_112 = 1 << 112; uint256 internal constant _ROLE_113 = 1 << 113; uint256 internal constant _ROLE_114 = 1 << 114; uint256 internal constant _ROLE_115 = 1 << 115; uint256 internal constant _ROLE_116 = 1 << 116; uint256 internal constant _ROLE_117 = 1 << 117; uint256 internal constant _ROLE_118 = 1 << 118; uint256 internal constant _ROLE_119 = 1 << 119; uint256 internal constant _ROLE_120 = 1 << 120; uint256 internal constant _ROLE_121 = 1 << 121; uint256 internal constant _ROLE_122 = 1 << 122; uint256 internal constant _ROLE_123 = 1 << 123; uint256 internal constant _ROLE_124 = 1 << 124; uint256 internal constant _ROLE_125 = 1 << 125; uint256 internal constant _ROLE_126 = 1 << 126; uint256 internal constant _ROLE_127 = 1 << 127; uint256 internal constant _ROLE_128 = 1 << 128; uint256 internal constant _ROLE_129 = 1 << 129; uint256 internal constant _ROLE_130 = 1 << 130; uint256 internal constant _ROLE_131 = 1 << 131; uint256 internal constant _ROLE_132 = 1 << 132; uint256 internal constant _ROLE_133 = 1 << 133; uint256 internal constant _ROLE_134 = 1 << 134; uint256 internal constant _ROLE_135 = 1 << 135; uint256 internal constant _ROLE_136 = 1 << 136; uint256 internal constant _ROLE_137 = 1 << 137; uint256 internal constant _ROLE_138 = 1 << 138; uint256 internal constant _ROLE_139 = 1 << 139; uint256 internal constant _ROLE_140 = 1 << 140; uint256 internal constant _ROLE_141 = 1 << 141; uint256 internal constant _ROLE_142 = 1 << 142; uint256 internal constant _ROLE_143 = 1 << 143; uint256 internal constant _ROLE_144 = 1 << 144; uint256 internal constant _ROLE_145 = 1 << 145; uint256 internal constant _ROLE_146 = 1 << 146; uint256 internal constant _ROLE_147 = 1 << 147; uint256 internal constant _ROLE_148 = 1 << 148; uint256 internal constant _ROLE_149 = 1 << 149; uint256 internal constant _ROLE_150 = 1 << 150; uint256 internal constant _ROLE_151 = 1 << 151; uint256 internal constant _ROLE_152 = 1 << 152; uint256 internal constant _ROLE_153 = 1 << 153; uint256 internal constant _ROLE_154 = 1 << 154; uint256 internal constant _ROLE_155 = 1 << 155; uint256 internal constant _ROLE_156 = 1 << 156; uint256 internal constant _ROLE_157 = 1 << 157; uint256 internal constant _ROLE_158 = 1 << 158; uint256 internal constant _ROLE_159 = 1 << 159; uint256 internal constant _ROLE_160 = 1 << 160; uint256 internal constant _ROLE_161 = 1 << 161; uint256 internal constant _ROLE_162 = 1 << 162; uint256 internal constant _ROLE_163 = 1 << 163; uint256 internal constant _ROLE_164 = 1 << 164; uint256 internal constant _ROLE_165 = 1 << 165; uint256 internal constant _ROLE_166 = 1 << 166; uint256 internal constant _ROLE_167 = 1 << 167; uint256 internal constant _ROLE_168 = 1 << 168; uint256 internal constant _ROLE_169 = 1 << 169; uint256 internal constant _ROLE_170 = 1 << 170; uint256 internal constant _ROLE_171 = 1 << 171; uint256 internal constant _ROLE_172 = 1 << 172; uint256 internal constant _ROLE_173 = 1 << 173; uint256 internal constant _ROLE_174 = 1 << 174; uint256 internal constant _ROLE_175 = 1 << 175; uint256 internal constant _ROLE_176 = 1 << 176; uint256 internal constant _ROLE_177 = 1 << 177; uint256 internal constant _ROLE_178 = 1 << 178; uint256 internal constant _ROLE_179 = 1 << 179; uint256 internal constant _ROLE_180 = 1 << 180; uint256 internal constant _ROLE_181 = 1 << 181; uint256 internal constant _ROLE_182 = 1 << 182; uint256 internal constant _ROLE_183 = 1 << 183; uint256 internal constant _ROLE_184 = 1 << 184; uint256 internal constant _ROLE_185 = 1 << 185; uint256 internal constant _ROLE_186 = 1 << 186; uint256 internal constant _ROLE_187 = 1 << 187; uint256 internal constant _ROLE_188 = 1 << 188; uint256 internal constant _ROLE_189 = 1 << 189; uint256 internal constant _ROLE_190 = 1 << 190; uint256 internal constant _ROLE_191 = 1 << 191; uint256 internal constant _ROLE_192 = 1 << 192; uint256 internal constant _ROLE_193 = 1 << 193; uint256 internal constant _ROLE_194 = 1 << 194; uint256 internal constant _ROLE_195 = 1 << 195; uint256 internal constant _ROLE_196 = 1 << 196; uint256 internal constant _ROLE_197 = 1 << 197; uint256 internal constant _ROLE_198 = 1 << 198; uint256 internal constant _ROLE_199 = 1 << 199; uint256 internal constant _ROLE_200 = 1 << 200; uint256 internal constant _ROLE_201 = 1 << 201; uint256 internal constant _ROLE_202 = 1 << 202; uint256 internal constant _ROLE_203 = 1 << 203; uint256 internal constant _ROLE_204 = 1 << 204; uint256 internal constant _ROLE_205 = 1 << 205; uint256 internal constant _ROLE_206 = 1 << 206; uint256 internal constant _ROLE_207 = 1 << 207; uint256 internal constant _ROLE_208 = 1 << 208; uint256 internal constant _ROLE_209 = 1 << 209; uint256 internal constant _ROLE_210 = 1 << 210; uint256 internal constant _ROLE_211 = 1 << 211; uint256 internal constant _ROLE_212 = 1 << 212; uint256 internal constant _ROLE_213 = 1 << 213; uint256 internal constant _ROLE_214 = 1 << 214; uint256 internal constant _ROLE_215 = 1 << 215; uint256 internal constant _ROLE_216 = 1 << 216; uint256 internal constant _ROLE_217 = 1 << 217; uint256 internal constant _ROLE_218 = 1 << 218; uint256 internal constant _ROLE_219 = 1 << 219; uint256 internal constant _ROLE_220 = 1 << 220; uint256 internal constant _ROLE_221 = 1 << 221; uint256 internal constant _ROLE_222 = 1 << 222; uint256 internal constant _ROLE_223 = 1 << 223; uint256 internal constant _ROLE_224 = 1 << 224; uint256 internal constant _ROLE_225 = 1 << 225; uint256 internal constant _ROLE_226 = 1 << 226; uint256 internal constant _ROLE_227 = 1 << 227; uint256 internal constant _ROLE_228 = 1 << 228; uint256 internal constant _ROLE_229 = 1 << 229; uint256 internal constant _ROLE_230 = 1 << 230; uint256 internal constant _ROLE_231 = 1 << 231; uint256 internal constant _ROLE_232 = 1 << 232; uint256 internal constant _ROLE_233 = 1 << 233; uint256 internal constant _ROLE_234 = 1 << 234; uint256 internal constant _ROLE_235 = 1 << 235; uint256 internal constant _ROLE_236 = 1 << 236; uint256 internal constant _ROLE_237 = 1 << 237; uint256 internal constant _ROLE_238 = 1 << 238; uint256 internal constant _ROLE_239 = 1 << 239; uint256 internal constant _ROLE_240 = 1 << 240; uint256 internal constant _ROLE_241 = 1 << 241; uint256 internal constant _ROLE_242 = 1 << 242; uint256 internal constant _ROLE_243 = 1 << 243; uint256 internal constant _ROLE_244 = 1 << 244; uint256 internal constant _ROLE_245 = 1 << 245; uint256 internal constant _ROLE_246 = 1 << 246; uint256 internal constant _ROLE_247 = 1 << 247; uint256 internal constant _ROLE_248 = 1 << 248; uint256 internal constant _ROLE_249 = 1 << 249; uint256 internal constant _ROLE_250 = 1 << 250; uint256 internal constant _ROLE_251 = 1 << 251; uint256 internal constant _ROLE_252 = 1 << 252; uint256 internal constant _ROLE_253 = 1 << 253; uint256 internal constant _ROLE_254 = 1 << 254; uint256 internal constant _ROLE_255 = 1 << 255; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) library FixedPointMathLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The operation failed, as the output exceeds the maximum value of uint256. error ExpOverflow(); /// @dev The operation failed, as the output exceeds the maximum value of uint256. error FactorialOverflow(); /// @dev The operation failed, due to an multiplication overflow. error MulWadFailed(); /// @dev The operation failed, either due to a /// multiplication overflow, or a division by a zero. error DivWadFailed(); /// @dev The multiply-divide operation failed, either due to a /// multiplication overflow, or a division by a zero. error MulDivFailed(); /// @dev The division failed, as the denominator is zero. error DivFailed(); /// @dev The full precision multiply-divide operation failed, either due /// to the result being larger than 256 bits, or a division by a zero. error FullMulDivFailed(); /// @dev The output is undefined, as the input is less-than-or-equal to zero. error LnWadUndefined(); /// @dev The output is undefined, as the input is zero. error Log2Undefined(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The scalar of ETH and most ERC20s. uint256 internal constant WAD = 1e18; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SIMPLIFIED FIXED POINT OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `(x * y) / WAD` rounded down. function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if mul(y, gt(x, div(not(0), y))) { // Store the function selector of `MulWadFailed()`. mstore(0x00, 0xbac65e5b) // Revert with (offset, size). revert(0x1c, 0x04) } z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded up. function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if mul(y, gt(x, div(not(0), y))) { // Store the function selector of `MulWadFailed()`. mstore(0x00, 0xbac65e5b) // Revert with (offset, size). revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD)) } } /// @dev Equivalent to `(x * WAD) / y` rounded down. function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`. if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) { // Store the function selector of `DivWadFailed()`. mstore(0x00, 0x7c5f487d) // Revert with (offset, size). revert(0x1c, 0x04) } z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded up. function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`. if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) { // Store the function selector of `DivWadFailed()`. mstore(0x00, 0x7c5f487d) // Revert with (offset, size). revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y)) } } /// @dev Equivalent to `x` to the power of `y`. /// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`. function powWad(int256 x, int256 y) internal pure returns (int256) { // Using `ln(x)` means `x` must be greater than 0. return expWad((lnWad(x) * y) / int256(WAD)); } /// @dev Returns `exp(x)`, denominated in `WAD`. function expWad(int256 x) internal pure returns (int256 r) { unchecked { // When the result is < 0.5 we return zero. This happens when // x <= floor(log(0.5e18) * 1e18) ~ -42e18 if (x <= -42139678854452767551) return r; /// @solidity memory-safe-assembly assembly { // When the result is > (2**255 - 1) / 1e18 we can not represent it as an // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135. if iszero(slt(x, 135305999368893231589)) { // Store the function selector of `ExpOverflow()`. mstore(0x00, 0xa37bfec9) // Revert with (offset, size). revert(0x1c, 0x04) } } // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96 // for more intermediate precision and a binary basis. This base conversion // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. x = (x << 78) / 5 ** 18; // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers // of two such that exp(x) = exp(x') * 2**k, where k is an integer. // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96; x = x - k * 54916777467707473351141471128; // k is in the range [-61, 195]. // Evaluate using a (6, 7)-term rational approximation. // p is made monic, we'll multiply by a scale factor later. int256 y = x + 1346386616545796478920950773328; y = ((y * x) >> 96) + 57155421227552351082224309758442; int256 p = y + x - 94201549194550492254356042504812; p = ((p * y) >> 96) + 28719021644029726153956944680412240; p = p * x + (4385272521454847904659076985693276 << 96); // We leave p in 2**192 basis so we don't need to scale it back up for the division. int256 q = x - 2855989394907223263936484059900; q = ((q * x) >> 96) + 50020603652535783019961831881945; q = ((q * x) >> 96) - 533845033583426703283633433725380; q = ((q * x) >> 96) + 3604857256930695427073651918091429; q = ((q * x) >> 96) - 14423608567350463180887372962807573; q = ((q * x) >> 96) + 26449188498355588339934803723976023; /// @solidity memory-safe-assembly assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial won't have zeros in the domain as all its roots are complex. // No scaling is necessary because p is already 2**96 too large. r := sdiv(p, q) } // r should be in the range (0.09, 0.25) * 2**96. // We now need to multiply r by: // * the scale factor s = ~6.031367120. // * the 2**k factor from the range reduction. // * the 1e18 / 2**96 factor for base conversion. // We do this all at once, with an intermediate result in 2**213 // basis, so the final right shift is always by a positive amount. r = int256( (uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k) ); } } /// @dev Returns `ln(x)`, denominated in `WAD`. function lnWad(int256 x) internal pure returns (int256 r) { unchecked { /// @solidity memory-safe-assembly assembly { if iszero(sgt(x, 0)) { // Store the function selector of `LnWadUndefined()`. mstore(0x00, 0x1615e638) // Revert with (offset, size). revert(0x1c, 0x04) } } // We want to convert x from 10**18 fixed point to 2**96 fixed point. // We do this by multiplying by 2**96 / 10**18. But since // ln(x * C) = ln(x) + ln(C), we can simply do nothing here // and add ln(2**96 / 10**18) at the end. // Compute k = log2(x) - 96. int256 k; /// @solidity memory-safe-assembly assembly { let v := x k := shl(7, lt(0xffffffffffffffffffffffffffffffff, v)) k := or(k, shl(6, lt(0xffffffffffffffff, shr(k, v)))) k := or(k, shl(5, lt(0xffffffff, shr(k, v)))) // For the remaining 32 bits, use a De Bruijn lookup. // See: https://graphics.stanford.edu/~seander/bithacks.html v := shr(k, v) v := or(v, shr(1, v)) v := or(v, shr(2, v)) v := or(v, shr(4, v)) v := or(v, shr(8, v)) v := or(v, shr(16, v)) // forgefmt: disable-next-item k := sub(or(k, byte(shr(251, mul(v, shl(224, 0x07c4acdd))), 0x0009010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f)), 96) } // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) x <<= uint256(159 - k); x = int256(uint256(x) >> 159); // Evaluate using a (8, 8)-term rational approximation. // p is made monic, we will multiply by a scale factor later. int256 p = x + 3273285459638523848632254066296; p = ((p * x) >> 96) + 24828157081833163892658089445524; p = ((p * x) >> 96) + 43456485725739037958740375743393; p = ((p * x) >> 96) - 11111509109440967052023855526967; p = ((p * x) >> 96) - 45023709667254063763336534515857; p = ((p * x) >> 96) - 14706773417378608786704636184526; p = p * x - (795164235651350426258249787498 << 96); // We leave p in 2**192 basis so we don't need to scale it back up for the division. // q is monic by convention. int256 q = x + 5573035233440673466300451813936; q = ((q * x) >> 96) + 71694874799317883764090561454958; q = ((q * x) >> 96) + 283447036172924575727196451306956; q = ((q * x) >> 96) + 401686690394027663651624208769553; q = ((q * x) >> 96) + 204048457590392012362485061816622; q = ((q * x) >> 96) + 31853899698501571402653359427138; q = ((q * x) >> 96) + 909429971244387300277376558375; /// @solidity memory-safe-assembly assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial is known not to have zeros in the domain. // No scaling required because p is already 2**96 too large. r := sdiv(p, q) } // r is in the range (0, 0.125) * 2**96 // Finalization, we need to: // * multiply by the scale factor s = 5.549… // * add ln(2**96 / 10**18) // * add k * ln(2) // * multiply by 10**18 / 2**96 = 5**18 >> 78 // mul s * 5e18 * 2**96, base is now 5**18 * 2**192 r *= 1677202110996718588342820967067443963516166; // add ln(2) * k * 5e18 * 2**192 r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k; // add ln(2**96 / 10**18) * 5e18 * 2**192 r += 600920179829731861736702779321621459595472258049074101567377883020018308; // base conversion: mul 2**18 / 2**192 r >>= 174; } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* GENERAL NUMBER UTILITIES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Calculates `floor(a * b / d)` with full precision. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // forgefmt: disable-next-item for {} 1 {} { // 512-bit multiply `[prod1 prod0] = x * y`. // Compute the product mod `2**256` and mod `2**256 - 1` // then 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`. // Least significant 256 bits of the product. let prod0 := mul(x, y) let mm := mulmod(x, y, not(0)) // Most significant 256 bits of the product. let prod1 := sub(mm, add(prod0, lt(mm, prod0))) // Handle non-overflow cases, 256 by 256 division. if iszero(prod1) { if iszero(d) { // Store the function selector of `FullMulDivFailed()`. mstore(0x00, 0xae47f702) // Revert with (offset, size). revert(0x1c, 0x04) } result := div(prod0, d) break } // Make sure the result is less than `2**256`. // Also prevents `d == 0`. if iszero(gt(d, prod1)) { // Store the function selector of `FullMulDivFailed()`. mstore(0x00, 0xae47f702) // Revert with (offset, size). revert(0x1c, 0x04) } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from `[prod1 prod0]`. // Compute remainder using mulmod. let remainder := mulmod(x, y, d) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) // Factor powers of two out of `d`. // Compute largest power of two divisor of `d`. // Always greater or equal to 1. let twos := and(d, sub(0, d)) // Divide d by power of two. d := div(d, twos) // Divide [prod1 prod0] by the factors of two. prod0 := div(prod0, twos) // Shift in bits from `prod1` into `prod0`. For this we need // to flip `twos` such that it is `2**256 / twos`. // If `twos` is zero, then it becomes one. prod0 := or(prod0, mul(prod1, add(div(sub(0, twos), twos), 1))) // Invert `d mod 2**256` // Now that `d` is an odd number, it has an inverse // modulo `2**256` such that `d * inv = 1 mod 2**256`. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, `d * inv = 1 mod 2**4`. let inv := xor(mul(3, d), 2) // Now use 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. inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128 result := mul(prod0, mul(inv, sub(2, mul(d, inv)))) // inverse mod 2**256 break } } } /// @dev Calculates `floor(x * y / d)` with full precision, rounded up. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Uniswap-v3-core under MIT license: /// https://github.com/Uniswap/v3-core/blob/contracts/libraries/FullMath.sol function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) { result = fullMulDiv(x, y, d); /// @solidity memory-safe-assembly assembly { if mulmod(x, y, d) { if iszero(add(result, 1)) { // Store the function selector of `FullMulDivFailed()`. mstore(0x00, 0xae47f702) // Revert with (offset, size). revert(0x1c, 0x04) } result := add(result, 1) } } } /// @dev Returns `floor(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) { // Store the function selector of `MulDivFailed()`. mstore(0x00, 0xad251c27) // Revert with (offset, size). revert(0x1c, 0x04) } z := div(mul(x, y), d) } } /// @dev Returns `ceil(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) { // Store the function selector of `MulDivFailed()`. mstore(0x00, 0xad251c27) // Revert with (offset, size). revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d)) } } /// @dev Returns `ceil(x / d)`. /// Reverts if `d` is zero. function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { if iszero(d) { // Store the function selector of `DivFailed()`. mstore(0x00, 0x65244e4e) // Revert with (offset, size). revert(0x1c, 0x04) } z := add(iszero(iszero(mod(x, d))), div(x, d)) } } /// @dev Returns `max(0, x - y)`. function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(gt(x, y), sub(x, y)) } } /// @dev Returns the square root of `x`. function sqrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // Let `y = x / 2**r`. // We check `y >= 2**(k + 8)` but shift right by `k` bits // each branch to ensure that if `x >= 256`, then `y >= 256`. let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffffff, shr(r, x)))) z := shl(shr(1, r), z) // Goal was to get `z*z*y` within a small factor of `x`. More iterations could // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`. // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small. // That's not possible if `x < 256` but we can just verify those cases exhaustively. // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`. // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`. // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps. // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)` // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`, // with largest error when `s = 1` and when `s = 256` or `1/256`. // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`. // Then we can estimate `sqrt(y)` using // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`. // There is no overflow risk here since `y < 2**136` after the first branch above. z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If `x+1` is a perfect square, the Babylonian method cycles between // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case. // If you don't care whether the floor or ceil square root is returned, you can remove this statement. z := sub(z, lt(div(x, z), z)) } } /// @dev Returns the cube root of `x`. /// Credit to bout3fiddy and pcaversaccio under AGPLv3 license: /// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy function cbrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) z := shl(add(div(r, 3), lt(0xf, shr(r, x))), 0xff) z := div(z, byte(mod(r, 3), shl(232, 0x7f624b))) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := sub(z, lt(div(x, mul(z, z)), z)) } } /// @dev Returns the factorial of `x`. function factorial(uint256 x) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { if iszero(lt(10, x)) { // forgefmt: disable-next-item result := and( shr(mul(22, x), 0x375f0016260009d80004ec0002d00001e0000180000180000200000400001), 0x3fffff ) break } if iszero(lt(57, x)) { let end := 31 result := 8222838654177922817725562880000000 if iszero(lt(end, x)) { end := 10 result := 3628800 } for { let w := not(0) } 1 {} { result := mul(result, x) x := add(x, w) if eq(x, end) { break } } break } // Store the function selector of `FactorialOverflow()`. mstore(0x00, 0xaba0f2a2) // Revert with (offset, size). revert(0x1c, 0x04) } } } /// @dev Returns the log2 of `x`. /// Equivalent to computing the index of the most significant bit (MSB) of `x`. function log2(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { if iszero(x) { // Store the function selector of `Log2Undefined()`. mstore(0x00, 0x5be3aa5c) // Revert with (offset, size). revert(0x1c, 0x04) } r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) // For the remaining 32 bits, use a De Bruijn lookup. // See: https://graphics.stanford.edu/~seander/bithacks.html x := shr(r, x) x := or(x, shr(1, x)) x := or(x, shr(2, x)) x := or(x, shr(4, x)) x := or(x, shr(8, x)) x := or(x, shr(16, x)) // forgefmt: disable-next-item r := or(r, byte(shr(251, mul(x, shl(224, 0x07c4acdd))), 0x0009010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f)) } } /// @dev Returns the log2 of `x`, rounded up. function log2Up(uint256 x) internal pure returns (uint256 r) { unchecked { uint256 isNotPo2; assembly { isNotPo2 := iszero(iszero(and(x, sub(x, 1)))) } return log2(x) + isNotPo2; } } /// @dev Returns the average of `x` and `y`. function avg(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = (x & y) + ((x ^ y) >> 1); } } /// @dev Returns the average of `x` and `y`. function avg(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = (x >> 1) + (y >> 1) + (((x & 1) + (y & 1)) >> 1); } } /// @dev Returns the absolute value of `x`. function abs(int256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let mask := sub(0, shr(255, x)) z := xor(mask, add(mask, x)) } } /// @dev Returns the absolute distance between `x` and `y`. function dist(int256 x, int256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let a := sub(y, x) z := xor(a, mul(xor(a, sub(x, y)), sgt(x, y))) } } /// @dev Returns the minimum of `x` and `y`. function min(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), lt(y, x))) } } /// @dev Returns the minimum of `x` and `y`. function min(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), slt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), gt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), sgt(y, x))) } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(uint256 x, uint256 minValue, uint256 maxValue) internal pure returns (uint256 z) { z = min(max(x, minValue), maxValue); } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) { z = min(max(x, minValue), maxValue); } /// @dev Returns greatest common divisor of `x` and `y`. function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // forgefmt: disable-next-item for { z := x } y {} { let t := y y := mod(z, y) z := t } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RAW NUMBER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `x + y`, without checking for overflow. function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x + y; } } /// @dev Returns `x + y`, without checking for overflow. function rawAdd(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x + y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x - y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x - y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x * y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x * y; } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(x, y) } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mod(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawSMod(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := smod(x, y) } } /// @dev Returns `(x + y) % d`, return 0 if `d` if zero. function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := addmod(x, y, d) } } /// @dev Returns `(x * y) % d`, return 0 if `d` if zero. function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mulmod(x, y, d) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Gas optimized verification of proof of inclusion for a leaf in a Merkle tree. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleProofLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol) library MerkleProofLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MERKLE PROOF VERIFICATION OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`. function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool isValid) { /// @solidity memory-safe-assembly assembly { if mload(proof) { // Initialize `offset` to the offset of `proof` elements in memory. let offset := add(proof, 0x20) // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(offset, shl(5, mload(proof))) // Iterate over proof elements to compute root hash. for {} 1 {} { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(leaf, mload(offset))) // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), mload(offset)) // Reuse `leaf` to store the hash to reduce stack operations. leaf := keccak256(0x00, 0x40) offset := add(offset, 0x20) if iszero(lt(offset, end)) { break } } } isValid := eq(leaf, root) } } /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`. function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool isValid) { /// @solidity memory-safe-assembly assembly { if proof.length { // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(proof.offset, shl(5, proof.length)) // Initialize `offset` to the offset of `proof` in the calldata. let offset := proof.offset // Iterate over proof elements to compute root hash. for {} 1 {} { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(leaf, calldataload(offset))) // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), calldataload(offset)) // Reuse `leaf` to store the hash to reduce stack operations. leaf := keccak256(0x00, 0x40) offset := add(offset, 0x20) if iszero(lt(offset, end)) { break } } } isValid := eq(leaf, root) } } /// @dev Returns whether all `leafs` exist in the Merkle tree with `root`, /// given `proof` and `flags`. function verifyMultiProof( bytes32[] memory proof, bytes32 root, bytes32[] memory leafs, bool[] memory flags ) internal pure returns (bool isValid) { // Rebuilds the root by consuming and producing values on a queue. // The queue starts with the `leafs` array, and goes into a `hashes` array. // After the process, the last element on the queue is verified // to be equal to the `root`. // // The `flags` array denotes whether the sibling // should be popped from the queue (`flag == true`), or // should be popped from the `proof` (`flag == false`). /// @solidity memory-safe-assembly assembly { // Cache the lengths of the arrays. let leafsLength := mload(leafs) let proofLength := mload(proof) let flagsLength := mload(flags) // Advance the pointers of the arrays to point to the data. leafs := add(0x20, leafs) proof := add(0x20, proof) flags := add(0x20, flags) // If the number of flags is correct. for {} eq(add(leafsLength, proofLength), add(flagsLength, 1)) {} { // For the case where `proof.length + leafs.length == 1`. if iszero(flagsLength) { // `isValid = (proof.length == 1 ? proof[0] : leafs[0]) == root`. isValid := eq(mload(xor(leafs, mul(xor(proof, leafs), proofLength))), root) break } // We can use the free memory space for the queue. // We don't need to allocate, since the queue is temporary. let hashesFront := mload(0x40) // Copy the leafs into the hashes. // Sometimes, a little memory expansion costs less than branching. // Should cost less, even with a high free memory offset of 0x7d00. // Left shift by 5 is equivalent to multiplying by 0x20. leafsLength := shl(5, leafsLength) for { let i := 0 } iszero(eq(i, leafsLength)) { i := add(i, 0x20) } { mstore(add(hashesFront, i), mload(add(leafs, i))) } // Compute the back of the hashes. let hashesBack := add(hashesFront, leafsLength) // This is the end of the memory for the queue. // We recycle `flagsLength` to save on stack variables // (this trick may not always save gas). flagsLength := add(hashesBack, shl(5, flagsLength)) for {} 1 {} { // Pop from `hashes`. let a := mload(hashesFront) // Pop from `hashes`. let b := mload(add(hashesFront, 0x20)) hashesFront := add(hashesFront, 0x40) // If the flag is false, load the next proof, // else, pops from the queue. if iszero(mload(flags)) { // Loads the next proof. b := mload(proof) proof := add(proof, 0x20) // Unpop from `hashes`. hashesFront := sub(hashesFront, 0x20) } // Advance to the next flag. flags := add(flags, 0x20) // Slot of `a` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(a, b)) // Hash the scratch space and push the result onto the queue. mstore(scratch, a) mstore(xor(scratch, 0x20), b) mstore(hashesBack, keccak256(0x00, 0x40)) hashesBack := add(hashesBack, 0x20) if iszero(lt(hashesBack, flagsLength)) { break } } // Checks if the last value in the queue is same as the root. isValid := eq(mload(sub(hashesBack, 0x20)), root) break } } } /// @dev Returns whether all `leafs` exist in the Merkle tree with `root`, /// given `proof` and `flags`. function verifyMultiProofCalldata( bytes32[] calldata proof, bytes32 root, bytes32[] calldata leafs, bool[] calldata flags ) internal pure returns (bool isValid) { // Rebuilds the root by consuming and producing values on a queue. // The queue starts with the `leafs` array, and goes into a `hashes` array. // After the process, the last element on the queue is verified // to be equal to the `root`. // // The `flags` array denotes whether the sibling // should be popped from the queue (`flag == true`), or // should be popped from the `proof` (`flag == false`). /// @solidity memory-safe-assembly assembly { // If the number of flags is correct. for {} eq(add(leafs.length, proof.length), add(flags.length, 1)) {} { // For the case where `proof.length + leafs.length == 1`. if iszero(flags.length) { // `isValid = (proof.length == 1 ? proof[0] : leafs[0]) == root`. // forgefmt: disable-next-item isValid := eq( calldataload( xor(leafs.offset, mul(xor(proof.offset, leafs.offset), proof.length)) ), root ) break } // We can use the free memory space for the queue. // We don't need to allocate, since the queue is temporary. let hashesFront := mload(0x40) // Copy the leafs into the hashes. // Sometimes, a little memory expansion costs less than branching. // Should cost less, even with a high free memory offset of 0x7d00. // Left shift by 5 is equivalent to multiplying by 0x20. calldatacopy(hashesFront, leafs.offset, shl(5, leafs.length)) // Compute the back of the hashes. let hashesBack := add(hashesFront, shl(5, leafs.length)) // This is the end of the memory for the queue. // We recycle `flags.length` to save on stack variables // (this trick may not always save gas). flags.length := add(hashesBack, shl(5, flags.length)) // We don't need to make a copy of `proof.offset` or `flags.offset`, // as they are pass-by-value (this trick may not always save gas). for {} 1 {} { // Pop from `hashes`. let a := mload(hashesFront) // Pop from `hashes`. let b := mload(add(hashesFront, 0x20)) hashesFront := add(hashesFront, 0x40) // If the flag is false, load the next proof, // else, pops from the queue. if iszero(calldataload(flags.offset)) { // Loads the next proof. b := calldataload(proof.offset) proof.offset := add(proof.offset, 0x20) // Unpop from `hashes`. hashesFront := sub(hashesFront, 0x20) } // Advance to the next flag offset. flags.offset := add(flags.offset, 0x20) // Slot of `a` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(a, b)) // Hash the scratch space and push the result onto the queue. mstore(scratch, a) mstore(xor(scratch, 0x20), b) mstore(hashesBack, keccak256(0x00, 0x40)) hashesBack := add(hashesBack, 0x20) if iszero(lt(hashesBack, flags.length)) { break } } // Checks if the last value in the queue is same as the root. isValid := eq(mload(sub(hashesBack, 0x20)), root) break } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EMPTY CALLDATA HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an empty calldata bytes32 array. function emptyProof() internal pure returns (bytes32[] calldata proof) { /// @solidity memory-safe-assembly assembly { proof.length := 0 } } /// @dev Returns an empty calldata bytes32 array. function emptyLeafs() internal pure returns (bytes32[] calldata leafs) { /// @solidity memory-safe-assembly assembly { leafs.length := 0 } } /// @dev Returns an empty calldata bool array. function emptyFlags() internal pure returns (bool[] calldata flags) { /// @solidity memory-safe-assembly assembly { flags.length := 0 } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Safe integer casting library that reverts on overflow. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeCastLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol) library SafeCastLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ error Overflow(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* UNSIGNED INTEGER SAFE CASTING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function toUint8(uint256 x) internal pure returns (uint8) { if (x >= 1 << 8) _revertOverflow(); return uint8(x); } function toUint16(uint256 x) internal pure returns (uint16) { if (x >= 1 << 16) _revertOverflow(); return uint16(x); } function toUint24(uint256 x) internal pure returns (uint24) { if (x >= 1 << 24) _revertOverflow(); return uint24(x); } function toUint32(uint256 x) internal pure returns (uint32) { if (x >= 1 << 32) _revertOverflow(); return uint32(x); } function toUint40(uint256 x) internal pure returns (uint40) { if (x >= 1 << 40) _revertOverflow(); return uint40(x); } function toUint48(uint256 x) internal pure returns (uint48) { if (x >= 1 << 48) _revertOverflow(); return uint48(x); } function toUint56(uint256 x) internal pure returns (uint56) { if (x >= 1 << 56) _revertOverflow(); return uint56(x); } function toUint64(uint256 x) internal pure returns (uint64) { if (x >= 1 << 64) _revertOverflow(); return uint64(x); } function toUint72(uint256 x) internal pure returns (uint72) { if (x >= 1 << 72) _revertOverflow(); return uint72(x); } function toUint80(uint256 x) internal pure returns (uint80) { if (x >= 1 << 80) _revertOverflow(); return uint80(x); } function toUint88(uint256 x) internal pure returns (uint88) { if (x >= 1 << 88) _revertOverflow(); return uint88(x); } function toUint96(uint256 x) internal pure returns (uint96) { if (x >= 1 << 96) _revertOverflow(); return uint96(x); } function toUint104(uint256 x) internal pure returns (uint104) { if (x >= 1 << 104) _revertOverflow(); return uint104(x); } function toUint112(uint256 x) internal pure returns (uint112) { if (x >= 1 << 112) _revertOverflow(); return uint112(x); } function toUint120(uint256 x) internal pure returns (uint120) { if (x >= 1 << 120) _revertOverflow(); return uint120(x); } function toUint128(uint256 x) internal pure returns (uint128) { if (x >= 1 << 128) _revertOverflow(); return uint128(x); } function toUint136(uint256 x) internal pure returns (uint136) { if (x >= 1 << 136) _revertOverflow(); return uint136(x); } function toUint144(uint256 x) internal pure returns (uint144) { if (x >= 1 << 144) _revertOverflow(); return uint144(x); } function toUint152(uint256 x) internal pure returns (uint152) { if (x >= 1 << 152) _revertOverflow(); return uint152(x); } function toUint160(uint256 x) internal pure returns (uint160) { if (x >= 1 << 160) _revertOverflow(); return uint160(x); } function toUint168(uint256 x) internal pure returns (uint168) { if (x >= 1 << 168) _revertOverflow(); return uint168(x); } function toUint176(uint256 x) internal pure returns (uint176) { if (x >= 1 << 176) _revertOverflow(); return uint176(x); } function toUint184(uint256 x) internal pure returns (uint184) { if (x >= 1 << 184) _revertOverflow(); return uint184(x); } function toUint192(uint256 x) internal pure returns (uint192) { if (x >= 1 << 192) _revertOverflow(); return uint192(x); } function toUint200(uint256 x) internal pure returns (uint200) { if (x >= 1 << 200) _revertOverflow(); return uint200(x); } function toUint208(uint256 x) internal pure returns (uint208) { if (x >= 1 << 208) _revertOverflow(); return uint208(x); } function toUint216(uint256 x) internal pure returns (uint216) { if (x >= 1 << 216) _revertOverflow(); return uint216(x); } function toUint224(uint256 x) internal pure returns (uint224) { if (x >= 1 << 224) _revertOverflow(); return uint224(x); } function toUint232(uint256 x) internal pure returns (uint232) { if (x >= 1 << 232) _revertOverflow(); return uint232(x); } function toUint240(uint256 x) internal pure returns (uint240) { if (x >= 1 << 240) _revertOverflow(); return uint240(x); } function toUint248(uint256 x) internal pure returns (uint248) { if (x >= 1 << 248) _revertOverflow(); return uint248(x); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SIGNED INTEGER SAFE CASTING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function toInt8(int256 x) internal pure returns (int8) { int8 y = int8(x); if (x != y) _revertOverflow(); return y; } function toInt16(int256 x) internal pure returns (int16) { int16 y = int16(x); if (x != y) _revertOverflow(); return y; } function toInt24(int256 x) internal pure returns (int24) { int24 y = int24(x); if (x != y) _revertOverflow(); return y; } function toInt32(int256 x) internal pure returns (int32) { int32 y = int32(x); if (x != y) _revertOverflow(); return y; } function toInt40(int256 x) internal pure returns (int40) { int40 y = int40(x); if (x != y) _revertOverflow(); return y; } function toInt48(int256 x) internal pure returns (int48) { int48 y = int48(x); if (x != y) _revertOverflow(); return y; } function toInt56(int256 x) internal pure returns (int56) { int56 y = int56(x); if (x != y) _revertOverflow(); return y; } function toInt64(int256 x) internal pure returns (int64) { int64 y = int64(x); if (x != y) _revertOverflow(); return y; } function toInt72(int256 x) internal pure returns (int72) { int72 y = int72(x); if (x != y) _revertOverflow(); return y; } function toInt80(int256 x) internal pure returns (int80) { int80 y = int80(x); if (x != y) _revertOverflow(); return y; } function toInt88(int256 x) internal pure returns (int88) { int88 y = int88(x); if (x != y) _revertOverflow(); return y; } function toInt96(int256 x) internal pure returns (int96) { int96 y = int96(x); if (x != y) _revertOverflow(); return y; } function toInt104(int256 x) internal pure returns (int104) { int104 y = int104(x); if (x != y) _revertOverflow(); return y; } function toInt112(int256 x) internal pure returns (int112) { int112 y = int112(x); if (x != y) _revertOverflow(); return y; } function toInt120(int256 x) internal pure returns (int120) { int120 y = int120(x); if (x != y) _revertOverflow(); return y; } function toInt128(int256 x) internal pure returns (int128) { int128 y = int128(x); if (x != y) _revertOverflow(); return y; } function toInt136(int256 x) internal pure returns (int136) { int136 y = int136(x); if (x != y) _revertOverflow(); return y; } function toInt144(int256 x) internal pure returns (int144) { int144 y = int144(x); if (x != y) _revertOverflow(); return y; } function toInt152(int256 x) internal pure returns (int152) { int152 y = int152(x); if (x != y) _revertOverflow(); return y; } function toInt160(int256 x) internal pure returns (int160) { int160 y = int160(x); if (x != y) _revertOverflow(); return y; } function toInt168(int256 x) internal pure returns (int168) { int168 y = int168(x); if (x != y) _revertOverflow(); return y; } function toInt176(int256 x) internal pure returns (int176) { int176 y = int176(x); if (x != y) _revertOverflow(); return y; } function toInt184(int256 x) internal pure returns (int184) { int184 y = int184(x); if (x != y) _revertOverflow(); return y; } function toInt192(int256 x) internal pure returns (int192) { int192 y = int192(x); if (x != y) _revertOverflow(); return y; } function toInt200(int256 x) internal pure returns (int200) { int200 y = int200(x); if (x != y) _revertOverflow(); return y; } function toInt208(int256 x) internal pure returns (int208) { int208 y = int208(x); if (x != y) _revertOverflow(); return y; } function toInt216(int256 x) internal pure returns (int216) { int216 y = int216(x); if (x != y) _revertOverflow(); return y; } function toInt224(int256 x) internal pure returns (int224) { int224 y = int224(x); if (x != y) _revertOverflow(); return y; } function toInt232(int256 x) internal pure returns (int232) { int232 y = int232(x); if (x != y) _revertOverflow(); return y; } function toInt240(int256 x) internal pure returns (int240) { int240 y = int240(x); if (x != y) _revertOverflow(); return y; } function toInt248(int256 x) internal pure returns (int248) { int248 y = int248(x); if (x != y) _revertOverflow(); return y; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function _revertOverflow() private pure { /// @solidity memory-safe-assembly assembly { // Store the function selector of `Overflow()`. mstore(0x00, 0x35278d12) // Revert with (offset, size). revert(0x1c, 0x04) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Caution! This library won't check that a token has code, responsibility is delegated to the caller. library SafeTransferLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ETH transfer has failed. error ETHTransferFailed(); /// @dev The ERC20 `transferFrom` has failed. error TransferFromFailed(); /// @dev The ERC20 `transfer` has failed. error TransferFailed(); /// @dev The ERC20 `approve` has failed. error ApproveFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Suggested gas stipend for contract receiving ETH /// that disallows any storage writes. uint256 internal constant _GAS_STIPEND_NO_STORAGE_WRITES = 2300; /// @dev Suggested gas stipend for contract receiving ETH to perform a few /// storage reads and writes, but low enough to prevent griefing. /// Multiply by a small constant (e.g. 2), if needed. uint256 internal constant _GAS_STIPEND_NO_GRIEF = 100000; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ETH OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sends `amount` (in wei) ETH to `to`. /// Reverts upon failure. function safeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { // Transfer the ETH and check if it succeeded or not. if iszero(call(gas(), to, amount, 0, 0, 0, 0)) { // Store the function selector of `ETHTransferFailed()`. mstore(0x00, 0xb12d13eb) // Revert with (offset, size). revert(0x1c, 0x04) } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`. /// The `gasStipend` can be set to a low enough value to prevent /// storage writes or gas griefing. /// /// If sending via the normal procedure fails, force sends the ETH by /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH. /// /// Reverts if the current contract has insufficient balance. function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal { /// @solidity memory-safe-assembly assembly { // If insufficient balance, revert. if lt(selfbalance(), amount) { // Store the function selector of `ETHTransferFailed()`. mstore(0x00, 0xb12d13eb) // Revert with (offset, size). revert(0x1c, 0x04) } // Transfer the ETH and check if it succeeded or not. if iszero(call(gasStipend, to, amount, 0, 0, 0, 0)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. // We can directly use `SELFDESTRUCT` in the contract creation. // Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758 pop(create(amount, 0x0b, 0x16)) } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with a gas stipend /// equal to `_GAS_STIPEND_NO_GRIEF`. This gas stipend is a reasonable default /// for 99% of cases and can be overriden with the three-argument version of this /// function if necessary. /// /// If sending via the normal procedure fails, force sends the ETH by /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH. /// /// Reverts if the current contract has insufficient balance. function forceSafeTransferETH(address to, uint256 amount) internal { // Manually inlined because the compiler doesn't inline functions with branches. /// @solidity memory-safe-assembly assembly { // If insufficient balance, revert. if lt(selfbalance(), amount) { // Store the function selector of `ETHTransferFailed()`. mstore(0x00, 0xb12d13eb) // Revert with (offset, size). revert(0x1c, 0x04) } // Transfer the ETH and check if it succeeded or not. if iszero(call(_GAS_STIPEND_NO_GRIEF, to, amount, 0, 0, 0, 0)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. // We can directly use `SELFDESTRUCT` in the contract creation. // Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758 pop(create(amount, 0x0b, 0x16)) } } } /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`. /// The `gasStipend` can be set to a low enough value to prevent /// storage writes or gas griefing. /// /// Simply use `gasleft()` for `gasStipend` if you don't need a gas stipend. /// /// Note: Does NOT revert upon failure. /// Returns whether the transfer of ETH is successful instead. function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { // Transfer the ETH and check if it succeeded or not. success := call(gasStipend, to, amount, 0, 0, 0, 0) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sends `amount` of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for /// the current contract to manage. function safeTransferFrom(address token, address from, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. // Store the function selector of `transferFrom(address,address,uint256)`. mstore(0x00, 0x23b872dd) mstore(0x20, from) // Store the `from` argument. mstore(0x40, to) // Store the `to` argument. mstore(0x60, amount) // Store the `amount` argument. if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends all of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for /// the current contract to manage. function safeTransferAllFrom(address token, address from, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, from) // Store the `from` argument. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x1c, 0x04) } // Store the function selector of `transferFrom(address,address,uint256)`. mstore(0x00, 0x23b872dd) mstore(0x40, to) // Store the `to` argument. // The `amount` argument is already written to the memory word at 0x6a. amount := mload(0x60) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransfer(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x1a, to) // Store the `to` argument. mstore(0x3a, amount) // Store the `amount` argument. // Store the function selector of `transfer(address,uint256)`, // left by 6 bytes (enough for 8tb of memory represented by the free memory pointer). // We waste 6-3 = 3 bytes to save on 6 runtime gas (PUSH1 0x224 SHL). mstore(0x00, 0xa9059cbb000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x16, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that was overwritten, // which is guaranteed to be zero, if less than 8tb of memory is used. mstore(0x3a, 0) } } /// @dev Sends all of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransferAll(address token, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, address()) // Store the address of the current contract. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x3a, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x1a, to) // Store the `to` argument. // The `amount` argument is already written to the memory word at 0x3a. amount := mload(0x3a) // Store the function selector of `transfer(address,uint256)`, // left by 6 bytes (enough for 8tb of memory represented by the free memory pointer). // We waste 6-3 = 3 bytes to save on 6 runtime gas (PUSH1 0x224 SHL). mstore(0x00, 0xa9059cbb000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x16, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that was overwritten, // which is guaranteed to be zero, if less than 8tb of memory is used. mstore(0x3a, 0) } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// Reverts upon failure. function safeApprove(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x1a, to) // Store the `to` argument. mstore(0x3a, amount) // Store the `amount` argument. // Store the function selector of `approve(address,uint256)`, // left by 6 bytes (enough for 8tb of memory represented by the free memory pointer). // We waste 6-3 = 3 bytes to save on 6 runtime gas (PUSH1 0x224 SHL). mstore(0x00, 0x095ea7b3000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x16, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `ApproveFailed()`. mstore(0x00, 0x3e3f8f73) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that was overwritten, // which is guaranteed to be zero, if less than 8tb of memory is used. mstore(0x3a, 0) } } /// @dev Returns the amount of ERC20 `token` owned by `account`. /// Returns zero if the `token` does not exist. function balanceOf(address token, address account) internal view returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, account) // Store the `account` argument. amount := mul( mload(0x20), and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x20, 0x20) ) ) } } }
{ "remappings": [ "@core/=contracts/core/", "@modules/=contracts/modules/", "ERC721A-Upgradeable/=lib/ERC721A-Upgradeable/contracts/", "chiru-labs/ERC721A-Upgradeable/=lib/ERC721A-Upgradeable/contracts/", "closedsea/=lib/closedsea/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/closedsea/lib/openzeppelin-contracts/lib/erc4626-tests/", "erc721a-upgradeable/=lib/closedsea/lib/erc721a-upgradeable/contracts/", "erc721a/=lib/closedsea/lib/erc721a/contracts/", "forge-std/=lib/forge-std/src/", "multicaller/=lib/multicaller/src/", "murky/=lib/murky/src/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "openzeppelin/=lib/openzeppelin-contracts/contracts/", "operator-filter-registry/=lib/closedsea/lib/operator-filter-registry/", "preapprove/=lib/preapprove/src/", "solady/=lib/solady/src/", "solmate/=lib/solady/lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 1000 }, "metadata": { "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"CallerNotDelegated","type":"error"},{"inputs":[{"internalType":"uint32","name":"available","type":"uint32"}],"name":"ExceedsAvailableSupply","type":"error"},{"inputs":[],"name":"ExceedsMaxPerAccount","type":"error"},{"inputs":[],"name":"InvalidAffiliate","type":"error"},{"inputs":[],"name":"InvalidAffiliateFeeBPS","type":"error"},{"inputs":[],"name":"InvalidMerkleProof","type":"error"},{"inputs":[],"name":"InvalidPlatformFeeBPS","type":"error"},{"inputs":[],"name":"InvalidPlatformFlatFee","type":"error"},{"inputs":[],"name":"InvalidTimeRange","type":"error"},{"inputs":[],"name":"MaxMintablePerAccountIsZero","type":"error"},{"inputs":[],"name":"MerkleRootHashIsEmpty","type":"error"},{"inputs":[],"name":"MintDoesNotExist","type":"error"},{"inputs":[{"internalType":"uint256","name":"blockTimestamp","type":"uint256"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"}],"name":"MintNotOpen","type":"error"},{"inputs":[],"name":"MintPaused","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"PlatformFeeAddressIsZero","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[{"internalType":"uint256","name":"paid","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"Underpaid","type":"error"},{"inputs":[{"internalType":"uint256","name":"paid","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"WrongPayment","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"edition","type":"address"},{"indexed":false,"internalType":"uint128","name":"mintId","type":"uint128"},{"indexed":false,"internalType":"uint16","name":"bps","type":"uint16"}],"name":"AffiliateFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"affiliate","type":"address"},{"indexed":false,"internalType":"uint256","name":"accrued","type":"uint256"}],"name":"AffiliateFeesWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"edition","type":"address"},{"indexed":false,"internalType":"uint128","name":"mintId","type":"uint128"},{"indexed":false,"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"AffiliateMerkleRootSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"allowlisted","type":"address"},{"indexed":false,"internalType":"uint32","name":"quantity","type":"uint32"}],"name":"DropClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"edition","type":"address"},{"indexed":false,"internalType":"uint128","name":"mintId","type":"uint128"},{"indexed":false,"internalType":"uint32","name":"maxMintablePerAccount","type":"uint32"}],"name":"MaxMintablePerAccountSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"edition","type":"address"},{"indexed":false,"internalType":"uint128","name":"mintId","type":"uint128"},{"indexed":false,"internalType":"uint32","name":"maxMintable","type":"uint32"}],"name":"MaxMintableSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"edition","type":"address"},{"indexed":false,"internalType":"uint128","name":"mintId","type":"uint128"},{"indexed":false,"internalType":"bytes32","name":"merkleRootHash","type":"bytes32"},{"indexed":false,"internalType":"uint96","name":"price","type":"uint96"},{"indexed":false,"internalType":"uint32","name":"startTime","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"endTime","type":"uint32"},{"indexed":false,"internalType":"uint16","name":"affiliateFeeBPS","type":"uint16"},{"indexed":false,"internalType":"uint32","name":"maxMintable","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"maxMintablePerAccount","type":"uint32"}],"name":"MerkleDropMintCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"edition","type":"address"},{"indexed":false,"internalType":"uint128","name":"mintId","type":"uint128"},{"indexed":false,"internalType":"bytes32","name":"merkleRootHash","type":"bytes32"}],"name":"MerkleRootHashSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"edition","type":"address"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"uint128","name":"mintId","type":"uint128"},{"indexed":false,"internalType":"uint32","name":"startTime","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"endTime","type":"uint32"},{"indexed":false,"internalType":"uint16","name":"affiliateFeeBPS","type":"uint16"}],"name":"MintConfigCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"edition","type":"address"},{"indexed":false,"internalType":"uint128","name":"mintId","type":"uint128"},{"indexed":false,"internalType":"bool","name":"paused","type":"bool"}],"name":"MintPausedSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"edition","type":"address"},{"indexed":false,"internalType":"uint128","name":"mintId","type":"uint128"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint32","name":"fromTokenId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"quantity","type":"uint32"},{"indexed":false,"internalType":"uint128","name":"requiredEtherValue","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"platformFee","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"affiliateFee","type":"uint128"},{"indexed":false,"internalType":"address","name":"affiliate","type":"address"},{"indexed":false,"internalType":"bool","name":"affiliated","type":"bool"},{"indexed":true,"internalType":"uint256","name":"attributionId","type":"uint256"}],"name":"Minted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"PlatformFeeAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"bps","type":"uint16"}],"name":"PlatformFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"accrued","type":"uint128"}],"name":"PlatformFeesWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint96","name":"flatFee","type":"uint96"}],"name":"PlatformFlatFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"edition","type":"address"},{"indexed":false,"internalType":"uint128","name":"mintId","type":"uint128"},{"indexed":false,"internalType":"uint96","name":"price","type":"uint96"}],"name":"PriceSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"edition","type":"address"},{"indexed":false,"internalType":"uint128","name":"mintId","type":"uint128"},{"indexed":false,"internalType":"uint32","name":"startTime","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"endTime","type":"uint32"}],"name":"TimeRangeSet","type":"event"},{"inputs":[],"name":"BPS_DENOMINATOR","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_AFFILIATE_FEE_BPS","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PLATFORM_FEE_BPS","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PLATFORM_FLAT_FEE","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"affiliateFeesAccrued","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"}],"name":"affiliateMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"bytes32","name":"merkleRootHash","type":"bytes32"},{"internalType":"uint96","name":"price","type":"uint96"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint16","name":"affiliateFeeBPS","type":"uint16"},{"internalType":"uint32","name":"maxMintable","type":"uint32"},{"internalType":"uint32","name":"maxMintablePerAccount","type":"uint32"}],"name":"createEditionMint","outputs":[{"internalType":"uint128","name":"mintId","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"},{"internalType":"address","name":"affiliate","type":"address"}],"name":"isAffiliated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"},{"internalType":"address","name":"affiliate","type":"address"},{"internalType":"bytes32[]","name":"affiliateProof","type":"bytes32[]"}],"name":"isAffiliatedWithProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"},{"internalType":"uint32","name":"quantity","type":"uint32"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"address","name":"affiliate","type":"address"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"},{"internalType":"address","name":"to","type":"address"}],"name":"mintCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"}],"name":"mintInfo","outputs":[{"components":[{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint16","name":"affiliateFeeBPS","type":"uint16"},{"internalType":"bool","name":"mintPaused","type":"bool"},{"internalType":"uint96","name":"price","type":"uint96"},{"internalType":"uint32","name":"maxMintable","type":"uint32"},{"internalType":"uint32","name":"maxMintablePerAccount","type":"uint32"},{"internalType":"uint32","name":"totalMinted","type":"uint32"},{"internalType":"bytes32","name":"merkleRootHash","type":"bytes32"},{"internalType":"bytes32","name":"affiliateMerkleRoot","type":"bytes32"}],"internalType":"struct MintInfo","name":"info","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint32","name":"quantity","type":"uint32"},{"internalType":"address","name":"allowlisted","type":"address"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"address","name":"affiliate","type":"address"},{"internalType":"bytes32[]","name":"affiliateProof","type":"bytes32[]"},{"internalType":"uint256","name":"attributionId","type":"uint256"}],"name":"mintTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"moduleInterfaceId","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"nextMintId","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownershipHandoverValidFor","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platformFeeAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platformFeeBPS","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platformFeesAccrued","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platformFlatFee","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"},{"internalType":"uint16","name":"bps","type":"uint16"}],"name":"setAffiliateFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"},{"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"setAffiliateMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"},{"internalType":"bool","name":"paused","type":"bool"}],"name":"setEditionMintPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"},{"internalType":"uint32","name":"maxMintable","type":"uint32"}],"name":"setMaxMintable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"},{"internalType":"uint32","name":"maxMintablePerAccount","type":"uint32"}],"name":"setMaxMintablePerAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"},{"internalType":"bytes32","name":"merkleRootHash","type":"bytes32"}],"name":"setMerkleRootHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"bps","type":"uint16"}],"name":"setPlatformFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setPlatformFeeAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint96","name":"flatFee","type":"uint96"}],"name":"setPlatformFlatFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"},{"internalType":"uint96","name":"price","type":"uint96"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"}],"name":"setTimeRange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint32","name":"quantity","type":"uint32"}],"name":"totalPrice","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"affiliate","type":"address"}],"name":"withdrawForAffiliate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawForPlatform","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5061001a3361001f565b61005b565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6129e28061006a6000396000f3fe6080604052600436106102d15760003560e01c8063aec96b6e11610179578063d7533f02116100d6578063ed14834f1161008a578063f574029611610064578063f57402961461079d578063fc63e69e146107bd578063fee81cf4146107dd57600080fd5b8063ed14834f14610757578063f04e283e14610777578063f2fde38b1461078a57600080fd5b8063e37a0cea116100bb578063e37a0cea146106ee578063e71924f11461070e578063ebaaa3a11461073557600080fd5b8063d7533f02146106ba578063e1a45218146106d857600080fd5b8063c309c47d1161012d578063c7dd322811610112578063c7dd322814610658578063c94dcf8f1461067a578063d73f3aab1461069a57600080fd5b8063c309c47d14610618578063c3190a2e1461063857600080fd5b8063b84158a41161015e578063b84158a4146105b8578063be0c9b6c146105d8578063bf013d7b146105f857600080fd5b8063aec96b6e14610585578063b24e737e146105a557600080fd5b80635cbc742c116102325780637614a751116101e65780639375da5a116101c05780639375da5a1461050f57806398040f461461052f578063ac1fc22c1461054f57600080fd5b80637614a751146104c25780638d01513c146104915780638da5cb5b146104e257600080fd5b80636aa99da3116102175780636aa99da31461046c5780636c5f55f714610491578063715018a6146104ba57600080fd5b80635cbc742c1461041e57806365bd416d1461043e57600080fd5b806322163b86116102895780632848caef1161026e5780632848caef146103c2578063522f7386146103f657806354d1f13d1461041657600080fd5b806322163b861461038257806325692962146103ba57600080fd5b806308bfa2bf116102ba57806308bfa2bf14610338578063153229bd1461034f578063159a76bd1461036f57600080fd5b806301ffc9a7146102d657806303a6ccd01461030b575b600080fd5b3480156102e257600080fd5b506102f66102f1366004612262565b610810565b60405190151581526020015b60405180910390f35b34801561031757600080fd5b5061032b6103263660046122cf565b61083c565b6040516103029190612304565b34801561034457600080fd5b5061034d610941565b005b34801561035b57600080fd5b5061034d61036a3660046123e9565b6109ea565b61034d61037d36600461247a565b610a88565b34801561038e57600080fd5b506001546103a2906001600160801b031681565b6040516001600160801b039091168152602001610302565b61034d610aa4565b3480156103ce57600080fd5b506103de67016345785d8a000081565b6040516001600160601b039091168152602001610302565b34801561040257600080fd5b5061034d610411366004612512565b610af4565b61034d610b89565b34801561042a57600080fd5b5061034d61043936600461256d565b610bc5565b34801561044a57600080fd5b5061045e610459366004612588565b610c7e565b604051908152602001610302565b34801561047857600080fd5b50600054600160a01b90046001600160601b03166103a2565b34801561049d57600080fd5b506104a76103e881565b60405161ffff9091168152602001610302565b61034d610ccc565b3480156104ce57600080fd5b5061034d6104dd3660046123e9565b610ce0565b3480156104ee57600080fd5b50638b78c6d819545b6040516001600160a01b039091168152602001610302565b34801561051b57600080fd5b5061034d61052a3660046125c6565b610d9c565b34801561053b57600080fd5b5061045e61054a3660046122cf565b610e31565b34801561055b57600080fd5b506103a261056a3660046125c6565b6003602052600090815260409020546001600160801b031681565b34801561059157600080fd5b5061034d6105a03660046125e3565b610e48565b61034d6105b3366004612639565b610f3b565b3480156105c457600080fd5b506103a26105d3366004612726565b611159565b3480156105e457600080fd5b5061034d6105f336600461277c565b611180565b34801561060457600080fd5b506102f6610613366004612797565b611242565b34801561062457600080fd5b506103a2610633366004612811565b6112a2565b34801561064457600080fd5b5061034d6106533660046128a3565b611428565b34801561066457600080fd5b50604051635e9a2e5f60e01b8152602001610302565b34801561068657600080fd5b506102f6610695366004612588565b6114c0565b3480156106a657600080fd5b5061034d6106b53660046128e1565b6114d7565b3480156106c657600080fd5b506040516202a3008152602001610302565b3480156106e457600080fd5b506104a761271081565b3480156106fa57600080fd5b5061034d6107093660046128a3565b611591565b34801561071a57600080fd5b506001546103de90600160801b90046001600160601b031681565b34801561074157600080fd5b506001546104a790600160e01b900461ffff1681565b34801561076357600080fd5b506000546104f7906001600160a01b031681565b61034d6107853660046125c6565b6115f4565b61034d6107983660046125c6565b611634565b3480156107a957600080fd5b5061034d6107b83660046125c6565b61165b565b3480156107c957600080fd5b5061034d6107d836600461291d565b611710565b3480156107e957600080fd5b5061045e6107f83660046125c6565b63389a75e1600c908152600091909152602090205490565b600061081b8261178f565b8061083657506001600160e01b03198216635e9a2e5f60e01b145b92915050565b6040805161014081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290529061089784846117f7565b600081815260046020908152604091829020835463ffffffff600160801b820481168852600160a01b820481169388019390935261ffff600160c01b8204169387019390935260ff600160d01b840416151560608701526001600160601b038316608087015260018082015480841660a0890152600160601b909404831660c088015264010000000090930490911660e08601525461010085015201546101208301525092915050565b6000546001600160a01b03168061096b576040516362ccef3360e01b815260040160405180910390fd5b6001546001600160801b031680156109e657600180546fffffffffffffffffffffffffffffffff191690556109a9826001600160801b038316611865565b6040516001600160801b03821681527fa8a9aa21b43d916fdaf4bdf9975892e984e7dbe00c0befea632d6fe5bbead73a9060200160405180910390a15b5050565b826109f4816118a5565b8160046000610a09610a0688886117f7565b90565b81526020808201929092526040908101600020600101805463ffffffff191663ffffffff94851617905580516001600160801b0387168152928516918301919091526001600160a01b038616917f4c3c29668821111c3ddbcf87e1cd6047dc735ef691d46e09671629cb42cdd94891015b60405180910390a250505050565b610a9c868633878188888836600080610f3b565b505050505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b82610afe816118a5565b81610b0985856117f7565b8054911515600160d01b027fffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffff909216919091179055604080516001600160801b038516815283151560208201526001600160a01b038616917fe430910c8e4bfa8180b70a0b2aa923b82d6712a1d165e223053ef439a3f861479101610a7a565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b610bcd611a40565b6103e861ffff82161115610c0d576040517f3d1e858400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160e01b61ffff8416908102919091179091556040519081527f1426859b6b96e2e9ae302b23a42f763f4b0ae916a71a093e61c77120458b2e95906020015b60405180910390a150565b600060056000610c91610a0687876117f7565b81526020019081526020016000206000836001600160a01b03166001600160a01b031681526020019081526020016000205490509392505050565b610cd4611a40565b610cde6000611a5b565b565b82610cea816118a5565b8163ffffffff16600003610d115760405163a017714560e01b815260040160405180910390fd5b81610d1c85856117f7565b80547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff16600160601b63ffffffff93841602179055604080516001600160801b038616815291841660208301526001600160a01b038616917f021f3ca4d64a14574ed4fc7115d2c667604e54efb94b6187ed8117d49c6e47559101610a7a565b610da4611a40565b6001600160a01b038116610dcb576040516362ccef3360e01b815260040160405180910390fd5b600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527fda1940b15ab63ed4db791f1c7ec186c01a546f6ce58fa1dcc0561b8638a1bd1290602001610c73565b6000610e3d83836117f7565b600101549392505050565b83610e52816118a5565b8163ffffffff168363ffffffff1610610e7e5760405163536a71af60e01b815260040160405180910390fd5b6000610e8a86866117f7565b80547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff16600160801b63ffffffff87811691820263ffffffff60a01b191692909217600160a01b928716928302178355604080516001600160801b038a16815260208101929092528101919091529091506001600160a01b038716907f13bc03d97cc4e2accb3b8290af069c19619d32a4e9c5219f8580108766fb18fd9060600160405180910390a2505050505050565b6000610f478c8c6117f7565b6000818152600460205260409020600181015491925090610f7a9063ffffffff64010000000082048116918d9116611a99565b60018201805463ffffffff929092166401000000000267ffffffff00000000199092169190911790556001600160a01b0389161580610fd45750610fd288888360000154610fcd8d6000526014600c2090565b611b0f565b155b1561100b576040517fb05e92fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b038a16148015906110365750886001600160a01b03168b6001600160a01b031614155b1561107b57611045338a611b49565b61107b576040517ffe736e0100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815460008381526005602090815260408083206001600160a01b038e1684529091529020805463ffffffff8d811690910191829055600160601b90920490911610156110f3576040517f1b75136500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111038d8d8d8d8a8a8a8a611b8b565b604080516001600160a01b038b16815263ffffffff8c1660208201527fbbce3c6646076fce6266a06486d114fd6f4fcdce3df843aadf9c56a2d89721a0910160405180910390a150505050505050505050505050565b60008163ffffffff1661116c86866117f7565b546001600160601b03160295945050505050565b611188611a40565b67016345785d8a00006001600160601b03821611156111d3576040517f5d2be82000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff16600160801b6001600160601b038416908102919091179091556040519081527f267d27ed20a4d7ecba313e2039580b03e8c3d8018eeefe72709708735b02116490602001610c73565b60008061124f87876117f7565b6001015490508061126d5750506001600160a01b0383161515611299565b6001600160a01b038516158015906112955750611295848483610fcd896000526014600c2090565b9150505b95945050505050565b6000876112c25760405163b00db6fb60e01b815260040160405180910390fd5b8163ffffffff166000036112e95760405163a017714560e01b815260040160405180910390fd5b6112f589878787611ffb565b6001600160a01b038a1660009081526002602090815260408083206001600160801b038516845290915281209192509080546001600160601b038a166fffffffffffffffffffffffffffffffff1990911617600160601b63ffffffff8616021781559050600060048183815260208082019290925260409081016000208c815560018101805463ffffffff191663ffffffff8a811691821790925583516001600160801b03891681529485018f90526001600160601b038e16938501939093528b811660608501528a8116608085015261ffff8a1660a085015260c084019290925290861660e083015291506001600160a01b038c16907fd9faafd9b789bcd20399f1fafa1c6459996ac840e9177ee687c23cdbe3b7a9cb906101000160405180910390a2505098975050505050505050565b82611432816118a5565b816114505760405163b00db6fb60e01b815260040160405180910390fd5b8160046000611462610a0688886117f7565b815260208082019290925260409081016000209290925581516001600160801b03861681529081018490526001600160a01b038616917fa863d0ab0f23accb1c42ee00c0587f1c94539e15956a678a54c1e710ba07066e9101610a7a565b60006114cf8484843685611242565b949350505050565b826114e1816118a5565b6103e861ffff8316111561150857604051631a52ce6f60e01b815260040160405180910390fd5b8161151385856117f7565b80547fffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffff16600160c01b61ffff93841602179055604080516001600160801b038616815291841660208301526001600160a01b038616917fae6d744348a49699fcb91e6a563f2224c0fb27c21053a9218ee827f9d6e698c79101610a7a565b8261159b816118a5565b816115a685856117f7565b60010155604080516001600160801b0385168152602081018490526001600160a01b038616917f50beeb3db2bdaab85213836eb4be24fe53e830e8ee419c5859ea380e3b7102759101610a7a565b6115fc611a40565b63389a75e1600c52806000526020600c20805442111561162457636f5e88186000526004601cfd5b6000905561163181611a5b565b50565b61163c611a40565b8060601b61165257637448fbae6000526004601cfd5b61163181611a5b565b6001600160a01b0381166000908152600360205260409020546001600160801b031680156109e6576001600160a01b038216600090815260036020526040902080546fffffffffffffffffffffffffffffffff191690556116c5826001600160801b038316611865565b6040516001600160801b03821681526001600160a01b038316907f0a1adaaf9d9caba9cf65528900e946b718d511ebd66ae81d5eb71e7fd0122c4a9060200160405180910390a25050565b8261171a816118a5565b8161172585856117f7565b80546bffffffffffffffffffffffff19166001600160601b03928316179055604080516001600160801b038616815291841660208301526001600160a01b038616917f7c77af090cbae157811da55b6d8ae1e307a85f5aa1dd2f7a13183279a8c2b4b29101610a7a565b60006001600160e01b031982167ff8ccd08e00000000000000000000000000000000000000000000000000000000148061083657506001600160e01b031982167f01ffc9a7000000000000000000000000000000000000000000000000000000001492915050565b6001600160a01b03821660009081526002602090815260408083206001600160801b038516845290915290208054600160d81b900460ff16610836576040517f947dbacd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8047101561187b5763b12d13eb6000526004601cfd5b6000806000808486620186a0f16109e657816000526073600b5360ff6020536016600b82f0505050565b60006118af6121e4565b9050816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119139190612959565b6001600160a01b0316816001600160a01b0316146109e657816001600160a01b031663514e62fc82846001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611979573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199d9190612976565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa1580156119e6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a0a919061298f565b6109e6576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b638b78c6d819543314610cde576382b429006000526004601cfd5b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b600063ffffffff848116818516019083168111156114cf576000611acd8463ffffffff168763ffffffff1680821191030290565b6040517fbdc0f4ce00000000000000000000000000000000000000000000000000000000815263ffffffff821660048201529091506024015b60405180910390fd5b60008315611b41578360051b8501855b803580851160051b94855260209485185260406000209301818110611b1f5750505b501492915050565b6000604051639c395bc26000528360205282604052602060006044601c6d76a84fef008cdabe6409d2fe638b5afa600160005114169150806040525092915050565b6000611b9789896117f7565b9050611bdb6040518060e001604052806000151581526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b815463ffffffff600160801b8204811691600160a01b90041642821115611c2b5760405163296f4f6960e01b815242600482015263ffffffff808416602483015282166044820152606401611b06565b8063ffffffff16421115611c685760405163296f4f6960e01b815242600482015263ffffffff808416602483015282166044820152606401611b06565b8354600160d01b900460ff1615611cab576040517fd7d248ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050600154600160801b90046001600160601b031663ffffffff8816026060820152611cd98a8a8a8a611159565b6001600160801b031660a0820181905260608201510160c082018190523414611d3d5760c08101516040517f0dd32d1c0000000000000000000000000000000000000000000000000000000081523460048201526024810191909152604401611b06565b606081015160015460a083015161271061ffff600160e01b8404169091020490910160808301819052611d79916001600160801b03160161222a565b600180546fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055608081015160c0820151036040820152611dbf8a8a888888611242565b1580158252611e6457815460a082015161271091600160c01b900461ffff16020460208083018290526040808401805184900390526001600160a01b03891660009081526003909252902054611e20916001600160801b039091160161222a565b6001600160a01b038716600090815260036020526040902080546fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055611ea5565b6001600160a01b03861615611ea5576040517f20d6c38900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408082015190517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b03808b166004830181905263ffffffff8b16602484015286939092918e16917f1c9d0475cac0f75d579d1156e780903d43532d6212c6890ce4f6f278770dc915918e9184916340c10f199160440160206040518083038185885af1158015611f43573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611f689190612976565b8c8760c00151886080015189602001518f8b60000151604051611fe79897969594939291906001600160801b03988916815263ffffffff97881660208201529590961660408601529286166060850152908516608084015290931660a08201526001600160a01b039290921660c0830152151560e08201526101000190565b60405180910390a450505050505050505050565b600084612007816118a5565b8363ffffffff168563ffffffff16106120335760405163536a71af60e01b815260040160405180910390fd5b6103e861ffff8416111561205a57604051631a52ce6f60e01b815260040160405180910390fd5b600080546001600160a01b0388168252600260209081526040808420600160a01b9093046001600160601b03168085529290915282209093508054600160d81b7fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff909116600160801b63ffffffff8a81169190910263ffffffff60a01b191691909117600160a01b91891691909102177fffffffff00ff0000ffffffffffffffffffffffffffffffffffffffffffffffff16600160c01b61ffff8816027fffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff16171781559050612154600184016001600160801b0316612243565b600080546001600160601b0392909216600160a01b026001600160a01b03928316179055604080516001600160801b038616815263ffffffff898116602083015288169181019190915261ffff8616606082015233918916907feeb5941fb79bbfe40edd76c2e086e8ccdb0b463fc8ac07416266100b4dfddccf9060800160405180910390a35050949350505050565b336e2fd5aeb385d324b580fca7c838239f198101610a0657602060008060006e2fd5aeb385d324b580fca7c83823a05afa61221e57600080fd5b506000513d6020140290565b6000600160801b821061223f5761223f612254565b5090565b6000600160601b821061223f5761223f5b6335278d126000526004601cfd5b60006020828403121561227457600080fd5b81356001600160e01b03198116811461228c57600080fd5b9392505050565b6001600160a01b038116811461163157600080fd5b80356122b381612293565b919050565b80356001600160801b03811681146122b357600080fd5b600080604083850312156122e257600080fd5b82356122ed81612293565b91506122fb602084016122b8565b90509250929050565b815163ffffffff1681526101408101602083015161232a602084018263ffffffff169052565b506040830151612340604084018261ffff169052565b506060830151612354606084018215159052565b50608083015161236f60808401826001600160601b03169052565b5060a083015161238760a084018263ffffffff169052565b5060c083015161239f60c084018263ffffffff169052565b5060e08301516123b760e084018263ffffffff169052565b50610100838101519083015261012092830151929091019190915290565b803563ffffffff811681146122b357600080fd5b6000806000606084860312156123fe57600080fd5b833561240981612293565b9250612417602085016122b8565b9150612425604085016123d5565b90509250925092565b60008083601f84011261244057600080fd5b50813567ffffffffffffffff81111561245857600080fd5b6020830191508360208260051b850101111561247357600080fd5b9250929050565b60008060008060008060a0878903121561249357600080fd5b863561249e81612293565b95506124ac602088016122b8565b94506124ba604088016123d5565b9350606087013567ffffffffffffffff8111156124d657600080fd5b6124e289828a0161242e565b90945092505060808701356124f681612293565b809150509295509295509295565b801515811461163157600080fd5b60008060006060848603121561252757600080fd5b833561253281612293565b9250612540602085016122b8565b9150604084013561255081612504565b809150509250925092565b803561ffff811681146122b357600080fd5b60006020828403121561257f57600080fd5b61228c8261255b565b60008060006060848603121561259d57600080fd5b83356125a881612293565b92506125b6602085016122b8565b9150604084013561255081612293565b6000602082840312156125d857600080fd5b813561228c81612293565b600080600080608085870312156125f957600080fd5b843561260481612293565b9350612612602086016122b8565b9250612620604086016123d5565b915061262e606086016123d5565b905092959194509250565b60008060008060008060008060008060006101208c8e03121561265b57600080fd5b6126658c35612293565b8b359a5061267560208d016122b8565b995061268460408d0135612293565b60408c0135985061269760608d016123d5565b97506126a560808d016122a8565b965067ffffffffffffffff8060a08e013511156126c157600080fd5b6126d18e60a08f01358f0161242e565b90975095506126e260c08e016122a8565b94508060e08e013511156126f557600080fd5b506127068d60e08e01358e0161242e565b81945080935050506101008c013590509295989b509295989b9093969950565b6000806000806080858703121561273c57600080fd5b843561274781612293565b9350612755602086016122b8565b9250604085013561262081612293565b80356001600160601b03811681146122b357600080fd5b60006020828403121561278e57600080fd5b61228c82612765565b6000806000806000608086880312156127af57600080fd5b85356127ba81612293565b94506127c8602087016122b8565b935060408601356127d881612293565b9250606086013567ffffffffffffffff8111156127f457600080fd5b6128008882890161242e565b969995985093965092949392505050565b600080600080600080600080610100898b03121561282e57600080fd5b883561283981612293565b97506020890135965061284e60408a01612765565b955061285c60608a016123d5565b945061286a60808a016123d5565b935061287860a08a0161255b565b925061288660c08a016123d5565b915061289460e08a016123d5565b90509295985092959890939650565b6000806000606084860312156128b857600080fd5b83356128c381612293565b92506128d1602085016122b8565b9150604084013590509250925092565b6000806000606084860312156128f657600080fd5b833561290181612293565b925061290f602085016122b8565b91506124256040850161255b565b60008060006060848603121561293257600080fd5b833561293d81612293565b925061294b602085016122b8565b915061242560408501612765565b60006020828403121561296b57600080fd5b815161228c81612293565b60006020828403121561298857600080fd5b5051919050565b6000602082840312156129a157600080fd5b815161228c8161250456fea26469706673582212205092f522ca1363c063828807113eb9ff8b153dbe9cce632686febb2643bafab164736f6c63430008130033
Deployed Bytecode
0x6080604052600436106102d15760003560e01c8063aec96b6e11610179578063d7533f02116100d6578063ed14834f1161008a578063f574029611610064578063f57402961461079d578063fc63e69e146107bd578063fee81cf4146107dd57600080fd5b8063ed14834f14610757578063f04e283e14610777578063f2fde38b1461078a57600080fd5b8063e37a0cea116100bb578063e37a0cea146106ee578063e71924f11461070e578063ebaaa3a11461073557600080fd5b8063d7533f02146106ba578063e1a45218146106d857600080fd5b8063c309c47d1161012d578063c7dd322811610112578063c7dd322814610658578063c94dcf8f1461067a578063d73f3aab1461069a57600080fd5b8063c309c47d14610618578063c3190a2e1461063857600080fd5b8063b84158a41161015e578063b84158a4146105b8578063be0c9b6c146105d8578063bf013d7b146105f857600080fd5b8063aec96b6e14610585578063b24e737e146105a557600080fd5b80635cbc742c116102325780637614a751116101e65780639375da5a116101c05780639375da5a1461050f57806398040f461461052f578063ac1fc22c1461054f57600080fd5b80637614a751146104c25780638d01513c146104915780638da5cb5b146104e257600080fd5b80636aa99da3116102175780636aa99da31461046c5780636c5f55f714610491578063715018a6146104ba57600080fd5b80635cbc742c1461041e57806365bd416d1461043e57600080fd5b806322163b86116102895780632848caef1161026e5780632848caef146103c2578063522f7386146103f657806354d1f13d1461041657600080fd5b806322163b861461038257806325692962146103ba57600080fd5b806308bfa2bf116102ba57806308bfa2bf14610338578063153229bd1461034f578063159a76bd1461036f57600080fd5b806301ffc9a7146102d657806303a6ccd01461030b575b600080fd5b3480156102e257600080fd5b506102f66102f1366004612262565b610810565b60405190151581526020015b60405180910390f35b34801561031757600080fd5b5061032b6103263660046122cf565b61083c565b6040516103029190612304565b34801561034457600080fd5b5061034d610941565b005b34801561035b57600080fd5b5061034d61036a3660046123e9565b6109ea565b61034d61037d36600461247a565b610a88565b34801561038e57600080fd5b506001546103a2906001600160801b031681565b6040516001600160801b039091168152602001610302565b61034d610aa4565b3480156103ce57600080fd5b506103de67016345785d8a000081565b6040516001600160601b039091168152602001610302565b34801561040257600080fd5b5061034d610411366004612512565b610af4565b61034d610b89565b34801561042a57600080fd5b5061034d61043936600461256d565b610bc5565b34801561044a57600080fd5b5061045e610459366004612588565b610c7e565b604051908152602001610302565b34801561047857600080fd5b50600054600160a01b90046001600160601b03166103a2565b34801561049d57600080fd5b506104a76103e881565b60405161ffff9091168152602001610302565b61034d610ccc565b3480156104ce57600080fd5b5061034d6104dd3660046123e9565b610ce0565b3480156104ee57600080fd5b50638b78c6d819545b6040516001600160a01b039091168152602001610302565b34801561051b57600080fd5b5061034d61052a3660046125c6565b610d9c565b34801561053b57600080fd5b5061045e61054a3660046122cf565b610e31565b34801561055b57600080fd5b506103a261056a3660046125c6565b6003602052600090815260409020546001600160801b031681565b34801561059157600080fd5b5061034d6105a03660046125e3565b610e48565b61034d6105b3366004612639565b610f3b565b3480156105c457600080fd5b506103a26105d3366004612726565b611159565b3480156105e457600080fd5b5061034d6105f336600461277c565b611180565b34801561060457600080fd5b506102f6610613366004612797565b611242565b34801561062457600080fd5b506103a2610633366004612811565b6112a2565b34801561064457600080fd5b5061034d6106533660046128a3565b611428565b34801561066457600080fd5b50604051635e9a2e5f60e01b8152602001610302565b34801561068657600080fd5b506102f6610695366004612588565b6114c0565b3480156106a657600080fd5b5061034d6106b53660046128e1565b6114d7565b3480156106c657600080fd5b506040516202a3008152602001610302565b3480156106e457600080fd5b506104a761271081565b3480156106fa57600080fd5b5061034d6107093660046128a3565b611591565b34801561071a57600080fd5b506001546103de90600160801b90046001600160601b031681565b34801561074157600080fd5b506001546104a790600160e01b900461ffff1681565b34801561076357600080fd5b506000546104f7906001600160a01b031681565b61034d6107853660046125c6565b6115f4565b61034d6107983660046125c6565b611634565b3480156107a957600080fd5b5061034d6107b83660046125c6565b61165b565b3480156107c957600080fd5b5061034d6107d836600461291d565b611710565b3480156107e957600080fd5b5061045e6107f83660046125c6565b63389a75e1600c908152600091909152602090205490565b600061081b8261178f565b8061083657506001600160e01b03198216635e9a2e5f60e01b145b92915050565b6040805161014081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290529061089784846117f7565b600081815260046020908152604091829020835463ffffffff600160801b820481168852600160a01b820481169388019390935261ffff600160c01b8204169387019390935260ff600160d01b840416151560608701526001600160601b038316608087015260018082015480841660a0890152600160601b909404831660c088015264010000000090930490911660e08601525461010085015201546101208301525092915050565b6000546001600160a01b03168061096b576040516362ccef3360e01b815260040160405180910390fd5b6001546001600160801b031680156109e657600180546fffffffffffffffffffffffffffffffff191690556109a9826001600160801b038316611865565b6040516001600160801b03821681527fa8a9aa21b43d916fdaf4bdf9975892e984e7dbe00c0befea632d6fe5bbead73a9060200160405180910390a15b5050565b826109f4816118a5565b8160046000610a09610a0688886117f7565b90565b81526020808201929092526040908101600020600101805463ffffffff191663ffffffff94851617905580516001600160801b0387168152928516918301919091526001600160a01b038616917f4c3c29668821111c3ddbcf87e1cd6047dc735ef691d46e09671629cb42cdd94891015b60405180910390a250505050565b610a9c868633878188888836600080610f3b565b505050505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b82610afe816118a5565b81610b0985856117f7565b8054911515600160d01b027fffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffff909216919091179055604080516001600160801b038516815283151560208201526001600160a01b038616917fe430910c8e4bfa8180b70a0b2aa923b82d6712a1d165e223053ef439a3f861479101610a7a565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b610bcd611a40565b6103e861ffff82161115610c0d576040517f3d1e858400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160e01b61ffff8416908102919091179091556040519081527f1426859b6b96e2e9ae302b23a42f763f4b0ae916a71a093e61c77120458b2e95906020015b60405180910390a150565b600060056000610c91610a0687876117f7565b81526020019081526020016000206000836001600160a01b03166001600160a01b031681526020019081526020016000205490509392505050565b610cd4611a40565b610cde6000611a5b565b565b82610cea816118a5565b8163ffffffff16600003610d115760405163a017714560e01b815260040160405180910390fd5b81610d1c85856117f7565b80547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff16600160601b63ffffffff93841602179055604080516001600160801b038616815291841660208301526001600160a01b038616917f021f3ca4d64a14574ed4fc7115d2c667604e54efb94b6187ed8117d49c6e47559101610a7a565b610da4611a40565b6001600160a01b038116610dcb576040516362ccef3360e01b815260040160405180910390fd5b600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527fda1940b15ab63ed4db791f1c7ec186c01a546f6ce58fa1dcc0561b8638a1bd1290602001610c73565b6000610e3d83836117f7565b600101549392505050565b83610e52816118a5565b8163ffffffff168363ffffffff1610610e7e5760405163536a71af60e01b815260040160405180910390fd5b6000610e8a86866117f7565b80547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff16600160801b63ffffffff87811691820263ffffffff60a01b191692909217600160a01b928716928302178355604080516001600160801b038a16815260208101929092528101919091529091506001600160a01b038716907f13bc03d97cc4e2accb3b8290af069c19619d32a4e9c5219f8580108766fb18fd9060600160405180910390a2505050505050565b6000610f478c8c6117f7565b6000818152600460205260409020600181015491925090610f7a9063ffffffff64010000000082048116918d9116611a99565b60018201805463ffffffff929092166401000000000267ffffffff00000000199092169190911790556001600160a01b0389161580610fd45750610fd288888360000154610fcd8d6000526014600c2090565b611b0f565b155b1561100b576040517fb05e92fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b038a16148015906110365750886001600160a01b03168b6001600160a01b031614155b1561107b57611045338a611b49565b61107b576040517ffe736e0100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815460008381526005602090815260408083206001600160a01b038e1684529091529020805463ffffffff8d811690910191829055600160601b90920490911610156110f3576040517f1b75136500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111038d8d8d8d8a8a8a8a611b8b565b604080516001600160a01b038b16815263ffffffff8c1660208201527fbbce3c6646076fce6266a06486d114fd6f4fcdce3df843aadf9c56a2d89721a0910160405180910390a150505050505050505050505050565b60008163ffffffff1661116c86866117f7565b546001600160601b03160295945050505050565b611188611a40565b67016345785d8a00006001600160601b03821611156111d3576040517f5d2be82000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff16600160801b6001600160601b038416908102919091179091556040519081527f267d27ed20a4d7ecba313e2039580b03e8c3d8018eeefe72709708735b02116490602001610c73565b60008061124f87876117f7565b6001015490508061126d5750506001600160a01b0383161515611299565b6001600160a01b038516158015906112955750611295848483610fcd896000526014600c2090565b9150505b95945050505050565b6000876112c25760405163b00db6fb60e01b815260040160405180910390fd5b8163ffffffff166000036112e95760405163a017714560e01b815260040160405180910390fd5b6112f589878787611ffb565b6001600160a01b038a1660009081526002602090815260408083206001600160801b038516845290915281209192509080546001600160601b038a166fffffffffffffffffffffffffffffffff1990911617600160601b63ffffffff8616021781559050600060048183815260208082019290925260409081016000208c815560018101805463ffffffff191663ffffffff8a811691821790925583516001600160801b03891681529485018f90526001600160601b038e16938501939093528b811660608501528a8116608085015261ffff8a1660a085015260c084019290925290861660e083015291506001600160a01b038c16907fd9faafd9b789bcd20399f1fafa1c6459996ac840e9177ee687c23cdbe3b7a9cb906101000160405180910390a2505098975050505050505050565b82611432816118a5565b816114505760405163b00db6fb60e01b815260040160405180910390fd5b8160046000611462610a0688886117f7565b815260208082019290925260409081016000209290925581516001600160801b03861681529081018490526001600160a01b038616917fa863d0ab0f23accb1c42ee00c0587f1c94539e15956a678a54c1e710ba07066e9101610a7a565b60006114cf8484843685611242565b949350505050565b826114e1816118a5565b6103e861ffff8316111561150857604051631a52ce6f60e01b815260040160405180910390fd5b8161151385856117f7565b80547fffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffff16600160c01b61ffff93841602179055604080516001600160801b038616815291841660208301526001600160a01b038616917fae6d744348a49699fcb91e6a563f2224c0fb27c21053a9218ee827f9d6e698c79101610a7a565b8261159b816118a5565b816115a685856117f7565b60010155604080516001600160801b0385168152602081018490526001600160a01b038616917f50beeb3db2bdaab85213836eb4be24fe53e830e8ee419c5859ea380e3b7102759101610a7a565b6115fc611a40565b63389a75e1600c52806000526020600c20805442111561162457636f5e88186000526004601cfd5b6000905561163181611a5b565b50565b61163c611a40565b8060601b61165257637448fbae6000526004601cfd5b61163181611a5b565b6001600160a01b0381166000908152600360205260409020546001600160801b031680156109e6576001600160a01b038216600090815260036020526040902080546fffffffffffffffffffffffffffffffff191690556116c5826001600160801b038316611865565b6040516001600160801b03821681526001600160a01b038316907f0a1adaaf9d9caba9cf65528900e946b718d511ebd66ae81d5eb71e7fd0122c4a9060200160405180910390a25050565b8261171a816118a5565b8161172585856117f7565b80546bffffffffffffffffffffffff19166001600160601b03928316179055604080516001600160801b038616815291841660208301526001600160a01b038616917f7c77af090cbae157811da55b6d8ae1e307a85f5aa1dd2f7a13183279a8c2b4b29101610a7a565b60006001600160e01b031982167ff8ccd08e00000000000000000000000000000000000000000000000000000000148061083657506001600160e01b031982167f01ffc9a7000000000000000000000000000000000000000000000000000000001492915050565b6001600160a01b03821660009081526002602090815260408083206001600160801b038516845290915290208054600160d81b900460ff16610836576040517f947dbacd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8047101561187b5763b12d13eb6000526004601cfd5b6000806000808486620186a0f16109e657816000526073600b5360ff6020536016600b82f0505050565b60006118af6121e4565b9050816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119139190612959565b6001600160a01b0316816001600160a01b0316146109e657816001600160a01b031663514e62fc82846001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611979573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199d9190612976565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa1580156119e6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a0a919061298f565b6109e6576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b638b78c6d819543314610cde576382b429006000526004601cfd5b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b600063ffffffff848116818516019083168111156114cf576000611acd8463ffffffff168763ffffffff1680821191030290565b6040517fbdc0f4ce00000000000000000000000000000000000000000000000000000000815263ffffffff821660048201529091506024015b60405180910390fd5b60008315611b41578360051b8501855b803580851160051b94855260209485185260406000209301818110611b1f5750505b501492915050565b6000604051639c395bc26000528360205282604052602060006044601c6d76a84fef008cdabe6409d2fe638b5afa600160005114169150806040525092915050565b6000611b9789896117f7565b9050611bdb6040518060e001604052806000151581526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b815463ffffffff600160801b8204811691600160a01b90041642821115611c2b5760405163296f4f6960e01b815242600482015263ffffffff808416602483015282166044820152606401611b06565b8063ffffffff16421115611c685760405163296f4f6960e01b815242600482015263ffffffff808416602483015282166044820152606401611b06565b8354600160d01b900460ff1615611cab576040517fd7d248ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050600154600160801b90046001600160601b031663ffffffff8816026060820152611cd98a8a8a8a611159565b6001600160801b031660a0820181905260608201510160c082018190523414611d3d5760c08101516040517f0dd32d1c0000000000000000000000000000000000000000000000000000000081523460048201526024810191909152604401611b06565b606081015160015460a083015161271061ffff600160e01b8404169091020490910160808301819052611d79916001600160801b03160161222a565b600180546fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055608081015160c0820151036040820152611dbf8a8a888888611242565b1580158252611e6457815460a082015161271091600160c01b900461ffff16020460208083018290526040808401805184900390526001600160a01b03891660009081526003909252902054611e20916001600160801b039091160161222a565b6001600160a01b038716600090815260036020526040902080546fffffffffffffffffffffffffffffffff19166001600160801b0392909216919091179055611ea5565b6001600160a01b03861615611ea5576040517f20d6c38900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408082015190517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b03808b166004830181905263ffffffff8b16602484015286939092918e16917f1c9d0475cac0f75d579d1156e780903d43532d6212c6890ce4f6f278770dc915918e9184916340c10f199160440160206040518083038185885af1158015611f43573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611f689190612976565b8c8760c00151886080015189602001518f8b60000151604051611fe79897969594939291906001600160801b03988916815263ffffffff97881660208201529590961660408601529286166060850152908516608084015290931660a08201526001600160a01b039290921660c0830152151560e08201526101000190565b60405180910390a450505050505050505050565b600084612007816118a5565b8363ffffffff168563ffffffff16106120335760405163536a71af60e01b815260040160405180910390fd5b6103e861ffff8416111561205a57604051631a52ce6f60e01b815260040160405180910390fd5b600080546001600160a01b0388168252600260209081526040808420600160a01b9093046001600160601b03168085529290915282209093508054600160d81b7fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff909116600160801b63ffffffff8a81169190910263ffffffff60a01b191691909117600160a01b91891691909102177fffffffff00ff0000ffffffffffffffffffffffffffffffffffffffffffffffff16600160c01b61ffff8816027fffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff16171781559050612154600184016001600160801b0316612243565b600080546001600160601b0392909216600160a01b026001600160a01b03928316179055604080516001600160801b038616815263ffffffff898116602083015288169181019190915261ffff8616606082015233918916907feeb5941fb79bbfe40edd76c2e086e8ccdb0b463fc8ac07416266100b4dfddccf9060800160405180910390a35050949350505050565b336e2fd5aeb385d324b580fca7c838239f198101610a0657602060008060006e2fd5aeb385d324b580fca7c83823a05afa61221e57600080fd5b506000513d6020140290565b6000600160801b821061223f5761223f612254565b5090565b6000600160601b821061223f5761223f5b6335278d126000526004601cfd5b60006020828403121561227457600080fd5b81356001600160e01b03198116811461228c57600080fd5b9392505050565b6001600160a01b038116811461163157600080fd5b80356122b381612293565b919050565b80356001600160801b03811681146122b357600080fd5b600080604083850312156122e257600080fd5b82356122ed81612293565b91506122fb602084016122b8565b90509250929050565b815163ffffffff1681526101408101602083015161232a602084018263ffffffff169052565b506040830151612340604084018261ffff169052565b506060830151612354606084018215159052565b50608083015161236f60808401826001600160601b03169052565b5060a083015161238760a084018263ffffffff169052565b5060c083015161239f60c084018263ffffffff169052565b5060e08301516123b760e084018263ffffffff169052565b50610100838101519083015261012092830151929091019190915290565b803563ffffffff811681146122b357600080fd5b6000806000606084860312156123fe57600080fd5b833561240981612293565b9250612417602085016122b8565b9150612425604085016123d5565b90509250925092565b60008083601f84011261244057600080fd5b50813567ffffffffffffffff81111561245857600080fd5b6020830191508360208260051b850101111561247357600080fd5b9250929050565b60008060008060008060a0878903121561249357600080fd5b863561249e81612293565b95506124ac602088016122b8565b94506124ba604088016123d5565b9350606087013567ffffffffffffffff8111156124d657600080fd5b6124e289828a0161242e565b90945092505060808701356124f681612293565b809150509295509295509295565b801515811461163157600080fd5b60008060006060848603121561252757600080fd5b833561253281612293565b9250612540602085016122b8565b9150604084013561255081612504565b809150509250925092565b803561ffff811681146122b357600080fd5b60006020828403121561257f57600080fd5b61228c8261255b565b60008060006060848603121561259d57600080fd5b83356125a881612293565b92506125b6602085016122b8565b9150604084013561255081612293565b6000602082840312156125d857600080fd5b813561228c81612293565b600080600080608085870312156125f957600080fd5b843561260481612293565b9350612612602086016122b8565b9250612620604086016123d5565b915061262e606086016123d5565b905092959194509250565b60008060008060008060008060008060006101208c8e03121561265b57600080fd5b6126658c35612293565b8b359a5061267560208d016122b8565b995061268460408d0135612293565b60408c0135985061269760608d016123d5565b97506126a560808d016122a8565b965067ffffffffffffffff8060a08e013511156126c157600080fd5b6126d18e60a08f01358f0161242e565b90975095506126e260c08e016122a8565b94508060e08e013511156126f557600080fd5b506127068d60e08e01358e0161242e565b81945080935050506101008c013590509295989b509295989b9093969950565b6000806000806080858703121561273c57600080fd5b843561274781612293565b9350612755602086016122b8565b9250604085013561262081612293565b80356001600160601b03811681146122b357600080fd5b60006020828403121561278e57600080fd5b61228c82612765565b6000806000806000608086880312156127af57600080fd5b85356127ba81612293565b94506127c8602087016122b8565b935060408601356127d881612293565b9250606086013567ffffffffffffffff8111156127f457600080fd5b6128008882890161242e565b969995985093965092949392505050565b600080600080600080600080610100898b03121561282e57600080fd5b883561283981612293565b97506020890135965061284e60408a01612765565b955061285c60608a016123d5565b945061286a60808a016123d5565b935061287860a08a0161255b565b925061288660c08a016123d5565b915061289460e08a016123d5565b90509295985092959890939650565b6000806000606084860312156128b857600080fd5b83356128c381612293565b92506128d1602085016122b8565b9150604084013590509250925092565b6000806000606084860312156128f657600080fd5b833561290181612293565b925061290f602085016122b8565b91506124256040850161255b565b60008060006060848603121561293257600080fd5b833561293d81612293565b925061294b602085016122b8565b915061242560408501612765565b60006020828403121561296b57600080fd5b815161228c81612293565b60006020828403121561298857600080fd5b5051919050565b6000602082840312156129a157600080fd5b815161228c8161250456fea26469706673582212205092f522ca1363c063828807113eb9ff8b153dbe9cce632686febb2643bafab164736f6c63430008130033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | Ether (ETH) | 100.00% | $3,288.33 | 1.3041 | $4,288.15 |
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.