Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 841 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Mint | 16871358 | 682 days ago | IN | 0.05 ETH | 0.00314461 | ||||
Mint | 16871157 | 682 days ago | IN | 0.05 ETH | 0.00349863 | ||||
Mint | 16871133 | 682 days ago | IN | 0.05 ETH | 0.00289842 | ||||
Mint | 16871117 | 682 days ago | IN | 0.05 ETH | 0.0030712 | ||||
Mint | 16871103 | 682 days ago | IN | 0.05 ETH | 0.00334969 | ||||
Mint | 16871081 | 682 days ago | IN | 0.05 ETH | 0.0031434 | ||||
Mint | 16871078 | 682 days ago | IN | 0.05 ETH | 0.00316259 | ||||
Mint | 16871068 | 682 days ago | IN | 0.05 ETH | 0.00301528 | ||||
Mint | 16871061 | 682 days ago | IN | 0.05 ETH | 0.00339388 | ||||
Mint | 16870928 | 682 days ago | IN | 0.05 ETH | 0.00327401 | ||||
Mint | 16870917 | 682 days ago | IN | 0.05 ETH | 0.00331878 | ||||
Mint | 16870894 | 682 days ago | IN | 0.05 ETH | 0.00326554 | ||||
Mint | 16870892 | 682 days ago | IN | 0.05 ETH | 0.00320396 | ||||
Mint | 16870863 | 682 days ago | IN | 0.05 ETH | 0.00348609 | ||||
Mint | 16870862 | 682 days ago | IN | 0.05 ETH | 0.00345269 | ||||
Mint | 16870854 | 682 days ago | IN | 0.05 ETH | 0.0039241 | ||||
Mint | 16870853 | 682 days ago | IN | 0.05 ETH | 0.00408439 | ||||
Mint | 16870852 | 682 days ago | IN | 0.05 ETH | 0.00365405 | ||||
Mint | 16870850 | 682 days ago | IN | 0.05 ETH | 0.00376722 | ||||
Mint | 16870848 | 682 days ago | IN | 0.05 ETH | 0.00403577 | ||||
Mint | 16870847 | 682 days ago | IN | 0.05 ETH | 0.0041792 | ||||
Mint | 16870847 | 682 days ago | IN | 0.05 ETH | 0.00408404 | ||||
Mint | 16870847 | 682 days ago | IN | 0.05 ETH | 0.00420928 | ||||
Mint | 16870843 | 682 days ago | IN | 0.05 ETH | 0.00454978 | ||||
Mint | 16870843 | 682 days ago | IN | 0.05 ETH | 0.00452987 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
16871358 | 682 days ago | 0.05 ETH | ||||
16871157 | 682 days ago | 0.05 ETH | ||||
16871133 | 682 days ago | 0.05 ETH | ||||
16871117 | 682 days ago | 0.05 ETH | ||||
16871103 | 682 days ago | 0.05 ETH | ||||
16871081 | 682 days ago | 0.05 ETH | ||||
16871078 | 682 days ago | 0.05 ETH | ||||
16871068 | 682 days ago | 0.05 ETH | ||||
16871061 | 682 days ago | 0.05 ETH | ||||
16870928 | 682 days ago | 0.05 ETH | ||||
16870917 | 682 days ago | 0.05 ETH | ||||
16870894 | 682 days ago | 0.05 ETH | ||||
16870892 | 682 days ago | 0.05 ETH | ||||
16870863 | 682 days ago | 0.05 ETH | ||||
16870862 | 682 days ago | 0.05 ETH | ||||
16870854 | 682 days ago | 0.05 ETH | ||||
16870853 | 682 days ago | 0.05 ETH | ||||
16870852 | 682 days ago | 0.05 ETH | ||||
16870850 | 682 days ago | 0.05 ETH | ||||
16870848 | 682 days ago | 0.05 ETH | ||||
16870847 | 682 days ago | 0.05 ETH | ||||
16870847 | 682 days ago | 0.05 ETH | ||||
16870847 | 682 days ago | 0.05 ETH | ||||
16870843 | 682 days ago | 0.05 ETH | ||||
16870843 | 682 days ago | 0.05 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
MerkleDropMinter
Compiler Version
v0.8.16+commit.07a7930e
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 { ISoundFeeRegistry } from "@core/interfaces/ISoundFeeRegistry.sol"; import { BaseMinter } from "@modules/BaseMinter.sol"; import { IMerkleDropMinter, EditionMintData, MintInfo } from "./interfaces/IMerkleDropMinter.sol"; import { IMinterModule } from "@core/interfaces/IMinterModule.sol"; import { ISoundEditionV1 } from "@core/interfaces/ISoundEditionV1.sol"; /** * @title MerkleDropMinter * @dev Module for minting Sound editions using a merkle tree of approved accounts. * @author Sound.xyz */ contract MerkleDropMinter is IMerkleDropMinter, BaseMinter { // ============================================================= // STORAGE // ============================================================= /** * @dev Edition mint data. * Maps `edition` => `mintId` => value. */ mapping(address => mapping(uint128 => EditionMintData)) internal _editionMintData; // ============================================================= // CONSTRUCTOR // ============================================================= constructor(ISoundFeeRegistry feeRegistry_) BaseMinter(feeRegistry_) {} // ============================================================= // PUBLIC / EXTERNAL WRITE FUNCTIONS // ============================================================= /** * @inheritdoc IMerkleDropMinter */ 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); EditionMintData storage data = _editionMintData[edition][mintId]; data.merkleRootHash = merkleRootHash; data.price = price; data.maxMintable = maxMintable; data.maxMintablePerAccount = maxMintablePerAccount; // prettier-ignore emit MerkleDropMintCreated( edition, mintId, merkleRootHash, price, startTime, endTime, affiliateFeeBPS, maxMintable, maxMintablePerAccount ); } /** * @inheritdoc IMerkleDropMinter */ function mint( address edition, uint128 mintId, uint32 requestedQuantity, bytes32[] calldata merkleProof, address affiliate ) public payable { EditionMintData storage data = _editionMintData[edition][mintId]; // Increase `totalMinted` by `requestedQuantity`. // Require that the increased value does not exceed `maxMintable`. data.totalMinted = _incrementTotalMinted(data.totalMinted, requestedQuantity, data.maxMintable); bytes32 leaf = keccak256(abi.encodePacked(msg.sender)); bool valid = MerkleProofLib.verify(merkleProof, data.merkleRootHash, leaf); if (!valid) revert InvalidMerkleProof(); unchecked { // Check the additional `requestedQuantity` does not exceed the maximum mintable per account. uint256 numberMinted = ISoundEditionV1(edition).numberMinted(msg.sender); // Won't overflow. The total number of tokens minted in `edition` won't exceed `type(uint32).max`, // and `quantity` has 32 bits. if (numberMinted + requestedQuantity > data.maxMintablePerAccount) revert ExceedsMaxPerAccount(); } _mint(edition, mintId, requestedQuantity, affiliate); emit DropClaimed(msg.sender, requestedQuantity); } /** * @inheritdoc IMerkleDropMinter */ function setPrice( address edition, uint128 mintId, uint96 price ) public onlyEditionOwnerOrAdmin(edition) { _editionMintData[edition][mintId].price = price; emit PriceSet(edition, mintId, price); } /** * @inheritdoc IMerkleDropMinter */ function setMaxMintablePerAccount( address edition, uint128 mintId, uint32 maxMintablePerAccount ) public onlyEditionOwnerOrAdmin(edition) { if (maxMintablePerAccount == 0) revert MaxMintablePerAccountIsZero(); _editionMintData[edition][mintId].maxMintablePerAccount = maxMintablePerAccount; emit MaxMintablePerAccountSet(edition, mintId, maxMintablePerAccount); } /** * @inheritdoc IMerkleDropMinter */ function setMaxMintable( address edition, uint128 mintId, uint32 maxMintable ) public onlyEditionOwnerOrAdmin(edition) { _editionMintData[edition][mintId].maxMintable = maxMintable; emit MaxMintableSet(edition, mintId, maxMintable); } /* * @inheritdoc IMerkleDropMinter */ function setMerkleRootHash( address edition, uint128 mintId, bytes32 merkleRootHash ) public onlyEditionOwnerOrAdmin(edition) { if (merkleRootHash == bytes32(0)) revert MerkleRootHashIsEmpty(); _editionMintData[edition][mintId].merkleRootHash = merkleRootHash; emit MerkleRootHashSet(edition, mintId, merkleRootHash); } // ============================================================= // PUBLIC / EXTERNAL VIEW FUNCTIONS // ============================================================= /** * @inheritdoc IMinterModule */ function totalPrice( address edition, uint128 mintId, address, /* minter */ uint32 quantity ) public view virtual override(BaseMinter, IMinterModule) returns (uint128) { unchecked { // Will not overflow, as `price` is 96 bits, and `quantity` is 32 bits. 96 + 32 = 128. return uint128(uint256(_editionMintData[edition][mintId].price) * uint256(quantity)); } } /** * @inheritdoc IMerkleDropMinter */ function mintInfo(address edition, uint128 mintId) external view returns (MintInfo memory) { BaseData memory baseData = _baseData[edition][mintId]; EditionMintData storage mintData = _editionMintData[edition][mintId]; MintInfo memory combinedMintData = MintInfo( baseData.startTime, baseData.endTime, baseData.affiliateFeeBPS, baseData.mintPaused, mintData.price, mintData.maxMintable, mintData.maxMintablePerAccount, mintData.totalMinted, mintData.merkleRootHash ); return combinedMintData; } /** * @inheritdoc IERC165 */ function supportsInterface(bytes4 interfaceId) public view override(IERC165, BaseMinter) returns (bool) { return BaseMinter.supportsInterface(interfaceId) || interfaceId == type(IMerkleDropMinter).interfaceId; } /** * @inheritdoc IMinterModule */ function moduleInterfaceId() public pure returns (bytes4) { return type(IMerkleDropMinter).interfaceId; } }
// 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 { function verify( bytes32[] calldata proof, bytes32 root, bytes32 leaf ) internal pure returns (bool isValid) { 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. // prettier-ignore 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) // prettier-ignore if iszero(lt(offset, end)) { break } } } isValid := eq(leaf, root) } } function verifyMultiProof( 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`). assembly { // If the number of flags is correct. // prettier-ignore 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`. 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. let end := add(hashesBack, shl(5, flags.length)) let flagsOffset := flags.offset let proofOffset := proof.offset // prettier-ignore 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(flagsOffset)) { // Loads the next proof. b := calldataload(proofOffset) proofOffset := add(proofOffset, 0x20) // Unpop from `hashes`. hashesFront := sub(hashesFront, 0x20) } // Advance to the next flag offset. flagsOffset := add(flagsOffset, 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) // prettier-ignore if iszero(lt(hashesBack, end)) { break } } // Checks if the last value in the queue is same as the root. isValid := eq(mload(sub(hashesBack, 0x20)), root) break } } } }
// 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 pragma solidity ^0.8.16; /** * @title ISoundFeeRegistry * @author Sound.xyz */ interface ISoundFeeRegistry { // ============================================================= // EVENTS // ============================================================= /** * @dev Emitted when the `soundFeeAddress` is changed. */ event SoundFeeAddressSet(address soundFeeAddress); /** * @dev Emitted when the `platformFeeBPS` is changed. */ event PlatformFeeSet(uint16 platformFeeBPS); // ============================================================= // ERRORS // ============================================================= /** * @dev The new `soundFeeAddress` must not be address(0). */ error InvalidSoundFeeAddress(); /** * @dev The platform fee numerator must not exceed `_MAX_BPS`. */ error InvalidPlatformFeeBPS(); // ============================================================= // PUBLIC / EXTERNAL WRITE FUNCTIONS // ============================================================= /** * @dev Sets the `soundFeeAddress`. * * Calling conditions: * - The caller must be the owner of the contract. * * @param soundFeeAddress_ The sound fee address. */ function setSoundFeeAddress(address soundFeeAddress_) external; /** * @dev Sets the `platformFeePBS`. * * Calling conditions: * - The caller must be the owner of the contract. * * @param platformFeeBPS_ Platform fee amount in bps (basis points). */ function setPlatformFeeBPS(uint16 platformFeeBPS_) external; // ============================================================= // PUBLIC / EXTERNAL VIEW FUNCTIONS // ============================================================= /** * @dev The sound protocol's address that receives platform fees. * @return The configured value. */ function soundFeeAddress() external view returns (address); /** * @dev The numerator of the platform fee. * @return The configured value. */ function platformFeeBPS() external view returns (uint16); /** * @dev The platform fee for `requiredEtherValue`. * @param requiredEtherValue The required Ether value for payment. * @return fee The computed value. */ function platformFee(uint128 requiredEtherValue) external view returns (uint128 fee); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import { OwnableRoles } from "solady/auth/OwnableRoles.sol"; import { ISoundEditionV1 } from "@core/interfaces/ISoundEditionV1.sol"; import { IMinterModule } from "@core/interfaces/IMinterModule.sol"; import { ISoundFeeRegistry } from "@core/interfaces/ISoundFeeRegistry.sol"; import { IERC165 } from "openzeppelin/utils/introspection/IERC165.sol"; import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; import { FixedPointMathLib } from "solady/utils/FixedPointMathLib.sol"; /** * @title Minter Base * @dev The `BaseMinter` class maintains a central storage record of edition mint instances. */ abstract contract BaseMinter is IMinterModule { // ============================================================= // CONSTANTS // ============================================================= /** * @dev This is the denominator, in basis points (BPS), for: * - platform fees * - affiliate fees */ uint16 private constant _MAX_BPS = 10_000; // ============================================================= // STORAGE // ============================================================= /** * @dev The next mint ID. Shared amongst all editions connected. */ uint128 private _nextMintId; /** * @dev How much platform fees have been accrued. */ uint128 private _platformFeesAccrued; /** * @dev Maps an edition and the mint ID to a mint instance. */ mapping(address => mapping(uint256 => BaseData)) internal _baseData; /** * @dev Maps an address to how much affiliate fees have they accrued. */ mapping(address => uint128) private _affiliateFeesAccrued; /** * @dev The fee registry. Used for handling platform fees. */ ISoundFeeRegistry public immutable feeRegistry; // ============================================================= // CONSTRUCTOR // ============================================================= constructor(ISoundFeeRegistry feeRegistry_) { if (address(feeRegistry_) == address(0)) revert FeeRegistryIsZeroAddress(); feeRegistry = feeRegistry_; } // ============================================================= // PUBLIC / EXTERNAL WRITE FUNCTIONS // ============================================================= /** * @inheritdoc IMinterModule */ function setEditionMintPaused( address edition, uint128 mintId, bool paused ) public virtual onlyEditionOwnerOrAdmin(edition) { _baseData[edition][mintId].mintPaused = paused; emit MintPausedSet(edition, mintId, paused); } /** * @inheritdoc IMinterModule */ function setTimeRange( address edition, uint128 mintId, uint32 startTime, uint32 endTime ) public virtual onlyEditionOwnerOrAdmin(edition) onlyValidTimeRange(startTime, endTime) { _baseData[edition][mintId].startTime = startTime; _baseData[edition][mintId].endTime = endTime; emit TimeRangeSet(edition, mintId, startTime, endTime); } /** * @inheritdoc IMinterModule */ function setAffiliateFee( address edition, uint128 mintId, uint16 feeBPS ) public virtual override onlyEditionOwnerOrAdmin(edition) onlyValidAffiliateFeeBPS(feeBPS) { _baseData[edition][mintId].affiliateFeeBPS = feeBPS; emit AffiliateFeeSet(edition, mintId, feeBPS); } /** * @inheritdoc IMinterModule */ function withdrawForAffiliate(address affiliate) public override { uint256 accrued = _affiliateFeesAccrued[affiliate]; if (accrued != 0) { _affiliateFeesAccrued[affiliate] = 0; SafeTransferLib.safeTransferETH(affiliate, accrued); } } /** * @inheritdoc IMinterModule */ function withdrawForPlatform() public override { uint256 accrued = _platformFeesAccrued; if (accrued != 0) { _platformFeesAccrued = 0; SafeTransferLib.safeTransferETH(feeRegistry.soundFeeAddress(), accrued); } } // ============================================================= // PUBLIC / EXTERNAL VIEW FUNCTIONS // ============================================================= /** * @dev Getter for the max basis points. */ function MAX_BPS() external pure returns (uint16) { return _MAX_BPS; } /** * @inheritdoc IMinterModule */ function affiliateFeesAccrued(address affiliate) external view returns (uint128) { return _affiliateFeesAccrued[affiliate]; } /** * @inheritdoc IMinterModule */ function platformFeesAccrued() external view returns (uint128) { return _platformFeesAccrued; } /** * @inheritdoc IMinterModule */ function isAffiliated( address, /* edition */ uint128, /* mintId */ address affiliate ) public view virtual override returns (bool) { return affiliate != address(0); } /** * @inheritdoc IMinterModule */ function nextMintId() public view returns (uint128) { return _nextMintId; } /** * @inheritdoc IERC165 */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IMinterModule).interfaceId || interfaceId == this.supportsInterface.selector; } /** * @inheritdoc IMinterModule */ function totalPrice( address edition, uint128 mintId, address minter, uint32 quantity ) public view virtual override returns (uint128); // ============================================================= // INTERNAL / PRIVATE HELPERS // ============================================================= /** * @dev Restricts the function to be only callable by the owner or admin of `edition`. * @param edition The edition address. */ modifier onlyEditionOwnerOrAdmin(address edition) virtual { if ( msg.sender != OwnableRoles(edition).owner() && !OwnableRoles(edition).hasAnyRole(msg.sender, ISoundEditionV1(edition).ADMIN_ROLE()) ) revert Unauthorized(); _; } /** * @dev Restricts the start time to be less than the end time. * @param startTime The start time of the mint. * @param endTime The end time of the mint. */ modifier onlyValidTimeRange(uint32 startTime, uint32 endTime) virtual { if (startTime >= endTime) revert InvalidTimeRange(); _; } /** * @dev Restricts the affiliate fee numerator to not exceed the `MAX_BPS`. */ modifier onlyValidAffiliateFeeBPS(uint16 affiliateFeeBPS) virtual { if (affiliateFeeBPS > _MAX_BPS) revert InvalidAffiliateFeeBPS(); _; } /** * @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) onlyValidTimeRange(startTime, endTime) onlyValidAffiliateFeeBPS(affiliateFeeBPS) returns (uint128 mintId) { mintId = _nextMintId; BaseData storage data = _baseData[edition][mintId]; data.startTime = startTime; data.endTime = endTime; data.affiliateFeeBPS = affiliateFeeBPS; _nextMintId = mintId + 1; emit MintConfigCreated(edition, msg.sender, mintId, startTime, endTime, affiliateFeeBPS); } /** * @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 quantity The quantity of tokens to mint. * @param affiliate The affiliate (referral) address. */ function _mint( address edition, uint128 mintId, uint32 quantity, address affiliate ) internal { BaseData storage baseData = _baseData[edition][mintId]; /* --------------------- 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 ------------ */ uint128 requiredEtherValue = totalPrice(edition, mintId, msg.sender, quantity); // Reverts if the payment is not exact. if (msg.value < requiredEtherValue) revert Underpaid(msg.value, requiredEtherValue); (uint128 remainingPayment, uint128 platformFee) = _deductPlatformFee(requiredEtherValue); // Check if the mint is an affiliated mint. bool affiliated = isAffiliated(edition, mintId, affiliate); uint128 affiliateFee; unchecked { if (affiliated) { // Compute the affiliate fee. // Won't overflow, as `remainingPayment` is 128 bits, and `affiliateFeeBPS` is 16 bits. affiliateFee = uint128( (uint256(remainingPayment) * uint256(baseData.affiliateFeeBPS)) / uint256(_MAX_BPS) ); // Deduct the affiliate fee from the remaining payment. // Won't underflow as `affiliateFee <= remainingPayment`. remainingPayment -= affiliateFee; // Increment the affiliate fees accrued. // Overflow is incredibly unrealistic. _affiliateFeesAccrued[affiliate] += affiliateFee; } } /* ------------------------- MINT --------------------------- */ // Emit the event. emit Minted( edition, mintId, msg.sender, // Need to put this call here to avoid stack-too-deep error (it returns fromTokenId) uint32(ISoundEditionV1(edition).mint{ value: remainingPayment }(msg.sender, quantity)), quantity, requiredEtherValue, platformFee, affiliateFee, affiliate, affiliated ); /* ------------------------- REFUND ------------------------- */ unchecked { // 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 > requiredEtherValue) { SafeTransferLib.safeTransferETH(msg.sender, msg.value - requiredEtherValue); } } } /** * @dev Deducts the platform fee from `requiredEtherValue`. * @param requiredEtherValue The amount of Ether required. * @return remainingPayment The remaining payment Ether amount. * @return platformFee The platform fee. */ function _deductPlatformFee(uint128 requiredEtherValue) internal returns (uint128 remainingPayment, uint128 platformFee) { unchecked { // Compute the platform fee. platformFee = feeRegistry.platformFee(requiredEtherValue); // Increment the platform fees accrued. // Overflow is incredibly unrealistic. _platformFeesAccrued += platformFee; // Deduct the platform fee. // Won't underflow as `platformFee <= requiredEtherValue`; remainingPayment = requiredEtherValue - platformFee; } } /** * @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); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import { IMinterModule } from "@core/interfaces/IMinterModule.sol"; /** * @dev Data unique to a merkle drop mint. */ struct EditionMintData { // Hash of the root node for the merkle tree drop bytes32 merkleRootHash; // The price at which each token will be sold, in ETH. uint96 price; // The maximum number of tokens that can can be minted for this sale. uint32 maxMintable; // The maximum number of tokens that a wallet can mint. uint32 maxMintablePerAccount; // 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; } /** * @title IMerkleDropMinter * @dev Interface for the `MerkleDropMinter` module. * @author Sound.xyz */ interface IMerkleDropMinter is IMinterModule { // ============================================================= // 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 indexed 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 recipient The address of the account that claimed the tokens. * @param quantity The quantity of tokens claimed. */ event DropClaimed(address recipient, 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 indexed 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 indexed 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 indexed 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 indexed mintId, bytes32 merkleRootHash); // ============================================================= // ERRORS // ============================================================= /** * @dev The merkle proof is invalid. */ error InvalidMerkleProof(); /** * @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 mintId The ID of the mint instance. * @param requestedQuantity The quantity of tokens to mint. */ function mint( address edition, uint128 mintId, uint32 requestedQuantity, bytes32[] calldata merkleProof, 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 IMerkleDropMinter.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.16; import { IERC165 } from "openzeppelin/utils/introspection/IERC165.sol"; import { ISoundFeeRegistry } from "./ISoundFeeRegistry.sol"; /** * @title IMinterModule * @notice The interface for Sound protocol minter modules. */ interface IMinterModule is IERC165 { // ============================================================= // STRUCTS // ============================================================= struct BaseData { // 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; } // ============================================================= // 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 indexed 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 indexed mintId, uint16 bps); /** * @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. */ event Minted( address indexed edition, uint128 indexed mintId, address indexed buyer, uint32 fromTokenId, uint32 quantity, uint128 requiredEtherValue, uint128 platformFee, uint128 affiliateFee, address affiliate, bool affiliated ); // ============================================================= // 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 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 Unauthorized caller */ error Unauthorized(); /** * @dev The affiliate fee numerator must not exceed `MAX_BPS`. */ error InvalidAffiliateFeeBPS(); /** * @dev Fee registry cannot be the zero address. */ error FeeRegistryIsZeroAddress(); // ============================================================= // 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. */ function setAffiliateFee( address edition, uint128 mintId, uint16 affiliateFeeBPS ) 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 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. * @return The computed value. */ function isAffiliated( address edition, uint128 mintId, address affiliate ) external view returns (bool); /** * @dev The total price for `quantity` tokens for (`edition`, `mintId`). * @param edition The edition's address. * @param mintId The mint ID. * @param mintId The minter's address. * @param quantity The number of tokens to mint. * @return The computed value. */ function totalPrice( address edition, uint128 mintId, address minter, uint32 quantity ) external view returns (uint128); /** * @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); /** * @dev The fee registry. Used for handling platform fees. * @return The immutable value. */ function feeRegistry() external view returns (ISoundFeeRegistry); }
// 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_ ); // ============================================================= // 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.4; /// @notice Simple single owner and multiroles authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/OwnableRoles.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 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 cancelled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @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("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; /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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. /// /// The role slot of `user` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT)) /// 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. 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 { 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 { 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 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 { assembly { // Compute the role slot. mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT)) let roleSlot := keccak256(0x00, 0x20) // Load the current value and `or` it with `roles`. let newRoles := or(sload(roleSlot), roles) // Store the new value. sstore(roleSlot, newRoles) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, shl(96, user)), newRoles) } } /// @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 { assembly { // Compute the role slot. mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT)) let roleSlot := keccak256(0x00, 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. let newRoles := xor(currentRoles, and(currentRoles, roles)) // Then, store the new value. sstore(roleSlot, newRoles) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, shl(96, user)), newRoles) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public virtual onlyOwner { assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Reverts if the `newOwner` is the zero address. if iszero(newOwner) { mstore(0x00, _NEW_OWNER_IS_ZERO_ADDRESS_ERROR_SELECTOR) revert(0x1c, 0x04) } // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, caller(), newOwner) // Store the new value. sstore(not(_OWNER_SLOT_NOT), newOwner) } } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public virtual onlyOwner { assembly { // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, caller(), 0) // Store the new value. sstore(not(_OWNER_SLOT_NOT), 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 virtual { unchecked { uint256 expires = block.timestamp + ownershipHandoverValidFor(); assembly { // Compute and set the handover slot to 1. mstore(0x00, or(shl(96, caller()), _HANDOVER_SLOT_SEED)) sstore(keccak256(0x00, 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 virtual { assembly { // Compute and set the handover slot to 0. mstore(0x00, or(shl(96, caller()), _HANDOVER_SLOT_SEED)) sstore(keccak256(0x00, 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 virtual onlyOwner { assembly { // Clean the upper 96 bits. pendingOwner := shr(96, shl(96, pendingOwner)) // Compute and set the handover slot to 0. mstore(0x00, or(shl(96, pendingOwner), _HANDOVER_SLOT_SEED)) let handoverSlot := keccak256(0x00, 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) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, caller(), pendingOwner) // Store the new value. sstore(not(_OWNER_SLOT_NOT), pendingOwner) } } /// @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 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 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 virtual { _removeRoles(msg.sender, roles); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { 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) { assembly { // Compute the handover slot. mstore(0x00, or(shl(96, pendingOwner), _HANDOVER_SLOT_SEED)) // Load the handover slot. result := sload(keccak256(0x00, 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; } /// @dev Returns whether `user` has any of `roles`. function hasAnyRole(address user, uint256 roles) public view virtual returns (bool result) { assembly { // Compute the role slot. mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT)) // 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(0x00, 0x20)), roles))) } } /// @dev Returns whether `user` has all of `roles`. function hasAllRoles(address user, uint256 roles) public view virtual returns (bool result) { assembly { // Compute the role slot. mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT)) // Whether the stored value is contains all the set bits in `roles`. result := eq(and(sload(keccak256(0x00, 0x20)), roles), roles) } } /// @dev Returns the roles of `user`. function rolesOf(address user) public view virtual returns (uint256 roles) { assembly { // Compute the role slot. mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT)) // Load the stored value. roles := sload(keccak256(0x00, 0x20)) } } /// @dev Convenience function to return a `roles` bitmap from the `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) { assembly { // Skip the length slot. let o := add(ordinals, 0x20) // `shl` 5 is equivalent to multiplying by 0x20. let end := add(o, shl(5, mload(ordinals))) // prettier-ignore for {} iszero(eq(o, end)) { o := add(o, 0x20) } { roles := or(roles, shl(and(mload(o), 0xff), 1)) } } } /// @dev Convenience function to return a `roles` bitmap from the `ordinals`. /// 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) { assembly { // Grab the pointer to the free memory. let ptr := add(mload(0x40), 0x20) // 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. // prettier-ignore for { let i := 0 } 1 { i := add(i, 1) } { mstore(ptr, i) // `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(roles, 1))) roles := shr(1, roles) // prettier-ignore if iszero(roles) { break } } // Set `ordinals` to the start of the free memory. ordinals := mload(0x40) // Allocate the memory. mstore(0x40, ptr) // Store the length of `ordinals`. mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { 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) } } _; } /// @dev Marks a function as only callable by an account with `roles`. modifier onlyRoles(uint256 roles) virtual { assembly { // Compute the role slot. mstore(0x00, or(shl(96, caller()), _OWNER_SLOT_NOT)) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x00, 0x20)), roles)) { mstore(0x00, _UNAUTHORIZED_ERROR_SELECTOR) revert(0x1c, 0x04) } } _; } /// @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 { assembly { // If the caller is not the stored owner. if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { // Compute the role slot. mstore(0x00, or(shl(96, caller()), _OWNER_SLOT_NOT)) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x00, 0x20)), roles)) { mstore(0x00, _UNAUTHORIZED_ERROR_SELECTOR) revert(0x1c, 0x04) } } } _; } /// @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 { assembly { // Compute the role slot. mstore(0x00, or(shl(96, caller()), _OWNER_SLOT_NOT)) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x00, 0x20)), roles)) { // If the caller is not the stored owner. if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { mstore(0x00, _UNAUTHORIZED_ERROR_SELECTOR) revert(0x1c, 0x04) } } } _; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 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 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ error ETHTransferFailed(); error TransferFromFailed(); error TransferFailed(); error ApproveFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ETH OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function safeTransferETH(address to, uint256 amount) internal { 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) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function safeTransferFrom( address token, address from, address to, uint256 amount ) internal { assembly { // We'll write our calldata to this slot below, but restore it later. let memPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(0x00, 0x23b872dd) mstore(0x20, from) // Append the "from" argument. mstore(0x40, to) // Append the "to" argument. mstore(0x60, amount) // Append the "amount" argument. if iszero( and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), // We use 0x64 because that's the total length of our calldata (0x04 + 0x20 * 3) // Counterintuitively, this call() must be positioned after the or() in the // surrounding and() because and() evaluates its arguments from right to left. 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, memPointer) // Restore the memPointer. } } function safeTransfer( address token, address to, uint256 amount ) internal { assembly { // We'll write our calldata to this slot below, but restore it later. let memPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(0x00, 0xa9059cbb) mstore(0x20, to) // Append the "to" argument. mstore(0x40, amount) // Append the "amount" argument. if iszero( and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), // We use 0x44 because that's the total length of our calldata (0x04 + 0x20 * 2) // Counterintuitively, this call() must be positioned after the or() in the // surrounding and() because and() evaluates its arguments from right to left. call(gas(), token, 0, 0x1c, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x40, memPointer) // Restore the memPointer. } } function safeApprove( address token, address to, uint256 amount ) internal { assembly { // We'll write our calldata to this slot below, but restore it later. let memPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(0x00, 0x095ea7b3) mstore(0x20, to) // Append the "to" argument. mstore(0x40, amount) // Append the "amount" argument. if iszero( and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), // We use 0x44 because that's the total length of our calldata (0x04 + 0x20 * 2) // Counterintuitively, this call() must be positioned after the or() in the // surrounding and() because and() evaluates its arguments from right to left. call(gas(), token, 0, 0x1c, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `ApproveFailed()`. mstore(0x00, 0x3e3f8f73) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x40, memPointer) // Restore the memPointer. } } }
// 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 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 mulWadDown(uint256 x, uint256 y) internal pure returns (uint256 z) { 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) { 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 divWadDown(uint256 x, uint256 y) internal pure returns (uint256 z) { 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) { 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 0; // 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 (x >= 135305999368893231589) revert ExpOverflow(); // 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; 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 { if (x <= 0) revert LnWadUndefined(); // 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; 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)) // prettier-ignore 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; 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 Returns `floor(x * y / denominator)`. /// Reverts if `x * y` overflows, or `denominator` is zero. function mulDivDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, 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), denominator) } } /// @dev Returns `ceil(x * y / denominator)`. /// Reverts if `x * y` overflows, or `denominator` is zero. function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, 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), denominator))), div(mul(x, y), denominator)) } } /// @dev Returns `ceil(x / denominator)`. /// Reverts if `denominator` is zero. function divUp(uint256 x, uint256 denominator) internal pure returns (uint256 z) { assembly { if iszero(denominator) { // Store the function selector of `DivFailed()`. mstore(0x00, 0x65244e4e) // Revert with (offset, size). revert(0x1c, 0x04) } z := add(iszero(iszero(mod(x, denominator))), div(x, denominator)) } } /// @dev Returns `max(0, x - y)`. function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) { 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) { 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, gt(x, 0xffffffffffffffffffffffffffffffffff)) r := or(r, shl(6, gt(shr(r, x), 0xffffffffffffffffff))) r := or(r, shl(5, gt(shr(r, x), 0xffffffffff))) r := or(r, shl(4, gt(shr(r, x), 0xffffff))) 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 factorial of `x`. function factorial(uint256 x) public pure returns (uint256 result) { unchecked { if (x < 11) { // prettier-ignore result = (0x375f0016260009d80004ec0002d00001e0000180000180000200000400001 >> (x * 22)) & 0x3fffff; } else if (x < 32) { result = 3628800; do { result = result * x; x = x - 1; } while (x != 10); } else if (x < 58) { // Just cheat lol. result = 8222838654177922817725562880000000; do { result = result * x; x = x - 1; } while (x != 31); } else { revert FactorialOverflow(); } } } /// @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) { 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)) // prettier-ignore r := or(r, byte(shr(251, mul(x, shl(224, 0x07c4acdd))), 0x0009010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f)) } } /// @dev Returns the averege of `x` and `y`. function avg(uint256 x, uint256 y) internal pure returns (uint256 z) { assembly { z := add(and(x, y), shr(1, xor(x, y))) } } /// @dev Returns the absolute value of `x`. function abs(int256 x) internal pure returns (uint256 z) { assembly { let mask := mul(shr(255, x), not(0)) 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) { 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) { assembly { z := xor(x, mul(xor(x, y), lt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(uint256 x, uint256 y) internal pure returns (uint256 z) { assembly { z := xor(x, mul(xor(x, y), gt(y, x))) } } /// @dev Returns gcd of `x` and `y`. function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) { assembly { // prettier-ignore for { z := x } y {} { let t := y y := mod(z, y) z := t } } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp( uint256 x, uint256 minValue, uint256 maxValue ) internal pure returns (uint256 z) { return min(max(x, minValue), maxValue); } }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.2.2 // 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; /** * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @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; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the * zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} * for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll}. */ function isApprovedForAll(address owner, address operator) external view returns (bool); // ============================================================= // 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 // 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.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); }
{ "remappings": [ "@core/=contracts/core/", "@modules/=contracts/modules/", "ERC721A-Upgradeable/=lib/ERC721A-Upgradeable/contracts/", "chiru-labs/ERC721A-Upgradeable/=lib/ERC721A-Upgradeable/contracts/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/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/", "solady/=lib/solady/src/", "solmate/=lib/solady/lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 1000 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract ISoundFeeRegistry","name":"feeRegistry_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint32","name":"available","type":"uint32"}],"name":"ExceedsAvailableSupply","type":"error"},{"inputs":[],"name":"ExceedsMaxPerAccount","type":"error"},{"inputs":[],"name":"FeeRegistryIsZeroAddress","type":"error"},{"inputs":[],"name":"InvalidAffiliateFeeBPS","type":"error"},{"inputs":[],"name":"InvalidMerkleProof","type":"error"},{"inputs":[],"name":"InvalidTimeRange","type":"error"},{"inputs":[],"name":"MaxMintablePerAccountIsZero","type":"error"},{"inputs":[],"name":"MerkleRootHashIsEmpty","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":"Unauthorized","type":"error"},{"inputs":[{"internalType":"uint256","name":"paid","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"Underpaid","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"edition","type":"address"},{"indexed":true,"internalType":"uint128","name":"mintId","type":"uint128"},{"indexed":false,"internalType":"uint16","name":"bps","type":"uint16"}],"name":"AffiliateFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","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":true,"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":true,"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":true,"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":true,"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":true,"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"}],"name":"Minted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"edition","type":"address"},{"indexed":true,"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":true,"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":"MAX_BPS","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"affiliate","type":"address"}],"name":"affiliateFeesAccrued","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","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":[],"name":"feeRegistry","outputs":[{"internalType":"contract ISoundFeeRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint128","name":"","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":"uint32","name":"requestedQuantity","type":"uint32"},{"internalType":"bytes32[]","name":"merkleProof","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"}],"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":"struct MintInfo","name":"","type":"tuple"}],"stateMutability":"view","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":"platformFeesAccrued","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"},{"internalType":"uint16","name":"feeBPS","type":"uint16"}],"name":"setAffiliateFee","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":"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":"affiliate","type":"address"}],"name":"withdrawForAffiliate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawForPlatform","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a06040523480156200001157600080fd5b5060405162002a3e38038062002a3e833981016040819052620000349162000070565b806001600160a01b0381166200005d57604051636cdc033760e11b815260040160405180910390fd5b6001600160a01b031660805250620000a2565b6000602082840312156200008357600080fd5b81516001600160a01b03811681146200009b57600080fd5b9392505050565b608051612972620000cc60003960008181610490015281816106c901526122a101526129726000f3fe60806040526004361061016a5760003560e01c8063aec96b6e116100cb578063c7dd32281161007f578063f574029611610059578063f5740296146105e1578063fc63e69e14610601578063fd967f471461062157600080fd5b8063c7dd322814610573578063c94dcf8f14610595578063d73f3aab146105c157600080fd5b8063b84158a4116100b0578063b84158a4146104ca578063c309c47d14610533578063c3190a2e1461055357600080fd5b8063aec96b6e1461045e578063b3a408b81461047e57600080fd5b806322163b86116101225780636aa99da3116101075780636aa99da3146103e15780637614a751146103ff578063ac1fc22c1461041f57600080fd5b806322163b8614610388578063522f7386146103c157600080fd5b806308bfa2bf1161015357806308bfa2bf1461033e578063153229bd14610355578063159a76bd1461037557600080fd5b806301ffc9a71461016f57806303a6ccd0146101a4575b600080fd5b34801561017b57600080fd5b5061018f61018a366004612336565b61063e565b60405190151581526020015b60405180910390f35b3480156101b057600080fd5b506103316101bf3660046123a1565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810191909152506001600160a01b039190911660008181526001602081815260408084206001600160801b0396909616808552958252808420815160808082018452915463ffffffff80821683526401000000008204811683870190815268010000000000000000830461ffff9081168588019081526a010000000000000000000090940460ff16151560608087019182529b8b5260038952878b209c8b529b88529886902086516101208101885294518316855290518216968401969096529051909616928101929092529551151594810194909452908101546bffffffffffffffffffffffff8116948401949094526c010000000000000000000000008404821660a0840152600160801b8404821660c0840152600160a01b9093041660e0820152905461010082015290565b60405161019b91906123da565b34801561034a57600080fd5b5061035361066a565b005b34801561036157600080fd5b506103536103703660046124b0565b610742565b6103536103833660046124f7565b61096e565b34801561039457600080fd5b50600054600160801b90046001600160801b03165b6040516001600160801b03909116815260200161019b565b3480156103cd57600080fd5b506103536103dc3660046125c0565b610bbc565b3480156103ed57600080fd5b506000546001600160801b03166103a9565b34801561040b57600080fd5b5061035361041a3660046124b0565b610dce565b34801561042b57600080fd5b506103a961043a36600461260b565b6001600160a01b03166000908152600260205260409020546001600160801b031690565b34801561046a57600080fd5b50610353610479366004612628565b61100e565b34801561048a57600080fd5b506104b27f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161019b565b3480156104d657600080fd5b506103a96104e5366004612680565b6001600160a01b03841660009081526003602090815260408083206001600160801b03871684529091529020600101546bffffffffffffffffffffffff1663ffffffff821602949350505050565b34801561053f57600080fd5b506103a961054e3660046126ef565b611251565b34801561055f57600080fd5b5061035361056e366004612781565b61141d565b34801561057f57600080fd5b5060405163225a471360e21b815260200161019b565b3480156105a157600080fd5b5061018f6105b03660046127c2565b6001600160a01b0316151592915050565b3480156105cd57600080fd5b506103536105dc366004612802565b611619565b3480156105ed57600080fd5b506103536105fc36600461260b565b61184f565b34801561060d57600080fd5b5061035361061c366004612840565b6118b4565b34801561062d57600080fd5b50604051612710815260200161019b565b600061064982611ab9565b8061066457506001600160e01b0319821663225a471360e21b145b92915050565b600054600160801b90046001600160801b0316801561073f57600080546001600160801b03169055604080517f946f7c9e000000000000000000000000000000000000000000000000000000008152905161073f916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163946f7c9e916004808201926020929091908290030181865afa158015610715573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610739919061287e565b82611b21565b50565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a5919061287e565b6001600160a01b0316336001600160a01b0316141580156108a25750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561080f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610833919061289b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa15801561087c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a091906128b4565b155b156108bf576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03841660008181526003602090815260408083206001600160801b0388168085529083529281902060010180547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff89169081029190911790915590519081529192917f4c3c29668821111c3ddbcf87e1cd6047dc735ef691d46e09671629cb42cdd94891015b60405180910390a350505050565b6001600160a01b03861660009081526003602090815260408083206001600160801b0389168452909152902060018101546109cb9063ffffffff600160a01b820481169188916c0100000000000000000000000090910416611b3d565b60018201805463ffffffff92909216600160a01b027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9092169190911790556040516bffffffffffffffffffffffff193360601b1660208201526000906034016040516020818303038152906040528051906020012090506000610a558686856000015485611bbb565b905080610a8e576040517fb05e92fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fdc33e6810000000000000000000000000000000000000000000000000000000081523360048201526000906001600160a01b038b169063dc33e68190602401602060405180830381865afa158015610aee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b12919061289b565b600185015490915063ffffffff600160801b909104811690891682011115610b66576040517f1b75136500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50610b7389898987611bf5565b6040805133815263ffffffff891660208201527fbbce3c6646076fce6266a06486d114fd6f4fcdce3df843aadf9c56a2d89721a0910160405180910390a1505050505050505050565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1f919061287e565b6001600160a01b0316336001600160a01b031614158015610d1c5750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cad919061289b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610cf6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d1a91906128b4565b155b15610d39576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03841660008181526001602090815260408083206001600160801b0388168085529083529281902080546aff0000000000000000000019166a0100000000000000000000881515908102919091179091558151938452918301919091527fe430910c8e4bfa8180b70a0b2aa923b82d6712a1d165e223053ef439a3f86147910160405180910390a250505050565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e31919061287e565b6001600160a01b0316336001600160a01b031614158015610f2e5750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ebf919061289b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610f08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2c91906128b4565b155b15610f4b576040516282b42960e81b815260040160405180910390fd5b8163ffffffff16600003610f725760405163a017714560e01b815260040160405180910390fd5b6001600160a01b03841660008181526003602090815260408083206001600160801b0388168085529083529281902060010180547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff16600160801b63ffffffff89169081029190911790915590519081529192917f021f3ca4d64a14574ed4fc7115d2c667604e54efb94b6187ed8117d49c6e47559101610960565b83806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561104d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611071919061287e565b6001600160a01b0316336001600160a01b03161415801561116e5750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ff919061289b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611148573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116c91906128b4565b155b1561118b576040516282b42960e81b815260040160405180910390fd5b82828063ffffffff168263ffffffff16106111b95760405163536a71af60e01b815260040160405180910390fd5b6001600160a01b03871660008181526001602090815260408083206001600160801b038b1680855290835292819020805463ffffffff8b811667ffffffffffffffff199092168217640100000000918c16918202179092558251908152928301529192917f13bc03d97cc4e2accb3b8290af069c19619d32a4e9c5219f8580108766fb18fd910160405180910390a350505050505050565b6000876112715760405163b00db6fb60e01b815260040160405180910390fd5b8163ffffffff166000036112985760405163a017714560e01b815260040160405180910390fd5b6112a489878787611f6d565b90506000600360008b6001600160a01b03166001600160a01b031681526020019081526020016000206000836001600160801b03166001600160801b031681526020019081526020016000209050888160000181905550878160010160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508381600101600c6101000a81548163ffffffff021916908363ffffffff160217905550828160010160106101000a81548163ffffffff021916908363ffffffff160217905550816001600160801b03168a6001600160a01b03167fd9faafd9b789bcd20399f1fafa1c6459996ac840e9177ee687c23cdbe3b7a9cb8b8b8b8b8b8b8b60405161140897969594939291909687526bffffffffffffffffffffffff95909516602087015263ffffffff9384166040870152918316606086015261ffff166080850152811660a08401521660c082015260e00190565b60405180910390a35098975050505050505050565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561145c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611480919061287e565b6001600160a01b0316336001600160a01b03161415801561157d5750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061150e919061289b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611557573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061157b91906128b4565b155b1561159a576040516282b42960e81b815260040160405180910390fd5b816115b85760405163b00db6fb60e01b815260040160405180910390fd5b6001600160a01b03841660008181526003602090815260408083206001600160801b03881680855290835292819020869055518581529192917fa863d0ab0f23accb1c42ee00c0587f1c94539e15956a678a54c1e710ba07066e9101610960565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611658573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167c919061287e565b6001600160a01b0316336001600160a01b0316141580156117795750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061170a919061289b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611753573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177791906128b4565b155b15611796576040516282b42960e81b815260040160405180910390fd5b8161271061ffff821611156117be57604051631a52ce6f60e01b815260040160405180910390fd5b6001600160a01b03851660008181526001602090815260408083206001600160801b03891680855290835292819020805469ffff000000000000000019166801000000000000000061ffff8a169081029190911790915590519081529192917fae6d744348a49699fcb91e6a563f2224c0fb27c21053a9218ee827f9d6e698c7910160405180910390a35050505050565b6001600160a01b0381166000908152600260205260409020546001600160801b031680156118b0576001600160a01b038216600090815260026020526040902080546fffffffffffffffffffffffffffffffff191690556118b08282611b21565b5050565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611917919061287e565b6001600160a01b0316336001600160a01b031614158015611a145750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611981573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a5919061289b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa1580156119ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a1291906128b4565b155b15611a31576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03841660008181526003602090815260408083206001600160801b0388168085529083529281902060010180546bffffffffffffffffffffffff19166bffffffffffffffffffffffff881690811790915590519081529192917f7c77af090cbae157811da55b6d8ae1e307a85f5aa1dd2f7a13183279a8c2b4b29101610960565b60006001600160e01b031982167f37c74bd800000000000000000000000000000000000000000000000000000000148061066457506001600160e01b031982167f01ffc9a7000000000000000000000000000000000000000000000000000000001492915050565b60008060008084865af16118b05763b12d13eb6000526004601cfd5b600063ffffffff84811681851601908316811115611bb3576000611b718463ffffffff168763ffffffff1680821191030290565b6040517fbdc0f4ce00000000000000000000000000000000000000000000000000000000815263ffffffff821660048201529091506024015b60405180910390fd5b949350505050565b60008315611bed578360051b8501855b803580851160051b94855260209485185260406000209301818110611bcb5750505b501492915050565b6001600160a01b03841660009081526001602090815260408083206001600160801b03871684529091529020805463ffffffff8082169164010000000090041642821115611c6c5760405163296f4f6960e01b815242600482015263ffffffff808416602483015282166044820152606401611baa565b8063ffffffff16421115611ca95760405163296f4f6960e01b815242600482015263ffffffff808416602483015282166044820152606401611baa565b82546a0100000000000000000000900460ff1615611cf3576040517fd7d248ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50506001600160a01b03851660009081526003602090815260408083206001600160801b03881684529091528120600101546bffffffffffffffffffffffff1663ffffffff8516029050806001600160801b0316341015611d91576040517ff3ebc3840000000000000000000000000000000000000000000000000000000081523460048201526001600160801b0382166024820152604401611baa565b600080611d9d8361225d565b90925090506001600160a01b03851615801590600090611e20575084546001600160a01b038716600090815260026020526040902080546001600160801b0381811661271061ffff68010000000000000000909604959095168883160294909404938401166fffffffffffffffffffffffffffffffff1990911617905592839003925b6040517f40c10f19000000000000000000000000000000000000000000000000000000008152336004820181905263ffffffff8a166024830152906001600160801b03808c16916001600160a01b038e16917f3d73a0206d94d61b7038abcd0eb766a5de22f9844b38a78449054d19a4f1b58a9183916340c10f1991908b169060440160206040518083038185885af1158015611ec1573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611ee6919061289b565b6040805163ffffffff9283168152918e1660208301526001600160801b038b8116838301528981166060840152871660808301526001600160a01b038d1660a083015287151560c0830152519081900360e00190a4846001600160801b0316341115611f6157611f6133866001600160801b03163403611b21565b50505050505050505050565b600084806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd2919061287e565b6001600160a01b0316336001600160a01b0316141580156120cf5750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561203c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612060919061289b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa1580156120a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120cd91906128b4565b155b156120ec576040516282b42960e81b815260040160405180910390fd5b84848063ffffffff168263ffffffff161061211a5760405163536a71af60e01b815260040160405180910390fd5b8461271061ffff8216111561214257604051631a52ce6f60e01b815260040160405180910390fd5b600080546001600160a01b038b1682526001602081815260408085206001600160801b0390941680865293909152909220805461ffff8a16680100000000000000000269ffff00000000000000001963ffffffff8d81166401000000000267ffffffffffffffff19909416908f16179290921791909116178155909650906121cb9087906128d1565b600080546fffffffffffffffffffffffffffffffff19166001600160801b0392831617905560408051918816825263ffffffff808c1660208401528a169082015261ffff8816606082015233906001600160a01b038c16907feeb5941fb79bbfe40edd76c2e086e8ccdb0b463fc8ac07416266100b4dfddccf9060800160405180910390a35050505050949350505050565b6040517f0d411b210000000000000000000000000000000000000000000000000000000081526001600160801b038216600482015260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690630d411b2190602401602060405180830381865afa1580156122e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061230c919061291f565b600080546001600160801b03600160801b8083048216850182160291161790559283900393915050565b60006020828403121561234857600080fd5b81356001600160e01b03198116811461236057600080fd5b9392505050565b6001600160a01b038116811461073f57600080fd5b803561238781612367565b919050565b6001600160801b038116811461073f57600080fd5b600080604083850312156123b457600080fd5b82356123bf81612367565b915060208301356123cf8161238c565b809150509250929050565b60006101208201905063ffffffff808451168352806020850151166020840152506040830151612410604084018261ffff169052565b506060830151612424606084018215159052565b50608083015161244460808401826bffffffffffffffffffffffff169052565b5060a083015161245c60a084018263ffffffff169052565b5060c083015161247460c084018263ffffffff169052565b5060e083015161248c60e084018263ffffffff169052565b5061010092830151919092015290565b803563ffffffff8116811461238757600080fd5b6000806000606084860312156124c557600080fd5b83356124d081612367565b925060208401356124e08161238c565b91506124ee6040850161249c565b90509250925092565b60008060008060008060a0878903121561251057600080fd5b863561251b81612367565b9550602087013561252b8161238c565b94506125396040880161249c565b9350606087013567ffffffffffffffff8082111561255657600080fd5b818901915089601f83011261256a57600080fd5b81358181111561257957600080fd5b8a60208260051b850101111561258e57600080fd5b6020830195508094505050506125a66080880161237c565b90509295509295509295565b801515811461073f57600080fd5b6000806000606084860312156125d557600080fd5b83356125e081612367565b925060208401356125f08161238c565b91506040840135612600816125b2565b809150509250925092565b60006020828403121561261d57600080fd5b813561236081612367565b6000806000806080858703121561263e57600080fd5b843561264981612367565b935060208501356126598161238c565b92506126676040860161249c565b91506126756060860161249c565b905092959194509250565b6000806000806080858703121561269657600080fd5b84356126a181612367565b935060208501356126b18161238c565b9250604085013561266781612367565b80356bffffffffffffffffffffffff8116811461238757600080fd5b803561ffff8116811461238757600080fd5b600080600080600080600080610100898b03121561270c57600080fd5b883561271781612367565b97506020890135965061272c60408a016126c1565b955061273a60608a0161249c565b945061274860808a0161249c565b935061275660a08a016126dd565b925061276460c08a0161249c565b915061277260e08a0161249c565b90509295985092959890939650565b60008060006060848603121561279657600080fd5b83356127a181612367565b925060208401356127b18161238c565b929592945050506040919091013590565b6000806000606084860312156127d757600080fd5b83356127e281612367565b925060208401356127f28161238c565b9150604084013561260081612367565b60008060006060848603121561281757600080fd5b833561282281612367565b925060208401356128328161238c565b91506124ee604085016126dd565b60008060006060848603121561285557600080fd5b833561286081612367565b925060208401356128708161238c565b91506124ee604085016126c1565b60006020828403121561289057600080fd5b815161236081612367565b6000602082840312156128ad57600080fd5b5051919050565b6000602082840312156128c657600080fd5b8151612360816125b2565b6001600160801b03818116838216019080821115612918577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5092915050565b60006020828403121561293157600080fd5b81516123608161238c56fea26469706673582212207b1aa8a3f201b60fe5339796d01136dbce207658848a084d80b13521cf75f1ec64736f6c6343000810003300000000000000000000000061353b0c3c3aae4e6c9e4e9fcde4a4be4417d2fa
Deployed Bytecode
0x60806040526004361061016a5760003560e01c8063aec96b6e116100cb578063c7dd32281161007f578063f574029611610059578063f5740296146105e1578063fc63e69e14610601578063fd967f471461062157600080fd5b8063c7dd322814610573578063c94dcf8f14610595578063d73f3aab146105c157600080fd5b8063b84158a4116100b0578063b84158a4146104ca578063c309c47d14610533578063c3190a2e1461055357600080fd5b8063aec96b6e1461045e578063b3a408b81461047e57600080fd5b806322163b86116101225780636aa99da3116101075780636aa99da3146103e15780637614a751146103ff578063ac1fc22c1461041f57600080fd5b806322163b8614610388578063522f7386146103c157600080fd5b806308bfa2bf1161015357806308bfa2bf1461033e578063153229bd14610355578063159a76bd1461037557600080fd5b806301ffc9a71461016f57806303a6ccd0146101a4575b600080fd5b34801561017b57600080fd5b5061018f61018a366004612336565b61063e565b60405190151581526020015b60405180910390f35b3480156101b057600080fd5b506103316101bf3660046123a1565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810191909152506001600160a01b039190911660008181526001602081815260408084206001600160801b0396909616808552958252808420815160808082018452915463ffffffff80821683526401000000008204811683870190815268010000000000000000830461ffff9081168588019081526a010000000000000000000090940460ff16151560608087019182529b8b5260038952878b209c8b529b88529886902086516101208101885294518316855290518216968401969096529051909616928101929092529551151594810194909452908101546bffffffffffffffffffffffff8116948401949094526c010000000000000000000000008404821660a0840152600160801b8404821660c0840152600160a01b9093041660e0820152905461010082015290565b60405161019b91906123da565b34801561034a57600080fd5b5061035361066a565b005b34801561036157600080fd5b506103536103703660046124b0565b610742565b6103536103833660046124f7565b61096e565b34801561039457600080fd5b50600054600160801b90046001600160801b03165b6040516001600160801b03909116815260200161019b565b3480156103cd57600080fd5b506103536103dc3660046125c0565b610bbc565b3480156103ed57600080fd5b506000546001600160801b03166103a9565b34801561040b57600080fd5b5061035361041a3660046124b0565b610dce565b34801561042b57600080fd5b506103a961043a36600461260b565b6001600160a01b03166000908152600260205260409020546001600160801b031690565b34801561046a57600080fd5b50610353610479366004612628565b61100e565b34801561048a57600080fd5b506104b27f00000000000000000000000061353b0c3c3aae4e6c9e4e9fcde4a4be4417d2fa81565b6040516001600160a01b03909116815260200161019b565b3480156104d657600080fd5b506103a96104e5366004612680565b6001600160a01b03841660009081526003602090815260408083206001600160801b03871684529091529020600101546bffffffffffffffffffffffff1663ffffffff821602949350505050565b34801561053f57600080fd5b506103a961054e3660046126ef565b611251565b34801561055f57600080fd5b5061035361056e366004612781565b61141d565b34801561057f57600080fd5b5060405163225a471360e21b815260200161019b565b3480156105a157600080fd5b5061018f6105b03660046127c2565b6001600160a01b0316151592915050565b3480156105cd57600080fd5b506103536105dc366004612802565b611619565b3480156105ed57600080fd5b506103536105fc36600461260b565b61184f565b34801561060d57600080fd5b5061035361061c366004612840565b6118b4565b34801561062d57600080fd5b50604051612710815260200161019b565b600061064982611ab9565b8061066457506001600160e01b0319821663225a471360e21b145b92915050565b600054600160801b90046001600160801b0316801561073f57600080546001600160801b03169055604080517f946f7c9e000000000000000000000000000000000000000000000000000000008152905161073f916001600160a01b037f00000000000000000000000061353b0c3c3aae4e6c9e4e9fcde4a4be4417d2fa169163946f7c9e916004808201926020929091908290030181865afa158015610715573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610739919061287e565b82611b21565b50565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610781573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a5919061287e565b6001600160a01b0316336001600160a01b0316141580156108a25750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561080f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610833919061289b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa15801561087c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a091906128b4565b155b156108bf576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03841660008181526003602090815260408083206001600160801b0388168085529083529281902060010180547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff89169081029190911790915590519081529192917f4c3c29668821111c3ddbcf87e1cd6047dc735ef691d46e09671629cb42cdd94891015b60405180910390a350505050565b6001600160a01b03861660009081526003602090815260408083206001600160801b0389168452909152902060018101546109cb9063ffffffff600160a01b820481169188916c0100000000000000000000000090910416611b3d565b60018201805463ffffffff92909216600160a01b027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9092169190911790556040516bffffffffffffffffffffffff193360601b1660208201526000906034016040516020818303038152906040528051906020012090506000610a558686856000015485611bbb565b905080610a8e576040517fb05e92fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fdc33e6810000000000000000000000000000000000000000000000000000000081523360048201526000906001600160a01b038b169063dc33e68190602401602060405180830381865afa158015610aee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b12919061289b565b600185015490915063ffffffff600160801b909104811690891682011115610b66576040517f1b75136500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50610b7389898987611bf5565b6040805133815263ffffffff891660208201527fbbce3c6646076fce6266a06486d114fd6f4fcdce3df843aadf9c56a2d89721a0910160405180910390a1505050505050505050565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1f919061287e565b6001600160a01b0316336001600160a01b031614158015610d1c5750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cad919061289b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610cf6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d1a91906128b4565b155b15610d39576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03841660008181526001602090815260408083206001600160801b0388168085529083529281902080546aff0000000000000000000019166a0100000000000000000000881515908102919091179091558151938452918301919091527fe430910c8e4bfa8180b70a0b2aa923b82d6712a1d165e223053ef439a3f86147910160405180910390a250505050565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e31919061287e565b6001600160a01b0316336001600160a01b031614158015610f2e5750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ebf919061289b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610f08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2c91906128b4565b155b15610f4b576040516282b42960e81b815260040160405180910390fd5b8163ffffffff16600003610f725760405163a017714560e01b815260040160405180910390fd5b6001600160a01b03841660008181526003602090815260408083206001600160801b0388168085529083529281902060010180547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff16600160801b63ffffffff89169081029190911790915590519081529192917f021f3ca4d64a14574ed4fc7115d2c667604e54efb94b6187ed8117d49c6e47559101610960565b83806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561104d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611071919061287e565b6001600160a01b0316336001600160a01b03161415801561116e5750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ff919061289b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611148573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116c91906128b4565b155b1561118b576040516282b42960e81b815260040160405180910390fd5b82828063ffffffff168263ffffffff16106111b95760405163536a71af60e01b815260040160405180910390fd5b6001600160a01b03871660008181526001602090815260408083206001600160801b038b1680855290835292819020805463ffffffff8b811667ffffffffffffffff199092168217640100000000918c16918202179092558251908152928301529192917f13bc03d97cc4e2accb3b8290af069c19619d32a4e9c5219f8580108766fb18fd910160405180910390a350505050505050565b6000876112715760405163b00db6fb60e01b815260040160405180910390fd5b8163ffffffff166000036112985760405163a017714560e01b815260040160405180910390fd5b6112a489878787611f6d565b90506000600360008b6001600160a01b03166001600160a01b031681526020019081526020016000206000836001600160801b03166001600160801b031681526020019081526020016000209050888160000181905550878160010160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508381600101600c6101000a81548163ffffffff021916908363ffffffff160217905550828160010160106101000a81548163ffffffff021916908363ffffffff160217905550816001600160801b03168a6001600160a01b03167fd9faafd9b789bcd20399f1fafa1c6459996ac840e9177ee687c23cdbe3b7a9cb8b8b8b8b8b8b8b60405161140897969594939291909687526bffffffffffffffffffffffff95909516602087015263ffffffff9384166040870152918316606086015261ffff166080850152811660a08401521660c082015260e00190565b60405180910390a35098975050505050505050565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561145c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611480919061287e565b6001600160a01b0316336001600160a01b03161415801561157d5750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061150e919061289b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611557573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061157b91906128b4565b155b1561159a576040516282b42960e81b815260040160405180910390fd5b816115b85760405163b00db6fb60e01b815260040160405180910390fd5b6001600160a01b03841660008181526003602090815260408083206001600160801b03881680855290835292819020869055518581529192917fa863d0ab0f23accb1c42ee00c0587f1c94539e15956a678a54c1e710ba07066e9101610960565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611658573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167c919061287e565b6001600160a01b0316336001600160a01b0316141580156117795750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061170a919061289b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611753573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177791906128b4565b155b15611796576040516282b42960e81b815260040160405180910390fd5b8161271061ffff821611156117be57604051631a52ce6f60e01b815260040160405180910390fd5b6001600160a01b03851660008181526001602090815260408083206001600160801b03891680855290835292819020805469ffff000000000000000019166801000000000000000061ffff8a169081029190911790915590519081529192917fae6d744348a49699fcb91e6a563f2224c0fb27c21053a9218ee827f9d6e698c7910160405180910390a35050505050565b6001600160a01b0381166000908152600260205260409020546001600160801b031680156118b0576001600160a01b038216600090815260026020526040902080546fffffffffffffffffffffffffffffffff191690556118b08282611b21565b5050565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611917919061287e565b6001600160a01b0316336001600160a01b031614158015611a145750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611981573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a5919061289b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa1580156119ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a1291906128b4565b155b15611a31576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03841660008181526003602090815260408083206001600160801b0388168085529083529281902060010180546bffffffffffffffffffffffff19166bffffffffffffffffffffffff881690811790915590519081529192917f7c77af090cbae157811da55b6d8ae1e307a85f5aa1dd2f7a13183279a8c2b4b29101610960565b60006001600160e01b031982167f37c74bd800000000000000000000000000000000000000000000000000000000148061066457506001600160e01b031982167f01ffc9a7000000000000000000000000000000000000000000000000000000001492915050565b60008060008084865af16118b05763b12d13eb6000526004601cfd5b600063ffffffff84811681851601908316811115611bb3576000611b718463ffffffff168763ffffffff1680821191030290565b6040517fbdc0f4ce00000000000000000000000000000000000000000000000000000000815263ffffffff821660048201529091506024015b60405180910390fd5b949350505050565b60008315611bed578360051b8501855b803580851160051b94855260209485185260406000209301818110611bcb5750505b501492915050565b6001600160a01b03841660009081526001602090815260408083206001600160801b03871684529091529020805463ffffffff8082169164010000000090041642821115611c6c5760405163296f4f6960e01b815242600482015263ffffffff808416602483015282166044820152606401611baa565b8063ffffffff16421115611ca95760405163296f4f6960e01b815242600482015263ffffffff808416602483015282166044820152606401611baa565b82546a0100000000000000000000900460ff1615611cf3576040517fd7d248ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50506001600160a01b03851660009081526003602090815260408083206001600160801b03881684529091528120600101546bffffffffffffffffffffffff1663ffffffff8516029050806001600160801b0316341015611d91576040517ff3ebc3840000000000000000000000000000000000000000000000000000000081523460048201526001600160801b0382166024820152604401611baa565b600080611d9d8361225d565b90925090506001600160a01b03851615801590600090611e20575084546001600160a01b038716600090815260026020526040902080546001600160801b0381811661271061ffff68010000000000000000909604959095168883160294909404938401166fffffffffffffffffffffffffffffffff1990911617905592839003925b6040517f40c10f19000000000000000000000000000000000000000000000000000000008152336004820181905263ffffffff8a166024830152906001600160801b03808c16916001600160a01b038e16917f3d73a0206d94d61b7038abcd0eb766a5de22f9844b38a78449054d19a4f1b58a9183916340c10f1991908b169060440160206040518083038185885af1158015611ec1573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611ee6919061289b565b6040805163ffffffff9283168152918e1660208301526001600160801b038b8116838301528981166060840152871660808301526001600160a01b038d1660a083015287151560c0830152519081900360e00190a4846001600160801b0316341115611f6157611f6133866001600160801b03163403611b21565b50505050505050505050565b600084806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd2919061287e565b6001600160a01b0316336001600160a01b0316141580156120cf5750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561203c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612060919061289b565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa1580156120a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120cd91906128b4565b155b156120ec576040516282b42960e81b815260040160405180910390fd5b84848063ffffffff168263ffffffff161061211a5760405163536a71af60e01b815260040160405180910390fd5b8461271061ffff8216111561214257604051631a52ce6f60e01b815260040160405180910390fd5b600080546001600160a01b038b1682526001602081815260408085206001600160801b0390941680865293909152909220805461ffff8a16680100000000000000000269ffff00000000000000001963ffffffff8d81166401000000000267ffffffffffffffff19909416908f16179290921791909116178155909650906121cb9087906128d1565b600080546fffffffffffffffffffffffffffffffff19166001600160801b0392831617905560408051918816825263ffffffff808c1660208401528a169082015261ffff8816606082015233906001600160a01b038c16907feeb5941fb79bbfe40edd76c2e086e8ccdb0b463fc8ac07416266100b4dfddccf9060800160405180910390a35050505050949350505050565b6040517f0d411b210000000000000000000000000000000000000000000000000000000081526001600160801b038216600482015260009081906001600160a01b037f00000000000000000000000061353b0c3c3aae4e6c9e4e9fcde4a4be4417d2fa1690630d411b2190602401602060405180830381865afa1580156122e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061230c919061291f565b600080546001600160801b03600160801b8083048216850182160291161790559283900393915050565b60006020828403121561234857600080fd5b81356001600160e01b03198116811461236057600080fd5b9392505050565b6001600160a01b038116811461073f57600080fd5b803561238781612367565b919050565b6001600160801b038116811461073f57600080fd5b600080604083850312156123b457600080fd5b82356123bf81612367565b915060208301356123cf8161238c565b809150509250929050565b60006101208201905063ffffffff808451168352806020850151166020840152506040830151612410604084018261ffff169052565b506060830151612424606084018215159052565b50608083015161244460808401826bffffffffffffffffffffffff169052565b5060a083015161245c60a084018263ffffffff169052565b5060c083015161247460c084018263ffffffff169052565b5060e083015161248c60e084018263ffffffff169052565b5061010092830151919092015290565b803563ffffffff8116811461238757600080fd5b6000806000606084860312156124c557600080fd5b83356124d081612367565b925060208401356124e08161238c565b91506124ee6040850161249c565b90509250925092565b60008060008060008060a0878903121561251057600080fd5b863561251b81612367565b9550602087013561252b8161238c565b94506125396040880161249c565b9350606087013567ffffffffffffffff8082111561255657600080fd5b818901915089601f83011261256a57600080fd5b81358181111561257957600080fd5b8a60208260051b850101111561258e57600080fd5b6020830195508094505050506125a66080880161237c565b90509295509295509295565b801515811461073f57600080fd5b6000806000606084860312156125d557600080fd5b83356125e081612367565b925060208401356125f08161238c565b91506040840135612600816125b2565b809150509250925092565b60006020828403121561261d57600080fd5b813561236081612367565b6000806000806080858703121561263e57600080fd5b843561264981612367565b935060208501356126598161238c565b92506126676040860161249c565b91506126756060860161249c565b905092959194509250565b6000806000806080858703121561269657600080fd5b84356126a181612367565b935060208501356126b18161238c565b9250604085013561266781612367565b80356bffffffffffffffffffffffff8116811461238757600080fd5b803561ffff8116811461238757600080fd5b600080600080600080600080610100898b03121561270c57600080fd5b883561271781612367565b97506020890135965061272c60408a016126c1565b955061273a60608a0161249c565b945061274860808a0161249c565b935061275660a08a016126dd565b925061276460c08a0161249c565b915061277260e08a0161249c565b90509295985092959890939650565b60008060006060848603121561279657600080fd5b83356127a181612367565b925060208401356127b18161238c565b929592945050506040919091013590565b6000806000606084860312156127d757600080fd5b83356127e281612367565b925060208401356127f28161238c565b9150604084013561260081612367565b60008060006060848603121561281757600080fd5b833561282281612367565b925060208401356128328161238c565b91506124ee604085016126dd565b60008060006060848603121561285557600080fd5b833561286081612367565b925060208401356128708161238c565b91506124ee604085016126c1565b60006020828403121561289057600080fd5b815161236081612367565b6000602082840312156128ad57600080fd5b5051919050565b6000602082840312156128c657600080fd5b8151612360816125b2565b6001600160801b03818116838216019080821115612918577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5092915050565b60006020828403121561293157600080fd5b81516123608161238c56fea26469706673582212207b1aa8a3f201b60fe5339796d01136dbce207658848a084d80b13521cf75f1ec64736f6c63430008100033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000061353b0c3c3aae4e6c9e4e9fcde4a4be4417d2fa
-----Decoded View---------------
Arg [0] : feeRegistry_ (address): 0x61353B0C3C3AAe4e6c9e4e9FcDe4a4BE4417D2FA
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000061353b0c3c3aae4e6c9e4e9fcde4a4be4417d2fa
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.