Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 448 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Mint | 17371714 | 542 days ago | IN | 0.07 ETH | 0.00490216 | ||||
Mint | 17371700 | 542 days ago | IN | 0.07 ETH | 0.00458808 | ||||
Mint | 17370270 | 542 days ago | IN | 0.07 ETH | 0.00491571 | ||||
Mint | 17316948 | 550 days ago | IN | 0.07 ETH | 0.00585812 | ||||
Mint | 17308325 | 551 days ago | IN | 0.07 ETH | 0.00424181 | ||||
Mint | 17282285 | 555 days ago | IN | 0.07 ETH | 0.00782411 | ||||
Mint | 17276892 | 556 days ago | IN | 0.07 ETH | 0.00599343 | ||||
Mint | 17276888 | 556 days ago | IN | 0.07 ETH | 0.00547604 | ||||
Mint | 17276880 | 556 days ago | IN | 0.07 ETH | 0.00567391 | ||||
Mint | 17266443 | 557 days ago | IN | 0.07 ETH | 0.00889988 | ||||
Mint | 17266436 | 557 days ago | IN | 0.07 ETH | 0.00901795 | ||||
Mint | 17177127 | 570 days ago | IN | 0.005 ETH | 0.00860632 | ||||
Mint | 17166262 | 571 days ago | IN | 0.07 ETH | 0.00941244 | ||||
Mint | 17123535 | 577 days ago | IN | 0.07 ETH | 0.0052476 | ||||
Mint | 17039502 | 589 days ago | IN | 0.07 ETH | 0.00392953 | ||||
Mint | 17039500 | 589 days ago | IN | 0.07 ETH | 0.00404319 | ||||
Mint | 17039498 | 589 days ago | IN | 0.07 ETH | 0.0042864 | ||||
Mint | 17032358 | 590 days ago | IN | 0.005 ETH | 0.00282093 | ||||
Mint | 17028467 | 591 days ago | IN | 0.07 ETH | 0.00252271 | ||||
Mint | 17028462 | 591 days ago | IN | 0.07 ETH | 0.0024829 | ||||
Mint | 16967399 | 599 days ago | IN | 0.07 ETH | 0.00235873 | ||||
Mint | 16944613 | 603 days ago | IN | 0.04 ETH | 0.00288035 | ||||
Mint | 16944568 | 603 days ago | IN | 0.04 ETH | 0.00261047 | ||||
Mint | 16889438 | 610 days ago | IN | 0.07 ETH | 0.00147192 | ||||
Mint | 16888227 | 611 days ago | IN | 0.07 ETH | 0.00131639 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
17371714 | 542 days ago | 0.07 ETH | ||||
17371700 | 542 days ago | 0.07 ETH | ||||
17370270 | 542 days ago | 0.07 ETH | ||||
17316948 | 550 days ago | 0.07 ETH | ||||
17308325 | 551 days ago | 0.07 ETH | ||||
17282285 | 555 days ago | 0.07 ETH | ||||
17276892 | 556 days ago | 0.07 ETH | ||||
17276888 | 556 days ago | 0.07 ETH | ||||
17276880 | 556 days ago | 0.07 ETH | ||||
17266443 | 557 days ago | 0.07 ETH | ||||
17266436 | 557 days ago | 0.07 ETH | ||||
17177127 | 570 days ago | 0.005 ETH | ||||
17166262 | 571 days ago | 0.07 ETH | ||||
17123535 | 577 days ago | 0.07 ETH | ||||
17039502 | 589 days ago | 0.07 ETH | ||||
17039500 | 589 days ago | 0.07 ETH | ||||
17039498 | 589 days ago | 0.07 ETH | ||||
17032358 | 590 days ago | 0.005 ETH | ||||
17028467 | 591 days ago | 0.07 ETH | ||||
17028462 | 591 days ago | 0.07 ETH | ||||
16967399 | 599 days ago | 0.07 ETH | ||||
16944613 | 603 days ago | 0.04 ETH | ||||
16944568 | 603 days ago | 0.04 ETH | ||||
16889438 | 610 days ago | 0.07 ETH | ||||
16888227 | 611 days ago | 0.07 ETH |
Loading...
Loading
Contract Name:
RangeEditionMinter
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 { IERC165 } from "openzeppelin/utils/introspection/IERC165.sol"; import { ISoundFeeRegistry } from "@core/interfaces/ISoundFeeRegistry.sol"; import { IRangeEditionMinter, EditionMintData, MintInfo } from "./interfaces/IRangeEditionMinter.sol"; import { BaseMinter } from "./BaseMinter.sol"; import { IMinterModule } from "@core/interfaces/IMinterModule.sol"; import { ISoundEditionV1 } from "@core/interfaces/ISoundEditionV1.sol"; /* * @title RangeEditionMinter * @notice Module for range edition mints of Sound editions. * @author Sound.xyz */ contract RangeEditionMinter is IRangeEditionMinter, BaseMinter { // ============================================================= // STORAGE // ============================================================= /** * @dev Edition mint data * edition => mintId => EditionMintData */ mapping(address => mapping(uint128 => EditionMintData)) internal _editionMintData; // ============================================================= // CONSTRUCTOR // ============================================================= constructor(ISoundFeeRegistry feeRegistry_) BaseMinter(feeRegistry_) {} // ============================================================= // PUBLIC / EXTERNAL WRITE FUNCTIONS // ============================================================= /** * @inheritdoc IRangeEditionMinter */ function createEditionMint( address edition, uint96 price, uint32 startTime, uint32 cutoffTime, uint32 endTime, uint16 affiliateFeeBPS, uint32 maxMintableLower, uint32 maxMintableUpper, uint32 maxMintablePerAccount ) public onlyValidCombinedTimeRange(startTime, cutoffTime, endTime) returns (uint128 mintId) { if (maxMintableLower > maxMintableUpper) revert InvalidMaxMintableRange(); if (maxMintablePerAccount == 0) revert MaxMintablePerAccountIsZero(); mintId = _createEditionMint(edition, startTime, endTime, affiliateFeeBPS); EditionMintData storage data = _editionMintData[edition][mintId]; data.price = price; data.cutoffTime = cutoffTime; data.maxMintableLower = maxMintableLower; data.maxMintableUpper = maxMintableUpper; data.maxMintablePerAccount = maxMintablePerAccount; // prettier-ignore emit RangeEditionMintCreated( edition, mintId, price, startTime, cutoffTime, endTime, affiliateFeeBPS, maxMintableLower, maxMintableUpper, maxMintablePerAccount ); } /** * @inheritdoc IRangeEditionMinter */ function mint( address edition, uint128 mintId, uint32 quantity, address affiliate ) public payable { EditionMintData storage data = _editionMintData[edition][mintId]; uint32 _maxMintable = _getMaxMintable(data); // Increase `totalMinted` by `quantity`. // Require that the increased value does not exceed `maxMintable`. data.totalMinted = _incrementTotalMinted(data.totalMinted, quantity, _maxMintable); 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 + quantity > data.maxMintablePerAccount) revert ExceedsMaxPerAccount(); } _mint(edition, mintId, quantity, affiliate); } /** * @inheritdoc IRangeEditionMinter */ function setTimeRange( address edition, uint128 mintId, uint32 startTime, uint32 cutoffTime, uint32 endTime ) public onlyEditionOwnerOrAdmin(edition) onlyValidCombinedTimeRange(startTime, cutoffTime, endTime) { // Set cutoffTime first, as its stored value gets validated later in the execution. EditionMintData storage data = _editionMintData[edition][mintId]; data.cutoffTime = cutoffTime; // This calls the overriden `setTimeRange`, which will check that // `startTime < cutoffTime < endTime`. RangeEditionMinter.setTimeRange(edition, mintId, startTime, endTime); emit CutoffTimeSet(edition, mintId, cutoffTime); } /** * @inheritdoc BaseMinter */ function setTimeRange( address edition, uint128 mintId, uint32 startTime, uint32 endTime ) public override(BaseMinter, IMinterModule) onlyEditionOwnerOrAdmin(edition) { EditionMintData storage data = _editionMintData[edition][mintId]; if (!(startTime < data.cutoffTime && data.cutoffTime < endTime)) revert InvalidTimeRange(); BaseMinter.setTimeRange(edition, mintId, startTime, endTime); } /** * @inheritdoc IRangeEditionMinter */ function setMaxMintableRange( address edition, uint128 mintId, uint32 maxMintableLower, uint32 maxMintableUpper ) public onlyEditionOwnerOrAdmin(edition) { if (maxMintableLower > maxMintableUpper) revert InvalidMaxMintableRange(); EditionMintData storage data = _editionMintData[edition][mintId]; data.maxMintableLower = maxMintableLower; data.maxMintableUpper = maxMintableUpper; emit MaxMintableRangeSet(edition, mintId, maxMintableLower, maxMintableUpper); } /** * @inheritdoc IRangeEditionMinter */ function setPrice( address edition, uint128 mintId, uint96 price ) public onlyEditionOwnerOrAdmin(edition) { _editionMintData[edition][mintId].price = price; emit PriceSet(edition, mintId, price); } /** * @inheritdoc IRangeEditionMinter */ 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); } // ============================================================= // 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 IRangeEditionMinter */ 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.maxMintableUpper, mintData.maxMintableLower, mintData.maxMintablePerAccount, mintData.totalMinted, mintData.cutoffTime ); return combinedMintData; } /** * @inheritdoc IERC165 */ function supportsInterface(bytes4 interfaceId) public view override(IERC165, BaseMinter) returns (bool) { return BaseMinter.supportsInterface(interfaceId) || interfaceId == type(IRangeEditionMinter).interfaceId; } /** * @inheritdoc IMinterModule */ function moduleInterfaceId() public pure returns (bytes4) { return type(IRangeEditionMinter).interfaceId; } // ============================================================= // INTERNAL / PRIVATE HELPERS // ============================================================= /** * @dev Restricts the `startTime` to be less than `cutoffTime`, * and `cutoffTime` to be less than `endTime`. * @param startTime The start unix timestamp of the mint. * @param cutoffTime The cutoff unix timestamp of the mint. * @param endTime The end unix timestamp of the mint. */ modifier onlyValidCombinedTimeRange( uint32 startTime, uint32 cutoffTime, uint32 endTime ) { if (!(startTime < cutoffTime && cutoffTime < endTime)) revert InvalidTimeRange(); _; } /** * @dev Gets the current maximum mintable quantity. * @param data The edition mint data. * @return The computed value. */ function _getMaxMintable(EditionMintData storage data) internal view returns (uint32) { uint32 _maxMintable; if (block.timestamp < data.cutoffTime) { _maxMintable = data.maxMintableUpper; } else { _maxMintable = data.maxMintableLower; } return _maxMintable; } }
// 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 { IMinterModule } from "@core/interfaces/IMinterModule.sol"; /** * @dev Data unique to a range edition mint. */ struct EditionMintData { // The price at which each token will be sold, in ETH. uint96 price; // The timestamp (in seconds since unix epoch) after which the // max amount of tokens mintable will drop from // `maxMintableUpper` to `maxMintableLower`. uint32 cutoffTime; // The total number of tokens minted. Includes permissioned mints. uint32 totalMinted; // The lower limit of the maximum number of tokens that can be minted. uint32 maxMintableLower; // The upper limit of the maximum number of tokens that can be minted. uint32 maxMintableUpper; // The maximum number of tokens that a wallet can mint. uint32 maxMintablePerAccount; } /** * @dev All the information about a range edition mint (combines EditionMintData with BaseData). */ struct MintInfo { uint32 startTime; uint32 endTime; uint16 affiliateFeeBPS; bool mintPaused; uint96 price; uint32 maxMintableUpper; uint32 maxMintableLower; uint32 maxMintablePerAccount; uint32 totalMinted; uint32 cutoffTime; } /** * @title IRangeEditionMinter * @dev Interface for the `RangeEditionMinter` module. * @author Sound.xyz */ interface IRangeEditionMinter is IMinterModule { // ============================================================= // EVENTS // ============================================================= /** * @dev Emitted when a range edition is created. * @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`. * @param startTime Start timestamp of sale (in seconds since unix epoch). * @param cutoffTime The timestamp (in seconds since unix epoch) after which the * max amount of tokens mintable will drop from * `maxMintableUpper` to `maxMintableLower`. * @param endTime End timestamp of sale (in seconds since unix epoch). * @param affiliateFeeBPS The affiliate fee in basis points. * @param maxMintableLower The lower limit of the maximum number of tokens that can be minted. * @param maxMintableUpper The upper limit of the maximum number of tokens that can be minted. */ event RangeEditionMintCreated( address indexed edition, uint128 indexed mintId, uint96 price, uint32 startTime, uint32 cutoffTime, uint32 endTime, uint16 affiliateFeeBPS, uint32 maxMintableLower, uint32 maxMintableUpper, uint32 maxMintablePerAccount ); event CutoffTimeSet(address indexed edition, uint128 indexed mintId, uint32 cutoffTime); /** * @dev Emitted when the max mintable range is updated. * @param edition Address of the song edition contract we are minting for. * @param mintId The mint ID. * @param maxMintableLower The lower limit of the maximum number of tokens that can be minted. * @param maxMintableUpper The upper limit of the maximum number of tokens that can be minted. */ event MaxMintableRangeSet( address indexed edition, uint128 indexed mintId, uint32 maxMintableLower, uint32 maxMintableUpper ); /** * @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 `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); // ============================================================= // ERRORS // ============================================================= /** * @dev The `maxMintableLower` must not be greater than `maxMintableUpper`. */ error InvalidMaxMintableRange(); /** * @dev The number of tokens minted has exceeded the number allowed for each account. */ error ExceedsMaxPerAccount(); /** * @dev The max mintable per account cannot be zero. */ error MaxMintablePerAccountIsZero(); // ============================================================= // PUBLIC / EXTERNAL WRITE FUNCTIONS // ============================================================= /* * @dev Initializes a range mint instance * @param edition Address of the song edition contract we are minting for. * @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 cutoffTime The timestamp (in seconds since unix epoch) after which the * max amount of tokens mintable will drop from * `maxMintableUpper` to `maxMintableLower`. * @param endTime End timestamp of sale (in seconds since unix epoch). * @param affiliateFeeBPS The affiliate fee in basis points. * @param maxMintableLower The lower limit of the maximum number of tokens that can be minted. * @param maxMintableUpper The upper limit of the maximum number of tokens that can be minted. * @param maxMintablePerAccount_ The maximum number of tokens that can be minted by an account. * @return mintId The ID for the new mint instance. */ function createEditionMint( address edition, uint96 price, uint32 startTime, uint32 cutoffTime, uint32 endTime, uint16 affiliateFeeBPS, uint32 maxMintableLower, uint32 maxMintableUpper, uint32 maxMintablePerAccount_ ) external returns (uint128 mintId); /* * @dev Sets the time range. * @param edition Address of the song edition contract we are minting for. * @param startTime Start timestamp of sale (in seconds since unix epoch). * @param cutoffTime The timestamp (in seconds since unix epoch) after which the * max amount of tokens mintable will drop from * `maxMintableUpper` to `maxMintableLower`. * @param endTime End timestamp of sale (in seconds since unix epoch). */ function setTimeRange( address edition, uint128 mintId, uint32 startTime, uint32 cutoffTime, uint32 endTime ) external; /* * @dev Sets the max mintable range. * @param edition Address of the song edition contract we are minting for. * @param maxMintableLower The lower limit of the maximum number of tokens that can be minted. * @param maxMintableUpper The upper limit of the maximum number of tokens that can be minted. */ function setMaxMintableRange( address edition, uint128 mintId, uint32 maxMintableLower, uint32 maxMintableUpper ) external; /* * @dev Mints tokens for a given edition. * @param edition Address of the song edition contract we are minting for. * @param quantity Token quantity to mint in song `edition`. */ function mint( address edition, uint128 mintId, uint32 quantity, 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; // ============================================================= // PUBLIC / EXTERNAL VIEW FUNCTIONS // ============================================================= /** * @dev Returns {IRangeEditionMinter.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 { 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 { 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":"InvalidMaxMintableRange","type":"error"},{"inputs":[],"name":"InvalidTimeRange","type":"error"},{"inputs":[],"name":"MaxMintablePerAccountIsZero","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":true,"internalType":"address","name":"edition","type":"address"},{"indexed":true,"internalType":"uint128","name":"mintId","type":"uint128"},{"indexed":false,"internalType":"uint32","name":"cutoffTime","type":"uint32"}],"name":"CutoffTimeSet","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":"maxMintableLower","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"maxMintableUpper","type":"uint32"}],"name":"MaxMintableRangeSet","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":"uint96","name":"price","type":"uint96"},{"indexed":false,"internalType":"uint32","name":"startTime","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"cutoffTime","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"endTime","type":"uint32"},{"indexed":false,"internalType":"uint16","name":"affiliateFeeBPS","type":"uint16"},{"indexed":false,"internalType":"uint32","name":"maxMintableLower","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"maxMintableUpper","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"maxMintablePerAccount","type":"uint32"}],"name":"RangeEditionMintCreated","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":"uint96","name":"price","type":"uint96"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"cutoffTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint16","name":"affiliateFeeBPS","type":"uint16"},{"internalType":"uint32","name":"maxMintableLower","type":"uint32"},{"internalType":"uint32","name":"maxMintableUpper","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":"quantity","type":"uint32"},{"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":"maxMintableUpper","type":"uint32"},{"internalType":"uint32","name":"maxMintableLower","type":"uint32"},{"internalType":"uint32","name":"maxMintablePerAccount","type":"uint32"},{"internalType":"uint32","name":"totalMinted","type":"uint32"},{"internalType":"uint32","name":"cutoffTime","type":"uint32"}],"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":"maxMintablePerAccount","type":"uint32"}],"name":"setMaxMintablePerAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"},{"internalType":"uint32","name":"maxMintableLower","type":"uint32"},{"internalType":"uint32","name":"maxMintableUpper","type":"uint32"}],"name":"setMaxMintableRange","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":"address","name":"edition","type":"address"},{"internalType":"uint128","name":"mintId","type":"uint128"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"cutoffTime","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
60a06040523480156200001157600080fd5b5060405162002cf938038062002cf9833981016040819052620000349162000070565b806001600160a01b0381166200005d57604051636cdc033760e11b815260040160405180910390fd5b6001600160a01b031660805250620000a2565b6000602082840312156200008357600080fd5b81516001600160a01b03811681146200009b57600080fd5b9392505050565b608051612c2d620000cc60003960008181610491015281816106da01526125680152612c2d6000f3fe60806040526004361061016a5760003560e01c8063b3a408b8116100cb578063c7dd32281161007f578063f574029611610059578063f5740296146105f2578063fc63e69e14610612578063fd967f471461063257600080fd5b8063c7dd322814610584578063c94dcf8f146105a6578063d73f3aab146105d257600080fd5b8063b40bf08e116100b0578063b40bf08e146104de578063b84158a4146104fe578063bf9c0e561461056457600080fd5b8063b3a408b81461047f578063b3b34f99146104cb57600080fd5b80636aa99da3116101225780637cbf126b116101075780637cbf126b14610400578063ac1fc22c14610420578063aec96b6e1461045f57600080fd5b80636aa99da3146103c25780637614a751146103e057600080fd5b806308bfa2bf1161015357806308bfa2bf1461035257806322163b8614610369578063522f7386146103a257600080fd5b806301ffc9a71461016f57806303a6ccd0146101a4575b600080fd5b34801561017b57600080fd5b5061018f61018a3660046125fd565b61064f565b60405190151581526020015b60405180910390f35b3480156101b057600080fd5b506103456101bf366004612658565b6040805161014081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810191909152506001600160a01b03821660008181526001602090815260408083206001600160801b038616808552908352818420825160808082018552915463ffffffff80821683526401000000008204811683880190815261ffff680100000000000000008404811685890190815260ff6a010000000000000000000090950494909416151560608087019182529b8b5260038a52888b20978b52968952988790208751610140810189529451831685529051821697840197909752905190961693810193909352905115159482019490945290546bffffffffffffffffffffffff811693820193909352600160c01b8304821660a0820152600160a01b8304821660c0820152600160e01b8304821660e0820152600160801b83048216610100820152600160601b9092041661012082015292915050565b60405161019b9190612691565b34801561035e57600080fd5b5061036761067b565b005b34801561037557600080fd5b50600054600160801b90046001600160801b03165b6040516001600160801b03909116815260200161019b565b3480156103ae57600080fd5b506103676103bd366004612781565b610753565b3480156103ce57600080fd5b506000546001600160801b031661038a565b3480156103ec57600080fd5b506103676103fb3660046127e5565b610965565b34801561040c57600080fd5b5061038a61041b36600461285a565b610ba8565b34801561042c57600080fd5b5061038a61043b366004612904565b6001600160a01b03166000908152600260205260409020546001600160801b031690565b34801561046b57600080fd5b5061036761047a366004612921565b610e19565b34801561048b57600080fd5b506104b37f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161019b565b6103676104d9366004612979565b611024565b3480156104ea57600080fd5b506103676104f9366004612921565b611191565b34801561050a57600080fd5b5061038a6105193660046129d3565b6001600160a01b03841660009081526003602090815260408083206001600160801b03871684529091529020546bffffffffffffffffffffffff1663ffffffff821602949350505050565b34801561057057600080fd5b5061036761057f366004612a14565b611410565b34801561059057600080fd5b50604051634d4a2e3560e01b815260200161019b565b3480156105b257600080fd5b5061018f6105c1366004612a7d565b6001600160a01b0316151592915050565b3480156105de57600080fd5b506103676105ed366004612abd565b61169a565b3480156105fe57600080fd5b5061036761060d366004612904565b6118d0565b34801561061e57600080fd5b5061036761062d366004612afb565b611935565b34801561063e57600080fd5b50604051612710815260200161019b565b600061065a82611b37565b8061067557506001600160e01b03198216634d4a2e3560e01b145b92915050565b600054600160801b90046001600160801b0316801561075057600080546001600160801b03169055604080517f946f7c9e0000000000000000000000000000000000000000000000000000000081529051610750916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163946f7c9e916004808201926020929091908290030181865afa158015610726573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074a9190612b39565b82611b9f565b50565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610792573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b69190612b39565b6001600160a01b0316336001600160a01b0316141580156108b35750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610820573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108449190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa15801561088d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b19190612b6f565b155b156108d0576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03841660008181526001602090815260408083206001600160801b0388168085529083529281902080546aff0000000000000000000019166a0100000000000000000000881515908102919091179091558151938452918301919091527fe430910c8e4bfa8180b70a0b2aa923b82d6712a1d165e223053ef439a3f86147910160405180910390a250505050565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c89190612b39565b6001600160a01b0316336001600160a01b031614158015610ac55750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a569190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610a9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac39190612b6f565b155b15610ae2576040516282b42960e81b815260040160405180910390fd5b8163ffffffff16600003610b095760405163a017714560e01b815260040160405180910390fd5b6001600160a01b03841660008181526003602090815260408083206001600160801b0388168085529083529281902080547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160e01b63ffffffff89169081029190911790915590519081529192917f021f3ca4d64a14574ed4fc7115d2c667604e54efb94b6187ed8117d49c6e475591015b60405180910390a350505050565b60008787878163ffffffff168363ffffffff16108015610bd357508063ffffffff168263ffffffff16105b610bf05760405163536a71af60e01b815260040160405180910390fd5b8563ffffffff168763ffffffff161115610c1d57604051633a964d4760e01b815260040160405180910390fd5b8463ffffffff16600003610c445760405163a017714560e01b815260040160405180910390fd5b610c508d8c8b8b611bbb565b93506000600360008f6001600160a01b03166001600160a01b031681526020019081526020016000206000866001600160801b03166001600160801b0316815260200190815260200160002090508c8160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508a81600001600c6101000a81548163ffffffff021916908363ffffffff160217905550878160000160146101000a81548163ffffffff021916908363ffffffff160217905550868160000160186101000a81548163ffffffff021916908363ffffffff1602179055508581600001601c6101000a81548163ffffffff021916908363ffffffff160217905550846001600160801b03168e6001600160a01b03167f9a9e0edce33a498fe7d57bfc9e7b46f9a2cd45507d8853c0c18c4c7bd860798c8f8f8f8f8f8f8f8f604051610e009897969594939291906bffffffffffffffffffffffff98909816885263ffffffff96871660208901529486166040880152928516606087015261ffff919091166080860152831660a0850152821660c08401521660e08201526101000190565b60405180910390a3505050509998505050505050505050565b83806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7c9190612b39565b6001600160a01b0316336001600160a01b031614158015610f795750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0a9190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610f53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f779190612b6f565b155b15610f96576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03851660009081526003602090815260408083206001600160801b03881684529091529020805463ffffffff600160601b9091048116908516108015610ff35750805463ffffffff808516600160601b90920416105b6110105760405163536a71af60e01b815260040160405180910390fd5b61101c86868686611eab565b505050505050565b6001600160a01b03841660009081526003602090815260408083206001600160801b038716845290915281209061105a826120ee565b825490915061107790600160801b900463ffffffff168583612131565b825463ffffffff91909116600160801b027fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff9091161782556040517fdc33e6810000000000000000000000000000000000000000000000000000000081523360048201526000906001600160a01b0388169063dc33e68190602401602060405180830381865afa15801561110f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111339190612b56565b835490915063ffffffff600160e01b909104811690861682011115611184576040517f1b75136500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5061101c868686866121af565b83806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f49190612b39565b6001600160a01b0316336001600160a01b0316141580156112f15750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561125e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112829190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa1580156112cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ef9190612b6f565b155b1561130e576040516282b42960e81b815260040160405180910390fd5b8163ffffffff168363ffffffff16111561133b57604051633a964d4760e01b815260040160405180910390fd5b6001600160a01b03851660008181526003602090815260408083206001600160801b0389168085529083529281902080547fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff16600160a01b63ffffffff8a81169182027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff1692909217600160c01b928a1692830217835583519081529384015293917f6d809c5e613207ec6ca68c0d872f18cf6e493a727c39e150f185b4b6d13be977910160405180910390a3505050505050565b84806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561144f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114739190612b39565b6001600160a01b0316336001600160a01b0316141580156115705750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115019190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa15801561154a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156e9190612b6f565b155b1561158d576040516282b42960e81b815260040160405180910390fd5b8383838163ffffffff168363ffffffff161080156115b657508063ffffffff168263ffffffff16105b6115d35760405163536a71af60e01b815260040160405180910390fd5b6001600160a01b03891660009081526003602090815260408083206001600160801b038c168452909152902080547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff16600160601b63ffffffff89160217815561163f8a8a8a89610e19565b60405163ffffffff881681526001600160801b038a16906001600160a01b038c16907f33bbd71c3e2f573cc929e30067dcf5801791814427f844484fa25dee910d13529060200160405180910390a350505050505050505050565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116fd9190612b39565b6001600160a01b0316336001600160a01b0316141580156117fa5750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611767573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061178b9190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa1580156117d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f89190612b6f565b155b15611817576040516282b42960e81b815260040160405180910390fd5b8161271061ffff8216111561183f57604051631a52ce6f60e01b815260040160405180910390fd5b6001600160a01b03851660008181526001602090815260408083206001600160801b03891680855290835292819020805469ffff000000000000000019166801000000000000000061ffff8a169081029190911790915590519081529192917fae6d744348a49699fcb91e6a563f2224c0fb27c21053a9218ee827f9d6e698c7910160405180910390a35050505050565b6001600160a01b0381166000908152600260205260409020546001600160801b03168015611931576001600160a01b038216600090815260026020526040902080546fffffffffffffffffffffffffffffffff191690556119318282611b9f565b5050565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611974573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119989190612b39565b6001600160a01b0316336001600160a01b031614158015611a955750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a269190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611a6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a939190612b6f565b155b15611ab2576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03841660008181526003602090815260408083206001600160801b0388168085529083529281902080546bffffffffffffffffffffffff19166bffffffffffffffffffffffff881690811790915590519081529192917f7c77af090cbae157811da55b6d8ae1e307a85f5aa1dd2f7a13183279a8c2b4b29101610b9a565b60006001600160e01b031982167f37c74bd800000000000000000000000000000000000000000000000000000000148061067557506001600160e01b031982167f01ffc9a7000000000000000000000000000000000000000000000000000000001492915050565b60008060008084865af16119315763b12d13eb6000526004601cfd5b600084806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c209190612b39565b6001600160a01b0316336001600160a01b031614158015611d1d5750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cae9190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611cf7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d1b9190612b6f565b155b15611d3a576040516282b42960e81b815260040160405180910390fd5b84848063ffffffff168263ffffffff1610611d685760405163536a71af60e01b815260040160405180910390fd5b8461271061ffff82161115611d9057604051631a52ce6f60e01b815260040160405180910390fd5b600080546001600160a01b038b1682526001602081815260408085206001600160801b0390941680865293909152909220805461ffff8a16680100000000000000000269ffff00000000000000001963ffffffff8d81166401000000000267ffffffffffffffff19909416908f1617929092179190911617815590965090611e19908790612b8c565b600080546fffffffffffffffffffffffffffffffff19166001600160801b0392831617905560408051918816825263ffffffff808c1660208401528a169082015261ffff8816606082015233906001600160a01b038c16907feeb5941fb79bbfe40edd76c2e086e8ccdb0b463fc8ac07416266100b4dfddccf9060800160405180910390a35050505050949350505050565b83806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611eea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f0e9190612b39565b6001600160a01b0316336001600160a01b03161415801561200b5750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9c9190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611fe5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120099190612b6f565b155b15612028576040516282b42960e81b815260040160405180910390fd5b82828063ffffffff168263ffffffff16106120565760405163536a71af60e01b815260040160405180910390fd5b6001600160a01b03871660008181526001602090815260408083206001600160801b038b1680855290835292819020805463ffffffff8b811667ffffffffffffffff199092168217640100000000918c16918202179092558251908152928301529192917f13bc03d97cc4e2accb3b8290af069c19619d32a4e9c5219f8580108766fb18fd910160405180910390a350505050505050565b80546000908190600160601b900463ffffffff1642101561211e57508154600160c01b900463ffffffff16610675565b505054600160a01b900463ffffffff1690565b600063ffffffff848116818516019083168111156121a75760006121658463ffffffff168763ffffffff1680821191030290565b6040517fbdc0f4ce00000000000000000000000000000000000000000000000000000000815263ffffffff821660048201529091506024015b60405180910390fd5b949350505050565b6001600160a01b03841660009081526001602090815260408083206001600160801b03871684529091529020805463ffffffff80821691640100000000900416428211156122265760405163296f4f6960e01b815242600482015263ffffffff80841660248301528216604482015260640161219e565b8063ffffffff164211156122635760405163296f4f6960e01b815242600482015263ffffffff80841660248301528216604482015260640161219e565b82546a0100000000000000000000900460ff16156122ad576040517fd7d248ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50506001600160a01b03851660009081526003602090815260408083206001600160801b03881684529091528120546bffffffffffffffffffffffff1663ffffffff8516029050806001600160801b0316341015612348576040517ff3ebc3840000000000000000000000000000000000000000000000000000000081523460048201526001600160801b038216602482015260440161219e565b60008061235483612524565b90925090506001600160a01b038516158015906000906123d7575084546001600160a01b038716600090815260026020526040902080546001600160801b0381811661271061ffff68010000000000000000909604959095168883160294909404938401166fffffffffffffffffffffffffffffffff1990911617905592839003925b6040517f40c10f19000000000000000000000000000000000000000000000000000000008152336004820181905263ffffffff8a166024830152906001600160801b03808c16916001600160a01b038e16917f3d73a0206d94d61b7038abcd0eb766a5de22f9844b38a78449054d19a4f1b58a9183916340c10f1991908b169060440160206040518083038185885af1158015612478573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061249d9190612b56565b6040805163ffffffff9283168152918e1660208301526001600160801b038b8116838301528981166060840152871660808301526001600160a01b038d1660a083015287151560c0830152519081900360e00190a4846001600160801b03163411156125185761251833866001600160801b03163403611b9f565b50505050505050505050565b6040517f0d411b210000000000000000000000000000000000000000000000000000000081526001600160801b038216600482015260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690630d411b2190602401602060405180830381865afa1580156125af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125d39190612bda565b600080546001600160801b03600160801b8083048216850182160291161790559283900393915050565b60006020828403121561260f57600080fd5b81356001600160e01b03198116811461262757600080fd5b9392505050565b6001600160a01b038116811461075057600080fd5b6001600160801b038116811461075057600080fd5b6000806040838503121561266b57600080fd5b82356126768161262e565b9150602083013561268681612643565b809150509250929050565b815163ffffffff168152610140810160208301516126b7602084018263ffffffff169052565b5060408301516126cd604084018261ffff169052565b5060608301516126e1606084018215159052565b50608083015161270160808401826bffffffffffffffffffffffff169052565b5060a083015161271960a084018263ffffffff169052565b5060c083015161273160c084018263ffffffff169052565b5060e083015161274960e084018263ffffffff169052565b506101008381015163ffffffff908116918401919091526101209384015116929091019190915290565b801515811461075057600080fd5b60008060006060848603121561279657600080fd5b83356127a18161262e565b925060208401356127b181612643565b915060408401356127c181612773565b809150509250925092565b803563ffffffff811681146127e057600080fd5b919050565b6000806000606084860312156127fa57600080fd5b83356128058161262e565b9250602084013561281581612643565b9150612823604085016127cc565b90509250925092565b80356bffffffffffffffffffffffff811681146127e057600080fd5b803561ffff811681146127e057600080fd5b60008060008060008060008060006101208a8c03121561287957600080fd5b89356128848161262e565b985061289260208b0161282c565b97506128a060408b016127cc565b96506128ae60608b016127cc565b95506128bc60808b016127cc565b94506128ca60a08b01612848565b93506128d860c08b016127cc565b92506128e660e08b016127cc565b91506128f56101008b016127cc565b90509295985092959850929598565b60006020828403121561291657600080fd5b81356126278161262e565b6000806000806080858703121561293757600080fd5b84356129428161262e565b9350602085013561295281612643565b9250612960604086016127cc565b915061296e606086016127cc565b905092959194509250565b6000806000806080858703121561298f57600080fd5b843561299a8161262e565b935060208501356129aa81612643565b92506129b8604086016127cc565b915060608501356129c88161262e565b939692955090935050565b600080600080608085870312156129e957600080fd5b84356129f48161262e565b93506020850135612a0481612643565b925060408501356129608161262e565b600080600080600060a08688031215612a2c57600080fd5b8535612a378161262e565b94506020860135612a4781612643565b9350612a55604087016127cc565b9250612a63606087016127cc565b9150612a71608087016127cc565b90509295509295909350565b600080600060608486031215612a9257600080fd5b8335612a9d8161262e565b92506020840135612aad81612643565b915060408401356127c18161262e565b600080600060608486031215612ad257600080fd5b8335612add8161262e565b92506020840135612aed81612643565b915061282360408501612848565b600080600060608486031215612b1057600080fd5b8335612b1b8161262e565b92506020840135612b2b81612643565b91506128236040850161282c565b600060208284031215612b4b57600080fd5b81516126278161262e565b600060208284031215612b6857600080fd5b5051919050565b600060208284031215612b8157600080fd5b815161262781612773565b6001600160801b03818116838216019080821115612bd3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5092915050565b600060208284031215612bec57600080fd5b81516126278161264356fea2646970667358221220e6e60a5930261afc75edc0eafc3bcbe6158d2e60715a587e5245b26a11628efb64736f6c6343000810003300000000000000000000000061353b0c3c3aae4e6c9e4e9fcde4a4be4417d2fa
Deployed Bytecode
0x60806040526004361061016a5760003560e01c8063b3a408b8116100cb578063c7dd32281161007f578063f574029611610059578063f5740296146105f2578063fc63e69e14610612578063fd967f471461063257600080fd5b8063c7dd322814610584578063c94dcf8f146105a6578063d73f3aab146105d257600080fd5b8063b40bf08e116100b0578063b40bf08e146104de578063b84158a4146104fe578063bf9c0e561461056457600080fd5b8063b3a408b81461047f578063b3b34f99146104cb57600080fd5b80636aa99da3116101225780637cbf126b116101075780637cbf126b14610400578063ac1fc22c14610420578063aec96b6e1461045f57600080fd5b80636aa99da3146103c25780637614a751146103e057600080fd5b806308bfa2bf1161015357806308bfa2bf1461035257806322163b8614610369578063522f7386146103a257600080fd5b806301ffc9a71461016f57806303a6ccd0146101a4575b600080fd5b34801561017b57600080fd5b5061018f61018a3660046125fd565b61064f565b60405190151581526020015b60405180910390f35b3480156101b057600080fd5b506103456101bf366004612658565b6040805161014081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810191909152506001600160a01b03821660008181526001602090815260408083206001600160801b038616808552908352818420825160808082018552915463ffffffff80821683526401000000008204811683880190815261ffff680100000000000000008404811685890190815260ff6a010000000000000000000090950494909416151560608087019182529b8b5260038a52888b20978b52968952988790208751610140810189529451831685529051821697840197909752905190961693810193909352905115159482019490945290546bffffffffffffffffffffffff811693820193909352600160c01b8304821660a0820152600160a01b8304821660c0820152600160e01b8304821660e0820152600160801b83048216610100820152600160601b9092041661012082015292915050565b60405161019b9190612691565b34801561035e57600080fd5b5061036761067b565b005b34801561037557600080fd5b50600054600160801b90046001600160801b03165b6040516001600160801b03909116815260200161019b565b3480156103ae57600080fd5b506103676103bd366004612781565b610753565b3480156103ce57600080fd5b506000546001600160801b031661038a565b3480156103ec57600080fd5b506103676103fb3660046127e5565b610965565b34801561040c57600080fd5b5061038a61041b36600461285a565b610ba8565b34801561042c57600080fd5b5061038a61043b366004612904565b6001600160a01b03166000908152600260205260409020546001600160801b031690565b34801561046b57600080fd5b5061036761047a366004612921565b610e19565b34801561048b57600080fd5b506104b37f00000000000000000000000061353b0c3c3aae4e6c9e4e9fcde4a4be4417d2fa81565b6040516001600160a01b03909116815260200161019b565b6103676104d9366004612979565b611024565b3480156104ea57600080fd5b506103676104f9366004612921565b611191565b34801561050a57600080fd5b5061038a6105193660046129d3565b6001600160a01b03841660009081526003602090815260408083206001600160801b03871684529091529020546bffffffffffffffffffffffff1663ffffffff821602949350505050565b34801561057057600080fd5b5061036761057f366004612a14565b611410565b34801561059057600080fd5b50604051634d4a2e3560e01b815260200161019b565b3480156105b257600080fd5b5061018f6105c1366004612a7d565b6001600160a01b0316151592915050565b3480156105de57600080fd5b506103676105ed366004612abd565b61169a565b3480156105fe57600080fd5b5061036761060d366004612904565b6118d0565b34801561061e57600080fd5b5061036761062d366004612afb565b611935565b34801561063e57600080fd5b50604051612710815260200161019b565b600061065a82611b37565b8061067557506001600160e01b03198216634d4a2e3560e01b145b92915050565b600054600160801b90046001600160801b0316801561075057600080546001600160801b03169055604080517f946f7c9e0000000000000000000000000000000000000000000000000000000081529051610750916001600160a01b037f00000000000000000000000061353b0c3c3aae4e6c9e4e9fcde4a4be4417d2fa169163946f7c9e916004808201926020929091908290030181865afa158015610726573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074a9190612b39565b82611b9f565b50565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610792573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b69190612b39565b6001600160a01b0316336001600160a01b0316141580156108b35750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610820573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108449190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa15801561088d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b19190612b6f565b155b156108d0576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03841660008181526001602090815260408083206001600160801b0388168085529083529281902080546aff0000000000000000000019166a0100000000000000000000881515908102919091179091558151938452918301919091527fe430910c8e4bfa8180b70a0b2aa923b82d6712a1d165e223053ef439a3f86147910160405180910390a250505050565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c89190612b39565b6001600160a01b0316336001600160a01b031614158015610ac55750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a569190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610a9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac39190612b6f565b155b15610ae2576040516282b42960e81b815260040160405180910390fd5b8163ffffffff16600003610b095760405163a017714560e01b815260040160405180910390fd5b6001600160a01b03841660008181526003602090815260408083206001600160801b0388168085529083529281902080547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160e01b63ffffffff89169081029190911790915590519081529192917f021f3ca4d64a14574ed4fc7115d2c667604e54efb94b6187ed8117d49c6e475591015b60405180910390a350505050565b60008787878163ffffffff168363ffffffff16108015610bd357508063ffffffff168263ffffffff16105b610bf05760405163536a71af60e01b815260040160405180910390fd5b8563ffffffff168763ffffffff161115610c1d57604051633a964d4760e01b815260040160405180910390fd5b8463ffffffff16600003610c445760405163a017714560e01b815260040160405180910390fd5b610c508d8c8b8b611bbb565b93506000600360008f6001600160a01b03166001600160a01b031681526020019081526020016000206000866001600160801b03166001600160801b0316815260200190815260200160002090508c8160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508a81600001600c6101000a81548163ffffffff021916908363ffffffff160217905550878160000160146101000a81548163ffffffff021916908363ffffffff160217905550868160000160186101000a81548163ffffffff021916908363ffffffff1602179055508581600001601c6101000a81548163ffffffff021916908363ffffffff160217905550846001600160801b03168e6001600160a01b03167f9a9e0edce33a498fe7d57bfc9e7b46f9a2cd45507d8853c0c18c4c7bd860798c8f8f8f8f8f8f8f8f604051610e009897969594939291906bffffffffffffffffffffffff98909816885263ffffffff96871660208901529486166040880152928516606087015261ffff919091166080860152831660a0850152821660c08401521660e08201526101000190565b60405180910390a3505050509998505050505050505050565b83806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7c9190612b39565b6001600160a01b0316336001600160a01b031614158015610f795750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0a9190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015610f53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f779190612b6f565b155b15610f96576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03851660009081526003602090815260408083206001600160801b03881684529091529020805463ffffffff600160601b9091048116908516108015610ff35750805463ffffffff808516600160601b90920416105b6110105760405163536a71af60e01b815260040160405180910390fd5b61101c86868686611eab565b505050505050565b6001600160a01b03841660009081526003602090815260408083206001600160801b038716845290915281209061105a826120ee565b825490915061107790600160801b900463ffffffff168583612131565b825463ffffffff91909116600160801b027fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff9091161782556040517fdc33e6810000000000000000000000000000000000000000000000000000000081523360048201526000906001600160a01b0388169063dc33e68190602401602060405180830381865afa15801561110f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111339190612b56565b835490915063ffffffff600160e01b909104811690861682011115611184576040517f1b75136500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5061101c868686866121af565b83806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f49190612b39565b6001600160a01b0316336001600160a01b0316141580156112f15750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561125e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112829190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa1580156112cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ef9190612b6f565b155b1561130e576040516282b42960e81b815260040160405180910390fd5b8163ffffffff168363ffffffff16111561133b57604051633a964d4760e01b815260040160405180910390fd5b6001600160a01b03851660008181526003602090815260408083206001600160801b0389168085529083529281902080547fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff16600160a01b63ffffffff8a81169182027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff1692909217600160c01b928a1692830217835583519081529384015293917f6d809c5e613207ec6ca68c0d872f18cf6e493a727c39e150f185b4b6d13be977910160405180910390a3505050505050565b84806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561144f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114739190612b39565b6001600160a01b0316336001600160a01b0316141580156115705750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115019190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa15801561154a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156e9190612b6f565b155b1561158d576040516282b42960e81b815260040160405180910390fd5b8383838163ffffffff168363ffffffff161080156115b657508063ffffffff168263ffffffff16105b6115d35760405163536a71af60e01b815260040160405180910390fd5b6001600160a01b03891660009081526003602090815260408083206001600160801b038c168452909152902080547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff16600160601b63ffffffff89160217815561163f8a8a8a89610e19565b60405163ffffffff881681526001600160801b038a16906001600160a01b038c16907f33bbd71c3e2f573cc929e30067dcf5801791814427f844484fa25dee910d13529060200160405180910390a350505050505050505050565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116fd9190612b39565b6001600160a01b0316336001600160a01b0316141580156117fa5750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611767573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061178b9190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa1580156117d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f89190612b6f565b155b15611817576040516282b42960e81b815260040160405180910390fd5b8161271061ffff8216111561183f57604051631a52ce6f60e01b815260040160405180910390fd5b6001600160a01b03851660008181526001602090815260408083206001600160801b03891680855290835292819020805469ffff000000000000000019166801000000000000000061ffff8a169081029190911790915590519081529192917fae6d744348a49699fcb91e6a563f2224c0fb27c21053a9218ee827f9d6e698c7910160405180910390a35050505050565b6001600160a01b0381166000908152600260205260409020546001600160801b03168015611931576001600160a01b038216600090815260026020526040902080546fffffffffffffffffffffffffffffffff191690556119318282611b9f565b5050565b82806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611974573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119989190612b39565b6001600160a01b0316336001600160a01b031614158015611a955750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a269190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611a6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a939190612b6f565b155b15611ab2576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03841660008181526003602090815260408083206001600160801b0388168085529083529281902080546bffffffffffffffffffffffff19166bffffffffffffffffffffffff881690811790915590519081529192917f7c77af090cbae157811da55b6d8ae1e307a85f5aa1dd2f7a13183279a8c2b4b29101610b9a565b60006001600160e01b031982167f37c74bd800000000000000000000000000000000000000000000000000000000148061067557506001600160e01b031982167f01ffc9a7000000000000000000000000000000000000000000000000000000001492915050565b60008060008084865af16119315763b12d13eb6000526004601cfd5b600084806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c209190612b39565b6001600160a01b0316336001600160a01b031614158015611d1d5750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cae9190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611cf7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d1b9190612b6f565b155b15611d3a576040516282b42960e81b815260040160405180910390fd5b84848063ffffffff168263ffffffff1610611d685760405163536a71af60e01b815260040160405180910390fd5b8461271061ffff82161115611d9057604051631a52ce6f60e01b815260040160405180910390fd5b600080546001600160a01b038b1682526001602081815260408085206001600160801b0390941680865293909152909220805461ffff8a16680100000000000000000269ffff00000000000000001963ffffffff8d81166401000000000267ffffffffffffffff19909416908f1617929092179190911617815590965090611e19908790612b8c565b600080546fffffffffffffffffffffffffffffffff19166001600160801b0392831617905560408051918816825263ffffffff808c1660208401528a169082015261ffff8816606082015233906001600160a01b038c16907feeb5941fb79bbfe40edd76c2e086e8ccdb0b463fc8ac07416266100b4dfddccf9060800160405180910390a35050505050949350505050565b83806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611eea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f0e9190612b39565b6001600160a01b0316336001600160a01b03161415801561200b5750806001600160a01b031663514e62fc33836001600160a01b03166375b238fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9c9190612b56565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015611fe5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120099190612b6f565b155b15612028576040516282b42960e81b815260040160405180910390fd5b82828063ffffffff168263ffffffff16106120565760405163536a71af60e01b815260040160405180910390fd5b6001600160a01b03871660008181526001602090815260408083206001600160801b038b1680855290835292819020805463ffffffff8b811667ffffffffffffffff199092168217640100000000918c16918202179092558251908152928301529192917f13bc03d97cc4e2accb3b8290af069c19619d32a4e9c5219f8580108766fb18fd910160405180910390a350505050505050565b80546000908190600160601b900463ffffffff1642101561211e57508154600160c01b900463ffffffff16610675565b505054600160a01b900463ffffffff1690565b600063ffffffff848116818516019083168111156121a75760006121658463ffffffff168763ffffffff1680821191030290565b6040517fbdc0f4ce00000000000000000000000000000000000000000000000000000000815263ffffffff821660048201529091506024015b60405180910390fd5b949350505050565b6001600160a01b03841660009081526001602090815260408083206001600160801b03871684529091529020805463ffffffff80821691640100000000900416428211156122265760405163296f4f6960e01b815242600482015263ffffffff80841660248301528216604482015260640161219e565b8063ffffffff164211156122635760405163296f4f6960e01b815242600482015263ffffffff80841660248301528216604482015260640161219e565b82546a0100000000000000000000900460ff16156122ad576040517fd7d248ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50506001600160a01b03851660009081526003602090815260408083206001600160801b03881684529091528120546bffffffffffffffffffffffff1663ffffffff8516029050806001600160801b0316341015612348576040517ff3ebc3840000000000000000000000000000000000000000000000000000000081523460048201526001600160801b038216602482015260440161219e565b60008061235483612524565b90925090506001600160a01b038516158015906000906123d7575084546001600160a01b038716600090815260026020526040902080546001600160801b0381811661271061ffff68010000000000000000909604959095168883160294909404938401166fffffffffffffffffffffffffffffffff1990911617905592839003925b6040517f40c10f19000000000000000000000000000000000000000000000000000000008152336004820181905263ffffffff8a166024830152906001600160801b03808c16916001600160a01b038e16917f3d73a0206d94d61b7038abcd0eb766a5de22f9844b38a78449054d19a4f1b58a9183916340c10f1991908b169060440160206040518083038185885af1158015612478573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061249d9190612b56565b6040805163ffffffff9283168152918e1660208301526001600160801b038b8116838301528981166060840152871660808301526001600160a01b038d1660a083015287151560c0830152519081900360e00190a4846001600160801b03163411156125185761251833866001600160801b03163403611b9f565b50505050505050505050565b6040517f0d411b210000000000000000000000000000000000000000000000000000000081526001600160801b038216600482015260009081906001600160a01b037f00000000000000000000000061353b0c3c3aae4e6c9e4e9fcde4a4be4417d2fa1690630d411b2190602401602060405180830381865afa1580156125af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125d39190612bda565b600080546001600160801b03600160801b8083048216850182160291161790559283900393915050565b60006020828403121561260f57600080fd5b81356001600160e01b03198116811461262757600080fd5b9392505050565b6001600160a01b038116811461075057600080fd5b6001600160801b038116811461075057600080fd5b6000806040838503121561266b57600080fd5b82356126768161262e565b9150602083013561268681612643565b809150509250929050565b815163ffffffff168152610140810160208301516126b7602084018263ffffffff169052565b5060408301516126cd604084018261ffff169052565b5060608301516126e1606084018215159052565b50608083015161270160808401826bffffffffffffffffffffffff169052565b5060a083015161271960a084018263ffffffff169052565b5060c083015161273160c084018263ffffffff169052565b5060e083015161274960e084018263ffffffff169052565b506101008381015163ffffffff908116918401919091526101209384015116929091019190915290565b801515811461075057600080fd5b60008060006060848603121561279657600080fd5b83356127a18161262e565b925060208401356127b181612643565b915060408401356127c181612773565b809150509250925092565b803563ffffffff811681146127e057600080fd5b919050565b6000806000606084860312156127fa57600080fd5b83356128058161262e565b9250602084013561281581612643565b9150612823604085016127cc565b90509250925092565b80356bffffffffffffffffffffffff811681146127e057600080fd5b803561ffff811681146127e057600080fd5b60008060008060008060008060006101208a8c03121561287957600080fd5b89356128848161262e565b985061289260208b0161282c565b97506128a060408b016127cc565b96506128ae60608b016127cc565b95506128bc60808b016127cc565b94506128ca60a08b01612848565b93506128d860c08b016127cc565b92506128e660e08b016127cc565b91506128f56101008b016127cc565b90509295985092959850929598565b60006020828403121561291657600080fd5b81356126278161262e565b6000806000806080858703121561293757600080fd5b84356129428161262e565b9350602085013561295281612643565b9250612960604086016127cc565b915061296e606086016127cc565b905092959194509250565b6000806000806080858703121561298f57600080fd5b843561299a8161262e565b935060208501356129aa81612643565b92506129b8604086016127cc565b915060608501356129c88161262e565b939692955090935050565b600080600080608085870312156129e957600080fd5b84356129f48161262e565b93506020850135612a0481612643565b925060408501356129608161262e565b600080600080600060a08688031215612a2c57600080fd5b8535612a378161262e565b94506020860135612a4781612643565b9350612a55604087016127cc565b9250612a63606087016127cc565b9150612a71608087016127cc565b90509295509295909350565b600080600060608486031215612a9257600080fd5b8335612a9d8161262e565b92506020840135612aad81612643565b915060408401356127c18161262e565b600080600060608486031215612ad257600080fd5b8335612add8161262e565b92506020840135612aed81612643565b915061282360408501612848565b600080600060608486031215612b1057600080fd5b8335612b1b8161262e565b92506020840135612b2b81612643565b91506128236040850161282c565b600060208284031215612b4b57600080fd5b81516126278161262e565b600060208284031215612b6857600080fd5b5051919050565b600060208284031215612b8157600080fd5b815161262781612773565b6001600160801b03818116838216019080821115612bd3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5092915050565b600060208284031215612bec57600080fd5b81516126278161264356fea2646970667358221220e6e60a5930261afc75edc0eafc3bcbe6158d2e60715a587e5245b26a11628efb64736f6c63430008100033
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.