Source Code
Overview
GLMR Balance
GLMR Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 1,507 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Set Approval For... | 13683342 | 44 days ago | IN | 0 GLMR | 0.00366514 | ||||
| Set Approval For... | 13204579 | 83 days ago | IN | 0 GLMR | 0.00435311 | ||||
| Set Approval For... | 12853597 | 112 days ago | IN | 0 GLMR | 0.00374167 | ||||
| Set Approval For... | 12224586 | 160 days ago | IN | 0 GLMR | 0.00374167 | ||||
| Set Approval For... | 11195923 | 233 days ago | IN | 0 GLMR | 0.0074448 | ||||
| Set Approval For... | 9974991 | 320 days ago | IN | 0 GLMR | 0.00705284 | ||||
| Set Approval For... | 9493629 | 354 days ago | IN | 0 GLMR | 0.00743212 | ||||
| Set Approval For... | 8590836 | 418 days ago | IN | 0 GLMR | 0.02821137 | ||||
| Set Approval For... | 8455414 | 428 days ago | IN | 0 GLMR | 0.02821137 | ||||
| Set Approval For... | 8451835 | 428 days ago | IN | 0 GLMR | 0.02821137 | ||||
| Set Approval For... | 8080056 | 455 days ago | IN | 0 GLMR | 0.028216 | ||||
| Set Approval For... | 7932145 | 465 days ago | IN | 0 GLMR | 0.02837721 | ||||
| Set Approval For... | 7487628 | 496 days ago | IN | 0 GLMR | 0.014076 | ||||
| Set Approval For... | 7472821 | 497 days ago | IN | 0 GLMR | 0.014108 | ||||
| Set Approval For... | 7472821 | 497 days ago | IN | 0 GLMR | 0.0155188 | ||||
| Set Approval For... | 6608235 | 558 days ago | IN | 0 GLMR | 0.0070943 | ||||
| Set Approval For... | 6473990 | 576 days ago | IN | 0 GLMR | 0.007054 | ||||
| Set Approval For... | 6370491 | 591 days ago | IN | 0 GLMR | 0.007054 | ||||
| Set Approval For... | 6336725 | 596 days ago | IN | 0 GLMR | 0.007054 | ||||
| Set Approval For... | 6149952 | 622 days ago | IN | 0 GLMR | 0.00720435 | ||||
| Set Approval For... | 6149934 | 622 days ago | IN | 0 GLMR | 0.00731692 | ||||
| Set Approval For... | 6149878 | 622 days ago | IN | 0 GLMR | 0.00731692 | ||||
| Set Approval For... | 6149847 | 622 days ago | IN | 0 GLMR | 0.00709178 | ||||
| Withdraw Raised | 6130300 | 625 days ago | IN | 0 GLMR | 0.0115432 | ||||
| Set Approval For... | 6084340 | 631 days ago | IN | 0 GLMR | 0.00718521 |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
RMRKEvrlootPinkPromo
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 175 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
import "@rmrk-team/evm-contracts/contracts/RMRK/extension/RMRKRoyalties.sol";
import "@rmrk-team/evm-contracts/contracts/RMRK/multiasset/RMRKMultiAsset.sol";
import "@rmrk-team/evm-contracts/contracts/RMRK/utils/RMRKCollectionMetadata.sol";
import {IAttributes} from "./IAttributes.sol";
import "./MintingUtils.sol";
import "./InitData.sol";
error RMRKMintZero();
error RMRKWrongValueSent();
error MintOverMaxVIP();
error MintOverMaxPer();
/**
* @title RMRKAbstractMultiAssetImpl
* @author RMRK team
* @notice Abstract implementation of RMRK multi asset module.
*/
contract RMRKEvrlootPinkPromo is
IRMRKInitData,
RMRKMintingUtils,
RMRKCollectionMetadata,
RMRKRoyalties,
RMRKMultiAsset,
IAttributes
{
uint256 private _totalAssets;
string private _tokenUri;
string private _tokenUriVIP;
mapping(uint256 => uint8) internal _vipStatus;
/**
* @notice Used to initialize the smart contract.
* @param name_ Name of the token collection
* @param symbol_ Symbol of the token collection
* @param collectionMetadata_ The collection metadata URI
* @param tokenURI_ The base URI of the token metadata
* @param data The `InitData` struct containing additional initialization data
*/
constructor(
string memory name_,
string memory symbol_,
string memory collectionMetadata_,
string memory tokenURI_,
InitData memory data
)
RMRKMintingUtils(
data.maxSupply,
data.maxVIPSupply,
data.pricePerMintVIP,
data.pricePerMintNonVIP
)
RMRKCollectionMetadata(collectionMetadata_)
RMRKRoyalties(data.royaltyRecipient, data.royaltyPercentageBps)
RMRKMultiAsset(name_, symbol_)
{
_setTokenURIs(tokenURI_, data.tokenURIVIP);
}
/**
* @notice Used to mint the desired number of tokens to the specified address.
* @dev The `data` value of the `_safeMint` method is set to an empty value.
* @dev Can only be called while the open sale is open.
* @param to Address to which to mint the token
* @param numToMint Number of tokens to mint
* @return The ID of the first token to be minted in the current minting cycle
*/
function mintVIP(
address to,
uint256 numToMint
) public payable virtual notLocked saleIsOpen returns (uint256) {
if (numToMint == uint256(0)) revert RMRKMintZero();
if (numToMint + _nextId > _maxVIPSupply) revert RMRKMintOverMax();
uint256 mintPriceRequired = numToMint * _pricePerMintVIP;
if (mintPriceRequired != msg.value) revert RMRKWrongValueSent();
if (_vipMinted[to] + numToMint > MAX_VIP_PER_ACCOUNT)
revert MintOverMaxVIP();
uint256 nextToken = _nextId + 1;
unchecked {
_nextId += numToMint;
_totalSupply += numToMint;
_totalVIPSupply += numToMint;
_vipMinted[to] += numToMint;
}
uint256 totalSupplyOffset = _nextId + 1;
for (uint256 i = nextToken; i < totalSupplyOffset; ) {
_safeMint(to, i, "");
// Set VIP Status
_vipStatus[i] = 1;
unchecked {
++i;
}
}
return nextToken;
}
/**
* @notice Used to mint the desired number of tokens to the specified address.
* @dev The `data` value of the `_safeMint` method is set to an empty value.
* @dev Can only be called while the open sale is open.
* @param to Address to which to mint the token
* @param numToMint Number of tokens to mint
* @return The ID of the first token to be minted in the current minting cycle
*/
function mint(
address to,
uint256 numToMint
) public payable virtual notLocked saleIsOpen returns (uint256) {
if (numToMint == uint256(0)) revert RMRKMintZero();
if (numToMint + _nextId > _maxSupply) revert RMRKMintOverMax();
uint256 mintPriceRequired = numToMint * _pricePerMintNonVIP;
if (mintPriceRequired != msg.value) revert RMRKWrongValueSent();
if (_nonVipMinted[to] + numToMint > MAX_NON_VIP_PER_ACCOUNT)
revert MintOverMaxPer();
uint256 nextToken = _nextId + 1;
unchecked {
_nextId += numToMint;
_totalSupply += numToMint;
_nonVipMinted[to] += numToMint;
}
uint256 totalSupplyOffset = _nextId + 1;
for (uint256 i = nextToken; i < totalSupplyOffset; ) {
_safeMint(to, i, "");
unchecked {
++i;
}
}
return nextToken;
}
/**
* @notice Used to retrieve token VIP status.
* @param tokenId ID of the token to check
*/
function isVIP(uint256 tokenId) public view returns (bool) {
return _vipStatus[tokenId] == 1;
}
/**
* @notice Retrieves attributes for use in missions -- for pink promo we will use luck attributes (position 0) and fishing (position 10)
* @dev If VIP status is 1, the luck/fishing attributes are 7/13, otherwise 3/9
* @param tokenId ID of the token to check
*/
function getAttributes(
uint256 tokenId,
bool
) public view returns (uint16[] memory attributes) {
uint8 vipStatus = _vipStatus[tokenId];
attributes = new uint16[](25);
if (vipStatus != 0) {
attributes[0] = 7; // Luck
attributes[10] = 13; // Fishing skill
} else {
attributes[0] = 3; // Luck
attributes[10] = 9; // Fishing skill
}
return attributes;
}
/**
* @notice Used to destroy the specified token.
* @dev The approval is cleared when the token is burned.
* @dev Requirements:
* - `tokenId` must exist.
* @param tokenId ID of the token to burn
*/
function burn(uint256 tokenId) public virtual onlyApprovedOrOwner(tokenId) {
_burn(tokenId);
}
/**
* @notice Used to add an asset to a token.
* @dev If the given asset is already added to the token, the execution will be reverted.
* @dev If the asset ID is invalid, the execution will be reverted.
* @dev If the token already has the maximum amount of pending assets (128), the execution will be
* reverted.
* @param tokenId ID of the token to add the asset to
* @param assetId ID of the asset to add to the token
* @param replacesAssetWithId ID of the asset to replace from the token's list of active assets
*/
function addAssetToToken(
uint256 tokenId,
uint64 assetId,
uint64 replacesAssetWithId
) public virtual onlyOwnerOrContributor {
_addAssetToToken(tokenId, assetId, replacesAssetWithId);
}
/**
* @notice Used to add a asset entry.
* @dev The ID of the asset is automatically assigned to be the next available asset ID.
* @param metadataURI Metadata URI of the asset
* @return ID of the newly added asset
*/
function addAssetEntry(
string memory metadataURI
) public virtual onlyOwnerOrContributor returns (uint256) {
unchecked {
++_totalAssets;
}
_addAssetEntry(uint64(_totalAssets), metadataURI);
return _totalAssets;
}
/**
* @notice Used to retrieve the total number of assets.
* @return The total number of assets
*/
function totalAssets() public view virtual returns (uint256) {
return _totalAssets;
}
/**
* @inheritdoc RMRKRoyalties
*/
function updateRoyaltyRecipient(
address newRoyaltyRecipient
) public virtual override onlyOwner {
_setRoyaltyRecipient(newRoyaltyRecipient);
}
/**
* @inheritdoc IERC165
*/
function supportsInterface(
bytes4 interfaceId
) public view virtual override(IERC165, RMRKMultiAsset) returns (bool) {
return
super.supportsInterface(interfaceId) ||
interfaceId == type(IERC2981).interfaceId ||
interfaceId == RMRK_INTERFACE ||
interfaceId == type(IAttributes).interfaceId;
}
/**
* @notice Used to retrieve the metadata URI of a token.
* @param tokenId ID of the token to retrieve the metadata URI for
* @return Metadata URI of the specified token
*/
function tokenURI(
uint256 tokenId
) public view virtual returns (string memory) {
if (_vipStatus[tokenId] == 1) {
return _tokenUriVIP;
} else {
return _tokenUri;
}
}
/**
* @notice Used to set the token URI configuration.
* @param tokenURI_ Metadata URI to apply to all tokens, either as base or as full URI for every token
* @param tokenURIVIP_ Metadata URI for VIP tokens
*/
function _setTokenURIs(
string memory tokenURI_,
string memory tokenURIVIP_
) internal virtual {
_tokenUri = tokenURI_;
_tokenUriVIP = tokenURIVIP_;
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual override {
super._beforeTokenTransfer(from, to, tokenId);
if (to == address(0)) {
unchecked {
_totalSupply -= 1;
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol)
pragma solidity ^0.8.0;
import "../utils/introspection/IERC165.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 IERC2981 is IERC165 {
/**
* @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 (token/ERC721/extensions/IERC721Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata is IERC721 {
/**
* @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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// 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: Apache-2.0
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/utils/Context.sol";
import "../library/RMRKErrors.sol";
/**
* @title Ownable
* @author RMRK team
* @notice A minimal ownable smart contractf or owner and contributors.
* @dev This smart contract is based on "openzeppelin's access/Ownable.sol".
*/
contract Ownable is Context {
address private _owner;
mapping(address => uint256) private _contributors;
/**
* @notice Used to anounce the transfer of ownership.
* @param previousOwner Address of the account that transferred their ownership role
* @param newOwner Address of the account receiving the ownership role
*/
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/**
* @notice Event that signifies that an address was granted contributor role or that the permission has been
* revoked.
* @dev This can only be triggered by a current owner, so there is no need to include that information in the event.
* @param contributor Address of the account that had contributor role status updated
* @param isContributor A boolean value signifying whether the role has been granted (`true`) or revoked (`false`)
*/
event ContributorUpdate(address indexed contributor, bool isContributor);
/**
* @dev Reverts if called by any account other than the owner or an approved contributor.
*/
modifier onlyOwnerOrContributor() {
_onlyOwnerOrContributor();
_;
}
/**
* @dev Reverts if called by any account other than the owner.
*/
modifier onlyOwner() {
_onlyOwner();
_;
}
/**
* @dev Initializes the contract by setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @notice Returns the address of the current owner.
* @return Address of the current owner
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @notice Leaves the contract without owner. Functions using the `onlyOwner` modifier will be disabled.
* @dev Can only be called by the current owner.
* @dev Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is
* only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @notice Transfers ownership of the contract to a new owner.
* @dev Can only be called by the current owner.
* @param newOwner Address of the new owner's account
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) revert RMRKNewOwnerIsZeroAddress();
_transferOwnership(newOwner);
}
/**
* @notice Transfers ownership of the contract to a new owner.
* @dev Internal function without access restriction.
* @dev Emits ***OwnershipTransferred*** event.
* @param newOwner Address of the new owner's account
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @notice Adds or removes a contributor to the smart contract.
* @dev Can only be called by the owner.
* @dev Emits ***ContributorUpdate*** event.
* @param contributor Address of the contributor's account
* @param grantRole A boolean value signifying whether the contributor role is being granted (`true`) or revoked
* (`false`)
*/
function manageContributor(
address contributor,
bool grantRole
) external onlyOwner {
if (contributor == address(0)) revert RMRKNewContributorIsZeroAddress();
grantRole
? _contributors[contributor] = 1
: _contributors[contributor] = 0;
emit ContributorUpdate(contributor, grantRole);
}
/**
* @notice Used to check if the address is one of the contributors.
* @param contributor Address of the contributor whose status we are checking
* @return Boolean value indicating whether the address is a contributor or not
*/
function isContributor(address contributor) public view returns (bool) {
return _contributors[contributor] == 1;
}
/**
* @notice Used to verify that the caller is either the owner or a contributor.
* @dev If the caller is not the owner or a contributor, the execution will be reverted.
*/
function _onlyOwnerOrContributor() private view {
if (owner() != _msgSender() && !isContributor(_msgSender()))
revert RMRKNotOwnerOrContributor();
}
/**
* @notice Used to verify that the caller is the owner.
* @dev If the caller is not the owner, the execution will be reverted.
*/
function _onlyOwner() private view {
if (owner() != _msgSender()) revert RMRKNotOwner();
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
import "./Ownable.sol";
import "../library/RMRKErrors.sol";
/**
* @title OwnableLock
* @author RMRK team
* @notice A minimal ownable lock smart contract.
*/
contract OwnableLock is Ownable {
uint256 private _lock;
/**
* @notice Emitted when the smart contract is locked.
*/
event LockSet();
/**
* @notice Reverts if the lock flag is set to true.
*/
modifier notLocked() {
_onlyNotLocked();
_;
}
/**
* @notice Locks the operation.
* @dev Once locked, functions using `notLocked` modifier cannot be executed.
* @dev Emits ***LockSet*** event.
*/
function setLock() public virtual onlyOwner {
_lock = 1;
emit LockSet();
}
/**
* @notice Used to retrieve the status of a lockable smart contract.
* @return A boolean value signifying whether the smart contract has been locked
*/
function getLock() public view returns (bool) {
return _lock == 1;
}
/**
* @notice Used to verify that the operation of the smart contract is not locked.
* @dev If the operation of the smart contract is locked, the execution will be reverted.
*/
function _onlyNotLocked() private view {
if (_lock == 1) revert RMRKLocked();
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
/**
* @title IRMRKCore
* @author RMRK team
* @notice Interface smart contract for RMRK core module.
*/
interface IRMRKCore {
/**
* @notice Used to retrieve the collection name.
* @return Name of the collection
*/
function name() external view returns (string memory);
/**
* @notice Used to retrieve the collection symbol.
* @return Symbol of the collection
*/
function symbol() external view returns (string memory);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
import "./IRMRKCore.sol";
/**
* @title RMRKCore
* @author RMRK team
* @notice Smart contract of the RMRK core module.
* @dev This is currently just a passthrough contract which allows for granular editing of base-level ERC721 functions.
*/
contract RMRKCore is IRMRKCore {
/**
* @notice Version of the @rmrk-team/evm-contracts package
* @return Version identifier of the smart contract
*/
string public constant VERSION = "1.2.1";
bytes4 public constant RMRK_INTERFACE = 0x524D524B; // "RMRK" in ASCII hex
/**
* @notice Used to initialize the smart contract.
* @param name_ Name of the token collection
* @param symbol_ Symbol of the token collection
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/// Token name
string private _name;
/// Token symbol
string private _symbol;
/**
* @notice Used to retrieve the collection name.
* @return Name of the collection
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @notice Used to retrieve the collection symbol.
* @return Symbol of the collection
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @notice Hook that is called before any token transfer. This includes minting and burning.
* @dev Calling conditions:
*
* - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be transferred to `to`.
* - When `from` is zero, `tokenId` will be minted to `to`.
* - When `to` is zero, ``from``'s `tokenId` will be burned.
* - `from` and `to` are never zero at the same time.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
* @param from Address from which the token is being transferred
* @param to Address to which the token is being transferred
* @param tokenId ID of the token being transferred
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual {}
/**
* @notice Hook that is called after any transfer of tokens. This includes minting and burning.
* @dev Calling conditions:
*
* - When `from` and `to` are both non-zero.
* - `from` and `to` are never zero at the same time.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
* @param from Address from which the token has been transferred
* @param to Address to which the token has been transferred
* @param tokenId ID of the token that has been transferred
*/
function _afterTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual {}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/interfaces/IERC2981.sol";
import "../library/RMRKErrors.sol";
/**
* @title RMRKRoyalties
* @author RMRK team
* @notice Smart contract of the RMRK Royalties module.
*/
abstract contract RMRKRoyalties is IERC2981 {
address private _royaltyRecipient;
uint256 private _royaltyPercentageBps;
/**
* @notice Used to initiate the smart contract.
* @dev `royaltyPercentageBps` is expressed in basis points, so 1 basis point equals 0.01% and 500 basis points
* equal 5%.
* @param royaltyRecipient Address to which royalties should be sent
* @param royaltyPercentageBps The royalty percentage expressed in basis points
*/
constructor(
address royaltyRecipient,
uint256 royaltyPercentageBps //in basis points
) {
_setRoyaltyRecipient(royaltyRecipient);
if (royaltyPercentageBps >= 10000) revert RMRKRoyaltiesTooHigh();
_royaltyPercentageBps = royaltyPercentageBps;
}
/**
* @notice Used to update recipient of royalties.
* @dev Custom access control has to be implemented to ensure that only the intended actors can update the
* beneficiary.
* @param newRoyaltyRecipient Address of the new recipient of royalties
*/
function updateRoyaltyRecipient(
address newRoyaltyRecipient
) external virtual;
/**
* @notice Used to update the royalty recipient.
* @param newRoyaltyRecipient Address of the new recipient of royalties
*/
function _setRoyaltyRecipient(address newRoyaltyRecipient) internal {
_royaltyRecipient = newRoyaltyRecipient;
}
/**
* @notice Used to retrieve the recipient of royalties.
* @return Address of the recipient of royalties
*/
function getRoyaltyRecipient() public view virtual returns (address) {
return _royaltyRecipient;
}
/**
* @notice Used to retrieve the specified royalty percentage.
* @return The royalty percentage expressed in the basis points
*/
function getRoyaltyPercentage() public view virtual returns (uint256) {
return _royaltyPercentageBps;
}
/**
* @notice Used to retrieve the information about who shall receive royalties of a sale of the specified token and
* how much they will be.
* @param tokenId ID of the token for which the royalty info is being retrieved
* @param salePrice Price of the token sale
* @return receiver The beneficiary receiving royalties of the sale
* @return royaltyAmount The value of the royalties recieved by the `receiver` from the sale
*/
function royaltyInfo(
uint256 tokenId,
uint256 salePrice
)
external
view
virtual
override
returns (address receiver, uint256 royaltyAmount)
{
receiver = _royaltyRecipient;
royaltyAmount = (salePrice * _royaltyPercentageBps) / 10000;
}
}// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.18; /// @title RMRKErrors /// @author RMRK team /// @notice A collection of errors used in the RMRK suite /// @dev Errors are kept in a centralised file in order to provide a central point of reference and to avoid error /// naming collisions due to inheritance /// Attempting to grant the token to 0x0 address error ERC721AddressZeroIsNotaValidOwner(); /// Attempting to grant approval to the current owner of the token error ERC721ApprovalToCurrentOwner(); /// Attempting to grant approval when not being owner or approved for all should not be permitted error ERC721ApproveCallerIsNotOwnerNorApprovedForAll(); /// Attempting to get approvals for a token owned by 0x0 (considered non-existent) error ERC721ApprovedQueryForNonexistentToken(); /// Attempting to grant approval to self error ERC721ApproveToCaller(); /// Attempting to use an invalid token ID error ERC721InvalidTokenId(); /// Attempting to mint to 0x0 address error ERC721MintToTheZeroAddress(); /// Attempting to manage a token without being its owner or approved by the owner error ERC721NotApprovedOrOwner(); /// Attempting to mint an already minted token error ERC721TokenAlreadyMinted(); /// Attempting to transfer the token from an address that is not the owner error ERC721TransferFromIncorrectOwner(); /// Attempting to safe transfer to an address that is unable to receive the token error ERC721TransferToNonReceiverImplementer(); /// Attempting to transfer the token to a 0x0 address error ERC721TransferToTheZeroAddress(); /// Attempting to grant approval of assets to their current owner error RMRKApprovalForAssetsToCurrentOwner(); /// Attempting to grant approval of assets without being the caller or approved for all error RMRKApproveForAssetsCallerIsNotOwnerNorApprovedForAll(); /// Attempting to incorrectly configue a Catalog item error RMRKBadConfig(); /// Attempting to set the priorities with an array of length that doesn't match the length of active assets array error RMRKBadPriorityListLength(); /// Attempting to add an asset entry with `Part`s, without setting the `Catalog` address error RMRKCatalogRequiredForParts(); /// Attempting to transfer a soulbound (non-transferrable) token error RMRKCannotTransferSoulbound(); /// Attempting to accept a child that has already been accepted error RMRKChildAlreadyExists(); /// Attempting to interact with a child, using index that is higher than the number of children error RMRKChildIndexOutOfRange(); /// Attempting to find the index of a child token on a parent which does not own it. error RMRKChildNotFoundInParent(); /// Attempting to pass collaborator address array and collaborator permission array of different lengths error RMRKCollaboratorArraysNotEqualLength(); /// Attempting to register a collection that is already registered error RMRKCollectionAlreadyRegistered(); /// Attempting to manage or interact with colleciton that is not registered error RMRKCollectionNotRegistered(); /// Attempting to equip a `Part` with a child not approved by the Catalog error RMRKEquippableEquipNotAllowedByCatalog(); /// Attempting to use ID 0, which is not supported /// @dev The ID 0 in RMRK suite is reserved for empty values. Guarding against its use ensures the expected operation error RMRKIdZeroForbidden(); /// Attempting to interact with an asset, using index greater than number of assets error RMRKIndexOutOfRange(); /// Attempting to reclaim a child that can't be reclaimed error RMRKInvalidChildReclaim(); /// Attempting to interact with an end-user account when the contract account is expected error RMRKIsNotContract(); /// Attempting to interact with a contract that had its operation locked error RMRKLocked(); /// Attempting to add a pending child after the number of pending children has reached the limit (default limit is 128) error RMRKMaxPendingChildrenReached(); /// Attempting to add a pending asset after the number of pending assets has reached the limit (default limit is /// 128) error RMRKMaxPendingAssetsReached(); /// Attempting to burn a total number of recursive children higher than maximum set /// @param childContract Address of the collection smart contract in which the maximum number of recursive burns was reached /// @param childId ID of the child token at which the maximum number of recursive burns was reached error RMRKMaxRecursiveBurnsReached(address childContract, uint256 childId); /// Attempting to mint a number of tokens that would cause the total supply to be greater than maximum supply error RMRKMintOverMax(); /// Attempting to mint a nested token to a smart contract that doesn't support nesting error RMRKMintToNonRMRKNestableImplementer(); /// Attempting to pass complementary arrays of different lengths error RMRKMismachedArrayLength(); /// Attempting to transfer a child before it is unequipped error RMRKMustUnequipFirst(); /// Attempting to nest a child over the nestable limit (current limit is 100 levels of nesting) error RMRKNestableTooDeep(); /// Attempting to nest the token to own descendant, which would create a loop and leave the looped tokens in limbo error RMRKNestableTransferToDescendant(); /// Attempting to nest the token to a smart contract that doesn't support nesting error RMRKNestableTransferToNonRMRKNestableImplementer(); /// Attempting to nest the token into itself error RMRKNestableTransferToSelf(); /// Attempting to interact with an asset that can not be found error RMRKNoAssetMatchingId(); /// Attempting to manage an asset without owning it or having been granted permission by the owner to do so error RMRKNotApprovedForAssetsOrOwner(); /// Attempting to interact with a token without being its owner or having been granted permission by the /// owner to do so /// @dev When a token is nested, only the direct owner (NFT parent) can mange it. In that case, approved addresses are /// not allowed to manage it, in order to ensure the expected behaviour error RMRKNotApprovedOrDirectOwner(); /// Attempting to manage a collection without being the collection's collaborator error RMRKNotCollectionCollaborator(); /// Attemting to manage a collection without being the collection's issuer error RMRKNotCollectionIssuer(); /// Attempting to manage a collection without being the collection's issuer or collaborator error RMRKNotCollectionIssuerOrCollaborator(); /// Attempting to compose an asset wihtout having an associated Catalog error RMRKNotComposableAsset(); /// Attempting to unequip an item that isn't equipped error RMRKNotEquipped(); /// Attempting to interact with a management function without being the smart contract's owner error RMRKNotOwner(); /// Attempting to interact with a function without being the owner or contributor of the collection error RMRKNotOwnerOrContributor(); /// Attempting to manage a collection without being the specific address error RMRKNotSpecificAddress(); /// Attempting to manage a token without being its owner error RMRKNotTokenOwner(); /// Attempting to transfer the ownership to the 0x0 address error RMRKNewOwnerIsZeroAddress(); /// Attempting to assign a 0x0 address as a contributor error RMRKNewContributorIsZeroAddress(); /// Attemtping to use `Ownable` interface without implementing it error RMRKOwnableNotImplemented(); /// Attempting an operation requiring the token being nested, while it is not error RMRKParentIsNotNFT(); /// Attempting to add a `Part` with an ID that is already used error RMRKPartAlreadyExists(); /// Attempting to use a `Part` that doesn't exist error RMRKPartDoesNotExist(); /// Attempting to use a `Part` that is `Fixed` when `Slot` kind of `Part` should be used error RMRKPartIsNotSlot(); /// Attempting to interact with a pending child using an index greater than the size of pending array error RMRKPendingChildIndexOutOfRange(); /// Attempting to add an asset using an ID that has already been used error RMRKAssetAlreadyExists(); /// Attempting to equip an item into a slot that already has an item equipped error RMRKSlotAlreadyUsed(); /// Attempting to equip an item into a `Slot` that the target asset does not implement error RMRKTargetAssetCannotReceiveSlot(); /// Attempting to equip a child into a `Slot` and parent that the child's collection doesn't support error RMRKTokenCannotBeEquippedWithAssetIntoSlot(); /// Attempting to compose a NFT of a token without active assets error RMRKTokenDoesNotHaveAsset(); /// Attempting to determine the asset with the top priority on a token without assets error RMRKTokenHasNoAssets(); /// Attempting to accept or transfer a child which does not match the one at the specified index error RMRKUnexpectedChildId(); /// Attempting to reject all pending assets but more assets than expected are pending error RMRKUnexpectedNumberOfAssets(); /// Attempting to reject all pending children but children assets than expected are pending error RMRKUnexpectedNumberOfChildren(); /// Attempting to accept or reject an asset which does not match the one at the specified index error RMRKUnexpectedAssetId(); /// Attempting an operation expecting a parent to the token which is not the actual one error RMRKUnexpectedParent(); /// Attempting not to pass an empty array of equippable addresses when adding or setting the equippable addresses error RMRKZeroLengthIdsPassed(); /// Attempting to set the royalties to a value higher than 100% (10000 in base points) error RMRKRoyaltiesTooHigh(); /// Attempting to do a bulk operation on a token that is not owned by the caller error RMRKCanOnlyDoBulkOperationsOnOwnedTokens(); /// Attempting to do a bulk operation with multiple tokens at a time error RMRKCanOnlyDoBulkOperationsWithOneTokenAtATime();
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
/**
* @title RMRKLib
* @author RMRK team
* @notice RMRK library smart contract.
*/
library RMRKLib {
/**
* @notice Used to remove an item from the array using the specified index.
* @dev The item is removed by replacing it with the last item and removing the last element.
* @param array An array of items containing the item to be removed
* @param index Index of the item to remove
*/
function removeItemByIndex(uint64[] storage array, uint256 index) internal {
//Check to see if this is already gated by require in all calls
require(index < array.length);
array[index] = array[array.length - 1];
array.pop();
}
/**
* @notice Used to determine the index of the item in the array by spedifying its value.
* @dev This was adapted from Cryptofin-Solidity `arrayUtils`.
* @dev If the item is not found the index returned will equal `0`.
* @param A The array containing the item to be found
* @param a The value of the item to find the index of
* @return The index of the item in the array
* @return A boolean value specifying whether the item was found
*/
function indexOf(
uint64[] memory A,
uint64 a
) internal pure returns (uint256, bool) {
uint256 length = A.length;
for (uint256 i; i < length; ) {
if (A[i] == a) {
return (i, true);
}
unchecked {
++i;
}
}
return (0, false);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
import "./IERC5773.sol";
import "../library/RMRKLib.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "../library/RMRKErrors.sol";
/**
* @title AbstractMultiAsset
* @author RMRK team
* @notice Abstract Smart contract implementing most of the common logic for contracts implementing IERC5773
*/
abstract contract AbstractMultiAsset is Context, IERC5773 {
using RMRKLib for uint64[];
/// Mapping of uint64 Ids to asset metadata
mapping(uint64 => string) private _assets;
/// Mapping of tokenId to new asset, to asset to be replaced
mapping(uint256 => mapping(uint64 => uint64)) private _assetReplacements;
/// Mapping of tokenId to an array of active assets
/// @dev Active recurses is unbounded, getting all would reach gas limit at around 30k items
/// so we leave this as internal in case a custom implementation needs to implement pagination
mapping(uint256 => uint64[]) internal _activeAssets;
/// Mapping of tokenId to an array of pending assets
mapping(uint256 => uint64[]) internal _pendingAssets;
/// Mapping of tokenId to an array of priorities for active assets
mapping(uint256 => uint64[]) internal _activeAssetPriorities;
/// Mapping of tokenId to assetId to whether the token has this asset assigned
mapping(uint256 => mapping(uint64 => bool)) private _tokenAssets;
/// Mapping from owner to operator approvals for assets
mapping(address => mapping(address => bool))
private _operatorApprovalsForAssets;
/**
* @inheritdoc IERC5773
*/
function getAssetMetadata(
uint256 tokenId,
uint64 assetId
) public view virtual returns (string memory) {
if (!_tokenAssets[tokenId][assetId]) revert RMRKTokenDoesNotHaveAsset();
return _assets[assetId];
}
/**
* @inheritdoc IERC5773
*/
function getActiveAssets(
uint256 tokenId
) public view virtual returns (uint64[] memory) {
return _activeAssets[tokenId];
}
/**
* @inheritdoc IERC5773
*/
function getPendingAssets(
uint256 tokenId
) public view virtual returns (uint64[] memory) {
return _pendingAssets[tokenId];
}
/**
* @inheritdoc IERC5773
*/
function getActiveAssetPriorities(
uint256 tokenId
) public view virtual returns (uint64[] memory) {
return _activeAssetPriorities[tokenId];
}
/**
* @inheritdoc IERC5773
*/
function getAssetReplacements(
uint256 tokenId,
uint64 newAssetId
) public view virtual returns (uint64) {
return _assetReplacements[tokenId][newAssetId];
}
/**
* @inheritdoc IERC5773
*/
function isApprovedForAllForAssets(
address owner,
address operator
) public view virtual returns (bool) {
return _operatorApprovalsForAssets[owner][operator];
}
/**
* @inheritdoc IERC5773
*/
function setApprovalForAllForAssets(
address operator,
bool approved
) public virtual {
if (_msgSender() == operator)
revert RMRKApprovalForAssetsToCurrentOwner();
_operatorApprovalsForAssets[_msgSender()][operator] = approved;
emit ApprovalForAllForAssets(_msgSender(), operator, approved);
}
/**
* @notice Used to accept a pending asset.
* @dev The call is reverted if there is no pending asset at a given index.
* @dev Emits ***AssetAccepted*** event.
* @param tokenId ID of the token for which to accept the pending asset
* @param index Index of the asset in the pending array to accept
* @param assetId ID of the asset to accept in token's pending array
*/
function _acceptAsset(
uint256 tokenId,
uint256 index,
uint64 assetId
) internal virtual {
_validatePendingAssetAtIndex(tokenId, index, assetId);
_beforeAcceptAsset(tokenId, index, assetId);
uint64 replacesId = _assetReplacements[tokenId][assetId];
uint256 replaceIndex;
bool replacefound;
if (replacesId != uint64(0))
(replaceIndex, replacefound) = _activeAssets[tokenId].indexOf(
replacesId
);
if (replacefound) {
// We don't want to remove and then push a new asset.
// This way we also keep the priority of the original asset
_activeAssets[tokenId][replaceIndex] = assetId;
delete _tokenAssets[tokenId][replacesId];
} else {
// We use the current size as next priority, by default priorities would be [0,1,2...]
_activeAssetPriorities[tokenId].push(
uint64(_activeAssets[tokenId].length)
);
_activeAssets[tokenId].push(assetId);
replacesId = uint64(0);
}
_removePendingAsset(tokenId, index, assetId);
emit AssetAccepted(tokenId, assetId, replacesId);
_afterAcceptAsset(tokenId, index, assetId);
}
/**
* @notice Used to reject the specified asset from the pending array.
* @dev The call is reverted if there is no pending asset at a given index.
* @dev Emits ***AssetRejected*** event.
* @param tokenId ID of the token that the asset is being rejected from
* @param index Index of the asset in the pending array to be rejected
* @param assetId ID of the asset expected to be in the index
*/
function _rejectAsset(
uint256 tokenId,
uint256 index,
uint64 assetId
) internal virtual {
_validatePendingAssetAtIndex(tokenId, index, assetId);
_beforeRejectAsset(tokenId, index, assetId);
_removePendingAsset(tokenId, index, assetId);
delete _tokenAssets[tokenId][assetId];
emit AssetRejected(tokenId, assetId);
_afterRejectAsset(tokenId, index, assetId);
}
/**
* @notice Used to validate the index on the pending assets array
* @dev The call is reverted if the index is out of range or the asset Id is not present at the index.
* @param tokenId ID of the token that the asset is validated from
* @param index Index of the asset in the pending array
* @param assetId Id of the asset expected to be in the index
*/
function _validatePendingAssetAtIndex(
uint256 tokenId,
uint256 index,
uint64 assetId
) private view {
if (index >= _pendingAssets[tokenId].length)
revert RMRKIndexOutOfRange();
if (assetId != _pendingAssets[tokenId][index])
revert RMRKUnexpectedAssetId();
}
/**
* @notice Used to remove the asset at the index on the pending assets array
* @param tokenId ID of the token that the asset is being removed from
* @param index Index of the asset in the pending array
* @param assetId Id of the asset expected to be in the index
*/
function _removePendingAsset(
uint256 tokenId,
uint256 index,
uint64 assetId
) private {
_pendingAssets[tokenId].removeItemByIndex(index);
delete _assetReplacements[tokenId][assetId];
}
/**
* @notice Used to reject all of the pending assets for the given token.
* @dev When rejecting all assets, the pending array is indiscriminately cleared.
* @dev If the number of pending assets is greater than the value of `maxRejections`, the exectuion will be
* reverted.
* @dev Emits ***AssetRejected*** event.
* @param tokenId ID of the token to reject all of the pending assets.
* @param maxRejections Maximum number of expected assets to reject, used to prevent from
* rejecting assets which arrive just before this operation.
*/
function _rejectAllAssets(
uint256 tokenId,
uint256 maxRejections
) internal virtual {
uint256 len = _pendingAssets[tokenId].length;
if (len > maxRejections) revert RMRKUnexpectedNumberOfAssets();
_beforeRejectAllAssets(tokenId);
for (uint256 i; i < len; ) {
uint64 assetId = _pendingAssets[tokenId][i];
delete _assetReplacements[tokenId][assetId];
unchecked {
++i;
}
}
delete (_pendingAssets[tokenId]);
emit AssetRejected(tokenId, uint64(0));
_afterRejectAllAssets(tokenId);
}
/**
* @notice Used to specify the priorities for a given token's active assets.
* @dev If the length of the priorities array doesn't match the length of the active assets array, the execution
* will be reverted.
* @dev The position of the priority value in the array corresponds the position of the asset in the active
* assets array it will be applied to.
* @dev Emits ***AssetPrioritySet*** event.
* @param tokenId ID of the token for which the priorities are being set
* @param priorities Array of priorities for the assets
*/
function _setPriority(
uint256 tokenId,
uint64[] calldata priorities
) internal virtual {
uint256 length = priorities.length;
if (length != _activeAssets[tokenId].length)
revert RMRKBadPriorityListLength();
_beforeSetPriority(tokenId, priorities);
_activeAssetPriorities[tokenId] = priorities;
emit AssetPrioritySet(tokenId);
_afterSetPriority(tokenId, priorities);
}
/**
* @notice Used to add an asset entry.
* @dev If the specified ID is already used by another asset, the execution will be reverted.
* @dev This internal function warrants custom access control to be implemented when used.
* @dev Emits ***AssetSet*** event.
* @param id ID of the asset to assign to the new asset
* @param metadataURI Metadata URI of the asset
*/
function _addAssetEntry(
uint64 id,
string memory metadataURI
) internal virtual {
if (id == uint64(0)) revert RMRKIdZeroForbidden();
if (bytes(_assets[id]).length > 0) revert RMRKAssetAlreadyExists();
_beforeAddAsset(id, metadataURI);
_assets[id] = metadataURI;
emit AssetSet(id);
_afterAddAsset(id, metadataURI);
}
/**
* @notice Used to add an asset to a token.
* @dev If the given asset is already added to the token, the execution will be reverted.
* @dev If the asset ID is invalid, the execution will be reverted.
* @dev If the token already has the maximum amount of pending assets (128), the execution will be
* reverted.
* @dev Emits ***AssetAddedToTokens*** event.
* @param tokenId ID of the token to add the asset to
* @param assetId ID of the asset to add to the token
* @param replacesAssetWithId ID of the asset to replace from the token's list of active assets
*/
function _addAssetToToken(
uint256 tokenId,
uint64 assetId,
uint64 replacesAssetWithId
) internal virtual {
if (_tokenAssets[tokenId][assetId]) revert RMRKAssetAlreadyExists();
if (bytes(_assets[assetId]).length == uint256(0))
revert RMRKNoAssetMatchingId();
if (_pendingAssets[tokenId].length >= 128)
revert RMRKMaxPendingAssetsReached();
_beforeAddAssetToToken(tokenId, assetId, replacesAssetWithId);
_tokenAssets[tokenId][assetId] = true;
_pendingAssets[tokenId].push(assetId);
if (replacesAssetWithId != uint64(0)) {
_assetReplacements[tokenId][assetId] = replacesAssetWithId;
}
uint256[] memory tokenIds = new uint256[](1);
tokenIds[0] = tokenId;
emit AssetAddedToTokens(tokenIds, assetId, replacesAssetWithId);
_afterAddAssetToToken(tokenId, assetId, replacesAssetWithId);
}
/**
* @notice Hook that is called before an asset is added.
* @param id ID of the asset
* @param metadataURI Metadata URI of the asset
*/
function _beforeAddAsset(
uint64 id,
string memory metadataURI
) internal virtual {}
/**
* @notice Hook that is called after an asset is added.
* @param id ID of the asset
* @param metadataURI Metadata URI of the asset
*/
function _afterAddAsset(
uint64 id,
string memory metadataURI
) internal virtual {}
/**
* @notice Hook that is called before adding an asset to a token's pending assets array.
* @dev If the asset doesn't intend to replace another asset, the `replacesAssetWithId` value should be `0`.
* @param tokenId ID of the token to which the asset is being added
* @param assetId ID of the asset that is being added
* @param replacesAssetWithId ID of the asset that this asset is attempting to replace
*/
function _beforeAddAssetToToken(
uint256 tokenId,
uint64 assetId,
uint64 replacesAssetWithId
) internal virtual {}
/**
* @notice Hook that is called after an asset has been added to a token's pending assets array.
* @dev If the asset doesn't intend to replace another asset, the `replacesAssetWithId` value should be `0`.
* @param tokenId ID of the token to which the asset is has been added
* @param assetId ID of the asset that is has been added
* @param replacesAssetWithId ID of the asset that this asset is attempting to replace
*/
function _afterAddAssetToToken(
uint256 tokenId,
uint64 assetId,
uint64 replacesAssetWithId
) internal virtual {}
/**
* @notice Hook that is called before an asset is accepted to a token's active assets array.
* @param tokenId ID of the token for which the asset is being accepted
* @param index Index of the asset in the token's pending assets array
* @param assetId ID of the asset expected to be located at the specified `index`
*/
function _beforeAcceptAsset(
uint256 tokenId,
uint256 index,
uint64 assetId
) internal virtual {}
/**
* @notice Hook that is called after an asset is accepted to a token's active assets array.
* @param tokenId ID of the token for which the asset has been accepted
* @param index Index of the asset in the token's pending assets array
* @param assetId ID of the asset expected to have been located at the specified `index`
*/
function _afterAcceptAsset(
uint256 tokenId,
uint256 index,
uint64 assetId
) internal virtual {}
/**
* @notice Hook that is called before rejecting an asset.
* @param tokenId ID of the token from which the asset is being rejected
* @param index Index of the asset in the token's pending assets array
* @param assetId ID of the asset expected to be located at the specified `index`
*/
function _beforeRejectAsset(
uint256 tokenId,
uint256 index,
uint64 assetId
) internal virtual {}
/**
* @notice Hook that is called after rejecting an asset.
* @param tokenId ID of the token from which the asset has been rejected
* @param index Index of the asset in the token's pending assets array
* @param assetId ID of the asset expected to have been located at the specified `index`
*/
function _afterRejectAsset(
uint256 tokenId,
uint256 index,
uint64 assetId
) internal virtual {}
/**
* @notice Hook that is called before rejecting all assets of a token.
* @param tokenId ID of the token from which all of the assets are being rejected
*/
function _beforeRejectAllAssets(uint256 tokenId) internal virtual {}
/**
* @notice Hook that is called after rejecting all assets of a token.
* @param tokenId ID of the token from which all of the assets have been rejected
*/
function _afterRejectAllAssets(uint256 tokenId) internal virtual {}
/**
* @notice Hook that is called before the priorities for token's assets is set.
* @param tokenId ID of the token for which the asset priorities are being set
* @param priorities[] An array of priorities for token's active resources
*/
function _beforeSetPriority(
uint256 tokenId,
uint64[] calldata priorities
) internal virtual {}
/**
* @notice Hook that is called after the priorities for token's assets is set.
* @param tokenId ID of the token for which the asset priorities have been set
* @param priorities[] An array of priorities for token's active resources
*/
function _afterSetPriority(
uint256 tokenId,
uint64[] calldata priorities
) internal virtual {}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/**
* @title IERC5773
* @author RMRK team
* @notice Interface smart contract of the RMRK multi asset module.
*/
interface IERC5773 is IERC165 {
/**
* @notice Used to notify listeners that an asset object is initialized at `assetId`.
* @param assetId ID of the asset that was initialized
*/
event AssetSet(uint64 indexed assetId);
/**
* @notice Used to notify listeners that an asset object at `assetId` is added to token's pending asset
* array.
* @param tokenIds An array of token IDs that received a new pending asset
* @param assetId ID of the asset that has been added to the token's pending assets array
* @param replacesId ID of the asset that would be replaced
*/
event AssetAddedToTokens(
uint256[] tokenIds,
uint64 indexed assetId,
uint64 indexed replacesId
);
/**
* @notice Used to notify listeners that an asset object at `assetId` is accepted by the token and migrated
* from token's pending assets array to active assets array of the token.
* @param tokenId ID of the token that had a new asset accepted
* @param assetId ID of the asset that was accepted
* @param replacesId ID of the asset that was replaced
*/
event AssetAccepted(
uint256 indexed tokenId,
uint64 indexed assetId,
uint64 indexed replacesId
);
/**
* @notice Used to notify listeners that an asset object at `assetId` is rejected from token and is dropped
* from the pending assets array of the token.
* @param tokenId ID of the token that had an asset rejected
* @param assetId ID of the asset that was rejected
*/
event AssetRejected(uint256 indexed tokenId, uint64 indexed assetId);
/**
* @notice Used to notify listeners that token's prioritiy array is reordered.
* @param tokenId ID of the token that had the asset priority array updated
*/
event AssetPrioritySet(uint256 indexed tokenId);
/**
* @notice Used to notify listeners that owner has granted an approval to the user to manage the assets of a
* given token.
* @dev Approvals must be cleared on transfer
* @param owner Address of the account that has granted the approval for all token's assets
* @param approved Address of the account that has been granted approval to manage the token's assets
* @param tokenId ID of the token on which the approval was granted
*/
event ApprovalForAssets(
address indexed owner,
address indexed approved,
uint256 indexed tokenId
);
/**
* @notice Used to notify listeners that owner has granted approval to the user to manage assets of all of their
* tokens.
* @param owner Address of the account that has granted the approval for all assets on all of their tokens
* @param operator Address of the account that has been granted the approval to manage the token's assets on all of
* the tokens
* @param approved Boolean value signifying whether the permission has been granted (`true`) or revoked (`false`)
*/
event ApprovalForAllForAssets(
address indexed owner,
address indexed operator,
bool approved
);
/**
* @notice Accepts an asset at from the pending array of given token.
* @dev Migrates the asset from the token's pending asset array to the token's active asset array.
* @dev Active assets cannot be removed by anyone, but can be replaced by a new asset.
* @dev Requirements:
*
* - The caller must own the token or be approved to manage the token's assets
* - `tokenId` must exist.
* - `index` must be in range of the length of the pending asset array.
* @dev Emits an {AssetAccepted} event.
* @param tokenId ID of the token for which to accept the pending asset
* @param index Index of the asset in the pending array to accept
* @param assetId ID of the asset expected to be in the index
*/
function acceptAsset(
uint256 tokenId,
uint256 index,
uint64 assetId
) external;
/**
* @notice Rejects an asset from the pending array of given token.
* @dev Removes the asset from the token's pending asset array.
* @dev Requirements:
*
* - The caller must own the token or be approved to manage the token's assets
* - `tokenId` must exist.
* - `index` must be in range of the length of the pending asset array.
* @dev Emits a {AssetRejected} event.
* @param tokenId ID of the token that the asset is being rejected from
* @param index Index of the asset in the pending array to be rejected
* @param assetId ID of the asset expected to be in the index
*/
function rejectAsset(
uint256 tokenId,
uint256 index,
uint64 assetId
) external;
/**
* @notice Rejects all assets from the pending array of a given token.
* @dev Effecitvely deletes the pending array.
* @dev Requirements:
*
* - The caller must own the token or be approved to manage the token's assets
* - `tokenId` must exist.
* @dev Emits a {AssetRejected} event with assetId = 0.
* @param tokenId ID of the token of which to clear the pending array.
* @param maxRejections Maximum number of expected assets to reject, used to prevent from rejecting assets which
* arrive just before this operation.
*/
function rejectAllAssets(uint256 tokenId, uint256 maxRejections) external;
/**
* @notice Sets a new priority array for a given token.
* @dev The priority array is a non-sequential list of `uint64`s, where the lowest value is considered highest
* priority.
* @dev Value `0` of a priority is a special case equivalent to unitialized.
* @dev Requirements:
*
* - The caller must own the token or be approved to manage the token's assets
* - `tokenId` must exist.
* - The length of `priorities` must be equal the length of the active assets array.
* @dev Emits a {AssetPrioritySet} event.
* @param tokenId ID of the token to set the priorities for
* @param priorities An array of priorities of active assets. The succesion of items in the priorities array
* matches that of the succesion of items in the active array
*/
function setPriority(
uint256 tokenId,
uint64[] calldata priorities
) external;
/**
* @notice Used to retrieve IDs of the active assets of given token.
* @dev Asset data is stored by reference, in order to access the data corresponding to the ID, call
* `getAssetMetadata(tokenId, assetId)`.
* @dev You can safely get 10k
* @param tokenId ID of the token to retrieve the IDs of the active assets
* @return An array of active asset IDs of the given token
*/
function getActiveAssets(
uint256 tokenId
) external view returns (uint64[] memory);
/**
* @notice Used to retrieve IDs of the pending assets of given token.
* @dev Asset data is stored by reference, in order to access the data corresponding to the ID, call
* `getAssetMetadata(tokenId, assetId)`.
* @param tokenId ID of the token to retrieve the IDs of the pending assets
* @return An array of pending asset IDs of the given token
*/
function getPendingAssets(
uint256 tokenId
) external view returns (uint64[] memory);
/**
* @notice Used to retrieve the priorities of the active resoources of a given token.
* @dev Asset priorities are a non-sequential array of uint64 values with an array size equal to active asset
* priorites.
* @param tokenId ID of the token for which to retrieve the priorities of the active assets
* @return An array of priorities of the active assets of the given token
*/
function getActiveAssetPriorities(
uint256 tokenId
) external view returns (uint64[] memory);
/**
* @notice Used to retrieve the asset that will be replaced if a given asset from the token's pending array
* is accepted.
* @dev Asset data is stored by reference, in order to access the data corresponding to the ID, call
* `getAssetMetadata(tokenId, assetId)`.
* @param tokenId ID of the token to check
* @param newAssetId ID of the pending asset which will be accepted
* @return ID of the asset which will be replaced
*/
function getAssetReplacements(
uint256 tokenId,
uint64 newAssetId
) external view returns (uint64);
/**
* @notice Used to fetch the asset metadata of the specified token's active asset with the given index.
* @dev Assets are stored by reference mapping `_assets[assetId]`.
* @dev Can be overriden to implement enumerate, fallback or other custom logic.
* @param tokenId ID of the token from which to retrieve the asset metadata
* @param assetId Asset Id, must be in the active assets array
* @return The metadata of the asset belonging to the specified index in the token's active assets
* array
*/
function getAssetMetadata(
uint256 tokenId,
uint64 assetId
) external view returns (string memory);
// Approvals
/**
* @notice Used to grant permission to the user to manage token's assets.
* @dev This differs from transfer approvals, as approvals are not cleared when the approved party accepts or
* rejects an asset, or sets asset priorities. This approval is cleared on token transfer.
* @dev Only a single account can be approved at a time, so approving the `0x0` address clears previous approvals.
* @dev Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
* @dev Emits an {ApprovalForAssets} event.
* @param to Address of the account to grant the approval to
* @param tokenId ID of the token for which the approval to manage the assets is granted
*/
function approveForAssets(address to, uint256 tokenId) external;
/**
* @notice Used to retrieve the address of the account approved to manage assets of a given token.
* @dev Requirements:
*
* - `tokenId` must exist.
* @param tokenId ID of the token for which to retrieve the approved address
* @return Address of the account that is approved to manage the specified token's assets
*/
function getApprovedForAssets(
uint256 tokenId
) external view returns (address);
/**
* @notice Used to add or remove an operator of assets for the caller.
* @dev Operators can call {acceptAsset}, {rejectAsset}, {rejectAllAssets} or {setPriority} for any token
* owned by the caller.
* @dev Requirements:
*
* - The `operator` cannot be the caller.
* @dev Emits an {ApprovalForAllForAssets} event.
* @param operator Address of the account to which the operator role is granted or revoked from
* @param approved The boolean value indicating whether the operator role is being granted (`true`) or revoked
* (`false`)
*/
function setApprovalForAllForAssets(
address operator,
bool approved
) external;
/**
* @notice Used to check whether the address has been granted the operator role by a given address or not.
* @dev See {setApprovalForAllForAssets}.
* @param owner Address of the account that we are checking for whether it has granted the operator role
* @param operator Address of the account that we are checking whether it has the operator role or not
* @return A boolean value indicating wehter the account we are checking has been granted the operator role
*/
function isApprovedForAllForAssets(
address owner,
address operator
) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/ERC721.sol)
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "./AbstractMultiAsset.sol";
import "../core/RMRKCore.sol";
import "../library/RMRKErrors.sol";
/**
* @title RMRKMultiAsset
* @author RMRK team
* @notice Smart contract of the RMRK Multi asset module.
*/
contract RMRKMultiAsset is IERC165, IERC721, AbstractMultiAsset, RMRKCore {
using Address for address;
// Mapping from token ID to owner address
mapping(uint256 => address) private _owners;
// Mapping owner address to token count
mapping(address => uint256) private _balances;
// Mapping from token ID to approved address
mapping(uint256 => address) private _tokenApprovals;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
// ------------------- ASSETS --------------
// Mapping from token ID to approved address for assets
mapping(uint256 => address) private _tokenApprovalsForAssets;
// -------------------------- ERC721 MODIFIERS ----------------------------
/**
* @notice Used to verify that the caller is the owner of the given token or approved by its owner to manage it.
* @dev If the caller is not the owner or approved by the owner, the execution is reverted.
* @param tokenId ID of the token being checked
*/
function _onlyApprovedOrOwner(uint256 tokenId) private view {
if (!_isApprovedOrOwner(_msgSender(), tokenId))
revert ERC721NotApprovedOrOwner();
}
/**
* @notice Used to verify that the caller is the owner of the given token or approved by its owner to manage it.
* @param tokenId ID of the token being checked
*/
modifier onlyApprovedOrOwner(uint256 tokenId) {
_onlyApprovedOrOwner(tokenId);
_;
}
// ----------------------- MODIFIERS FOR ASSETS ------------------------
/**
* @notice Internal function to check whether the queried user is either:
* 1. The root owner of the token associated with `tokenId`.
* 2. Is approved for all assets of the current owner via the `setApprovalForAllForAssets` function.
* 3. Is granted approval for the specific tokenId for asset management via the `approveForAssets` function.
* @param user Address of the user we are checking for permission
* @param tokenId ID of the token to query for permission for a given `user`
* @return A boolean value indicating whether the user is approved to manage the token or not
*/
function _isApprovedForAssetsOrOwner(
address user,
uint256 tokenId
) internal view virtual returns (bool) {
address owner = ownerOf(tokenId);
return (user == owner ||
isApprovedForAllForAssets(owner, user) ||
getApprovedForAssets(tokenId) == user);
}
/**
* @notice Used to verify that the caller is either the owner of the given token or approved by its owner to manage
* the assets on the given token.
* @dev If the caller is not the owner of the given token or approved by its owner to manage the assets on the
* given token, the execution will be reverted.
* @param tokenId ID of the token being checked
*/
function _onlyApprovedForAssetsOrOwner(uint256 tokenId) private view {
if (!_isApprovedForAssetsOrOwner(_msgSender(), tokenId))
revert RMRKNotApprovedForAssetsOrOwner();
}
/**
* @notice Used to verify that the caller is either the owner of the given token or approved by its owner to manage
* the assets on the given token.
* @param tokenId ID of the token being checked
*/
modifier onlyApprovedForAssetsOrOwner(uint256 tokenId) {
_onlyApprovedForAssetsOrOwner(tokenId);
_;
}
// ----------------------------- CONSTRUCTOR ------------------------------
/**
* @notice Initializes the contract by setting a name and a symbol to the token collection.
* @param name_ Name of the token collection
* @param symbol_ Symbol of the token collection
*/
constructor(
string memory name_,
string memory symbol_
) RMRKCore(name_, symbol_) {}
// ------------------------------- ERC721 ---------------------------------
/**
* @inheritdoc IERC165
*/
function supportsInterface(
bytes4 interfaceId
) public view virtual returns (bool) {
return
interfaceId == type(IERC165).interfaceId ||
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
interfaceId == type(IERC5773).interfaceId;
}
/**
* @notice Used to retrieve the number of tokens in ``owner``'s account.
* @param owner Address of the account being checked
* @return The balance of the given account
*/
function balanceOf(address owner) public view virtual returns (uint256) {
if (owner == address(0)) revert ERC721AddressZeroIsNotaValidOwner();
return _balances[owner];
}
/**
* @notice Used to retrieve the owner of the given token.
* @dev Requirements:
*
* - `tokenId` must exist.
* @param tokenId ID of the token for which to retrieve the token for
* @return Address of the account owning the token
*/
function ownerOf(uint256 tokenId) public view virtual returns (address) {
address owner = _owners[tokenId];
if (owner == address(0)) revert ERC721InvalidTokenId();
return owner;
}
/**
* @notice Used to grant a one-time approval to manage one's token.
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* @dev The approval is cleared when the token is transferred.
* @dev Only a single account can be approved at a time, so approving the zero address clears previous approvals.
* @dev Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
* @dev Emits an {Approval} event.
* @param to Address receiving the approval
* @param tokenId ID of the token for which the approval is being granted
*/
function approve(address to, uint256 tokenId) public virtual {
address owner = ownerOf(tokenId);
if (to == owner) revert ERC721ApprovalToCurrentOwner();
if (_msgSender() != owner && !isApprovedForAll(owner, _msgSender()))
revert ERC721ApproveCallerIsNotOwnerNorApprovedForAll();
_approve(to, tokenId);
}
/**
* @notice Used to retrieve the account approved to manage given token.
* @dev Requirements:
*
* - `tokenId` must exist.
* @param tokenId ID of the token to check for approval
* @return Address of the account approved to manage the token
*/
function getApproved(
uint256 tokenId
) public view virtual returns (address) {
_requireMinted(tokenId);
return _tokenApprovals[tokenId];
}
/**
* @notice Used to approve or remove `operator` as an operator for the caller.
* @dev Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
* @dev Requirements:
*
* - The `operator` cannot be the caller.
* @dev Emits an {ApprovalForAll} event.
* @param operator Address of the operator being managed
* @param approved A boolean value signifying whether the approval is being granted (`true`) or (`revoked`)
*/
function setApprovalForAll(address operator, bool approved) public virtual {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @notice Used to check if the given address is allowed to manage the tokens of the specified address.
* @param owner Address of the owner of the tokens
* @param operator Address being checked for approval
* @return A boolean value signifying whether the *operator* is allowed to manage the tokens of the *owner* (`true`)
* or not (`false`)
*/
function isApprovedForAll(
address owner,
address operator
) public view virtual returns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @notice Transfers a given token from `from` to `to`.
* @dev 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}.
* @dev Emits a {Transfer} event.
* @param from Address from which to transfer the token from
* @param to Address to which to transfer the token to
* @param tokenId ID of the token to transfer
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) public virtual onlyApprovedOrOwner(tokenId) {
_transfer(from, to, tokenId);
}
/**
* @notice Used to safely transfer a given token token from `from` to `to`.
* @dev Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
* @dev Emits a {Transfer} event.
* @param from Address to transfer the tokens from
* @param to Address to transfer the tokens to
* @param tokenId ID of the token to transfer
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public virtual {
safeTransferFrom(from, to, tokenId, "");
}
/**
* @notice Used to safely transfer a given token token from `from` to `to`.
* @dev Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
* @dev Emits a {Transfer} event.
* @param from Address to transfer the tokens from
* @param to Address to transfer the tokens to
* @param tokenId ID of the token to transfer
* @param data Additional data without a specified format to be sent along with the token transaction
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory data
) public virtual onlyApprovedOrOwner(tokenId) {
_safeTransfer(from, to, tokenId, data);
}
/**
* @notice 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.
* @dev `data` is additional data, it has no specified format and it is sent in call to `to`.
* @dev This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. implement alternative
* mechanisms to perform token transfer, such as signature-based.
* @dev Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
* @dev Emits a {Transfer} event.
* @param from Address from which to send the token from
* @param to Address to which to send the token to
* @param tokenId ID of the token to be sent
* @param data Additional data to send with the tokens
*/
function _safeTransfer(
address from,
address to,
uint256 tokenId,
bytes memory data
) internal virtual {
_transfer(from, to, tokenId);
if (!_checkOnERC721Received(from, to, tokenId, data))
revert ERC721TransferToNonReceiverImplementer();
}
/**
* @notice Used to check whether the given token exists.
* @dev Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
* @dev Tokens start existing when they are minted (`_mint`) and stop existing when they are burned (`_burn`).
* @param tokenId ID of the token being checked
* @return A boolean value signifying whether the token exists
*/
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _owners[tokenId] != address(0);
}
/**
* @notice Used to check whether the given account is allowed to manage the given token.
* @dev Requirements:
*
* - `tokenId` must exist.
* @param spender Address that is being checked for approval
* @param tokenId ID of the token being checked
* @return A boolean value indicating whether the `spender` is approved to manage the given token
*/
function _isApprovedOrOwner(
address spender,
uint256 tokenId
) internal view virtual returns (bool) {
address owner = ownerOf(tokenId);
return (spender == owner ||
isApprovedForAll(owner, spender) ||
getApproved(tokenId) == spender);
}
/**
* @notice Used to safely mint the token to the specified address while passing the additional data to contract
* recipients.
* @param to Address to which to mint the token.
* @param tokenId ID of the token to mint
* @param data Additional data to send with the tokens
*/
function _safeMint(
address to,
uint256 tokenId,
bytes memory data
) internal virtual {
_mint(to, tokenId);
if (!_checkOnERC721Received(address(0), to, tokenId, data))
revert ERC721TransferToNonReceiverImplementer();
}
/**
* @notice Used to mint a specified token to a given address.
* @dev WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible.
* @dev Requirements:
*
* - `tokenId` must not exist.
* - `to` cannot be the zero address.
* @dev Emits a {Transfer} event.
* @param to Address to mint the token to
* @param tokenId ID of the token to mint
*/
function _mint(address to, uint256 tokenId) internal virtual {
if (to == address(0)) revert ERC721MintToTheZeroAddress();
if (_exists(tokenId)) revert ERC721TokenAlreadyMinted();
if (tokenId == uint256(0)) revert RMRKIdZeroForbidden();
_beforeTokenTransfer(address(0), to, tokenId);
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
_afterTokenTransfer(address(0), to, tokenId);
}
/**
* @notice Used to destroy the specified token.
* @dev The approval is cleared when the token is burned.
* @dev Requirements:
*
* - `tokenId` must exist.
* @dev Emits a {Transfer} event.
* @param tokenId ID of the token to burn
*/
function _burn(uint256 tokenId) internal virtual {
address owner = ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId);
// Clear approvals
_approve(address(0), tokenId);
_approveForAssets(address(0), tokenId);
_balances[owner] -= 1;
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
_afterTokenTransfer(owner, address(0), tokenId);
}
/**
* @notice Used to transfer the specified token from one user to another.
* @dev As opposed to {transferFrom}, this imposes no restrictions on `msg.sender`.
* @dev Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* @dev Emits a {Transfer} event.
* @param from Address from which to transfer the token
* @param to Address to which to transfer the token
* @param tokenId ID of the token to transfer
*/
function _transfer(
address from,
address to,
uint256 tokenId
) internal virtual {
if (ownerOf(tokenId) != from) revert ERC721TransferFromIncorrectOwner();
if (to == address(0)) revert ERC721TransferToTheZeroAddress();
_beforeTokenTransfer(from, to, tokenId);
// Clear approvals from the previous owner
delete _tokenApprovals[tokenId];
delete _tokenApprovalsForAssets[tokenId];
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
_afterTokenTransfer(from, to, tokenId);
}
/**
* @notice Used to grant an approval to an address to manage the given token.
* @dev Emits an {Approval} event.
* @param to Address receiveing the approval
* @param tokenId ID of the token that the approval is being granted for
*/
function _approve(address to, uint256 tokenId) internal virtual {
_tokenApprovals[tokenId] = to;
emit Approval(ownerOf(tokenId), to, tokenId);
}
/**
* @notice Used to manage an approval to an address to manage all of the tokens of the user.
* @dev If the user attempts to grant the approval to themselves, the execution is reverted.
* @dev Emits an {ApprovalForAll} event.
* @param owner Address of the account for which the approval is being granted
* @param operator Address receiving approval to manage all of the tokens of the `owner`
* @param approved Boolean value signifying whether
*/
function _setApprovalForAll(
address owner,
address operator,
bool approved
) internal virtual {
if (owner == operator) revert ERC721ApproveToCaller();
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @notice Used to verify thet the token has been minted.
* @dev The token is considered minted if its owner is not the `0x0` address.
* @dev This function doesn't output any feedback about the token existing, but it reverts if the token doesn't
* exist.
* @param tokenId ID of the token being checked
*/
function _requireMinted(uint256 tokenId) internal view virtual {
if (!_exists(tokenId)) revert ERC721InvalidTokenId();
}
/**
* @notice Used to invoke {IERC721Receiver-onERC721Received} on a target address.
* @dev The call is not executed if the target address is not a contract.
* @param from Address representing the previous owner of the given token
* @param to Yarget address that will receive the tokens
* @param tokenId ID of the token to be transferred
* @param data Optional data to send along with the call
* @return Boolean value signifying whether the call correctly returned the expected magic value
*/
function _checkOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory data
) private returns (bool) {
if (to.isContract()) {
try
IERC721Receiver(to).onERC721Received(
_msgSender(),
from,
tokenId,
data
)
returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == uint256(0)) {
revert ERC721TransferToNonReceiverImplementer();
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
}
// ------------------------------- ASSETS ------------------------------
/**
* @inheritdoc IERC5773
*/
function acceptAsset(
uint256 tokenId,
uint256 index,
uint64 assetId
) public virtual onlyApprovedForAssetsOrOwner(tokenId) {
_acceptAsset(tokenId, index, assetId);
}
/**
* @inheritdoc IERC5773
*/
function rejectAsset(
uint256 tokenId,
uint256 index,
uint64 assetId
) public virtual onlyApprovedForAssetsOrOwner(tokenId) {
_rejectAsset(tokenId, index, assetId);
}
/**
* @inheritdoc IERC5773
*/
function rejectAllAssets(
uint256 tokenId,
uint256 maxRejections
) public virtual onlyApprovedForAssetsOrOwner(tokenId) {
_rejectAllAssets(tokenId, maxRejections);
}
/**
* @inheritdoc IERC5773
*/
function setPriority(
uint256 tokenId,
uint64[] calldata priorities
) public virtual onlyApprovedForAssetsOrOwner(tokenId) {
_setPriority(tokenId, priorities);
}
// ----------------------- APPROVALS FOR ASSETS ------------------------
/**
* @inheritdoc IERC5773
*/
function approveForAssets(address to, uint256 tokenId) public virtual {
address owner = ownerOf(tokenId);
if (to == owner) revert RMRKApprovalForAssetsToCurrentOwner();
if (
_msgSender() != owner &&
!isApprovedForAllForAssets(owner, _msgSender())
) revert RMRKApproveForAssetsCallerIsNotOwnerNorApprovedForAll();
_approveForAssets(to, tokenId);
}
/**
* @notice Used to grant an approval to an address to manage assets of a given token.
* @dev Emits ***ApprovalForAssets*** event.
* @param to Address of the account to grant the approval to
* @param tokenId ID of the token for which the approval is being given
*/
function _approveForAssets(address to, uint256 tokenId) internal virtual {
_tokenApprovalsForAssets[tokenId] = to;
emit ApprovalForAssets(ownerOf(tokenId), to, tokenId);
}
/**
* @inheritdoc IERC5773
*/
function getApprovedForAssets(
uint256 tokenId
) public view virtual returns (address) {
_requireMinted(tokenId);
return _tokenApprovalsForAssets[tokenId];
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
/**
* @title RMRKCollectionMetadata
* @author RMRK team
* @notice Smart contract of the RMRK Collection metadata module.
*/
contract RMRKCollectionMetadata {
string private _collectionMetadata;
/**
* @notice Used to initialize the contract with the given metadata.
* @param collectionMetadata_ The collection metadata with which to initialize the smart contract
*/
constructor(string memory collectionMetadata_) {
_setCollectionMetadata(collectionMetadata_);
}
/**
* @notice Used to set the metadata of the collection.
* @param newMetadata The new metadata of the collection
*/
function _setCollectionMetadata(string memory newMetadata) internal {
_collectionMetadata = newMetadata;
}
/**
* @notice Used to retrieve the metadata of the collection.
* @return string The metadata URI of the collection
*/
function collectionMetadata() public view returns (string memory) {
return _collectionMetadata;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.16;
/**
* @title IAttributes
* @author Evrloot team
* @notice Interface for Evrloot attributes calls
* @dev getTotal switch is used to get the total attributes for the asset considering equipped children
*/
interface IAttributes {
function getAttributes(
uint256 assetId,
bool getTotal
) external view returns (uint16[] memory);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
/**
* @title IRMRKInitData
* @author RMRK team
* @notice Interface representation of RMRK initialization data.
* @dev This interface provides a struct used to pack data to avoid stack too deep error for too many arguments.
*/
interface IRMRKInitData {
/**
* @notice Used to provide initialization data without running into stack too deep errors.
* @return erc20TokenAddress Address of the ERC20 token to be used when initializing a smart contract that supports
* ERC20 pay module
* @return tokenUriIsEnumerable Weather the token URI is enumerable or not
* @return royaltyRecipient Recipient of resale royalties
* @return royaltyPercentageBps The percentage to be paid from the sale of the token expressed in basis points
* @return maxSupply The maximum supply of tokens
* @return pricePerMint The price per single-token mint expressed in the lowest denomination of native currency
*/
struct InitData {
//address erc20TokenAddress; // 20 bytes
// bool tokenUriIsEnumerable; // 1 byte
// --- new slot ---
address royaltyRecipient; // 20 bytes
uint16 royaltyPercentageBps; // 2 bytes
// --- new slot ---
uint256 maxSupply;
uint256 maxVIPSupply;
// --- new slot ---
uint256 pricePerMintVIP;
uint256 pricePerMintNonVIP;
string tokenURIVIP;
// another 32 bytes
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
import "@rmrk-team/evm-contracts/contracts/RMRK/access/OwnableLock.sol";
import "@rmrk-team/evm-contracts/contracts/RMRK/library/RMRKErrors.sol";
error RMRKMintSaleClosed();
/**
* @title RMRKMintingUtils
* @author RMRK team
* @notice Smart contract of the RMRK minting utils module.
* @dev This smart contract includes the top-level utilities for managing minting and implements OwnableLock by default.
* @dev Max supply-related and pricing variables are immutable after deployment.
*/
contract RMRKMintingUtils is OwnableLock {
uint256 internal _nextId;
uint256 internal _totalSupply;
uint256 internal _totalVIPSupply;
uint256 internal _maxSupply;
uint256 internal _maxVIPSupply;
uint256 internal immutable _pricePerMintVIP;
uint256 internal immutable _pricePerMintNonVIP;
uint256 constant MAX_VIP_PER_ACCOUNT = 5;
uint256 constant MAX_NON_VIP_PER_ACCOUNT = 1;
mapping(address => uint256) internal _vipMinted;
mapping(address => uint256) internal _nonVipMinted;
bool internal _saleEnabled = false;
/**
* @notice Initializes the smart contract with a given maximum supply and minting price.
* @param maxSupply_ The maximum supply of tokens to initialize the smart contract with
* @param pricePerMintVIP_ The minting price to initialize the smart contract with, expressed in the smallest
* @param pricePerMintNonVIP_ Minting price for non-vip
* denomination of the native currency of the chain to which the smart contract is deployed to
*/
constructor(
uint256 maxSupply_,
uint256 maxVIPSupply_,
uint256 pricePerMintVIP_,
uint256 pricePerMintNonVIP_
) {
_maxSupply = maxSupply_;
_maxVIPSupply = maxVIPSupply_;
_pricePerMintVIP = pricePerMintVIP_;
_pricePerMintNonVIP = pricePerMintNonVIP_;
}
/**
* @notice Used to verify that the sale of the given token is still available.
* @dev If the maximum supply is reached, the execution will be reverted.
*/
modifier saleIsOpen() {
_checkSaleIsOpen();
_;
}
function enableSale(bool enabled) public onlyOwner {
_saleEnabled = enabled;
}
// function saleOpen() public view returns (bool) {
// return _saleEnabled;
// }
/**
* @inheritdoc OwnableLock
*/
function setLock() public virtual override onlyOwner {
super.setLock();
_maxSupply = _totalSupply;
}
/**
* @notice Used to retrieve the total supply of the tokens in a collection.
* @return The number of tokens in a collection
*/
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
/**
* @notice Used to retrieve the maximum supply of the collection.
* @return The maximum supply of tokens in the collection
*/
function maxSupply() public view returns (uint256) {
return _maxSupply;
}
/**
* @notice Used to retrieve the total supply of the tokens in a collection.
* @return The number of tokens in a collection
*/
function totalVIPSupply() public view returns (uint256) {
return _totalVIPSupply;
}
/**
* @notice Used to retrieve the maximum supply of the collection.
* @return The maximum supply of tokens in the collection
*/
function maxVIPSupply() public view returns (uint256) {
return _maxVIPSupply;
}
/**
* @notice Used to retrieve the price per mint.
* @return The price per mint of a single token expressed in the lowest denomination of a native currency
*/
function pricePerMintVIP() public view returns (uint256) {
return _pricePerMintVIP;
}
/**
* @notice Used to retrieve the price per mint.
* @return The price per mint of a single token expressed in the lowest denomination of a native currency
*/
function pricePerMintNonVIP() public view returns (uint256) {
return _pricePerMintNonVIP;
}
/**
* @notice Used to withdraw the minting proceedings to a specified address.
* @dev This function can only be called by the owner.
* @param to Address to receive the given amount of minting proceedings
* @param amount The amount to withdraw
*/
function withdrawRaised(address to, uint256 amount) external onlyOwner {
_withdraw(to, amount);
}
function balanceOfVIP(address account) public view returns (uint256) {
return _vipMinted[account];
}
/**
* @notice Used to withdraw the minting proceedings to a specified address.
* @param _address Address to receive the given amount of minting proceedings
* @param _amount The amount to withdraw
*/
function _withdraw(address _address, uint256 _amount) private {
(bool success, ) = _address.call{value: _amount}("");
require(success, "Transfer failed.");
}
/**
* @notice Used to verify that the sale is still open.
* @dev In case the maximum supply of the collection is reached, the execution is reverted.
*/
function _checkSaleIsOpen() private view {
if (!_saleEnabled) revert RMRKMintSaleClosed();
if (_nextId >= _maxSupply) revert RMRKMintOverMax();
}
}{
"optimizer": {
"enabled": true,
"runs": 175
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"string","name":"collectionMetadata_","type":"string"},{"internalType":"string","name":"tokenURI_","type":"string"},{"components":[{"internalType":"address","name":"royaltyRecipient","type":"address"},{"internalType":"uint16","name":"royaltyPercentageBps","type":"uint16"},{"internalType":"uint256","name":"maxSupply","type":"uint256"},{"internalType":"uint256","name":"maxVIPSupply","type":"uint256"},{"internalType":"uint256","name":"pricePerMintVIP","type":"uint256"},{"internalType":"uint256","name":"pricePerMintNonVIP","type":"uint256"},{"internalType":"string","name":"tokenURIVIP","type":"string"}],"internalType":"struct IRMRKInitData.InitData","name":"data","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ERC721AddressZeroIsNotaValidOwner","type":"error"},{"inputs":[],"name":"ERC721ApprovalToCurrentOwner","type":"error"},{"inputs":[],"name":"ERC721ApproveCallerIsNotOwnerNorApprovedForAll","type":"error"},{"inputs":[],"name":"ERC721ApproveToCaller","type":"error"},{"inputs":[],"name":"ERC721InvalidTokenId","type":"error"},{"inputs":[],"name":"ERC721MintToTheZeroAddress","type":"error"},{"inputs":[],"name":"ERC721NotApprovedOrOwner","type":"error"},{"inputs":[],"name":"ERC721TokenAlreadyMinted","type":"error"},{"inputs":[],"name":"ERC721TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"ERC721TransferToNonReceiverImplementer","type":"error"},{"inputs":[],"name":"ERC721TransferToTheZeroAddress","type":"error"},{"inputs":[],"name":"MintOverMaxPer","type":"error"},{"inputs":[],"name":"MintOverMaxVIP","type":"error"},{"inputs":[],"name":"RMRKApprovalForAssetsToCurrentOwner","type":"error"},{"inputs":[],"name":"RMRKApproveForAssetsCallerIsNotOwnerNorApprovedForAll","type":"error"},{"inputs":[],"name":"RMRKAssetAlreadyExists","type":"error"},{"inputs":[],"name":"RMRKBadPriorityListLength","type":"error"},{"inputs":[],"name":"RMRKIdZeroForbidden","type":"error"},{"inputs":[],"name":"RMRKIndexOutOfRange","type":"error"},{"inputs":[],"name":"RMRKLocked","type":"error"},{"inputs":[],"name":"RMRKMaxPendingAssetsReached","type":"error"},{"inputs":[],"name":"RMRKMintOverMax","type":"error"},{"inputs":[],"name":"RMRKMintSaleClosed","type":"error"},{"inputs":[],"name":"RMRKMintZero","type":"error"},{"inputs":[],"name":"RMRKNewContributorIsZeroAddress","type":"error"},{"inputs":[],"name":"RMRKNewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"RMRKNoAssetMatchingId","type":"error"},{"inputs":[],"name":"RMRKNotApprovedForAssetsOrOwner","type":"error"},{"inputs":[],"name":"RMRKNotOwner","type":"error"},{"inputs":[],"name":"RMRKNotOwnerOrContributor","type":"error"},{"inputs":[],"name":"RMRKRoyaltiesTooHigh","type":"error"},{"inputs":[],"name":"RMRKTokenDoesNotHaveAsset","type":"error"},{"inputs":[],"name":"RMRKUnexpectedAssetId","type":"error"},{"inputs":[],"name":"RMRKUnexpectedNumberOfAssets","type":"error"},{"inputs":[],"name":"RMRKWrongValueSent","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAllForAssets","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ApprovalForAssets","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"assetId","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"replacesId","type":"uint64"}],"name":"AssetAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"indexed":true,"internalType":"uint64","name":"assetId","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"replacesId","type":"uint64"}],"name":"AssetAddedToTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"AssetPrioritySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"assetId","type":"uint64"}],"name":"AssetRejected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"assetId","type":"uint64"}],"name":"AssetSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contributor","type":"address"},{"indexed":false,"internalType":"bool","name":"isContributor","type":"bool"}],"name":"ContributorUpdate","type":"event"},{"anonymous":false,"inputs":[],"name":"LockSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"RMRK_INTERFACE","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint64","name":"assetId","type":"uint64"}],"name":"acceptAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"metadataURI","type":"string"}],"name":"addAssetEntry","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint64","name":"assetId","type":"uint64"},{"internalType":"uint64","name":"replacesAssetWithId","type":"uint64"}],"name":"addAssetToToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approveForAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOfVIP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collectionMetadata","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"enableSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getActiveAssetPriorities","outputs":[{"internalType":"uint64[]","name":"","type":"uint64[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getActiveAssets","outputs":[{"internalType":"uint64[]","name":"","type":"uint64[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApprovedForAssets","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint64","name":"assetId","type":"uint64"}],"name":"getAssetMetadata","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint64","name":"newAssetId","type":"uint64"}],"name":"getAssetReplacements","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"name":"getAttributes","outputs":[{"internalType":"uint16[]","name":"attributes","type":"uint16[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLock","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getPendingAssets","outputs":[{"internalType":"uint64[]","name":"","type":"uint64[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRoyaltyPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRoyaltyRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAllForAssets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contributor","type":"address"}],"name":"isContributor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isVIP","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contributor","type":"address"},{"internalType":"bool","name":"grantRole","type":"bool"}],"name":"manageContributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxVIPSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"numToMint","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"numToMint","type":"uint256"}],"name":"mintVIP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pricePerMintNonVIP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pricePerMintVIP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"maxRejections","type":"uint256"}],"name":"rejectAllAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint64","name":"assetId","type":"uint64"}],"name":"rejectAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAllForAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setLock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint64[]","name":"priorities","type":"uint64[]"}],"name":"setPriority","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":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalVIPSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRoyaltyRecipient","type":"address"}],"name":"updateRoyaltyRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawRaised","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60c0604052600a805460ff191690553480156200001b57600080fd5b50604051620039d8380380620039d88339810160408190526200003e9162000375565b848481818460000151856020015161ffff16888760400151886060015189608001518a60a001516200007f620000796200012260201b60201c565b62000126565b60069390935560079190915560805260a0526200009c8162000176565b50600c80546001600160a01b0319166001600160a01b0384161790556127108110620000db57604051634006185d60e11b815260040160405180910390fd5b600d55506015620000ed8382620004e4565b506016620000fc8282620004e4565b505050505062000117828260c001516200018860201b60201c565b5050505050620005b0565b3390565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600b620001848282620004e4565b5050565b601d620001968382620004e4565b50601e620001a58282620004e4565b505050565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b0381118282101715620001e557620001e5620001aa565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620002165762000216620001aa565b604052919050565b600082601f8301126200023057600080fd5b81516001600160401b038111156200024c576200024c620001aa565b602062000262601f8301601f19168201620001eb565b82815285828487010111156200027757600080fd5b60005b83811015620002975785810183015182820184015282016200027a565b506000928101909101919091529392505050565b80516001600160a01b0381168114620002c357600080fd5b919050565b805161ffff81168114620002c357600080fd5b600060e08284031215620002ee57600080fd5b620002f8620001c0565b90506200030582620002ab565b81526200031560208301620002c8565b602082015260408201516040820152606082015160608201526080820151608082015260a082015160a082015260c082015160018060401b038111156200035b57600080fd5b62000369848285016200021e565b60c08301525092915050565b600080600080600060a086880312156200038e57600080fd5b85516001600160401b0380821115620003a657600080fd5b620003b489838a016200021e565b96506020880151915080821115620003cb57600080fd5b620003d989838a016200021e565b95506040880151915080821115620003f057600080fd5b620003fe89838a016200021e565b945060608801519150808211156200041557600080fd5b6200042389838a016200021e565b935060808801519150808211156200043a57600080fd5b506200044988828901620002db565b9150509295509295909350565b600181811c908216806200046b57607f821691505b6020821081036200048c57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620001a557600081815260208120601f850160051c81016020861015620004bb5750805b601f850160051c820191505b81811015620004dc57828155600101620004c7565b505050505050565b81516001600160401b03811115620005005762000500620001aa565b620005188162000511845462000456565b8462000492565b602080601f831160018114620005505760008415620005375750858301515b600019600386901b1c1916600185901b178555620004dc565b600085815260208120601f198616915b82811015620005815788860151825594840194600190910190840162000560565b5085821015620005a05787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a0516133f4620005e46000396000818161036e0152610f1701526000818161087401526115f701526133f46000f3fe6080604052600436106103065760003560e01c8063715018a6116101a1578063b88d4fde116100f2578063df6f556b116100a0578063e985e9c51161006f578063e985e9c514610a44578063f2fde38b14610a8d578063fc3517c814610aad578063ffa1ad7414610acd57600080fd5b8063df6f556b14610975578063e467a48f146109d1578063e4dc951f146109f1578063e7de4de414610a2457600080fd5b8063b88d4fde146108b8578063bb0f8b6d146108d8578063c70b5ae5146108f8578063c87b56dd1461090b578063d49304be1461092b578063d5abeb0114610940578063de8e602c1461095557600080fd5b806389ed2edf1161014f57806389ed2edf146107cb5780638d4f3bf5146107e05780638da5cb5b1461081457806395d89b411461083257806395edc18c146108475780639e74673f14610865578063a22cb4651461089857600080fd5b8063715018a6146106f35780637280281e1461070857806379e8ca9e146107285780637a573275146107485780637aba6f371461077e5780637e5852d9146107935780638507dc28146107ab57600080fd5b80632a55205a1161025b57806351532e5a1161020957806351532e5a1461061157806359c8b7dd1461063e5780635e2e3292146106535780635e94354a146106735780635ea72f36146106935780636352211e146106b357806370a08231146106d357600080fd5b80632a55205a1461051257806330ffb1d61461055157806333ed2845146105715780633600261d1461059157806340c10f19146105be57806342842e0e146105d157806342966c68146105f157600080fd5b8063149a4f01116102b8578063149a4f011461042e57806318160ddd146104435780631c7bb461146104585780631d0d35f51461047857806322e6d160146104b257806322f6da9c146104d257806323b872dd146104f257600080fd5b806301e1d1141461030b57806301ffc9a71461032f578063042242f81461035f57806306fdde0314610392578063081812fc146103b4578063095ea7b3146103ec5780630fc499f51461040e575b600080fd5b34801561031757600080fd5b50601c545b6040519081526020015b60405180910390f35b34801561033b57600080fd5b5061034f61034a366004612c63565b610afe565b6040519015158152602001610326565b34801561036b57600080fd5b507f000000000000000000000000000000000000000000000000000000000000000061031c565b34801561039e57600080fd5b506103a7610b60565b6040516103269190612ccd565b3480156103c057600080fd5b506103d46103cf366004612ce0565b610bf2565b6040516001600160a01b039091168152602001610326565b3480156103f857600080fd5b5061040c610407366004612d10565b610c19565b005b34801561041a57600080fd5b5061040c610429366004612d3a565b610ca5565b34801561043a57600080fd5b5060075461031c565b34801561044f57600080fd5b5060045461031c565b34801561046457600080fd5b5061040c610473366004612d6c565b610cce565b34801561048457600080fd5b5061034f610493366004612d3a565b6001600160a01b03166000908152600160208190526040909120541490565b3480156104be57600080fd5b5061034f6104cd366004612da8565b610ce1565b3480156104de57600080fd5b5061040c6104ed366004612dd2565b610d0f565b3480156104fe57600080fd5b5061040c61050d366004612dfe565b610d2a565b34801561051e57600080fd5b5061053261052d366004612e3a565b610d3f565b604080516001600160a01b039093168352602083019190915201610326565b34801561055d57600080fd5b5061031c61056c366004612ee7565b610d75565b34801561057d57600080fd5b5061040c61058c366004612d10565b610d9e565b34801561059d57600080fd5b506105b16105ac366004612f3f565b610db4565b6040516103269190612f62565b61031c6105cc366004612d10565b610eb1565b3480156105dd57600080fd5b5061040c6105ec366004612dfe565b61102d565b3480156105fd57600080fd5b5061040c61060c366004612ce0565b611048565b34801561061d57600080fd5b5061063161062c366004612ce0565b61105b565b6040516103269190612faa565b34801561064a57600080fd5b50600d5461031c565b34801561065f57600080fd5b506103a761066e366004612feb565b6110ef565b34801561067f57600080fd5b5061063161068e366004612ce0565b6111de565b34801561069f57600080fd5b5061040c6106ae366004612d10565b611247565b3480156106bf57600080fd5b506103d46106ce366004612ce0565b6112ce565b3480156106df57600080fd5b5061031c6106ee366004612d3a565b611304565b3480156106ff57600080fd5b5061040c611349565b34801561071457600080fd5b50610631610723366004612ce0565b61135d565b34801561073457600080fd5b5061040c61074336600461300e565b6113c6565b34801561075457600080fd5b5061031c610763366004612d3a565b6001600160a01b031660009081526008602052604090205490565b34801561078a57600080fd5b5061040c611483565b34801561079f57600080fd5b5060025460011461034f565b3480156107b757600080fd5b5061040c6107c636600461300e565b61149b565b3480156107d757600080fd5b506103a7611530565b3480156107ec57600080fd5b506107fb63524d524b60e01b81565b6040516001600160e01b03199091168152602001610326565b34801561082057600080fd5b506000546001600160a01b03166103d4565b34801561083e57600080fd5b506103a761153f565b34801561085357600080fd5b50600c546001600160a01b03166103d4565b34801561087157600080fd5b507f000000000000000000000000000000000000000000000000000000000000000061031c565b3480156108a457600080fd5b5061040c6108b336600461300e565b61154e565b3480156108c457600080fd5b5061040c6108d3366004613038565b611559565b3480156108e457600080fd5b5061040c6108f33660046130b3565b611576565b61031c610906366004612d10565b611591565b34801561091757600080fd5b506103a7610926366004612ce0565b611724565b34801561093757600080fd5b5060055461031c565b34801561094c57600080fd5b5060065461031c565b34801561096157600080fd5b5061040c6109703660046130ce565b6117d5565b34801561098157600080fd5b506109b9610990366004612feb565b6000918252600f602090815260408084206001600160401b039384168552909152909120541690565b6040516001600160401b039091168152602001610326565b3480156109dd57600080fd5b506103d46109ec366004612ce0565b6117ea565b3480156109fd57600080fd5b5061034f610a0c366004612ce0565b6000908152601f602052604090205460ff1660011490565b348015610a3057600080fd5b5061040c610a3f366004612e3a565b611811565b348015610a5057600080fd5b5061034f610a5f366004612da8565b6001600160a01b039182166000908152601a6020908152604080832093909416825291909152205460ff1690565b348015610a9957600080fd5b5061040c610aa8366004612d3a565b611825565b348015610ab957600080fd5b5061040c610ac8366004612dd2565b61185d565b348015610ad957600080fd5b506103a760405180604001604052806005815260200164312e322e3160d81b81525081565b6000610b0982611872565b80610b2457506001600160e01b0319821663152a902d60e11b145b80610b3f57506001600160e01b0319821663524d524b60e01b145b80610b5a57506001600160e01b03198216633600261d60e01b145b92915050565b606060158054610b6f9061314c565b80601f0160208091040260200160405190810160405280929190818152602001828054610b9b9061314c565b8015610be85780601f10610bbd57610100808354040283529160200191610be8565b820191906000526020600020905b815481529060010190602001808311610bcb57829003601f168201915b5050505050905090565b6000610bfd826118de565b506000908152601960205260409020546001600160a01b031690565b6000610c24826112ce565b9050806001600160a01b0316836001600160a01b031603610c5857604051630591db6d60e01b815260040160405180910390fd5b336001600160a01b03821614801590610c785750610c768133610a5f565b155b15610c9657604051634c12315960e11b815260040160405180910390fd5b610ca08383611913565b505050565b610cad611981565b600c80546001600160a01b0319166001600160a01b03831617905550565b50565b610cd66119ac565b610ca08383836119eb565b6001600160a01b03918216600090815260146020908152604080832093909416825291909152205460ff1690565b82610d1981611be1565b610d24848484611c08565b50505050565b80610d3481611c77565b610d24848484611c9e565b600c54600d546001600160a01b039091169060009061271090610d62908561319c565b610d6c91906131b3565b90509250929050565b6000610d7f6119ac565b601c805460010190819055610d949083611ded565b50601c545b919050565b610da6611981565b610db08282611eb3565b5050565b6000828152601f6020526040908190205481516019808252610340820190935260609260ff9092169181602001602082028036833701905050915060ff811615610e5357600782600081518110610e0d57610e0d6131d5565b602002602001019061ffff16908161ffff1681525050600d82600a81518110610e3857610e386131d5565b602002602001019061ffff16908161ffff1681525050610eaa565b600382600081518110610e6857610e686131d5565b602002602001019061ffff16908161ffff1681525050600982600a81518110610e9357610e936131d5565b602002602001019061ffff16908161ffff16815250505b5092915050565b6000610ebb611f4d565b610ec3611f70565b81610ee15760405163376bec4d60e01b815260040160405180910390fd5b600654600354610ef190846131eb565b1115610f1057604051635e91cdfb60e11b815260040160405180910390fd5b6000610f3c7f00000000000000000000000000000000000000000000000000000000000000008461319c565b9050348114610f5e576040516336ce5e4360e01b815260040160405180910390fd5b6001600160a01b038416600090815260096020526040902054600190610f859085906131eb565b1115610fa457604051633be4b58160e21b815260040160405180910390fd5b60006003546001610fb591906131eb565b600380548601815560048054870190556001600160a01b0387166000908152600960205260408120805488019055905491925090610ff49060016131eb565b9050815b818110156110225761101a878260405180602001604052806000815250611fb7565b600101610ff8565b509095945050505050565b610ca083838360405180602001604052806000815250611559565b8061105281611c77565b610db082611feb565b6000818152601160209081526040918290208054835181840281018401909452808452606093928301828280156110e357602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116110a05790505b50505050509050919050565b60008281526013602090815260408083206001600160401b038516845290915290205460609060ff1661113557604051631b9928fd60e31b815260040160405180910390fd5b6001600160401b0382166000908152600e6020526040902080546111589061314c565b80601f01602080910402602001604051908101604052809291908181526020018280546111849061314c565b80156111d15780601f106111a6576101008083540402835291602001916111d1565b820191906000526020600020905b8154815290600101906020018083116111b457829003601f168201915b5050505050905092915050565b6000818152601260209081526040918290208054835181840281018401909452808452606093928301828280156110e357600091825260209182902080546001600160401b031684529082028301929091600891018084116110a0575094979650505050505050565b6000611252826112ce565b9050806001600160a01b0316836001600160a01b031603611286576040516375f45abd60e01b815260040160405180910390fd5b336001600160a01b038216148015906112a657506112a48133610ce1565b155b156112c4576040516357a2e94960e11b815260040160405180910390fd5b610ca0838361209d565b6000818152601760205260408120546001600160a01b031680610b5a5760405163089ba7e160e41b815260040160405180910390fd5b60006001600160a01b03821661132d57604051633bb9143360e11b815260040160405180910390fd5b506001600160a01b031660009081526018602052604090205490565b611351611981565b61135b600061210b565b565b6000818152601060209081526040918290208054835181840281018401909452808452606093928301828280156110e357600091825260209182902080546001600160401b031684529082028301929091600891018084116110a0575094979650505050505050565b6113ce611981565b6001600160a01b0382166113f55760405163016b812760e71b815260040160405180910390fd5b8061141a576001600160a01b0382166000908152600160205260408120819055611439565b6001600160a01b03821660009081526001602081905260409091208190555b50816001600160a01b03167f4b5657e84cf8a17ac5587bbeb3cc2bab9826c4c67b8bad81b4849de49d37aac282604051611477911515815260200190565b60405180910390a25050565b61148b611981565b61149361215b565b600454600655565b6001600160a01b03821633036114c4576040516375f45abd60e01b815260040160405180910390fd5b3360008181526014602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f0cff4fcf777050010027190b8061fd8bfd1de16d81b1f94e9752df1427a26235910160405180910390a35050565b6060600b8054610b6f9061314c565b606060168054610b6f9061314c565b610db0338383612193565b8161156381611c77565b61156f85858585612232565b5050505050565b61157e611981565b600a805460ff1916911515919091179055565b600061159b611f4d565b6115a3611f70565b816115c15760405163376bec4d60e01b815260040160405180910390fd5b6007546003546115d190846131eb565b11156115f057604051635e91cdfb60e11b815260040160405180910390fd5b600061161c7f00000000000000000000000000000000000000000000000000000000000000008461319c565b905034811461163e576040516336ce5e4360e01b815260040160405180910390fd5b6001600160a01b0384166000908152600860205260409020546005906116659085906131eb565b111561168457604051630464dc2960e51b815260040160405180910390fd5b6000600354600161169591906131eb565b6003805486018155600480548701905560058054870190556001600160a01b03871660009081526008602052604081208054880190559054919250906116dc9060016131eb565b9050815b8181101561102257611702878260405180602001604052806000815250611fb7565b6000818152601f60205260409020805460ff19166001908117909155016116e0565b6000818152601f602052604090205460609060ff166001036117c857601e805461174d9061314c565b80601f01602080910402602001604051908101604052809291908181526020018280546117799061314c565b80156110e35780601f1061179b576101008083540402835291602001916110e3565b820191906000526020600020905b8154815290600101906020018083116117a95750939695505050505050565b601d805461174d9061314c565b826117df81611be1565b610d24848484612266565b60006117f5826118de565b506000908152601b60205260409020546001600160a01b031690565b8161181b81611be1565b610ca083836122e0565b61182d611981565b6001600160a01b03811661185457604051634ece6ecf60e01b815260040160405180910390fd5b610ccb8161210b565b8261186781611be1565b610d248484846123d8565b60006001600160e01b031982166301ffc9a760e01b14806118a357506001600160e01b031982166380ac58cd60e01b145b806118be57506001600160e01b03198216635b5e139f60e01b145b80610b5a57506001600160e01b0319821663035a194d60e11b1492915050565b6000818152601760205260409020546001600160a01b0316610ccb5760405163089ba7e160e41b815260040160405180910390fd5b600081815260196020526040902080546001600160a01b0319166001600160a01b0384169081179091558190611948826112ce565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000546001600160a01b0316331461135b57604051631c62d58f60e11b815260040160405180910390fd5b6000546001600160a01b031633148015906119cd57506119cb33610493565b155b1561135b576040516301eca16760e41b815260040160405180910390fd5b60008381526013602090815260408083206001600160401b038616845290915290205460ff1615611a2f576040516308fe3c3160e41b815260040160405180910390fd5b6001600160401b0382166000908152600e602052604081208054611a529061314c565b905003611a7257604051632aa5eff960e11b815260040160405180910390fd5b600083815260116020526040902054608011611aa15760405163bade3a7b60e01b815260040160405180910390fd5b60008381526013602090815260408083206001600160401b038681168086529184528285208054600160ff19909116811790915588865260118552928520805493840181558552929093206004820401805460039092166008026101000a808402199092169190930217909155811615611b4f576000838152600f602090815260408083206001600160401b0386811685529252909120805467ffffffffffffffff19169183169190911790555b604080516001808252818301909252600091602080830190803683370190505090508381600081518110611b8557611b856131d5565b602002602001018181525050816001600160401b0316836001600160401b03167f4a85a0221f784dbe75db7c29c422f474c15bde9211a98e50a30018fa8dfa937b83604051611bd491906131fe565b60405180910390a3610d24565b611beb338261261c565b610ccb57604051635d64832960e01b815260040160405180910390fd5b611c1383838361267b565b611c1e838383612723565b60008381526013602090815260408083206001600160401b0385168085529252808320805460ff1916905551909185917f1010837a46db9510cad56c9b63e97183557a136e9d4ddbec309ce52c99afb1249190a3505050565b611c813382612771565b610ccb576040516302728a9d60e41b815260040160405180910390fd5b826001600160a01b0316611cb1826112ce565b6001600160a01b031614611cd85760405163e146af6f60e01b815260040160405180910390fd5b6001600160a01b038216611cff576040516338f646ff60e21b815260040160405180910390fd5b611d0a8383836127dd565b600081815260196020908152604080832080546001600160a01b0319908116909155601b8352818420805490911690556001600160a01b038616835260189091528120805460019290611d5e908490613236565b90915550506001600160a01b0382166000908152601860205260408120805460019290611d8c9084906131eb565b909155505060008181526017602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6001600160401b038216611e14576040516312c33ce360e01b815260040160405180910390fd5b6001600160401b0382166000908152600e602052604081208054611e379061314c565b90501115611e58576040516308fe3c3160e41b815260040160405180910390fd5b6001600160401b0382166000908152600e60205260409020611e7a828261328f565b506040516001600160401b038316907f3cd061096eaf881067d936308fbd8b81d060c45ab2ec910c02b953162befc10990600090a25050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611f00576040519150601f19603f3d011682016040523d82523d6000602084013e611f05565b606091505b5050905080610ca05760405162461bcd60e51b815260206004820152601060248201526f2a3930b739b332b9103330b4b632b21760811b604482015260640160405180910390fd5b60025460010361135b5760405163ed1fa96f60e01b815260040160405180910390fd5b600a5460ff16611f93576040516306d3818760e11b815260040160405180910390fd5b6006546003541061135b57604051635e91cdfb60e11b815260040160405180910390fd5b611fc183836127fa565b611fce6000848484612908565b610ca05760405163bcb5663760e01b815260040160405180910390fd5b6000611ff6826112ce565b9050612004816000846127dd565b61200f600083611913565b61201a60008361209d565b6001600160a01b0381166000908152601860205260408120805460019290612043908490613236565b909155505060008281526017602052604080822080546001600160a01b0319169055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000818152601b6020526040902080546001600160a01b0319166001600160a01b03841690811790915581906120d2826112ce565b6001600160a01b03167fb90cc0d925ac3511ab6af2d7ca73ffcf7ec4bd871fff36b958ecf440079c463e60405160405180910390a45050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b612163611981565b60016002556040517f3e423347941b5c6e8c727e4071ffeb6869244ce75121d6a56ba8356086851c6c90600090a1565b816001600160a01b0316836001600160a01b0316036121c557604051630b7b99b960e21b815260040160405180910390fd5b6001600160a01b038381166000818152601a6020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b61223d848484611c9e565b61224984848484612908565b610d245760405163bcb5663760e01b815260040160405180910390fd5b6000838152601060205260409020548190811461229657604051633581be1d60e11b815260040160405180910390fd5b60008481526012602052604090206122af908484612b56565b5060405184907ff0bfd70b0068f973d58178846ca67112671ec45e060838f7de5662036bcf801790600090a2610d24565b6000828152601160205260409020548181111561231057604051635134ce8960e01b815260040160405180910390fd5b60005b8181101561238e57600084815260116020526040812080548390811061233b5761233b6131d5565b60009182526020808320600483040154888452600f8252604080852060039094166008026101000a9091046001600160401b031684529190529020805467ffffffffffffffff1916905550600101612313565b5060008381526011602052604081206123a691612c17565b60405160009084907f1010837a46db9510cad56c9b63e97183557a136e9d4ddbec309ce52c99afb124908390a3505050565b6123e383838361267b565b6000838152600f602090815260408083206001600160401b038086168552925282205416908082156124bb576124b583601060008981526020019081526020016000208054806020026020016040519081016040528092919081815260200182805480156124a257602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b03168152602001906008019060208260070104928301926001038202915080841161245f5790505b5050505050612a0790919063ffffffff16565b90925090505b801561253c5760008681526010602052604090208054859190849081106124e4576124e46131d5565b600091825260208083206004830401805460039093166008026101000a6001600160401b038181021990941695841602949094179093558882526013835260408083209187168352925220805460ff191690556125c7565b6000868152601260209081526040808320601083529083208054825460018181018555938652848620600480830490910180546001600160401b0394851660086003958616810261010090810a9283029288021990931691909117909255855496870186559488529587209085040180548b84169590921690950290920a9283029202191617905592505b6125d2868686612723565b826001600160401b0316846001600160401b0316877f3f2709a99f6c06b4e57bbb38eb0134332f96f51a3da314f41a515adbb28b17cc60405160405180910390a45b505050505050565b600080612628836112ce565b9050806001600160a01b0316846001600160a01b0316148061264f575061264f8185610ce1565b806126735750836001600160a01b0316612668846117ea565b6001600160a01b0316145b949350505050565b60008381526011602052604090205482106126a957604051630757d52160e01b815260040160405180910390fd5b60008381526011602052604090208054839081106126c9576126c96131d5565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b03166001600160401b0316816001600160401b031614610ca0576040516378eeeecf60e01b815260040160405180910390fd5b600083815260116020526040902061273b9083612a70565b6000928352600f602090815260408085206001600160401b039093168552919052909120805467ffffffffffffffff1916905550565b60008061277d836112ce565b9050806001600160a01b0316846001600160a01b031614806127c457506001600160a01b038082166000908152601a602090815260408083209388168352929052205460ff165b806126735750836001600160a01b031661266884610bf2565b6001600160a01b038216610ca05760048054600019019055505050565b6001600160a01b038216612821576040516325bd6bd360e01b815260040160405180910390fd5b6000818152601760205260409020546001600160a01b0316156128575760405163c5a8d37160e01b815260040160405180910390fd5b80612875576040516312c33ce360e01b815260040160405180910390fd5b612881600083836127dd565b6001600160a01b03821660009081526018602052604081208054600192906128aa9084906131eb565b909155505060008181526017602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60006001600160a01b0384163b156129fc57604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061294c90339089908890889060040161334e565b6020604051808303816000875af1925050508015612987575060408051601f3d908101601f191682019092526129849181019061338b565b60015b6129e2573d8080156129b5576040519150601f19603f3d011682016040523d82523d6000602084013e6129ba565b606091505b5080516129da5760405163bcb5663760e01b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050612673565b506001949350505050565b81516000908190815b81811015612a5f57846001600160401b0316868281518110612a3457612a346131d5565b60200260200101516001600160401b031603612a5757925060019150612a699050565b600101612a10565b5060008092509250505b9250929050565b81548110612a7d57600080fd5b81548290612a8d90600190613236565b81548110612a9d57612a9d6131d5565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b0316828281548110612ad857612ad86131d5565b90600052602060002090600491828204019190066008026101000a8154816001600160401b0302191690836001600160401b0316021790555081805480612b2157612b216133a8565b60008281526020902060046000199092019182040180546001600160401b03600860038516026101000a021916905590555050565b82805482825590600052602060002090600301600490048101928215612c075791602002820160005b83821115612bd25783356001600160401b031683826101000a8154816001600160401b0302191690836001600160401b031602179055509260200192600801602081600701049283019260010302612b7f565b8015612c055782816101000a8154906001600160401b030219169055600801602081600701049283019260010302612bd2565b505b50612c13929150612c38565b5090565b508054600082556003016004900490600052602060002090810190610ccb91905b5b80821115612c135760008155600101612c39565b6001600160e01b031981168114610ccb57600080fd5b600060208284031215612c7557600080fd5b8135612c8081612c4d565b9392505050565b6000815180845260005b81811015612cad57602081850181015186830182015201612c91565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000612c806020830184612c87565b600060208284031215612cf257600080fd5b5035919050565b80356001600160a01b0381168114610d9957600080fd5b60008060408385031215612d2357600080fd5b612d2c83612cf9565b946020939093013593505050565b600060208284031215612d4c57600080fd5b612c8082612cf9565b80356001600160401b0381168114610d9957600080fd5b600080600060608486031215612d8157600080fd5b83359250612d9160208501612d55565b9150612d9f60408501612d55565b90509250925092565b60008060408385031215612dbb57600080fd5b612dc483612cf9565b9150610d6c60208401612cf9565b600080600060608486031215612de757600080fd5b8335925060208401359150612d9f60408501612d55565b600080600060608486031215612e1357600080fd5b612e1c84612cf9565b9250612e2a60208501612cf9565b9150604084013590509250925092565b60008060408385031215612e4d57600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b60006001600160401b0380841115612e8c57612e8c612e5c565b604051601f8501601f19908116603f01168101908282118183101715612eb457612eb4612e5c565b81604052809350858152868686011115612ecd57600080fd5b858560208301376000602087830101525050509392505050565b600060208284031215612ef957600080fd5b81356001600160401b03811115612f0f57600080fd5b8201601f81018413612f2057600080fd5b61267384823560208401612e72565b80358015158114610d9957600080fd5b60008060408385031215612f5257600080fd5b82359150610d6c60208401612f2f565b6020808252825182820181905260009190848201906040850190845b81811015612f9e57835161ffff1683529284019291840191600101612f7e565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015612f9e5783516001600160401b031683529284019291840191600101612fc6565b60008060408385031215612ffe57600080fd5b82359150610d6c60208401612d55565b6000806040838503121561302157600080fd5b61302a83612cf9565b9150610d6c60208401612f2f565b6000806000806080858703121561304e57600080fd5b61305785612cf9565b935061306560208601612cf9565b92506040850135915060608501356001600160401b0381111561308757600080fd5b8501601f8101871361309857600080fd5b6130a787823560208401612e72565b91505092959194509250565b6000602082840312156130c557600080fd5b612c8082612f2f565b6000806000604084860312156130e357600080fd5b8335925060208401356001600160401b038082111561310157600080fd5b818601915086601f83011261311557600080fd5b81358181111561312457600080fd5b8760208260051b850101111561313957600080fd5b6020830194508093505050509250925092565b600181811c9082168061316057607f821691505b60208210810361318057634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610b5a57610b5a613186565b6000826131d057634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b80820180821115610b5a57610b5a613186565b6020808252825182820181905260009190848201906040850190845b81811015612f9e5783518352928401929184019160010161321a565b81810381811115610b5a57610b5a613186565b601f821115610ca057600081815260208120601f850160051c810160208610156132705750805b601f850160051c820191505b818110156126145782815560010161327c565b81516001600160401b038111156132a8576132a8612e5c565b6132bc816132b6845461314c565b84613249565b602080601f8311600181146132f157600084156132d95750858301515b600019600386901b1c1916600185901b178555612614565b600085815260208120601f198616915b8281101561332057888601518255948401946001909101908401613301565b508582101561333e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061338190830184612c87565b9695505050505050565b60006020828403121561339d57600080fd5b8151612c8081612c4d565b634e487b7160e01b600052603160045260246000fdfea264697066735822122030042155a931f73c020fd80f7595313bbb6bb78e8d8fc3c28a99a769a90d789864736f6c6343000815003300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000172450494e4b2078204576726c6f6f74205065726d697473000000000000000000000000000000000000000000000000000000000000000000000000000000000c50494e4b784576726c6f6f7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d576661764574444d7738664338744b6d7351325456596252704d4d70674e417a373471396d6d5a6e43624d3700000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d5a457858796f5259594c74554e6e77554e737937735366644b535969324c79414258455567784b64647450500000000000000000000000000000000000000000000000cb5eb537bad9c54a4dae2e3526473d79a496456a00000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000950000000000000000000000000000000000000000000000055de6a779bbac0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d595041386368476a75517a6171334a476b524b576932636a6d50734a4b316346594d54765a52524c736e38710000000000000000000000
Deployed Bytecode
0x6080604052600436106103065760003560e01c8063715018a6116101a1578063b88d4fde116100f2578063df6f556b116100a0578063e985e9c51161006f578063e985e9c514610a44578063f2fde38b14610a8d578063fc3517c814610aad578063ffa1ad7414610acd57600080fd5b8063df6f556b14610975578063e467a48f146109d1578063e4dc951f146109f1578063e7de4de414610a2457600080fd5b8063b88d4fde146108b8578063bb0f8b6d146108d8578063c70b5ae5146108f8578063c87b56dd1461090b578063d49304be1461092b578063d5abeb0114610940578063de8e602c1461095557600080fd5b806389ed2edf1161014f57806389ed2edf146107cb5780638d4f3bf5146107e05780638da5cb5b1461081457806395d89b411461083257806395edc18c146108475780639e74673f14610865578063a22cb4651461089857600080fd5b8063715018a6146106f35780637280281e1461070857806379e8ca9e146107285780637a573275146107485780637aba6f371461077e5780637e5852d9146107935780638507dc28146107ab57600080fd5b80632a55205a1161025b57806351532e5a1161020957806351532e5a1461061157806359c8b7dd1461063e5780635e2e3292146106535780635e94354a146106735780635ea72f36146106935780636352211e146106b357806370a08231146106d357600080fd5b80632a55205a1461051257806330ffb1d61461055157806333ed2845146105715780633600261d1461059157806340c10f19146105be57806342842e0e146105d157806342966c68146105f157600080fd5b8063149a4f01116102b8578063149a4f011461042e57806318160ddd146104435780631c7bb461146104585780631d0d35f51461047857806322e6d160146104b257806322f6da9c146104d257806323b872dd146104f257600080fd5b806301e1d1141461030b57806301ffc9a71461032f578063042242f81461035f57806306fdde0314610392578063081812fc146103b4578063095ea7b3146103ec5780630fc499f51461040e575b600080fd5b34801561031757600080fd5b50601c545b6040519081526020015b60405180910390f35b34801561033b57600080fd5b5061034f61034a366004612c63565b610afe565b6040519015158152602001610326565b34801561036b57600080fd5b507f000000000000000000000000000000000000000000000000000000000000000061031c565b34801561039e57600080fd5b506103a7610b60565b6040516103269190612ccd565b3480156103c057600080fd5b506103d46103cf366004612ce0565b610bf2565b6040516001600160a01b039091168152602001610326565b3480156103f857600080fd5b5061040c610407366004612d10565b610c19565b005b34801561041a57600080fd5b5061040c610429366004612d3a565b610ca5565b34801561043a57600080fd5b5060075461031c565b34801561044f57600080fd5b5060045461031c565b34801561046457600080fd5b5061040c610473366004612d6c565b610cce565b34801561048457600080fd5b5061034f610493366004612d3a565b6001600160a01b03166000908152600160208190526040909120541490565b3480156104be57600080fd5b5061034f6104cd366004612da8565b610ce1565b3480156104de57600080fd5b5061040c6104ed366004612dd2565b610d0f565b3480156104fe57600080fd5b5061040c61050d366004612dfe565b610d2a565b34801561051e57600080fd5b5061053261052d366004612e3a565b610d3f565b604080516001600160a01b039093168352602083019190915201610326565b34801561055d57600080fd5b5061031c61056c366004612ee7565b610d75565b34801561057d57600080fd5b5061040c61058c366004612d10565b610d9e565b34801561059d57600080fd5b506105b16105ac366004612f3f565b610db4565b6040516103269190612f62565b61031c6105cc366004612d10565b610eb1565b3480156105dd57600080fd5b5061040c6105ec366004612dfe565b61102d565b3480156105fd57600080fd5b5061040c61060c366004612ce0565b611048565b34801561061d57600080fd5b5061063161062c366004612ce0565b61105b565b6040516103269190612faa565b34801561064a57600080fd5b50600d5461031c565b34801561065f57600080fd5b506103a761066e366004612feb565b6110ef565b34801561067f57600080fd5b5061063161068e366004612ce0565b6111de565b34801561069f57600080fd5b5061040c6106ae366004612d10565b611247565b3480156106bf57600080fd5b506103d46106ce366004612ce0565b6112ce565b3480156106df57600080fd5b5061031c6106ee366004612d3a565b611304565b3480156106ff57600080fd5b5061040c611349565b34801561071457600080fd5b50610631610723366004612ce0565b61135d565b34801561073457600080fd5b5061040c61074336600461300e565b6113c6565b34801561075457600080fd5b5061031c610763366004612d3a565b6001600160a01b031660009081526008602052604090205490565b34801561078a57600080fd5b5061040c611483565b34801561079f57600080fd5b5060025460011461034f565b3480156107b757600080fd5b5061040c6107c636600461300e565b61149b565b3480156107d757600080fd5b506103a7611530565b3480156107ec57600080fd5b506107fb63524d524b60e01b81565b6040516001600160e01b03199091168152602001610326565b34801561082057600080fd5b506000546001600160a01b03166103d4565b34801561083e57600080fd5b506103a761153f565b34801561085357600080fd5b50600c546001600160a01b03166103d4565b34801561087157600080fd5b507f0000000000000000000000000000000000000000000000055de6a779bbac000061031c565b3480156108a457600080fd5b5061040c6108b336600461300e565b61154e565b3480156108c457600080fd5b5061040c6108d3366004613038565b611559565b3480156108e457600080fd5b5061040c6108f33660046130b3565b611576565b61031c610906366004612d10565b611591565b34801561091757600080fd5b506103a7610926366004612ce0565b611724565b34801561093757600080fd5b5060055461031c565b34801561094c57600080fd5b5060065461031c565b34801561096157600080fd5b5061040c6109703660046130ce565b6117d5565b34801561098157600080fd5b506109b9610990366004612feb565b6000918252600f602090815260408084206001600160401b039384168552909152909120541690565b6040516001600160401b039091168152602001610326565b3480156109dd57600080fd5b506103d46109ec366004612ce0565b6117ea565b3480156109fd57600080fd5b5061034f610a0c366004612ce0565b6000908152601f602052604090205460ff1660011490565b348015610a3057600080fd5b5061040c610a3f366004612e3a565b611811565b348015610a5057600080fd5b5061034f610a5f366004612da8565b6001600160a01b039182166000908152601a6020908152604080832093909416825291909152205460ff1690565b348015610a9957600080fd5b5061040c610aa8366004612d3a565b611825565b348015610ab957600080fd5b5061040c610ac8366004612dd2565b61185d565b348015610ad957600080fd5b506103a760405180604001604052806005815260200164312e322e3160d81b81525081565b6000610b0982611872565b80610b2457506001600160e01b0319821663152a902d60e11b145b80610b3f57506001600160e01b0319821663524d524b60e01b145b80610b5a57506001600160e01b03198216633600261d60e01b145b92915050565b606060158054610b6f9061314c565b80601f0160208091040260200160405190810160405280929190818152602001828054610b9b9061314c565b8015610be85780601f10610bbd57610100808354040283529160200191610be8565b820191906000526020600020905b815481529060010190602001808311610bcb57829003601f168201915b5050505050905090565b6000610bfd826118de565b506000908152601960205260409020546001600160a01b031690565b6000610c24826112ce565b9050806001600160a01b0316836001600160a01b031603610c5857604051630591db6d60e01b815260040160405180910390fd5b336001600160a01b03821614801590610c785750610c768133610a5f565b155b15610c9657604051634c12315960e11b815260040160405180910390fd5b610ca08383611913565b505050565b610cad611981565b600c80546001600160a01b0319166001600160a01b03831617905550565b50565b610cd66119ac565b610ca08383836119eb565b6001600160a01b03918216600090815260146020908152604080832093909416825291909152205460ff1690565b82610d1981611be1565b610d24848484611c08565b50505050565b80610d3481611c77565b610d24848484611c9e565b600c54600d546001600160a01b039091169060009061271090610d62908561319c565b610d6c91906131b3565b90509250929050565b6000610d7f6119ac565b601c805460010190819055610d949083611ded565b50601c545b919050565b610da6611981565b610db08282611eb3565b5050565b6000828152601f6020526040908190205481516019808252610340820190935260609260ff9092169181602001602082028036833701905050915060ff811615610e5357600782600081518110610e0d57610e0d6131d5565b602002602001019061ffff16908161ffff1681525050600d82600a81518110610e3857610e386131d5565b602002602001019061ffff16908161ffff1681525050610eaa565b600382600081518110610e6857610e686131d5565b602002602001019061ffff16908161ffff1681525050600982600a81518110610e9357610e936131d5565b602002602001019061ffff16908161ffff16815250505b5092915050565b6000610ebb611f4d565b610ec3611f70565b81610ee15760405163376bec4d60e01b815260040160405180910390fd5b600654600354610ef190846131eb565b1115610f1057604051635e91cdfb60e11b815260040160405180910390fd5b6000610f3c7f00000000000000000000000000000000000000000000000000000000000000008461319c565b9050348114610f5e576040516336ce5e4360e01b815260040160405180910390fd5b6001600160a01b038416600090815260096020526040902054600190610f859085906131eb565b1115610fa457604051633be4b58160e21b815260040160405180910390fd5b60006003546001610fb591906131eb565b600380548601815560048054870190556001600160a01b0387166000908152600960205260408120805488019055905491925090610ff49060016131eb565b9050815b818110156110225761101a878260405180602001604052806000815250611fb7565b600101610ff8565b509095945050505050565b610ca083838360405180602001604052806000815250611559565b8061105281611c77565b610db082611feb565b6000818152601160209081526040918290208054835181840281018401909452808452606093928301828280156110e357602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b0316815260200190600801906020826007010492830192600103820291508084116110a05790505b50505050509050919050565b60008281526013602090815260408083206001600160401b038516845290915290205460609060ff1661113557604051631b9928fd60e31b815260040160405180910390fd5b6001600160401b0382166000908152600e6020526040902080546111589061314c565b80601f01602080910402602001604051908101604052809291908181526020018280546111849061314c565b80156111d15780601f106111a6576101008083540402835291602001916111d1565b820191906000526020600020905b8154815290600101906020018083116111b457829003601f168201915b5050505050905092915050565b6000818152601260209081526040918290208054835181840281018401909452808452606093928301828280156110e357600091825260209182902080546001600160401b031684529082028301929091600891018084116110a0575094979650505050505050565b6000611252826112ce565b9050806001600160a01b0316836001600160a01b031603611286576040516375f45abd60e01b815260040160405180910390fd5b336001600160a01b038216148015906112a657506112a48133610ce1565b155b156112c4576040516357a2e94960e11b815260040160405180910390fd5b610ca0838361209d565b6000818152601760205260408120546001600160a01b031680610b5a5760405163089ba7e160e41b815260040160405180910390fd5b60006001600160a01b03821661132d57604051633bb9143360e11b815260040160405180910390fd5b506001600160a01b031660009081526018602052604090205490565b611351611981565b61135b600061210b565b565b6000818152601060209081526040918290208054835181840281018401909452808452606093928301828280156110e357600091825260209182902080546001600160401b031684529082028301929091600891018084116110a0575094979650505050505050565b6113ce611981565b6001600160a01b0382166113f55760405163016b812760e71b815260040160405180910390fd5b8061141a576001600160a01b0382166000908152600160205260408120819055611439565b6001600160a01b03821660009081526001602081905260409091208190555b50816001600160a01b03167f4b5657e84cf8a17ac5587bbeb3cc2bab9826c4c67b8bad81b4849de49d37aac282604051611477911515815260200190565b60405180910390a25050565b61148b611981565b61149361215b565b600454600655565b6001600160a01b03821633036114c4576040516375f45abd60e01b815260040160405180910390fd5b3360008181526014602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f0cff4fcf777050010027190b8061fd8bfd1de16d81b1f94e9752df1427a26235910160405180910390a35050565b6060600b8054610b6f9061314c565b606060168054610b6f9061314c565b610db0338383612193565b8161156381611c77565b61156f85858585612232565b5050505050565b61157e611981565b600a805460ff1916911515919091179055565b600061159b611f4d565b6115a3611f70565b816115c15760405163376bec4d60e01b815260040160405180910390fd5b6007546003546115d190846131eb565b11156115f057604051635e91cdfb60e11b815260040160405180910390fd5b600061161c7f0000000000000000000000000000000000000000000000055de6a779bbac00008461319c565b905034811461163e576040516336ce5e4360e01b815260040160405180910390fd5b6001600160a01b0384166000908152600860205260409020546005906116659085906131eb565b111561168457604051630464dc2960e51b815260040160405180910390fd5b6000600354600161169591906131eb565b6003805486018155600480548701905560058054870190556001600160a01b03871660009081526008602052604081208054880190559054919250906116dc9060016131eb565b9050815b8181101561102257611702878260405180602001604052806000815250611fb7565b6000818152601f60205260409020805460ff19166001908117909155016116e0565b6000818152601f602052604090205460609060ff166001036117c857601e805461174d9061314c565b80601f01602080910402602001604051908101604052809291908181526020018280546117799061314c565b80156110e35780601f1061179b576101008083540402835291602001916110e3565b820191906000526020600020905b8154815290600101906020018083116117a95750939695505050505050565b601d805461174d9061314c565b826117df81611be1565b610d24848484612266565b60006117f5826118de565b506000908152601b60205260409020546001600160a01b031690565b8161181b81611be1565b610ca083836122e0565b61182d611981565b6001600160a01b03811661185457604051634ece6ecf60e01b815260040160405180910390fd5b610ccb8161210b565b8261186781611be1565b610d248484846123d8565b60006001600160e01b031982166301ffc9a760e01b14806118a357506001600160e01b031982166380ac58cd60e01b145b806118be57506001600160e01b03198216635b5e139f60e01b145b80610b5a57506001600160e01b0319821663035a194d60e11b1492915050565b6000818152601760205260409020546001600160a01b0316610ccb5760405163089ba7e160e41b815260040160405180910390fd5b600081815260196020526040902080546001600160a01b0319166001600160a01b0384169081179091558190611948826112ce565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000546001600160a01b0316331461135b57604051631c62d58f60e11b815260040160405180910390fd5b6000546001600160a01b031633148015906119cd57506119cb33610493565b155b1561135b576040516301eca16760e41b815260040160405180910390fd5b60008381526013602090815260408083206001600160401b038616845290915290205460ff1615611a2f576040516308fe3c3160e41b815260040160405180910390fd5b6001600160401b0382166000908152600e602052604081208054611a529061314c565b905003611a7257604051632aa5eff960e11b815260040160405180910390fd5b600083815260116020526040902054608011611aa15760405163bade3a7b60e01b815260040160405180910390fd5b60008381526013602090815260408083206001600160401b038681168086529184528285208054600160ff19909116811790915588865260118552928520805493840181558552929093206004820401805460039092166008026101000a808402199092169190930217909155811615611b4f576000838152600f602090815260408083206001600160401b0386811685529252909120805467ffffffffffffffff19169183169190911790555b604080516001808252818301909252600091602080830190803683370190505090508381600081518110611b8557611b856131d5565b602002602001018181525050816001600160401b0316836001600160401b03167f4a85a0221f784dbe75db7c29c422f474c15bde9211a98e50a30018fa8dfa937b83604051611bd491906131fe565b60405180910390a3610d24565b611beb338261261c565b610ccb57604051635d64832960e01b815260040160405180910390fd5b611c1383838361267b565b611c1e838383612723565b60008381526013602090815260408083206001600160401b0385168085529252808320805460ff1916905551909185917f1010837a46db9510cad56c9b63e97183557a136e9d4ddbec309ce52c99afb1249190a3505050565b611c813382612771565b610ccb576040516302728a9d60e41b815260040160405180910390fd5b826001600160a01b0316611cb1826112ce565b6001600160a01b031614611cd85760405163e146af6f60e01b815260040160405180910390fd5b6001600160a01b038216611cff576040516338f646ff60e21b815260040160405180910390fd5b611d0a8383836127dd565b600081815260196020908152604080832080546001600160a01b0319908116909155601b8352818420805490911690556001600160a01b038616835260189091528120805460019290611d5e908490613236565b90915550506001600160a01b0382166000908152601860205260408120805460019290611d8c9084906131eb565b909155505060008181526017602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6001600160401b038216611e14576040516312c33ce360e01b815260040160405180910390fd5b6001600160401b0382166000908152600e602052604081208054611e379061314c565b90501115611e58576040516308fe3c3160e41b815260040160405180910390fd5b6001600160401b0382166000908152600e60205260409020611e7a828261328f565b506040516001600160401b038316907f3cd061096eaf881067d936308fbd8b81d060c45ab2ec910c02b953162befc10990600090a25050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611f00576040519150601f19603f3d011682016040523d82523d6000602084013e611f05565b606091505b5050905080610ca05760405162461bcd60e51b815260206004820152601060248201526f2a3930b739b332b9103330b4b632b21760811b604482015260640160405180910390fd5b60025460010361135b5760405163ed1fa96f60e01b815260040160405180910390fd5b600a5460ff16611f93576040516306d3818760e11b815260040160405180910390fd5b6006546003541061135b57604051635e91cdfb60e11b815260040160405180910390fd5b611fc183836127fa565b611fce6000848484612908565b610ca05760405163bcb5663760e01b815260040160405180910390fd5b6000611ff6826112ce565b9050612004816000846127dd565b61200f600083611913565b61201a60008361209d565b6001600160a01b0381166000908152601860205260408120805460019290612043908490613236565b909155505060008281526017602052604080822080546001600160a01b0319169055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000818152601b6020526040902080546001600160a01b0319166001600160a01b03841690811790915581906120d2826112ce565b6001600160a01b03167fb90cc0d925ac3511ab6af2d7ca73ffcf7ec4bd871fff36b958ecf440079c463e60405160405180910390a45050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b612163611981565b60016002556040517f3e423347941b5c6e8c727e4071ffeb6869244ce75121d6a56ba8356086851c6c90600090a1565b816001600160a01b0316836001600160a01b0316036121c557604051630b7b99b960e21b815260040160405180910390fd5b6001600160a01b038381166000818152601a6020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b61223d848484611c9e565b61224984848484612908565b610d245760405163bcb5663760e01b815260040160405180910390fd5b6000838152601060205260409020548190811461229657604051633581be1d60e11b815260040160405180910390fd5b60008481526012602052604090206122af908484612b56565b5060405184907ff0bfd70b0068f973d58178846ca67112671ec45e060838f7de5662036bcf801790600090a2610d24565b6000828152601160205260409020548181111561231057604051635134ce8960e01b815260040160405180910390fd5b60005b8181101561238e57600084815260116020526040812080548390811061233b5761233b6131d5565b60009182526020808320600483040154888452600f8252604080852060039094166008026101000a9091046001600160401b031684529190529020805467ffffffffffffffff1916905550600101612313565b5060008381526011602052604081206123a691612c17565b60405160009084907f1010837a46db9510cad56c9b63e97183557a136e9d4ddbec309ce52c99afb124908390a3505050565b6123e383838361267b565b6000838152600f602090815260408083206001600160401b038086168552925282205416908082156124bb576124b583601060008981526020019081526020016000208054806020026020016040519081016040528092919081815260200182805480156124a257602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b03168152602001906008019060208260070104928301926001038202915080841161245f5790505b5050505050612a0790919063ffffffff16565b90925090505b801561253c5760008681526010602052604090208054859190849081106124e4576124e46131d5565b600091825260208083206004830401805460039093166008026101000a6001600160401b038181021990941695841602949094179093558882526013835260408083209187168352925220805460ff191690556125c7565b6000868152601260209081526040808320601083529083208054825460018181018555938652848620600480830490910180546001600160401b0394851660086003958616810261010090810a9283029288021990931691909117909255855496870186559488529587209085040180548b84169590921690950290920a9283029202191617905592505b6125d2868686612723565b826001600160401b0316846001600160401b0316877f3f2709a99f6c06b4e57bbb38eb0134332f96f51a3da314f41a515adbb28b17cc60405160405180910390a45b505050505050565b600080612628836112ce565b9050806001600160a01b0316846001600160a01b0316148061264f575061264f8185610ce1565b806126735750836001600160a01b0316612668846117ea565b6001600160a01b0316145b949350505050565b60008381526011602052604090205482106126a957604051630757d52160e01b815260040160405180910390fd5b60008381526011602052604090208054839081106126c9576126c96131d5565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b03166001600160401b0316816001600160401b031614610ca0576040516378eeeecf60e01b815260040160405180910390fd5b600083815260116020526040902061273b9083612a70565b6000928352600f602090815260408085206001600160401b039093168552919052909120805467ffffffffffffffff1916905550565b60008061277d836112ce565b9050806001600160a01b0316846001600160a01b031614806127c457506001600160a01b038082166000908152601a602090815260408083209388168352929052205460ff165b806126735750836001600160a01b031661266884610bf2565b6001600160a01b038216610ca05760048054600019019055505050565b6001600160a01b038216612821576040516325bd6bd360e01b815260040160405180910390fd5b6000818152601760205260409020546001600160a01b0316156128575760405163c5a8d37160e01b815260040160405180910390fd5b80612875576040516312c33ce360e01b815260040160405180910390fd5b612881600083836127dd565b6001600160a01b03821660009081526018602052604081208054600192906128aa9084906131eb565b909155505060008181526017602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60006001600160a01b0384163b156129fc57604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061294c90339089908890889060040161334e565b6020604051808303816000875af1925050508015612987575060408051601f3d908101601f191682019092526129849181019061338b565b60015b6129e2573d8080156129b5576040519150601f19603f3d011682016040523d82523d6000602084013e6129ba565b606091505b5080516129da5760405163bcb5663760e01b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050612673565b506001949350505050565b81516000908190815b81811015612a5f57846001600160401b0316868281518110612a3457612a346131d5565b60200260200101516001600160401b031603612a5757925060019150612a699050565b600101612a10565b5060008092509250505b9250929050565b81548110612a7d57600080fd5b81548290612a8d90600190613236565b81548110612a9d57612a9d6131d5565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b0316828281548110612ad857612ad86131d5565b90600052602060002090600491828204019190066008026101000a8154816001600160401b0302191690836001600160401b0316021790555081805480612b2157612b216133a8565b60008281526020902060046000199092019182040180546001600160401b03600860038516026101000a021916905590555050565b82805482825590600052602060002090600301600490048101928215612c075791602002820160005b83821115612bd25783356001600160401b031683826101000a8154816001600160401b0302191690836001600160401b031602179055509260200192600801602081600701049283019260010302612b7f565b8015612c055782816101000a8154906001600160401b030219169055600801602081600701049283019260010302612bd2565b505b50612c13929150612c38565b5090565b508054600082556003016004900490600052602060002090810190610ccb91905b5b80821115612c135760008155600101612c39565b6001600160e01b031981168114610ccb57600080fd5b600060208284031215612c7557600080fd5b8135612c8081612c4d565b9392505050565b6000815180845260005b81811015612cad57602081850181015186830182015201612c91565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000612c806020830184612c87565b600060208284031215612cf257600080fd5b5035919050565b80356001600160a01b0381168114610d9957600080fd5b60008060408385031215612d2357600080fd5b612d2c83612cf9565b946020939093013593505050565b600060208284031215612d4c57600080fd5b612c8082612cf9565b80356001600160401b0381168114610d9957600080fd5b600080600060608486031215612d8157600080fd5b83359250612d9160208501612d55565b9150612d9f60408501612d55565b90509250925092565b60008060408385031215612dbb57600080fd5b612dc483612cf9565b9150610d6c60208401612cf9565b600080600060608486031215612de757600080fd5b8335925060208401359150612d9f60408501612d55565b600080600060608486031215612e1357600080fd5b612e1c84612cf9565b9250612e2a60208501612cf9565b9150604084013590509250925092565b60008060408385031215612e4d57600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b60006001600160401b0380841115612e8c57612e8c612e5c565b604051601f8501601f19908116603f01168101908282118183101715612eb457612eb4612e5c565b81604052809350858152868686011115612ecd57600080fd5b858560208301376000602087830101525050509392505050565b600060208284031215612ef957600080fd5b81356001600160401b03811115612f0f57600080fd5b8201601f81018413612f2057600080fd5b61267384823560208401612e72565b80358015158114610d9957600080fd5b60008060408385031215612f5257600080fd5b82359150610d6c60208401612f2f565b6020808252825182820181905260009190848201906040850190845b81811015612f9e57835161ffff1683529284019291840191600101612f7e565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015612f9e5783516001600160401b031683529284019291840191600101612fc6565b60008060408385031215612ffe57600080fd5b82359150610d6c60208401612d55565b6000806040838503121561302157600080fd5b61302a83612cf9565b9150610d6c60208401612f2f565b6000806000806080858703121561304e57600080fd5b61305785612cf9565b935061306560208601612cf9565b92506040850135915060608501356001600160401b0381111561308757600080fd5b8501601f8101871361309857600080fd5b6130a787823560208401612e72565b91505092959194509250565b6000602082840312156130c557600080fd5b612c8082612f2f565b6000806000604084860312156130e357600080fd5b8335925060208401356001600160401b038082111561310157600080fd5b818601915086601f83011261311557600080fd5b81358181111561312457600080fd5b8760208260051b850101111561313957600080fd5b6020830194508093505050509250925092565b600181811c9082168061316057607f821691505b60208210810361318057634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610b5a57610b5a613186565b6000826131d057634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b80820180821115610b5a57610b5a613186565b6020808252825182820181905260009190848201906040850190845b81811015612f9e5783518352928401929184019160010161321a565b81810381811115610b5a57610b5a613186565b601f821115610ca057600081815260208120601f850160051c810160208610156132705750805b601f850160051c820191505b818110156126145782815560010161327c565b81516001600160401b038111156132a8576132a8612e5c565b6132bc816132b6845461314c565b84613249565b602080601f8311600181146132f157600084156132d95750858301515b600019600386901b1c1916600185901b178555612614565b600085815260208120601f198616915b8281101561332057888601518255948401946001909101908401613301565b508582101561333e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061338190830184612c87565b9695505050505050565b60006020828403121561339d57600080fd5b8151612c8081612c4d565b634e487b7160e01b600052603160045260246000fdfea264697066735822122030042155a931f73c020fd80f7595313bbb6bb78e8d8fc3c28a99a769a90d789864736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000172450494e4b2078204576726c6f6f74205065726d697473000000000000000000000000000000000000000000000000000000000000000000000000000000000c50494e4b784576726c6f6f7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d576661764574444d7738664338744b6d7351325456596252704d4d70674e417a373471396d6d5a6e43624d3700000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d5a457858796f5259594c74554e6e77554e737937735366644b535969324c79414258455567784b64647450500000000000000000000000000000000000000000000000cb5eb537bad9c54a4dae2e3526473d79a496456a00000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000950000000000000000000000000000000000000000000000055de6a779bbac0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d595041386368476a75517a6171334a476b524b576932636a6d50734a4b316346594d54765a52524c736e38710000000000000000000000
-----Decoded View---------------
Arg [0] : name_ (string): $PINK x Evrloot Permits
Arg [1] : symbol_ (string): PINKxEvrloot
Arg [2] : collectionMetadata_ (string): ipfs://QmWfavEtDMw8fC8tKmsQ2TVYbRpMMpgNAz74q9mmZnCbM7
Arg [3] : tokenURI_ (string): ipfs://QmZExXyoRYYLtUNnwUNsy7sSfdKSYi2LyABXEUgxKddtPP
Arg [4] : data (tuple):
Arg [1] : royaltyRecipient (address): 0xCb5eB537bAd9C54A4Dae2E3526473D79A496456A
Arg [2] : royaltyPercentageBps (uint16): 500
Arg [3] : maxSupply (uint256): 1000
Arg [4] : maxVIPSupply (uint256): 149
Arg [5] : pricePerMintVIP (uint256): 99000000000000000000
Arg [6] : pricePerMintNonVIP (uint256): 0
Arg [7] : tokenURIVIP (string): ipfs://QmYPA8chGjuQzaq3JGkRKWi2cjmPsJK1cFYMTvZRRLsn8q
-----Encoded View---------------
25 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000180
Arg [4] : 00000000000000000000000000000000000000000000000000000000000001e0
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000017
Arg [6] : 2450494e4b2078204576726c6f6f74205065726d697473000000000000000000
Arg [7] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [8] : 50494e4b784576726c6f6f740000000000000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000035
Arg [10] : 697066733a2f2f516d576661764574444d7738664338744b6d73513254565962
Arg [11] : 52704d4d70674e417a373471396d6d5a6e43624d370000000000000000000000
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000035
Arg [13] : 697066733a2f2f516d5a457858796f5259594c74554e6e77554e737937735366
Arg [14] : 644b535969324c79414258455567784b64647450500000000000000000000000
Arg [15] : 000000000000000000000000cb5eb537bad9c54a4dae2e3526473d79a496456a
Arg [16] : 00000000000000000000000000000000000000000000000000000000000001f4
Arg [17] : 00000000000000000000000000000000000000000000000000000000000003e8
Arg [18] : 0000000000000000000000000000000000000000000000000000000000000095
Arg [19] : 0000000000000000000000000000000000000000000000055de6a779bbac0000
Arg [20] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [21] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [22] : 0000000000000000000000000000000000000000000000000000000000000035
Arg [23] : 697066733a2f2f516d595041386368476a75517a6171334a476b524b57693263
Arg [24] : 6a6d50734a4b316346594d54765a52524c736e38710000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in GLMR
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
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.