Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
Showing the last 2 transactions (View Advanced Filter)
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Initialize | 17919611 | 831 days ago | IN | 0 ETH | 0.0102844 | ||||
| 0x60a06040 | 16744236 | 996 days ago | IN | 0 ETH | 0.33685742 |
Showing the last 1 internal transaction (View Advanced Filter)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x60806040 | 16744236 | 996 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
TieredDrop
Compiler Version
v0.8.12+commit.f00d7308
Optimization Enabled:
Yes with 100 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
// $$\ $$\ $$\ $$\ $$\
// $$ | $$ | \__| $$ | $$ |
// $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\
// \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\
// $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
// $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
// \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ |
// \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/
import "lib/dynamic-contracts/src/presets/BaseRouter.sol";
import "../extension/Multicall.sol";
import "../dynamic-contracts/extension/Initializable.sol";
import "../dynamic-contracts/extension/Permissions.sol";
import "../dynamic-contracts/extension/ERC2771ContextUpgradeable.sol";
import "../dynamic-contracts/init/ContractMetadataInit.sol";
import "../dynamic-contracts/init/ERC721AInit.sol";
import "../dynamic-contracts/init/OwnableInit.sol";
import "../dynamic-contracts/init/PermissionsEnumerableInit.sol";
import "../dynamic-contracts/init/PrimarySaleInit.sol";
import "../dynamic-contracts/init/RoyaltyInit.sol";
import "../dynamic-contracts/init/SignatureActionInit.sol";
import "../dynamic-contracts/init/DefaultOperatorFiltererInit.sol";
/**
* Defualt extensions to add:
* - TieredDropLogic
* - PermissionsEnumerable
*/
contract TieredDrop is
Initializable,
Multicall,
ERC2771ContextUpgradeable,
BaseRouter,
DefaultOperatorFiltererInit,
PrimarySaleInit,
ContractMetadataInit,
ERC721AInit,
OwnableInit,
PermissionsEnumerableInit,
RoyaltyInit,
SignatureActionInit
{
/*///////////////////////////////////////////////////////////////
Constructor and Initializer logic
//////////////////////////////////////////////////////////////*/
constructor(Extension[] memory _extensions) BaseRouter(_extensions) {}
/// @dev Initiliazes the contract, like a constructor.
function initialize(
address _defaultAdmin,
string memory _name,
string memory _symbol,
string memory _contractURI,
address[] memory _trustedForwarders,
address _saleRecipient,
address _royaltyRecipient,
uint16 _royaltyBps
) external initializer {
// Initialize inherited contracts, most base-like -> most derived.
__ERC2771Context_init(_trustedForwarders);
__ERC721A_init(_name, _symbol);
__SignatureAction_init();
_setupContractURI(_contractURI);
_setupOwner(_defaultAdmin);
_setupRoles(_defaultAdmin);
_setupDefaultRoyaltyInfo(_royaltyRecipient, _royaltyBps);
_setupPrimarySaleRecipient(_saleRecipient);
_setupOperatorFilterer();
}
function _setupRoles(address _defaultAdmin) internal onlyInitializing {
bytes32 _operatorRole = keccak256("OPERATOR_ROLE");
bytes32 _transferRole = keccak256("TRANSFER_ROLE");
bytes32 _minterRole = keccak256("MINTER_ROLE");
bytes32 _defaultAdminRole = 0x00;
_setupRole(_defaultAdminRole, _defaultAdmin);
_setupRole(_minterRole, _defaultAdmin);
_setupRole(_transferRole, _defaultAdmin);
_setupRole(_transferRole, address(0));
_setupRole(_operatorRole, _defaultAdmin);
_setupRole(_operatorRole, address(0));
}
/*///////////////////////////////////////////////////////////////
Internal functions
//////////////////////////////////////////////////////////////*/
/// @dev Returns whether a plugin can be set in the given execution context.
function _canSetExtension() internal view virtual override returns (bool) {
bytes32 defaultAdminRole = 0x00;
return _hasRole(defaultAdminRole, _msgSender());
}
/// @dev Checks whether an account holds the given role.
function _hasRole(bytes32 role, address addr) internal view returns (bool) {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
return data._hasRole[role][addr];
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v3.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
////////// CHANGELOG: turn `approve` to virtual //////////
import "../../eip/interface/IERC721A.sol";
import "../../eip/interface/IERC721Receiver.sol";
import "../../lib/TWAddress.sol";
import "../../openzeppelin-presets/utils/Context.sol";
import "../../lib/TWStrings.sol";
import "../../eip/ERC165.sol";
import "../extension/Initializable.sol";
library ERC721AStorage {
bytes32 public constant ERC721A_STORAGE_POSITION = keccak256("erc721.a.storage");
struct Data {
// The tokenId of the next token to be minted.
uint256 _currentIndex;
// The number of tokens burned.
uint256 _burnCounter;
// Token name
string _name;
// Token symbol
string _symbol;
// Mapping from token ID to ownership details
// An empty struct value does not necessarily mean the token is unowned. See _ownershipOf implementation for details.
mapping(uint256 => IERC721A.TokenOwnership) _ownerships;
// Mapping owner address to address data
mapping(address => IERC721A.AddressData) _addressData;
// Mapping from token ID to approved address
mapping(uint256 => address) _tokenApprovals;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) _operatorApprovals;
}
function erc721AStorage() internal pure returns (Data storage erc721AData) {
bytes32 position = ERC721A_STORAGE_POSITION;
assembly {
erc721AData.slot := position
}
}
}
/**
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
* the Metadata extension. Built to optimize for lower gas during batch mints.
*
* Assumes serials are sequentially minted starting at _startTokenId() (defaults to 0, e.g. 0, 1, 2, 3..).
*
* Assumes that an owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
*
* Assumes that the maximum token id cannot exceed 2**256 - 1 (max value of uint256).
*/
contract ERC721AUpgradeable is Initializable, Context, ERC165, IERC721A {
using TWAddress for address;
using TWStrings for uint256;
function __ERC721A_init(string memory name_, string memory symbol_) internal onlyInitializing {
__ERC721A_init_unchained(name_, symbol_);
}
function __ERC721A_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
data._name = name_;
data._symbol = symbol_;
data._currentIndex = _startTokenId();
}
/**
* To change the starting tokenId, please override this function.
*/
function _startTokenId() internal view virtual returns (uint256) {
return 0;
}
/**
* @dev Burned tokens are calculated here, use _totalMinted() if you want to count just minted tokens.
*/
function totalSupply() public view override returns (uint256) {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
// Counter underflow is impossible as _burnCounter cannot be incremented
// more than _currentIndex - _startTokenId() times
unchecked {
return data._currentIndex - data._burnCounter - _startTokenId();
}
}
/**
* Returns the total amount of tokens minted in the contract.
*/
function _totalMinted() internal view returns (uint256) {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
// Counter underflow is impossible as _currentIndex does not decrement,
// and it is initialized to _startTokenId()
unchecked {
return data._currentIndex - _startTokenId();
}
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721-balanceOf}.
*/
function balanceOf(address owner) public view override returns (uint256) {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
if (owner == address(0)) revert BalanceQueryForZeroAddress();
return uint256(data._addressData[owner].balance);
}
/**
* Returns the number of tokens minted by `owner`.
*/
function _numberMinted(address owner) internal view returns (uint256) {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
return uint256(data._addressData[owner].numberMinted);
}
/**
* Returns the number of tokens burned by or on behalf of `owner`.
*/
function _numberBurned(address owner) internal view returns (uint256) {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
return uint256(data._addressData[owner].numberBurned);
}
/**
* Returns the auxillary data for `owner`. (e.g. number of whitelist mint slots used).
*/
function _getAux(address owner) internal view returns (uint64) {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
return data._addressData[owner].aux;
}
/**
* Sets the auxillary data for `owner`. (e.g. number of whitelist mint slots used).
* If there are multiple variables, please pack them into a uint64.
*/
function _setAux(address owner, uint64 aux) internal {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
data._addressData[owner].aux = aux;
}
/**
* Gas spent here starts off proportional to the maximum mint batch size.
* It gradually moves to O(1) as tokens get transferred around in the collection over time.
*/
function _ownershipOf(uint256 tokenId) internal view returns (TokenOwnership memory) {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
uint256 curr = tokenId;
unchecked {
if (_startTokenId() <= curr)
if (curr < data._currentIndex) {
TokenOwnership memory ownership = data._ownerships[curr];
if (!ownership.burned) {
if (ownership.addr != address(0)) {
return ownership;
}
// Invariant:
// There will always be an ownership that has an address and is not burned
// before an ownership that does not have an address and is not burned.
// Hence, curr will not underflow.
while (true) {
curr--;
ownership = data._ownerships[curr];
if (ownership.addr != address(0)) {
return ownership;
}
}
}
}
}
revert OwnerQueryForNonexistentToken();
}
/**
* @dev See {IERC721-ownerOf}.
*/
function ownerOf(uint256 tokenId) public view override returns (address) {
return _ownershipOf(tokenId).addr;
}
/**
* @dev See {IERC721Metadata-name}.
*/
function name() public view virtual override returns (string memory) {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
return data._name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/
function symbol() public view virtual override returns (string memory) {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
return data._symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
string memory baseURI = _baseURI();
return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overriden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return "";
}
/**
* @dev See {IERC721-approve}.
*/
function approve(address to, uint256 tokenId) public virtual override {
address owner = ERC721AUpgradeable.ownerOf(tokenId);
if (to == owner) revert ApprovalToCurrentOwner();
if (_msgSender() != owner)
if (!isApprovedForAll(owner, _msgSender())) {
revert ApprovalCallerNotOwnerNorApproved();
}
_approve(to, tokenId, owner);
}
/**
* @dev See {IERC721-getApproved}.
*/
function getApproved(uint256 tokenId) public view virtual override returns (address) {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();
return data._tokenApprovals[tokenId];
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
if (operator == _msgSender()) revert ApproveToCaller();
data._operatorApprovals[_msgSender()][operator] = approved;
emit ApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
return data._operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
_transfer(from, to, tokenId);
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public virtual override {
_transfer(from, to, tokenId);
if (to.isContract())
if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
revert TransferToNonERC721ReceiverImplementer();
}
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
*
* Tokens start existing when they are minted (`_mint`),
*/
function _exists(uint256 tokenId) internal view returns (bool) {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
return _startTokenId() <= tokenId && tokenId < data._currentIndex && !data._ownerships[tokenId].burned;
}
/**
* @dev Equivalent to `_safeMint(to, quantity, '')`.
*/
function _safeMint(address to, uint256 quantity) internal {
_safeMint(to, quantity, "");
}
/**
* @dev Safely mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
* - `quantity` must be greater than 0.
*
* Emits a {Transfer} event.
*/
function _safeMint(
address to,
uint256 quantity,
bytes memory _data
) internal {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
uint256 startTokenId = data._currentIndex;
if (to == address(0)) revert MintToZeroAddress();
if (quantity == 0) revert MintZeroQuantity();
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are incredibly unrealistic.
// balance or numberMinted overflow if current value of either + quantity > 1.8e19 (2**64) - 1
// updatedIndex overflows if _currentIndex + quantity > 1.2e77 (2**256) - 1
unchecked {
data._addressData[to].balance += uint64(quantity);
data._addressData[to].numberMinted += uint64(quantity);
data._ownerships[startTokenId].addr = to;
data._ownerships[startTokenId].startTimestamp = uint64(block.timestamp);
uint256 updatedIndex = startTokenId;
uint256 end = updatedIndex + quantity;
if (to.isContract()) {
do {
emit Transfer(address(0), to, updatedIndex);
if (!_checkContractOnERC721Received(address(0), to, updatedIndex++, _data)) {
revert TransferToNonERC721ReceiverImplementer();
}
} while (updatedIndex < end);
// Reentrancy protection
if (data._currentIndex != startTokenId) revert();
} else {
do {
emit Transfer(address(0), to, updatedIndex++);
} while (updatedIndex < end);
}
data._currentIndex = updatedIndex;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `quantity` must be greater than 0.
*
* Emits a {Transfer} event.
*/
function _mint(address to, uint256 quantity) internal {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
uint256 startTokenId = data._currentIndex;
if (to == address(0)) revert MintToZeroAddress();
if (quantity == 0) revert MintZeroQuantity();
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are incredibly unrealistic.
// balance or numberMinted overflow if current value of either + quantity > 1.8e19 (2**64) - 1
// updatedIndex overflows if _currentIndex + quantity > 1.2e77 (2**256) - 1
unchecked {
data._addressData[to].balance += uint64(quantity);
data._addressData[to].numberMinted += uint64(quantity);
data._ownerships[startTokenId].addr = to;
data._ownerships[startTokenId].startTimestamp = uint64(block.timestamp);
uint256 updatedIndex = startTokenId;
uint256 end = updatedIndex + quantity;
do {
emit Transfer(address(0), to, updatedIndex++);
} while (updatedIndex < end);
data._currentIndex = updatedIndex;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {Transfer} event.
*/
function _transfer(
address from,
address to,
uint256 tokenId
) private {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
TokenOwnership memory prevOwnership = _ownershipOf(tokenId);
if (prevOwnership.addr != from) revert TransferFromIncorrectOwner();
bool isApprovedOrOwner = (_msgSender() == from ||
isApprovedForAll(from, _msgSender()) ||
getApproved(tokenId) == _msgSender());
if (!isApprovedOrOwner) revert TransferCallerNotOwnerNorApproved();
if (to == address(0)) revert TransferToZeroAddress();
_beforeTokenTransfers(from, to, tokenId, 1);
// Clear approvals from the previous owner
_approve(address(0), tokenId, from);
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
// Counter overflow is incredibly unrealistic as tokenId would have to be 2**256.
unchecked {
data._addressData[from].balance -= 1;
data._addressData[to].balance += 1;
TokenOwnership storage currSlot = data._ownerships[tokenId];
currSlot.addr = to;
currSlot.startTimestamp = uint64(block.timestamp);
// If the ownership slot of tokenId+1 is not explicitly set, that means the transfer initiator owns it.
// Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls.
uint256 nextTokenId = tokenId + 1;
TokenOwnership storage nextSlot = data._ownerships[nextTokenId];
if (nextSlot.addr == address(0)) {
// This will suffice for checking _exists(nextTokenId),
// as a burned slot cannot contain the zero address.
if (nextTokenId != data._currentIndex) {
nextSlot.addr = from;
nextSlot.startTimestamp = prevOwnership.startTimestamp;
}
}
}
emit Transfer(from, to, tokenId);
_afterTokenTransfers(from, to, tokenId, 1);
}
/**
* @dev Equivalent to `_burn(tokenId, false)`.
*/
function _burn(uint256 tokenId) internal virtual {
_burn(tokenId, false);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
TokenOwnership memory prevOwnership = _ownershipOf(tokenId);
address from = prevOwnership.addr;
if (approvalCheck) {
bool isApprovedOrOwner = (_msgSender() == from ||
isApprovedForAll(from, _msgSender()) ||
getApproved(tokenId) == _msgSender());
if (!isApprovedOrOwner) revert TransferCallerNotOwnerNorApproved();
}
_beforeTokenTransfers(from, address(0), tokenId, 1);
// Clear approvals from the previous owner
_approve(address(0), tokenId, from);
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
// Counter overflow is incredibly unrealistic as tokenId would have to be 2**256.
unchecked {
AddressData storage addressData = data._addressData[from];
addressData.balance -= 1;
addressData.numberBurned += 1;
// Keep track of who burned the token, and the timestamp of burning.
TokenOwnership storage currSlot = data._ownerships[tokenId];
currSlot.addr = from;
currSlot.startTimestamp = uint64(block.timestamp);
currSlot.burned = true;
// If the ownership slot of tokenId+1 is not explicitly set, that means the burn initiator owns it.
// Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls.
uint256 nextTokenId = tokenId + 1;
TokenOwnership storage nextSlot = data._ownerships[nextTokenId];
if (nextSlot.addr == address(0)) {
// This will suffice for checking _exists(nextTokenId),
// as a burned slot cannot contain the zero address.
if (nextTokenId != data._currentIndex) {
nextSlot.addr = from;
nextSlot.startTimestamp = prevOwnership.startTimestamp;
}
}
}
emit Transfer(from, address(0), tokenId);
_afterTokenTransfers(from, address(0), tokenId, 1);
// Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.
unchecked {
data._burnCounter++;
}
}
/**
* @dev Approve `to` to operate on `tokenId`
*
* Emits a {Approval} event.
*/
function _approve(
address to,
uint256 tokenId,
address owner
) private {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
data._tokenApprovals[tokenId] = to;
emit Approval(owner, to, tokenId);
}
/**
* @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target contract.
*
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param _data bytes optional data to send along with the call
* @return bool whether the call correctly returned the expected magic value
*/
function _checkContractOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
return retval == IERC721Receiver(to).onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert TransferToNonERC721ReceiverImplementer();
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
/**
* @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. This includes minting.
* And also called before burning one token.
*
* startTokenId - the first token id to be transferred
* quantity - the amount to be transferred
*
* 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 for `to`.
* - When `to` is zero, `tokenId` will be burned by `from`.
* - `from` and `to` are never both zero.
*/
function _beforeTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
/**
* @dev Hook that is called after a set of serially-ordered token ids have been transferred. This includes
* minting.
* And also called after one token has been burned.
*
* startTokenId - the first token id to be transferred
* quantity - the amount to be transferred
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
* transferred to `to`.
* - When `from` is zero, `tokenId` has been minted for `to`.
* - When `to` is zero, `tokenId` has been burned by `from`.
* - `from` and `to` are never both zero.
*/
function _afterTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../../extension/interface/IContractMetadata.sol";
/**
* @author thirdweb.com
*
* @title Contract Metadata
* @notice Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI
* for you contract.
* Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea.
*/
library ContractMetadataStorage {
bytes32 public constant CONTRACT_METADATA_STORAGE_POSITION = keccak256("contract.metadata.storage");
struct Data {
/// @notice Returns the contract metadata URI.
string contractURI;
}
function contractMetadataStorage() internal pure returns (Data storage contractMetadataData) {
bytes32 position = CONTRACT_METADATA_STORAGE_POSITION;
assembly {
contractMetadataData.slot := position
}
}
}
abstract contract ContractMetadata is IContractMetadata {
/**
* @notice Lets a contract admin set the URI for contract-level metadata.
* @dev Caller should be authorized to setup contractURI, e.g. contract admin.
* See {_canSetContractURI}.
* Emits {ContractURIUpdated Event}.
*
* @param _uri keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
*/
function setContractURI(string memory _uri) external override {
if (!_canSetContractURI()) {
revert("Not authorized");
}
_setupContractURI(_uri);
}
/// @dev Lets a contract admin set the URI for contract-level metadata.
function _setupContractURI(string memory _uri) internal {
ContractMetadataStorage.Data storage data = ContractMetadataStorage.contractMetadataStorage();
string memory prevURI = data.contractURI;
data.contractURI = _uri;
emit ContractURIUpdated(prevURI, _uri);
}
/// @notice Returns the contract metadata URI.
function contractURI() public view virtual override returns (string memory) {
ContractMetadataStorage.Data storage data = ContractMetadataStorage.contractMetadataStorage();
return data.contractURI;
}
/// @dev Returns whether contract metadata can be set in the given execution context.
function _canSetContractURI() internal view virtual returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/cryptography/draft-EIP712.sol)
pragma solidity ^0.8.0;
import "../../openzeppelin-presets/utils/cryptography/ECDSA.sol";
import "./Initializable.sol";
library EIP712Storage {
bytes32 public constant EIP712_STORAGE_POSITION = keccak256("eip712.storage");
struct Data {
/* solhint-disable var-name-mixedcase */
bytes32 _HASHED_NAME;
bytes32 _HASHED_VERSION;
/* solhint-enable var-name-mixedcase */
}
function eip712Storage() internal pure returns (Data storage eip712Data) {
bytes32 position = EIP712_STORAGE_POSITION;
assembly {
eip712Data.slot := position
}
}
}
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
* thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
* they need in their contracts using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* _Available since v3.4._
*
* @custom:storage-size 52
*/
abstract contract EIP712Upgradeable is Initializable {
/* solhint-disable var-name-mixedcase */
bytes32 private constant _TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
/* solhint-enable var-name-mixedcase */
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
function __EIP712_init(string memory name, string memory version) internal onlyInitializing {
__EIP712_init_unchained(name, version);
}
function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {
bytes32 hashedName = keccak256(bytes(name));
bytes32 hashedVersion = keccak256(bytes(version));
EIP712Storage.Data storage data = EIP712Storage.eip712Storage();
data._HASHED_NAME = hashedName;
data._HASHED_VERSION = hashedVersion;
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
return _buildDomainSeparator(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash());
}
function _buildDomainSeparator(
bytes32 typeHash,
bytes32 nameHash,
bytes32 versionHash
) private view returns (bytes32) {
return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
/**
* @dev The hash of the name parameter for the EIP712 domain.
*
* NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
* are a concern.
*/
function _EIP712NameHash() internal view virtual returns (bytes32) {
EIP712Storage.Data storage data = EIP712Storage.eip712Storage();
return data._HASHED_NAME;
}
/**
* @dev The hash of the version parameter for the EIP712 domain.
*
* NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
* are a concern.
*/
function _EIP712VersionHash() internal view virtual returns (bytes32) {
EIP712Storage.Data storage data = EIP712Storage.eip712Storage();
return data._HASHED_VERSION;
}
}// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
import "../../extension/interface/IERC2771Context.sol";
import "./Initializable.sol";
/**
* @dev Context variant with ERC2771 support.
*/
library ERC2771ContextStorage {
bytes32 public constant ERC2771_CONTEXT_STORAGE_POSITION = keccak256("erc2771.context.storage");
struct Data {
mapping(address => bool) trustedForwarder;
}
function erc2771ContextStorage() internal pure returns (Data storage erc2771ContextData) {
bytes32 position = ERC2771_CONTEXT_STORAGE_POSITION;
assembly {
erc2771ContextData.slot := position
}
}
}
/**
* @dev Context variant with ERC2771 support.
*/
abstract contract ERC2771ContextUpgradeable is Initializable {
function __ERC2771Context_init(address[] memory trustedForwarder) internal onlyInitializing {
__ERC2771Context_init_unchained(trustedForwarder);
}
function __ERC2771Context_init_unchained(address[] memory trustedForwarder) internal onlyInitializing {
ERC2771ContextStorage.Data storage data = ERC2771ContextStorage.erc2771ContextStorage();
for (uint256 i = 0; i < trustedForwarder.length; i++) {
data.trustedForwarder[trustedForwarder[i]] = true;
}
}
function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
ERC2771ContextStorage.Data storage data = ERC2771ContextStorage.erc2771ContextStorage();
return data.trustedForwarder[forwarder];
}
function _msgSender() internal view virtual returns (address sender) {
if (isTrustedForwarder(msg.sender)) {
// The assembly code is more direct than the Solidity version using `abi.decode`.
assembly {
sender := shr(96, calldataload(sub(calldatasize(), 20)))
}
} else {
return msg.sender;
}
}
function _msgData() internal view virtual returns (bytes calldata) {
if (isTrustedForwarder(msg.sender)) {
return msg.data[:msg.data.length - 20];
} else {
return msg.data;
}
}
uint256[49] private __gap;
}// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
import "../../lib/TWAddress.sol";
library InitStorage {
/// @dev The location of the storage of the entrypoint contract's data.
bytes32 constant INIT_STORAGE_POSITION = keccak256("init.storage");
/// @dev Layout of the entrypoint contract's storage.
struct Data {
uint8 initialized;
bool initializing;
}
/// @dev Returns the entrypoint contract's data at the relevant storage location.
function initStorage() internal pure returns (Data storage initData) {
bytes32 position = INIT_STORAGE_POSITION;
assembly {
initData.slot := position
}
}
}
abstract contract Initializable {
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
*/
modifier initializer() {
InitStorage.Data storage data = InitStorage.initStorage();
uint8 _initialized = data.initialized;
bool _initializing = data.initializing;
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!TWAddress.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
data.initialized = 1;
if (isTopLevelCall) {
data.initializing = true;
}
_;
if (isTopLevelCall) {
data.initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
* initialization step. This is essential to configure modules that are added through upgrades and that require
* initialization.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*/
modifier reinitializer(uint8 version) {
InitStorage.Data storage data = InitStorage.initStorage();
uint8 _initialized = data.initialized;
bool _initializing = data.initializing;
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
data.initialized = version;
data.initializing = true;
_;
data.initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
InitStorage.Data storage data = InitStorage.initStorage();
require(data.initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*/
function _disableInitializers() internal virtual {
InitStorage.Data storage data = InitStorage.initStorage();
uint8 _initialized = data.initialized;
bool _initializing = data.initializing;
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
data.initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
}// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../../extension/interface/IOperatorFilterToggle.sol";
library OperatorFilterToggleStorage {
bytes32 public constant OPERATOR_FILTER_TOGGLE_STORAGE_POSITION = keccak256("operator.filter.toggle.storage");
struct Data {
bool operatorRestriction;
}
function operatorFilterToggleStorage() internal pure returns (Data storage operatorFilterToggleData) {
bytes32 position = OPERATOR_FILTER_TOGGLE_STORAGE_POSITION;
assembly {
operatorFilterToggleData.slot := position
}
}
}
abstract contract OperatorFilterToggle is IOperatorFilterToggle {
function operatorRestriction() external view override returns (bool) {
OperatorFilterToggleStorage.Data storage data = OperatorFilterToggleStorage.operatorFilterToggleStorage();
return data.operatorRestriction;
}
function setOperatorRestriction(bool _restriction) external {
require(_canSetOperatorRestriction(), "Not authorized to set operator restriction.");
_setOperatorRestriction(_restriction);
}
function _setOperatorRestriction(bool _restriction) internal {
OperatorFilterToggleStorage.Data storage data = OperatorFilterToggleStorage.operatorFilterToggleStorage();
data.operatorRestriction = _restriction;
emit OperatorRestriction(_restriction);
}
function _canSetOperatorRestriction() internal virtual returns (bool);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../../extension/interface/IOwnable.sol";
/**
* @title Ownable
* @notice Thirdweb's `Ownable` is a contract extension to be used with any base contract. It exposes functions for setting and reading
* who the 'owner' of the inheriting smart contract is, and lets the inheriting contract perform conditional logic that uses
* information about who the contract's owner is.
*/
library OwnableStorage {
bytes32 public constant OWNABLE_STORAGE_POSITION = keccak256("ownable.storage");
struct Data {
/// @dev Owner of the contract (purpose: OpenSea compatibility)
address _owner;
}
function ownableStorage() internal pure returns (Data storage ownableData) {
bytes32 position = OWNABLE_STORAGE_POSITION;
assembly {
ownableData.slot := position
}
}
}
abstract contract Ownable is IOwnable {
/// @dev Reverts if caller is not the owner.
modifier onlyOwner() {
OwnableStorage.Data storage data = OwnableStorage.ownableStorage();
if (msg.sender != data._owner) {
revert("Not authorized");
}
_;
}
/**
* @notice Returns the owner of the contract.
*/
function owner() public view override returns (address) {
OwnableStorage.Data storage data = OwnableStorage.ownableStorage();
return data._owner;
}
/**
* @notice Lets an authorized wallet set a new owner for the contract.
* @param _newOwner The address to set as the new owner of the contract.
*/
function setOwner(address _newOwner) external override {
if (!_canSetOwner()) {
revert("Not authorized");
}
_setupOwner(_newOwner);
}
/// @dev Lets a contract admin set a new owner for the contract. The new owner must be a contract admin.
function _setupOwner(address _newOwner) internal {
OwnableStorage.Data storage data = OwnableStorage.ownableStorage();
address _prevOwner = data._owner;
data._owner = _newOwner;
emit OwnerUpdated(_prevOwner, _newOwner);
}
/// @dev Returns whether owner can be set in the given execution context.
function _canSetOwner() internal view virtual returns (bool);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../../extension/interface/IPermissions.sol";
import "../../lib/TWStrings.sol";
/**
* @title Permissions
* @dev This contracts provides extending-contracts with role-based access control mechanisms
*/
library PermissionsStorage {
bytes32 public constant PERMISSIONS_STORAGE_POSITION = keccak256("permissions.storage");
struct Data {
/// @dev Map from keccak256 hash of a role => a map from address => whether address has role.
mapping(bytes32 => mapping(address => bool)) _hasRole;
/// @dev Map from keccak256 hash of a role to role admin. See {getRoleAdmin}.
mapping(bytes32 => bytes32) _getRoleAdmin;
}
function permissionsStorage() internal pure returns (Data storage permissionsData) {
bytes32 position = PERMISSIONS_STORAGE_POSITION;
assembly {
permissionsData.slot := position
}
}
}
contract Permissions is IPermissions {
/// @dev Default admin role for all roles. Only accounts with this role can grant/revoke other roles.
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/// @dev Modifier that checks if an account has the specified role; reverts otherwise.
modifier onlyRole(bytes32 role) {
_checkRole(role, _msgSender());
_;
}
/**
* @notice Checks whether an account has a particular role.
* @dev Returns `true` if `account` has been granted `role`.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account for which the role is being checked.
*/
function hasRole(bytes32 role, address account) public view override returns (bool) {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
return data._hasRole[role][account];
}
/**
* @notice Checks whether an account has a particular role;
* role restrictions can be swtiched on and off.
*
* @dev Returns `true` if `account` has been granted `role`.
* Role restrictions can be swtiched on and off:
* - If address(0) has ROLE, then the ROLE restrictions
* don't apply.
* - If address(0) does not have ROLE, then the ROLE
* restrictions will apply.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account for which the role is being checked.
*/
function hasRoleWithSwitch(bytes32 role, address account) public view returns (bool) {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
if (!data._hasRole[role][address(0)]) {
return data._hasRole[role][account];
}
return true;
}
/**
* @notice Returns the admin role that controls the specified role.
* @dev See {grantRole} and {revokeRole}.
* To change a role's admin, use {_setRoleAdmin}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
*/
function getRoleAdmin(bytes32 role) external view override returns (bytes32) {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
return data._getRoleAdmin[role];
}
/**
* @notice Grants a role to an account, if not previously granted.
* @dev Caller must have admin role for the `role`.
* Emits {RoleGranted Event}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account to which the role is being granted.
*/
function grantRole(bytes32 role, address account) public virtual override {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
_checkRole(data._getRoleAdmin[role], _msgSender());
if (data._hasRole[role][account]) {
revert("Can only grant to non holders");
}
_setupRole(role, account);
}
/**
* @notice Revokes role from an account.
* @dev Caller must have admin role for the `role`.
* Emits {RoleRevoked Event}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account from which the role is being revoked.
*/
function revokeRole(bytes32 role, address account) public virtual override {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
_checkRole(data._getRoleAdmin[role], _msgSender());
_revokeRole(role, account);
}
/**
* @notice Revokes role from the account.
* @dev Caller must have the `role`, with caller being the same as `account`.
* Emits {RoleRevoked Event}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account from which the role is being revoked.
*/
function renounceRole(bytes32 role, address account) public virtual override {
if (_msgSender() != account) {
revert("Can only renounce for self");
}
_revokeRole(role, account);
}
/// @dev Sets `adminRole` as `role`'s admin role.
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
bytes32 previousAdminRole = data._getRoleAdmin[role];
data._getRoleAdmin[role] = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/// @dev Sets up `role` for `account`
function _setupRole(bytes32 role, address account) internal virtual {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
data._hasRole[role][account] = true;
emit RoleGranted(role, account, _msgSender());
}
/// @dev Revokes `role` from `account`
function _revokeRole(bytes32 role, address account) internal virtual {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
_checkRole(role, account);
delete data._hasRole[role][account];
emit RoleRevoked(role, account, _msgSender());
}
/// @dev Checks `role` for `account`. Reverts with a message including the required role.
function _checkRole(bytes32 role, address account) internal view virtual {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
if (!data._hasRole[role][account]) {
revert(
string(
abi.encodePacked(
"Permissions: account ",
TWStrings.toHexString(uint160(account), 20),
" is missing role ",
TWStrings.toHexString(uint256(role), 32)
)
)
);
}
}
/// @dev Checks `role` for `account`. Reverts with a message including the required role.
function _checkRoleWithSwitch(bytes32 role, address account) internal view virtual {
if (!hasRoleWithSwitch(role, account)) {
revert(
string(
abi.encodePacked(
"Permissions: account ",
TWStrings.toHexString(uint160(account), 20),
" is missing role ",
TWStrings.toHexString(uint256(role), 32)
)
)
);
}
}
function _msgSender() internal view virtual returns (address sender) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../../extension/interface/IPermissionsEnumerable.sol";
import "./Permissions.sol";
/**
* @title PermissionsEnumerable
* @dev This contracts provides extending-contracts with role-based access control mechanisms.
* Also provides interfaces to view all members with a given role, and total count of members.
*/
library PermissionsEnumerableStorage {
bytes32 public constant PERMISSIONS_ENUMERABLE_STORAGE_POSITION = keccak256("permissions.enumerable.storage");
/**
* @notice A data structure to store data of members for a given role.
*
* @param index Current index in the list of accounts that have a role.
* @param members map from index => address of account that has a role
* @param indexOf map from address => index which the account has.
*/
struct RoleMembers {
uint256 index;
mapping(uint256 => address) members;
mapping(address => uint256) indexOf;
}
struct Data {
/// @dev map from keccak256 hash of a role to its members' data. See {RoleMembers}.
mapping(bytes32 => RoleMembers) roleMembers;
}
function permissionsEnumerableStorage() internal pure returns (Data storage permissionsEnumerableData) {
bytes32 position = PERMISSIONS_ENUMERABLE_STORAGE_POSITION;
assembly {
permissionsEnumerableData.slot := position
}
}
}
contract PermissionsEnumerable is IPermissionsEnumerable, Permissions {
/**
* @notice Returns the role-member from a list of members for a role,
* at a given index.
* @dev Returns `member` who has `role`, at `index` of role-members list.
* See struct {RoleMembers}, and mapping {roleMembers}
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param index Index in list of current members for the role.
*
* @return member Address of account that has `role`
*/
function getRoleMember(bytes32 role, uint256 index) external view override returns (address member) {
PermissionsEnumerableStorage.Data storage data = PermissionsEnumerableStorage.permissionsEnumerableStorage();
uint256 currentIndex = data.roleMembers[role].index;
uint256 check;
for (uint256 i = 0; i < currentIndex; i += 1) {
if (data.roleMembers[role].members[i] != address(0)) {
if (check == index) {
member = data.roleMembers[role].members[i];
return member;
}
check += 1;
} else if (hasRole(role, address(0)) && i == data.roleMembers[role].indexOf[address(0)]) {
check += 1;
}
}
}
/**
* @notice Returns total number of accounts that have a role.
* @dev Returns `count` of accounts that have `role`.
* See struct {RoleMembers}, and mapping {roleMembers}
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
*
* @return count Total number of accounts that have `role`
*/
function getRoleMemberCount(bytes32 role) external view override returns (uint256 count) {
PermissionsEnumerableStorage.Data storage data = PermissionsEnumerableStorage.permissionsEnumerableStorage();
uint256 currentIndex = data.roleMembers[role].index;
for (uint256 i = 0; i < currentIndex; i += 1) {
if (data.roleMembers[role].members[i] != address(0)) {
count += 1;
}
}
if (hasRole(role, address(0))) {
count += 1;
}
}
/// @dev Revokes `role` from `account`, and removes `account` from {roleMembers}
/// See {_removeMember}
function _revokeRole(bytes32 role, address account) internal override {
super._revokeRole(role, account);
_removeMember(role, account);
}
/// @dev Grants `role` to `account`, and adds `account` to {roleMembers}
/// See {_addMember}
function _setupRole(bytes32 role, address account) internal override {
super._setupRole(role, account);
_addMember(role, account);
}
/// @dev adds `account` to {roleMembers}, for `role`
function _addMember(bytes32 role, address account) internal {
PermissionsEnumerableStorage.Data storage data = PermissionsEnumerableStorage.permissionsEnumerableStorage();
uint256 idx = data.roleMembers[role].index;
data.roleMembers[role].index += 1;
data.roleMembers[role].members[idx] = account;
data.roleMembers[role].indexOf[account] = idx;
}
/// @dev removes `account` from {roleMembers}, for `role`
function _removeMember(bytes32 role, address account) internal {
PermissionsEnumerableStorage.Data storage data = PermissionsEnumerableStorage.permissionsEnumerableStorage();
uint256 idx = data.roleMembers[role].indexOf[account];
delete data.roleMembers[role].members[idx];
delete data.roleMembers[role].indexOf[account];
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../../extension/interface/IPrimarySale.sol";
library PrimarySaleStorage {
bytes32 public constant PRIMARY_SALE_STORAGE_POSITION = keccak256("primary.sale.storage");
struct Data {
address recipient;
}
function primarySaleStorage() internal pure returns (Data storage primarySaleData) {
bytes32 position = PRIMARY_SALE_STORAGE_POSITION;
assembly {
primarySaleData.slot := position
}
}
}
/**
* @title Primary Sale
* @notice Thirdweb's `PrimarySale` is a contract extension to be used with any base contract. It exposes functions for setting and reading
* the recipient of primary sales, and lets the inheriting contract perform conditional logic that uses information about
* primary sales, if desired.
*/
abstract contract PrimarySale is IPrimarySale {
/// @dev Returns primary sale recipient address.
function primarySaleRecipient() public view override returns (address) {
PrimarySaleStorage.Data storage data = PrimarySaleStorage.primarySaleStorage();
return data.recipient;
}
/**
* @notice Updates primary sale recipient.
* @dev Caller should be authorized to set primary sales info.
* See {_canSetPrimarySaleRecipient}.
* Emits {PrimarySaleRecipientUpdated Event}; See {_setupPrimarySaleRecipient}.
*
* @param _saleRecipient Address to be set as new recipient of primary sales.
*/
function setPrimarySaleRecipient(address _saleRecipient) external override {
if (!_canSetPrimarySaleRecipient()) {
revert("Not authorized");
}
_setupPrimarySaleRecipient(_saleRecipient);
}
/// @dev Lets a contract admin set the recipient for all primary sales.
function _setupPrimarySaleRecipient(address _saleRecipient) internal {
PrimarySaleStorage.Data storage data = PrimarySaleStorage.primarySaleStorage();
data.recipient = _saleRecipient;
emit PrimarySaleRecipientUpdated(_saleRecipient);
}
/// @dev Returns whether primary sale recipient can be set in the given execution context.
function _canSetPrimarySaleRecipient() internal view virtual returns (bool);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../../extension/interface/IRoyalty.sol";
library RoyaltyStorage {
bytes32 public constant ROYALTY_STORAGE_POSITION = keccak256("royalty.storage");
struct Data {
/// @dev The (default) address that receives all royalty value.
address royaltyRecipient;
/// @dev The (default) % of a sale to take as royalty (in basis points).
uint16 royaltyBps;
/// @dev Token ID => royalty recipient and bps for token
mapping(uint256 => IRoyalty.RoyaltyInfo) royaltyInfoForToken;
}
function royaltyStorage() internal pure returns (Data storage royaltyData) {
bytes32 position = ROYALTY_STORAGE_POSITION;
assembly {
royaltyData.slot := position
}
}
}
/**
* @title Royalty
* @notice Thirdweb's `Royalty` is a contract extension to be used with any base contract. It exposes functions for setting and reading
* the recipient of royalty fee and the royalty fee basis points, and lets the inheriting contract perform conditional logic
* that uses information about royalty fees, if desired.
*
* @dev The `Royalty` contract is ERC2981 compliant.
*/
abstract contract Royalty is IRoyalty {
/**
* @notice View royalty info for a given token and sale price.
* @dev Returns royalty amount and recipient for `tokenId` and `salePrice`.
* @param tokenId The tokenID of the NFT for which to query royalty info.
* @param salePrice Sale price of the token.
*
* @return receiver Address of royalty recipient account.
* @return royaltyAmount Royalty amount calculated at current royaltyBps value.
*/
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external
view
virtual
override
returns (address receiver, uint256 royaltyAmount)
{
(address recipient, uint256 bps) = getRoyaltyInfoForToken(tokenId);
receiver = recipient;
royaltyAmount = (salePrice * bps) / 10_000;
}
/**
* @notice View royalty info for a given token.
* @dev Returns royalty recipient and bps for `_tokenId`.
* @param _tokenId The tokenID of the NFT for which to query royalty info.
*/
function getRoyaltyInfoForToken(uint256 _tokenId) public view override returns (address, uint16) {
RoyaltyStorage.Data storage data = RoyaltyStorage.royaltyStorage();
RoyaltyInfo memory royaltyForToken = data.royaltyInfoForToken[_tokenId];
return
royaltyForToken.recipient == address(0)
? (data.royaltyRecipient, uint16(data.royaltyBps))
: (royaltyForToken.recipient, uint16(royaltyForToken.bps));
}
/**
* @notice Returns the defualt royalty recipient and BPS for this contract's NFTs.
*/
function getDefaultRoyaltyInfo() external view override returns (address, uint16) {
RoyaltyStorage.Data storage data = RoyaltyStorage.royaltyStorage();
return (data.royaltyRecipient, uint16(data.royaltyBps));
}
/**
* @notice Updates default royalty recipient and bps.
* @dev Caller should be authorized to set royalty info.
* See {_canSetRoyaltyInfo}.
* Emits {DefaultRoyalty Event}; See {_setupDefaultRoyaltyInfo}.
*
* @param _royaltyRecipient Address to be set as default royalty recipient.
* @param _royaltyBps Updated royalty bps.
*/
function setDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps) external override {
if (!_canSetRoyaltyInfo()) {
revert("Not authorized");
}
_setupDefaultRoyaltyInfo(_royaltyRecipient, _royaltyBps);
}
/// @dev Lets a contract admin update the default royalty recipient and bps.
function _setupDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps) internal {
if (_royaltyBps > 10_000) {
revert("Exceeds max bps");
}
RoyaltyStorage.Data storage data = RoyaltyStorage.royaltyStorage();
data.royaltyRecipient = _royaltyRecipient;
data.royaltyBps = uint16(_royaltyBps);
emit DefaultRoyalty(_royaltyRecipient, _royaltyBps);
}
/**
* @notice Updates default royalty recipient and bps for a particular token.
* @dev Sets royalty info for `_tokenId`. Caller should be authorized to set royalty info.
* See {_canSetRoyaltyInfo}.
* Emits {RoyaltyForToken Event}; See {_setupRoyaltyInfoForToken}.
*
* @param _recipient Address to be set as royalty recipient for given token Id.
* @param _bps Updated royalty bps for the token Id.
*/
function setRoyaltyInfoForToken(
uint256 _tokenId,
address _recipient,
uint256 _bps
) external override {
if (!_canSetRoyaltyInfo()) {
revert("Not authorized");
}
_setupRoyaltyInfoForToken(_tokenId, _recipient, _bps);
}
/// @dev Lets a contract admin set the royalty recipient and bps for a particular token Id.
function _setupRoyaltyInfoForToken(
uint256 _tokenId,
address _recipient,
uint256 _bps
) internal {
if (_bps > 10_000) {
revert("Exceeds max bps");
}
RoyaltyStorage.Data storage data = RoyaltyStorage.royaltyStorage();
data.royaltyInfoForToken[_tokenId] = RoyaltyInfo({ recipient: _recipient, bps: _bps });
emit RoyaltyForToken(_tokenId, _recipient, _bps);
}
/// @dev Returns whether royalty info can be set in the given execution context.
function _canSetRoyaltyInfo() internal view virtual returns (bool);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../../extension/interface/ISignatureAction.sol";
import "./EIP712Upgradeable.sol";
library SignatureActionStorage {
bytes32 public constant SIGNATURE_ACTION_STORAGE_POSITION = keccak256("signature.action.storage");
struct Data {
/// @dev Mapping from a signed request UID => whether the request is processed.
mapping(bytes32 => bool) executed;
}
function signatureActionStorage() internal pure returns (Data storage signatureActionData) {
bytes32 position = SIGNATURE_ACTION_STORAGE_POSITION;
assembly {
signatureActionData.slot := position
}
}
}
abstract contract SignatureActionUpgradeable is EIP712Upgradeable, ISignatureAction {
using ECDSA for bytes32;
bytes32 private constant TYPEHASH =
keccak256("GenericRequest(uint128 validityStartTimestamp,uint128 validityEndTimestamp,bytes32 uid,bytes data)");
function __SignatureAction_init() internal onlyInitializing {
__EIP712_init("SignatureAction", "1");
}
function __SignatureAction_init_unchained() internal onlyInitializing {}
/// @dev Verifies that a request is signed by an authorized account.
function verify(GenericRequest calldata _req, bytes calldata _signature)
public
view
override
returns (bool success, address signer)
{
SignatureActionStorage.Data storage data = SignatureActionStorage.signatureActionStorage();
signer = _recoverAddress(_req, _signature);
success = !data.executed[_req.uid] && _isAuthorizedSigner(signer);
}
/// @dev Returns whether a given address is authorized to sign requests.
function _isAuthorizedSigner(address _signer) internal view virtual returns (bool);
/// @dev Verifies a request and marks the request as processed.
function _processRequest(GenericRequest calldata _req, bytes calldata _signature)
internal
returns (address signer)
{
bool success;
(success, signer) = verify(_req, _signature);
if (!success) {
revert("Invalid req");
}
if (_req.validityStartTimestamp > block.timestamp || block.timestamp > _req.validityEndTimestamp) {
revert("Req expired");
}
SignatureActionStorage.Data storage data = SignatureActionStorage.signatureActionStorage();
data.executed[_req.uid] = true;
}
/// @dev Returns the address of the signer of the request.
function _recoverAddress(GenericRequest calldata _req, bytes calldata _signature) internal view returns (address) {
return _hashTypedDataV4(keccak256(_encodeRequest(_req))).recover(_signature);
}
/// @dev Encodes a request for recovery of the signer in `recoverAddress`.
function _encodeRequest(GenericRequest calldata _req) internal pure returns (bytes memory) {
return
abi.encode(
TYPEHASH,
_req.validityStartTimestamp,
_req.validityEndTimestamp,
_req.uid,
keccak256(_req.data)
);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import { ContractMetadataStorage } from "../extension/ContractMetadata.sol";
contract ContractMetadataInit {
event ContractURIUpdated(string prevURI, string newURI);
/// @dev Lets a contract admin set the URI for contract-level metadata.
function _setupContractURI(string memory _uri) internal {
ContractMetadataStorage.Data storage data = ContractMetadataStorage.contractMetadataStorage();
string memory prevURI = data.contractURI;
data.contractURI = _uri;
emit ContractURIUpdated(prevURI, _uri);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import "../../extension/interface/IOperatorFilterRegistry.sol";
import { OperatorFilterToggleStorage } from "../extension/OperatorFilterToggle.sol";
contract DefaultOperatorFiltererInit {
event OperatorRestriction(bool restriction);
IOperatorFilterRegistry constant OPERATOR_FILTER_REGISTRY =
IOperatorFilterRegistry(0x000000000000AAeB6D7670E522A718067333cd4E);
address constant DEFAULT_SUBSCRIPTION = address(0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6);
function _setupOperatorFilterer() internal {
__DefaultOperatorFilterer_init();
}
function __DefaultOperatorFilterer_init() private {
__OperatorFilterer_init(DEFAULT_SUBSCRIPTION, true);
OperatorFilterToggleStorage.Data storage data = OperatorFilterToggleStorage.operatorFilterToggleStorage();
data.operatorRestriction = true;
emit OperatorRestriction(true);
}
function __OperatorFilterer_init(address subscriptionOrRegistrantToCopy, bool subscribe) private {
// If an inheriting token contract is deployed to a network without the registry deployed, the modifier
// will not revert, but the contract will need to be registered with the registry once it is deployed in
// order for the modifier to filter addresses.
if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) {
if (!OPERATOR_FILTER_REGISTRY.isRegistered(address(this))) {
if (subscribe) {
OPERATOR_FILTER_REGISTRY.registerAndSubscribe(address(this), subscriptionOrRegistrantToCopy);
} else {
if (subscriptionOrRegistrantToCopy != address(0)) {
OPERATOR_FILTER_REGISTRY.registerAndCopyEntries(address(this), subscriptionOrRegistrantToCopy);
} else {
OPERATOR_FILTER_REGISTRY.register(address(this));
}
}
}
}
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import { ERC721AStorage } from "../eip/ERC721AUpgradeable.sol";
import "../extension/Initializable.sol";
contract ERC721AInit is Initializable {
function __ERC721A_init(string memory name_, string memory symbol_) internal onlyInitializing {
__ERC721A_init_unchained(name_, symbol_);
}
function __ERC721A_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
ERC721AStorage.Data storage data = ERC721AStorage.erc721AStorage();
data._name = name_;
data._symbol = symbol_;
data._currentIndex = _startTokenId();
}
function _startTokenId() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import { OwnableStorage } from "../extension/Ownable.sol";
contract OwnableInit {
event OwnerUpdated(address indexed prevOwner, address indexed newOwner);
/// @dev Lets a contract admin set a new owner for the contract. The new owner must be a contract admin.
function _setupOwner(address _newOwner) internal {
OwnableStorage.Data storage data = OwnableStorage.ownableStorage();
address _prevOwner = data._owner;
data._owner = _newOwner;
emit OwnerUpdated(_prevOwner, _newOwner);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import { PermissionsEnumerableStorage } from "../extension/PermissionsEnumerable.sol";
import "./PermissionsInit.sol";
contract PermissionsEnumerableInit is PermissionsInit {
/// @dev Sets up `role` for `account`
function _setupRole(bytes32 role, address account) internal override {
super._setupRole(role, account);
_addMember(role, account);
}
/// @dev adds `account` to {roleMembers}, for `role`
function _addMember(bytes32 role, address account) internal {
PermissionsEnumerableStorage.Data storage data = PermissionsEnumerableStorage.permissionsEnumerableStorage();
uint256 idx = data.roleMembers[role].index;
data.roleMembers[role].index += 1;
data.roleMembers[role].members[idx] = account;
data.roleMembers[role].indexOf[account] = idx;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import { PermissionsStorage } from "../extension/Permissions.sol";
contract PermissionsInit {
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/// @dev Sets up `role` for `account`
function _setupRole(bytes32 role, address account) internal virtual {
PermissionsStorage.Data storage data = PermissionsStorage.permissionsStorage();
data._hasRole[role][account] = true;
emit RoleGranted(role, account, msg.sender);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import { PrimarySaleStorage } from "../extension/PrimarySale.sol";
contract PrimarySaleInit {
/// @dev Emitted when a new sale recipient is set.
event PrimarySaleRecipientUpdated(address indexed recipient);
/// @dev Lets a contract admin set the recipient for all primary sales.
function _setupPrimarySaleRecipient(address _saleRecipient) internal {
PrimarySaleStorage.Data storage data = PrimarySaleStorage.primarySaleStorage();
data.recipient = _saleRecipient;
emit PrimarySaleRecipientUpdated(_saleRecipient);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import { RoyaltyStorage, IRoyalty } from "../extension/Royalty.sol";
contract RoyaltyInit {
event DefaultRoyalty(address indexed newRoyaltyRecipient, uint256 newRoyaltyBps);
/// @dev Lets a contract admin update the default royalty recipient and bps.
function _setupDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps) internal {
if (_royaltyBps > 10_000) {
revert("Exceeds max bps");
}
RoyaltyStorage.Data storage data = RoyaltyStorage.royaltyStorage();
data.royaltyRecipient = _royaltyRecipient;
data.royaltyBps = uint16(_royaltyBps);
emit DefaultRoyalty(_royaltyRecipient, _royaltyBps);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import { SignatureActionStorage } from "../extension/SignatureActionUpgradeable.sol";
import { EIP712Storage } from "../extension/EIP712Upgradeable.sol";
import "../extension/Initializable.sol";
contract EIP712Init is Initializable {
function __EIP712_init(string memory name, string memory version) internal onlyInitializing {
__EIP712_init_unchained(name, version);
}
function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {
bytes32 hashedName = keccak256(bytes(name));
bytes32 hashedVersion = keccak256(bytes(version));
EIP712Storage.Data storage data = EIP712Storage.eip712Storage();
data._HASHED_NAME = hashedName;
data._HASHED_VERSION = hashedVersion;
}
}
contract SignatureActionInit is EIP712Init {
function __SignatureAction_init() internal onlyInitializing {
__EIP712_init("SignatureAction", "1");
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./interface/IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* [EIP](https://eips.ethereum.org/EIPS/eip-165).
*
* 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
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
import "./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 payed 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/IERC721.sol)
pragma solidity ^0.8.0;
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address);
/**
* @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 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);
/**
* @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;
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v3.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import "./IERC721.sol";
import "./IERC721Metadata.sol";
/**
* @dev Interface of an ERC721A compliant contract.
*/
interface IERC721A is IERC721, IERC721Metadata {
/**
* The caller must own the token or be an approved operator.
*/
error ApprovalCallerNotOwnerNorApproved();
/**
* The token does not exist.
*/
error ApprovalQueryForNonexistentToken();
/**
* The caller cannot approve to their own address.
*/
error ApproveToCaller();
/**
* The caller cannot approve to the current owner.
*/
error ApprovalToCurrentOwner();
/**
* Cannot query the balance for the zero address.
*/
error BalanceQueryForZeroAddress();
/**
* Cannot mint to the zero address.
*/
error MintToZeroAddress();
/**
* The quantity of tokens minted must be more than zero.
*/
error MintZeroQuantity();
/**
* The token does not exist.
*/
error OwnerQueryForNonexistentToken();
/**
* The caller must own the token or be an approved operator.
*/
error TransferCallerNotOwnerNorApproved();
/**
* The token must be owned by `from`.
*/
error TransferFromIncorrectOwner();
/**
* Cannot safely transfer to a contract that does not implement the ERC721Receiver interface.
*/
error TransferToNonERC721ReceiverImplementer();
/**
* Cannot transfer to the zero address.
*/
error TransferToZeroAddress();
/**
* The token does not exist.
*/
error URIQueryForNonexistentToken();
// Compiler will pack this into a single 256bit word.
struct TokenOwnership {
// The address of the owner.
address addr;
// Keeps track of the start time of ownership with minimal overhead for tokenomics.
uint64 startTimestamp;
// Whether the token has been burned.
bool burned;
}
// Compiler will pack this into a single 256bit word.
struct AddressData {
// Realistically, 2**64-1 is more than enough.
uint64 balance;
// Keeps track of mint count with minimal overhead for tokenomics.
uint64 numberMinted;
// Keeps track of burn count with minimal overhead for tokenomics.
uint64 numberBurned;
// For miscellaneous variable(s) pertaining to the address
// (e.g. number of whitelist mint slots used).
// If there are multiple variables, please pack them into a uint64.
uint64 aux;
}
/**
* @dev Returns the total amount of tokens stored by the contract.
*
* Burned tokens are calculated here, use `_totalMinted()` if you want to count just minted tokens.
*/
function totalSupply() external view returns (uint256);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// Note: the ERC-165 identifier for this interface is 0x5b5e139f.
/* is ERC721 */
interface IERC721Metadata {
/// @notice A descriptive name for a collection of NFTs in this contract
function name() external view returns (string memory);
/// @notice An abbreviated name for NFTs in this contract
function symbol() external view returns (string memory);
/// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
/// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
/// 3986. The URI may point to a JSON file that conforms to the "ERC721
/// Metadata JSON Schema".
function tokenURI(uint256 _tokenId) external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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 `IERC721.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../lib/TWAddress.sol";
import "./interface/IMulticall.sol";
/**
* @dev Provides a function to batch together multiple calls in a single external call.
*
* _Available since v4.1._
*/
contract Multicall is IMulticall {
/**
* @notice Receives and executes a batch of function calls on this contract.
* @dev Receives and executes a batch of function calls on this contract.
*
* @param data The bytes data that makes up the batch of function calls to execute.
* @return results The bytes data that makes up the result of the batch of function calls executed.
*/
function multicall(bytes[] calldata data) external virtual override returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
results[i] = TWAddress.functionDelegateCall(address(this), data[i]);
}
return results;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI
* for you contract.
*
* Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea.
*/
interface IContractMetadata {
/// @dev Returns the metadata URI of the contract.
function contractURI() external view returns (string memory);
/**
* @dev Sets contract URI for the storefront-level metadata of the contract.
* Only module admin can call this function.
*/
function setContractURI(string calldata _uri) external;
/// @dev Emitted when the contract URI is updated.
event ContractURIUpdated(string prevURI, string newURI);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
interface IERC2771Context {
function isTrustedForwarder(address forwarder) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* @dev Provides a function to batch together multiple calls in a single external call.
*
* _Available since v4.1._
*/
interface IMulticall {
/**
* @dev Receives and executes a batch of function calls on this contract.
*/
function multicall(bytes[] calldata data) external returns (bytes[] memory results);
}// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
/// @author thirdweb
interface IOperatorFilterRegistry {
function isOperatorAllowed(address registrant, address operator) external view returns (bool);
function register(address registrant) external;
function registerAndSubscribe(address registrant, address subscription) external;
function registerAndCopyEntries(address registrant, address registrantToCopy) external;
function unregister(address addr) external;
function updateOperator(
address registrant,
address operator,
bool filtered
) external;
function updateOperators(
address registrant,
address[] calldata operators,
bool filtered
) external;
function updateCodeHash(
address registrant,
bytes32 codehash,
bool filtered
) external;
function updateCodeHashes(
address registrant,
bytes32[] calldata codeHashes,
bool filtered
) external;
function subscribe(address registrant, address registrantToSubscribe) external;
function unsubscribe(address registrant, bool copyExistingEntries) external;
function subscriptionOf(address addr) external returns (address registrant);
function subscribers(address registrant) external returns (address[] memory);
function subscriberAt(address registrant, uint256 index) external returns (address);
function copyEntriesOf(address registrant, address registrantToCopy) external;
function isOperatorFiltered(address registrant, address operator) external returns (bool);
function isCodeHashOfFiltered(address registrant, address operatorWithCode) external returns (bool);
function isCodeHashFiltered(address registrant, bytes32 codeHash) external returns (bool);
function filteredOperators(address addr) external returns (address[] memory);
function filteredCodeHashes(address addr) external returns (bytes32[] memory);
function filteredOperatorAt(address registrant, uint256 index) external returns (address);
function filteredCodeHashAt(address registrant, uint256 index) external returns (bytes32);
function isRegistered(address addr) external returns (bool);
function codeHashOf(address addr) external returns (bytes32);
}// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
/// @author thirdweb
interface IOperatorFilterToggle {
event OperatorRestriction(bool restriction);
function operatorRestriction() external view returns (bool);
function setOperatorRestriction(bool restriction) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* Thirdweb's `Ownable` is a contract extension to be used with any base contract. It exposes functions for setting and reading
* who the 'owner' of the inheriting smart contract is, and lets the inheriting contract perform conditional logic that uses
* information about who the contract's owner is.
*/
interface IOwnable {
/// @dev Returns the owner of the contract.
function owner() external view returns (address);
/// @dev Lets a module admin set a new owner for the contract. The new owner must be a module admin.
function setOwner(address _newOwner) external;
/// @dev Emitted when a new Owner is set.
event OwnerUpdated(address indexed prevOwner, address indexed newOwner);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IPermissions {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "./IPermissions.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
*/
interface IPermissionsEnumerable is IPermissions {
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* [forum post](https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296)
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* Thirdweb's `Primary` is a contract extension to be used with any base contract. It exposes functions for setting and reading
* the recipient of primary sales, and lets the inheriting contract perform conditional logic that uses information about
* primary sales, if desired.
*/
interface IPrimarySale {
/// @dev The adress that receives all primary sales value.
function primarySaleRecipient() external view returns (address);
/// @dev Lets a module admin set the default recipient of all primary sales.
function setPrimarySaleRecipient(address _saleRecipient) external;
/// @dev Emitted when a new sale recipient is set.
event PrimarySaleRecipientUpdated(address indexed recipient);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../../eip/interface/IERC2981.sol";
/**
* Thirdweb's `Royalty` is a contract extension to be used with any base contract. It exposes functions for setting and reading
* the recipient of royalty fee and the royalty fee basis points, and lets the inheriting contract perform conditional logic
* that uses information about royalty fees, if desired.
*
* The `Royalty` contract is ERC2981 compliant.
*/
interface IRoyalty is IERC2981 {
struct RoyaltyInfo {
address recipient;
uint256 bps;
}
/// @dev Returns the royalty recipient and fee bps.
function getDefaultRoyaltyInfo() external view returns (address, uint16);
/// @dev Lets a module admin update the royalty bps and recipient.
function setDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps) external;
/// @dev Lets a module admin set the royalty recipient for a particular token Id.
function setRoyaltyInfoForToken(
uint256 tokenId,
address recipient,
uint256 bps
) external;
/// @dev Returns the royalty recipient for a particular token Id.
function getRoyaltyInfoForToken(uint256 tokenId) external view returns (address, uint16);
/// @dev Emitted when royalty info is updated.
event DefaultRoyalty(address indexed newRoyaltyRecipient, uint256 newRoyaltyBps);
/// @dev Emitted when royalty recipient for tokenId is set
event RoyaltyForToken(uint256 indexed tokenId, address indexed royaltyRecipient, uint256 royaltyBps);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* thirdweb's `SignatureAction` extension smart contract can be used with any base smart contract. It provides a generic
* payload struct that can be signed by an authorized wallet and verified by the contract. The bytes `data` field provided
* in the payload can be abi encoded <-> decoded to use `SignatureContract` for any authorized signature action.
*/
interface ISignatureAction {
/**
* @notice The payload that must be signed by an authorized wallet.
*
* @param validityStartTimestamp The UNIX timestamp at and after which a signature is valid.
* @param validityEndTimestamp The UNIX timestamp at and after which a signature is invalid/expired.
* @param uid A unique non-repeatable ID for the payload.
* @param data Arbitrary bytes data to be used at the discretion of the contract.
*/
struct GenericRequest {
uint128 validityStartTimestamp;
uint128 validityEndTimestamp;
bytes32 uid;
bytes data;
}
/// @notice Emitted when a payload is verified and executed.
event RequestExecuted(address indexed user, address indexed signer, GenericRequest _req);
/**
* @notice Verfies that a payload is signed by an authorized wallet.
*
* @param req The payload signed by the authorized wallet.
* @param signature The signature produced by the authorized wallet signing the given payload.
*
* @return success Whether the payload is signed by the authorized wallet.
* @return signer The address of the signer.
*/
function verify(GenericRequest calldata req, bytes calldata signature)
external
view
returns (bool success, address signer);
}// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* @dev Collection of functions related to the address type
*/
library TWAddress {
/**
* @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
* ====
*
* [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.
*
* [EIP1884](https://eips.ethereum.org/EIPS/eip-1884) 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://diligence.consensys.net/posts/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.5.11/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 functionCall(target, data, "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");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return verifyCallResult(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) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(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) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason 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 {
// 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
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* @dev String operations.
*/
library TWStrings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../../../lib/TWStrings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
} else if (error == RecoverError.InvalidSignatureV) {
revert("ECDSA: invalid signature 'v' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
// Check the signature length
// - case 65: r,s,v signature (standard)
// - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else if (signature.length == 64) {
bytes32 r;
bytes32 vs;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly {
r := mload(add(signature, 0x20))
vs := mload(add(signature, 0x40))
}
return tryRecover(hash, r, vs);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
if (v != 27 && v != 28) {
return (address(0), RecoverError.InvalidSignatureV);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", TWStrings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}// SPDX-License-Identifier: MIT
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
pragma solidity ^0.8.0;
import "../interface/IRouter.sol";
abstract contract Router is IRouter {
fallback() external payable virtual {
/// @dev delegate calls the appropriate implementation smart contract for a given function.
address implementation = getImplementationForFunction(msg.sig);
_delegate(implementation);
}
receive() external payable virtual {}
/// @dev delegateCalls an `implementation` smart contract.
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/// @dev Unimplemented. Returns the implementation contract address for a given function signature.
function getImplementationForFunction(bytes4 _functionSelector) public view virtual returns (address);
}// SPDX-License-Identifier: MIT
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
pragma solidity ^0.8.0;
import "./IDefaultExtensionSet.sol";
interface IBaseRouter is IDefaultExtensionSet {
/*///////////////////////////////////////////////////////////////
External functions
//////////////////////////////////////////////////////////////*/
/// @dev Adds a new extension to the router.
function addExtension(Extension memory extension) external;
/// @dev Updates an existing extension in the router, or overrides a default extension.
function updateExtension(Extension memory extension) external;
/// @dev Removes an existing extension from the router.
function removeExtension(string memory extensionName) external;
}// SPDX-License-Identifier: MIT
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
pragma solidity ^0.8.0;
import "./IExtension.sol";
interface IDefaultExtensionSet is IExtension {
/*///////////////////////////////////////////////////////////////
View functions
//////////////////////////////////////////////////////////////*/
/// @dev Returns all extensions stored.
function getAllExtensions() external view returns (Extension[] memory);
/// @dev Returns all functions that belong to the given extension contract.
function getAllFunctionsOfExtension(string memory extensionName) external view returns (ExtensionFunction[] memory);
/// @dev Returns the extension metadata for a given function.
function getExtensionForFunction(bytes4 functionSelector) external view returns (ExtensionMetadata memory);
/// @dev Returns the extension's implementation smart contract address.
function getExtensionImplementation(string memory extensionName) external view returns (address);
/// @dev Returns the extension metadata and functions for a given extension.
function getExtension(string memory extensionName) external view returns (Extension memory);
}// SPDX-License-Identifier: MIT
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
pragma solidity ^0.8.0;
interface IExtension {
/*///////////////////////////////////////////////////////////////
Structs
//////////////////////////////////////////////////////////////*/
/**
* @notice A extension's metadata.
*
* @param name The unique name of the extension.
* @param metadataURI The URI where the metadata for the extension lives.
* @param implementation The implementation smart contract address of the extension.
*/
struct ExtensionMetadata {
string name;
string metadataURI;
address implementation;
}
/**
* @notice An interface to describe a extension's function.
*
* @param functionSelector The 4 byte selector of the function.
* @param functionSignature Function signature as a string. E.g. "transfer(address,address,uint256)"
*/
struct ExtensionFunction {
bytes4 functionSelector;
string functionSignature;
}
/**
* @notice An interface to describe an extension.
*
* @param metadata The extension's metadata; it's name, metadata URI and implementation contract address.
* @param functions The functions that belong to the extension.
*/
struct Extension {
ExtensionMetadata metadata;
ExtensionFunction[] functions;
}
/*///////////////////////////////////////////////////////////////
Events
//////////////////////////////////////////////////////////////*/
/// @dev Emitted when a extension is added; emitted for each function of the extension.
event ExtensionAdded(address indexed extensionAddress, bytes4 indexed functionSelector, string functionSignature);
/// @dev Emitted when extension is updated; emitted for each function of the extension.
event ExtensionUpdated(
address indexed oldExtensionAddress,
address indexed newExtensionAddress,
bytes4 indexed functionSelector,
string functionSignature
);
/// @dev Emitted when a extension is removed; emitted for each function of the extension.
event ExtensionRemoved(address indexed extensionAddress, bytes4 indexed functionSelector, string functionSignature);
}// SPDX-License-Identifier: MIT
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
pragma solidity ^0.8.0;
interface IRouter {
fallback() external payable;
receive() external payable;
function getImplementationForFunction(bytes4 _functionSelector) external view returns (address);
}// SPDX-License-Identifier: MIT
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
pragma solidity ^0.8.0;
// Interface
import "../interface/IBaseRouter.sol";
// Core
import "../core/Router.sol";
// Utils
import "./utils/StringSet.sol";
import "./utils/DefaultExtensionSet.sol";
import "./utils/ExtensionState.sol";
abstract contract BaseRouter is IBaseRouter, Router, ExtensionState {
using StringSet for StringSet.Set;
/*///////////////////////////////////////////////////////////////
State variables
//////////////////////////////////////////////////////////////*/
/// @notice The DefaultExtensionSet that stores default extensions of the router.
address public immutable defaultExtensionSet;
/*///////////////////////////////////////////////////////////////
Constructor
//////////////////////////////////////////////////////////////*/
constructor(Extension[] memory _extensions) {
DefaultExtensionSet map = new DefaultExtensionSet();
defaultExtensionSet = address(map);
uint256 len = _extensions.length;
for (uint256 i = 0; i < len; i += 1) {
map.setExtension(_extensions[i]);
}
}
/*///////////////////////////////////////////////////////////////
External functions
//////////////////////////////////////////////////////////////*/
/// @dev Adds a new extension to the router.
function addExtension(Extension memory _extension) external {
require(_canSetExtension(), "BaseRouter: caller not authorized.");
_addExtension(_extension);
}
/// @dev Updates an existing extension in the router, or overrides a default extension.
function updateExtension(Extension memory _extension) external {
require(_canSetExtension(), "BaseRouter: caller not authorized.");
_updateExtension(_extension);
}
/// @dev Removes an existing extension from the router.
function removeExtension(string memory _extensionName) external {
require(_canSetExtension(), "BaseRouter: caller not authorized.");
_removeExtension(_extensionName);
}
/*///////////////////////////////////////////////////////////////
View functions
//////////////////////////////////////////////////////////////*/
/**
* @notice Returns all extensions stored. Override default lugins stored in router are
* given precedence over default extensions in DefaultExtensionSet.
*/
function getAllExtensions() external view returns (Extension[] memory allExtensions) {
Extension[] memory defaultExtensions = IDefaultExtensionSet(defaultExtensionSet).getAllExtensions();
uint256 defaultExtensionsLen = defaultExtensions.length;
ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();
string[] memory names = data.extensionNames.values();
uint256 namesLen = names.length;
uint256 overrides = 0;
for (uint256 i = 0; i < defaultExtensionsLen; i += 1) {
if (data.extensionNames.contains(defaultExtensions[i].metadata.name)) {
overrides += 1;
}
}
uint256 total = (namesLen + defaultExtensionsLen) - overrides;
allExtensions = new Extension[](total);
uint256 idx = 0;
for (uint256 i = 0; i < defaultExtensionsLen; i += 1) {
string memory name = defaultExtensions[i].metadata.name;
if (!data.extensionNames.contains(name)) {
allExtensions[idx] = defaultExtensions[i];
idx += 1;
}
}
for (uint256 i = 0; i < namesLen; i += 1) {
allExtensions[idx] = data.extensions[names[i]];
idx += 1;
}
}
/// @dev Returns the extension metadata and functions for a given extension.
function getExtension(string memory _extensionName) public view returns (Extension memory) {
ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();
bool isLocalExtension = data.extensionNames.contains(_extensionName);
return isLocalExtension ? data.extensions[_extensionName] : IDefaultExtensionSet(defaultExtensionSet).getExtension(_extensionName);
}
/// @dev Returns the extension's implementation smart contract address.
function getExtensionImplementation(string memory _extensionName) external view returns (address) {
return getExtension(_extensionName).metadata.implementation;
}
/// @dev Returns all functions that belong to the given extension contract.
function getAllFunctionsOfExtension(string memory _extensionName) external view returns (ExtensionFunction[] memory) {
return getExtension(_extensionName).functions;
}
/// @dev Returns the extension metadata for a given function.
function getExtensionForFunction(bytes4 _functionSelector) public view returns (ExtensionMetadata memory) {
ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();
ExtensionMetadata memory metadata = data.extensionMetadata[_functionSelector];
bool isLocalExtension = metadata.implementation != address(0);
return isLocalExtension ? metadata : IDefaultExtensionSet(defaultExtensionSet).getExtensionForFunction(_functionSelector);
}
/// @dev Returns the extension implementation address stored in router, for the given function.
function getImplementationForFunction(bytes4 _functionSelector)
public
view
override
returns (address extensionAddress)
{
return getExtensionForFunction(_functionSelector).implementation;
}
/*///////////////////////////////////////////////////////////////
Internal functions
//////////////////////////////////////////////////////////////*/
/// @dev Returns whether a extension can be set in the given execution context.
function _canSetExtension() internal view virtual returns (bool);
}// SPDX-License-Identifier: MIT
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
pragma solidity ^0.8.0;
// Interface
import "../../interface/IDefaultExtensionSet.sol";
// Extensions
import "./ExtensionState.sol";
contract DefaultExtensionSet is IDefaultExtensionSet, ExtensionState {
using StringSet for StringSet.Set;
/*///////////////////////////////////////////////////////////////
State variables
//////////////////////////////////////////////////////////////*/
/// @notice The deployer of DefaultExtensionSet.
address private deployer;
/*///////////////////////////////////////////////////////////////
Constructor
//////////////////////////////////////////////////////////////*/
constructor() {
deployer = msg.sender;
}
/*///////////////////////////////////////////////////////////////
External functions
//////////////////////////////////////////////////////////////*/
/// @notice Stores a extension in the DefaultExtensionSet.
function setExtension(Extension memory _extension) external {
require(msg.sender == deployer, "DefaultExtensionSet: unauthorized caller.");
_addExtension(_extension);
}
/*///////////////////////////////////////////////////////////////
View functions
//////////////////////////////////////////////////////////////*/
/// @notice Returns all extensions stored.
function getAllExtensions() external view returns (Extension[] memory allExtensions) {
ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();
string[] memory names = data.extensionNames.values();
uint256 len = names.length;
allExtensions = new Extension[](len);
for (uint256 i = 0; i < len; i += 1) {
allExtensions[i] = data.extensions[names[i]];
}
}
/// @notice Returns the extension metadata and functions for a given extension.
function getExtension(string memory _extensionName) public view returns (Extension memory) {
ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();
require(data.extensionNames.contains(_extensionName), "DefaultExtensionSet: extension does not exist.");
return data.extensions[_extensionName];
}
/// @notice Returns the extension's implementation smart contract address.
function getExtensionImplementation(string memory _extensionName) external view returns (address) {
return getExtension(_extensionName).metadata.implementation;
}
/// @notice Returns all functions that belong to the given extension contract.
function getAllFunctionsOfExtension(string memory _extensionName) external view returns (ExtensionFunction[] memory) {
return getExtension(_extensionName).functions;
}
/// @notice Returns the extension metadata for a given function.
function getExtensionForFunction(bytes4 _functionSelector) external view returns (ExtensionMetadata memory) {
ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();
ExtensionMetadata memory metadata = data.extensionMetadata[_functionSelector];
require(metadata.implementation != address(0), "DefaultExtensionSet: no extension for function.");
return metadata;
}
}// SPDX-License-Identifier: MIT
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
pragma solidity ^0.8.0;
// Interface
import "../../interface/IExtension.sol";
// Extensions
import "./StringSet.sol";
library ExtensionStateStorage {
bytes32 public constant EXTENSION_STATE_STORAGE_POSITION = keccak256("extension.state.storage");
struct Data {
/// @dev Set of names of all extensions stored.
StringSet.Set extensionNames;
/// @dev Mapping from extension name => `Extension` i.e. extension metadata and functions.
mapping(string => IExtension.Extension) extensions;
/// @dev Mapping from function selector => extension metadata of the extension the function belongs to.
mapping(bytes4 => IExtension.ExtensionMetadata) extensionMetadata;
}
function extensionStateStorage() internal pure returns (Data storage extensionStateData) {
bytes32 position = EXTENSION_STATE_STORAGE_POSITION;
assembly {
extensionStateData.slot := position
}
}
}
contract ExtensionState is IExtension {
using StringSet for StringSet.Set;
/*///////////////////////////////////////////////////////////////
Internal functions
//////////////////////////////////////////////////////////////*/
/// @dev Stores a new extension in the contract.
function _addExtension(Extension memory _extension) internal {
ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();
string memory name = _extension.metadata.name;
require(data.extensionNames.add(name), "ExtensionState: extension already exists.");
data.extensions[name].metadata = _extension.metadata;
require(_extension.metadata.implementation != address(0), "ExtensionState: adding extension without implementation.");
uint256 len = _extension.functions.length;
for (uint256 i = 0; i < len; i += 1) {
require(
_extension.functions[i].functionSelector ==
bytes4(keccak256(abi.encodePacked(_extension.functions[i].functionSignature))),
"ExtensionState: fn selector and signature mismatch."
);
require(
data.extensionMetadata[_extension.functions[i].functionSelector].implementation == address(0),
"ExtensionState: extension already exists for function."
);
data.extensionMetadata[_extension.functions[i].functionSelector] = _extension.metadata;
data.extensions[name].functions.push(_extension.functions[i]);
emit ExtensionAdded(
_extension.metadata.implementation,
_extension.functions[i].functionSelector,
_extension.functions[i].functionSignature
);
}
}
/// @dev Updates / overrides an existing extension in the contract.
function _updateExtension(Extension memory _extension) internal {
ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();
string memory name = _extension.metadata.name;
require(data.extensionNames.contains(name), "ExtensionState: extension does not exist.");
address oldImplementation = data.extensions[name].metadata.implementation;
require(_extension.metadata.implementation != oldImplementation, "ExtensionState: re-adding same extension.");
data.extensions[name].metadata = _extension.metadata;
ExtensionFunction[] memory oldFunctions = data.extensions[name].functions;
uint256 oldFunctionsLen = oldFunctions.length;
delete data.extensions[name].functions;
for (uint256 i = 0; i < oldFunctionsLen; i += 1) {
delete data.extensionMetadata[oldFunctions[i].functionSelector];
}
uint256 len = _extension.functions.length;
for (uint256 i = 0; i < len; i += 1) {
require(
_extension.functions[i].functionSelector ==
bytes4(keccak256(abi.encodePacked(_extension.functions[i].functionSignature))),
"ExtensionState: fn selector and signature mismatch."
);
data.extensionMetadata[_extension.functions[i].functionSelector] = _extension.metadata;
data.extensions[name].functions.push(_extension.functions[i]);
emit ExtensionUpdated(
oldImplementation,
_extension.metadata.implementation,
_extension.functions[i].functionSelector,
_extension.functions[i].functionSignature
);
}
}
/// @dev Removes an existing extension from the contract.
function _removeExtension(string memory _extensionName) internal {
ExtensionStateStorage.Data storage data = ExtensionStateStorage.extensionStateStorage();
require(data.extensionNames.remove(_extensionName), "ExtensionState: extension does not exist.");
address implementation = data.extensions[_extensionName].metadata.implementation;
ExtensionFunction[] memory extensionFunctions = data.extensions[_extensionName].functions;
delete data.extensions[_extensionName];
uint256 len = extensionFunctions.length;
for (uint256 i = 0; i < len; i += 1) {
emit ExtensionRemoved(
implementation,
extensionFunctions[i].functionSelector,
extensionFunctions[i].functionSignature
);
delete data.extensionMetadata[extensionFunctions[i].functionSelector];
}
}
}// SPDX-License-Identifier: Apache 2.0
// @author: thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
pragma solidity ^0.8.0;
library StringSet {
struct Set {
// Storage of set values
string[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(string => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, string memory value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, string memory value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
string memory lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, string memory value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (string memory) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (string[] memory) {
return set._values;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Set storage set, string memory value) internal returns (bool) {
return _add(set, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Set storage set, string memory value) internal returns (bool) {
return _remove(set, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Set storage set, string memory value) internal view returns (bool) {
return _contains(set, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Set storage set) internal view returns (uint256) {
return _length(set);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Set storage set, uint256 index) internal view returns (string memory) {
return _at(set, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Set storage set) internal view returns (string[] memory) {
return _values(set);
}
}{
"optimizer": {
"enabled": true,
"runs": 100
},
"evmVersion": "london",
"remappings": [
":@chainlink/contracts/src/=node_modules/@chainlink/contracts/src/",
":@ds-test/=lib/ds-test/src/",
":@openzeppelin/=node_modules/@openzeppelin/",
":@std/=lib/forge-std/src/",
":contracts/=contracts/",
":ds-test/=lib/ds-test/src/",
":dynamic-contracts/=lib/dynamic-contracts/src/",
":erc721a-upgradeable/=node_modules/erc721a-upgradeable/",
":erc721a/=node_modules/erc721a/",
":forge-std/=lib/forge-std/src/"
],
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"internalType":"struct IExtension.Extension[]","name":"_extensions","type":"tuple[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"prevURI","type":"string"},{"indexed":false,"internalType":"string","name":"newURI","type":"string"}],"name":"ContractURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newRoyaltyRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"newRoyaltyBps","type":"uint256"}],"name":"DefaultRoyalty","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"extensionAddress","type":"address"},{"indexed":true,"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"indexed":false,"internalType":"string","name":"functionSignature","type":"string"}],"name":"ExtensionAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"extensionAddress","type":"address"},{"indexed":true,"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"indexed":false,"internalType":"string","name":"functionSignature","type":"string"}],"name":"ExtensionRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldExtensionAddress","type":"address"},{"indexed":true,"internalType":"address","name":"newExtensionAddress","type":"address"},{"indexed":true,"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"indexed":false,"internalType":"string","name":"functionSignature","type":"string"}],"name":"ExtensionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"restriction","type":"bool"}],"name":"OperatorRestriction","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"prevOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"}],"name":"PrimarySaleRecipientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"internalType":"struct IExtension.Extension","name":"_extension","type":"tuple"}],"name":"addExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultExtensionSet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllExtensions","outputs":[{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"internalType":"struct IExtension.Extension[]","name":"allExtensions","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_extensionName","type":"string"}],"name":"getAllFunctionsOfExtension","outputs":[{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_extensionName","type":"string"}],"name":"getExtension","outputs":[{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"internalType":"struct IExtension.Extension","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_functionSelector","type":"bytes4"}],"name":"getExtensionForFunction","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_extensionName","type":"string"}],"name":"getExtensionImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_functionSelector","type":"bytes4"}],"name":"getImplementationForFunction","outputs":[{"internalType":"address","name":"extensionAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_defaultAdmin","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"string","name":"_contractURI","type":"string"},{"internalType":"address[]","name":"_trustedForwarders","type":"address[]"},{"internalType":"address","name":"_saleRecipient","type":"address"},{"internalType":"address","name":"_royaltyRecipient","type":"address"},{"internalType":"uint16","name":"_royaltyBps","type":"uint16"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_extensionName","type":"string"}],"name":"removeExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"internalType":"struct IExtension.Extension","name":"_extension","type":"tuple"}],"name":"updateExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60a06040523480156200001157600080fd5b5060405162005bec38038062005bec83398101604081905262000034916200038d565b806000604051620000459062000121565b604051809103906000f08015801562000062573d6000803e3d6000fd5b506001600160a01b038116608052825190915060005b818110156200011657826001600160a01b031663fdc9f257858381518110620000a557620000a562000539565b60200260200101516040518263ffffffff1660e01b8152600401620000cb91906200057d565b600060405180830381600087803b158015620000e657600080fd5b505af1158015620000fb573d6000803e3d6000fd5b505050506001816200010e91906200065a565b905062000078565b505050505062000681565b6117f080620043fc83390190565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156200016a576200016a6200012f565b60405290565b604051606081016001600160401b03811182821017156200016a576200016a6200012f565b604051601f8201601f191681016001600160401b0381118282101715620001c057620001c06200012f565b604052919050565b60006001600160401b03821115620001e457620001e46200012f565b5060051b60200190565b60005b838110156200020b578181015183820152602001620001f1565b838111156200021b576000848401525b50505050565b600082601f8301126200023357600080fd5b81516001600160401b038111156200024f576200024f6200012f565b62000264601f8201601f191660200162000195565b8181528460208386010111156200027a57600080fd5b6200028d826020830160208701620001ee565b949350505050565b600082601f830112620002a757600080fd5b81516020620002c0620002ba83620001c8565b62000195565b82815260059290921b84018101918181019086841115620002e057600080fd5b8286015b84811015620003825780516001600160401b0380821115620003065760008081fd5b908801906040828b03601f1901811315620003215760008081fd5b6200032b62000145565b838801516001600160e01b031981168114620003475760008081fd5b81529083015190828211156200035d5760008081fd5b6200036d8c898487010162000221565b818901528652505050918301918301620002e4565b509695505050505050565b600060208284031215620003a057600080fd5b81516001600160401b0380821115620003b857600080fd5b818401915084601f830112620003cd57600080fd5b8151620003de620002ba82620001c8565b8082825260208201915060208360051b8601019250878311156200040157600080fd5b602085015b838110156200052d578051858111156200041f57600080fd5b8601601f196040828c03820112156200043757600080fd5b6200044162000145565b6020830151888111156200045457600080fd5b83016060818e03840112156200046957600080fd5b6200047362000170565b92506020810151898111156200048857600080fd5b620004998e60208385010162000221565b845250604081015189811115620004af57600080fd5b620004c08e60208385010162000221565b602085015250606001516001600160a01b0381168114620004e057600080fd5b806040840152508181526040830151915087821115620004ff57600080fd5b620005108c60208486010162000295565b602082015280865250505060208301925060208101905062000406565b50979650505050505050565b634e487b7160e01b600052603260045260246000fd5b6000815180845262000569816020860160208601620001ee565b601f01601f19169290920160200192915050565b600060208083528351604080838601528151606080870152620005a460c08701826200054f565b905083830151605f19878303016080880152620005c282826200054f565b938301516001600160a01b031660a0880152505082860151601f198684038101878401528151808552918501939185830190600581901b8401870160005b828110156200064b5785820385018452875180516001600160e01b031916835289015189830188905262000637888401826200054f565b988a0198948a019492505060010162000600565b509a9950505050505050505050565b600082198211156200067c57634e487b7160e01b600052601160045260246000fd5b500190565b608051613d4a620006b26000396000818161012a015281816104f20152818161057f0152610d5b0152613d4a6000f3fe6080604052600436106100b65760003560e01c8063a79602ee1161006f578063a79602ee146101f8578063ac9650d81461021a578063c22707ee14610247578063c54c07e114610274578063ce0b601314610294578063e05688fe146102b4578063ee7d2adf146102d4576100bd565b8063012b8729146100e25780631ee8b41b14610118578063212f6912146101595780634a00cc4814610186578063572b6c05146101a85780637c3b1137146101d8576100bd565b366100bd57005b60006100d46000356001600160e01b0319166102f4565b90506100df81610309565b50005b3480156100ee57600080fd5b506101026100fd36600461301d565b610332565b60405161010f91906130a9565b60405180910390f35b34801561012457600080fd5b5061014c7f000000000000000000000000000000000000000000000000000000000000000081565b60405161010f9190613127565b34801561016557600080fd5b50610179610174366004613151565b610347565b60405161010f91906131bb565b34801561019257600080fd5b5061019b610579565b60405161010f9190613264565b3480156101b457600080fd5b506101c86101c33660046132eb565b610a62565b604051901515815260200161010f565b3480156101e457600080fd5b5061014c6101f336600461301d565b610a9f565b34801561020457600080fd5b506102186102133660046133ac565b610ab5565b005b34801561022657600080fd5b5061023a61023536600461349b565b610c28565b60405161010f919061350f565b34801561025357600080fd5b5061026761026236600461301d565b610d1d565b60405161010f9190613564565b34801561028057600080fd5b5061021861028f366004613641565b611056565b3480156102a057600080fd5b5061014c6102af366004613151565b6102f4565b3480156102c057600080fd5b506102186102cf366004613641565b611086565b3480156102e057600080fd5b506102186102ef36600461301d565b6110b3565b60006102ff82610347565b6040015192915050565b3660008037600080366000845af43d6000803e808015610328573d6000f35b3d6000fd5b505050565b606061033d82610d1d565b6020015192915050565b61034f612dab565b60006103596110e0565b6001600160e01b031984166000908152600382016020526040808220815160608101909252805493945091929091908290829061039590613738565b80601f01602080910402602001604051908101604052809291908181526020018280546103c190613738565b801561040e5780601f106103e35761010080835404028352916020019161040e565b820191906000526020600020905b8154815290600101906020018083116103f157829003601f168201915b5050505050815260200160018201805461042790613738565b80601f016020809104026020016040519081016040528092919081815260200182805461045390613738565b80156104a05780601f10610475576101008083540402835291602001916104a0565b820191906000526020600020905b81548152906001019060200180831161048357829003601f168201915b5050509183525050600291909101546001600160a01b0390811660209092019190915260408201519192501615158061056e57604051631097b48960e11b81526001600160e01b0319861660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063212f691290602401600060405180830381865afa158015610541573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105699190810190613839565b610570565b815b95945050505050565b606060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634a00cc486040518163ffffffff1660e01b8152600401600060405180830381865afa1580156105db573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106039190810190613991565b805190915060006106126110e0565b9050600061061f82611104565b80519091506000805b8581101561067e5761065987828151811061064557610645613a41565b60209081029190910101515151869061110f565b1561066c57610669600183613a6d565b91505b610677600182613a6d565b9050610628565b5060008161068c8785613a6d565b6106969190613a85565b9050806001600160401b038111156106b0576106b0612f10565b6040519080825280602002602001820160405280156106e957816020015b6106d6612dd5565b8152602001906001900390816106ce5790505b5097506000805b8781101561078157600089828151811061070c5761070c613a41565b602090810291909101015151519050610725888261110f565b61076e5789828151811061073b5761073b613a41565b60200260200101518b848151811061075557610755613a41565b602090810291909101015261076b600184613a6d565b92505b5061077a600182613a6d565b90506106f0565b5060005b84811015610a5657866002018682815181106107a3576107a3613a41565b60200260200101516040516107b89190613a9c565b9081526040805191829003602001822060a083018252805490918391908201908390829082906107e790613738565b80601f016020809104026020016040519081016040528092919081815260200182805461081390613738565b80156108605780601f1061083557610100808354040283529160200191610860565b820191906000526020600020905b81548152906001019060200180831161084357829003601f168201915b5050505050815260200160018201805461087990613738565b80601f01602080910402602001604051908101604052809291908181526020018280546108a590613738565b80156108f25780601f106108c7576101008083540402835291602001916108f2565b820191906000526020600020905b8154815290600101906020018083116108d557829003601f168201915b5050509183525050600291909101546001600160a01b03166020918201529082526003830180546040805182850281018501909152818152938301939260009084015b82821015610a125760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b0319168252600181018054929391929184019161098190613738565b80601f01602080910402602001604051908101604052809291908181526020018280546109ad90613738565b80156109fa5780601f106109cf576101008083540402835291602001916109fa565b820191906000526020600020905b8154815290600101906020018083116109dd57829003601f168201915b50505050508152505081526020019060010190610935565b50505050815250508a8381518110610a2c57610a2c613a41565b6020908102919091010152610a42600183613a6d565b9150610a4f600182613a6d565b9050610785565b50505050505050505090565b6001600160a01b031660009081527fa140e363058a6cf3ca062c5e378319d7ddd21cedfbdca620f1c65b05028f156c602052604090205460ff1690565b6000610aaa82610d1d565b516040015192915050565b6000610abf611122565b805490915060ff808216916101009004168015808015610ae2575060018360ff16105b80610afa5750303b158015610afa57508260ff166001145b610b625760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b835460ff191660011784558015610b8157835461ff0019166101001784555b610b8a88611146565b610b948b8b611186565b610b9c6111c3565b610ba589611240565b610bae8c611344565b610bb78c6113b5565b610bc5868661ffff16611493565b610bce8761155e565b610bd66115c7565b8015610c1a57835461ff0019168455604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050505050505050565b6060816001600160401b03811115610c4257610c42612f10565b604051908082528060200260200182016040528015610c7557816020015b6060815260200190600190039081610c605790505b50905060005b82811015610d1557610ce530858584818110610c9957610c99613a41565b9050602002810190610cab9190613ab8565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506115d192505050565b828281518110610cf757610cf7613a41565b60200260200101819052508080610d0d90613b05565b915050610c7b565b505b92915050565b610d25612dd5565b6000610d2f6110e0565b90506000610d3d828561110f565b905080610dda5760405163611383f760e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c22707ee90610d90908790600401613b20565b600060405180830381865afa158015610dad573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610dd59190810190613b33565b61104e565b8160020184604051610dec9190613a9c565b9081526040805191829003602001822060a08301825280549091839190820190839082908290610e1b90613738565b80601f0160208091040260200160405190810160405280929190818152602001828054610e4790613738565b8015610e945780601f10610e6957610100808354040283529160200191610e94565b820191906000526020600020905b815481529060010190602001808311610e7757829003601f168201915b50505050508152602001600182018054610ead90613738565b80601f0160208091040260200160405190810160405280929190818152602001828054610ed990613738565b8015610f265780601f10610efb57610100808354040283529160200191610f26565b820191906000526020600020905b815481529060010190602001808311610f0957829003601f168201915b5050509183525050600291909101546001600160a01b03166020918201529082526003830180546040805182850281018501909152818152938301939260009084015b828210156110465760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b03191682526001810180549293919291840191610fb590613738565b80601f0160208091040260200160405190810160405280929190818152602001828054610fe190613738565b801561102e5780601f106110035761010080835404028352916020019161102e565b820191906000526020600020905b81548152906001019060200180831161101157829003601f168201915b50505050508152505081526020019060010190610f69565b505050915250505b949350505050565b61105e6115f6565b61107a5760405162461bcd60e51b8152600401610b5990613b67565b61108381611655565b50565b61108e6115f6565b6110aa5760405162461bcd60e51b8152600401610b5990613b67565b61108381611c1f565b6110bb6115f6565b6110d75760405162461bcd60e51b8152600401610b5990613b67565b611083816120d3565b7f1a039940024227c284ceea7ab90e5603ce17de27c93816eef22d65b14ee0087390565b6060610d17826123cd565b600061111b83836124aa565b9392505050565b7f627d6cbb4eb558f37de3c2ec08b04710e54e06be936a302f087f7bfb80f39ae090565b6000611150611122565b8054909150610100900460ff166111795760405162461bcd60e51b8152600401610b5990613ba9565b611182826124d7565b5050565b6000611190611122565b8054909150610100900460ff166111b95760405162461bcd60e51b8152600401610b5990613ba9565b61032d838361259b565b60006111cd611122565b8054909150610100900460ff166111f65760405162461bcd60e51b8152600401610b5990613ba9565b6110836040518060400160405280600f81526020016e29b4b3b730ba3ab932a0b1ba34b7b760891b815250604051806040016040528060018152602001603160f81b815250612642565b7fa7d40346e44ca145e94a946aa34a7d4a67245577dc18699a626fe0ffc6ce32818054600090829061127190613738565b80601f016020809104026020016040519081016040528092919081815260200182805461129d90613738565b80156112ea5780601f106112bf576101008083540402835291602001916112ea565b820191906000526020600020905b8154815290600101906020018083116112cd57829003601f168201915b50508651939450611305938693506020880192509050612df5565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a168184604051611337929190613bf4565b60405180910390a1505050565b7ffa02b2ade2dba28b48a24f204a68d8c0005ca2ccfd58c765cdddd023319a9b3f80546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a3505050565b60006113bf611122565b8054909150610100900460ff166113e85760405162461bcd60e51b8152600401610b5990613ba9565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b9297f8502233096d909befbda0999bb8ea2f3a6be3c138b9fbf003752a4c8bce86f6c7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a66000611457818761267f565b611461828761267f565b61146b838761267f565b61147683600061267f565b611480848761267f565b61148b84600061267f565b505050505050565b6127108111156114d75760405162461bcd60e51b815260206004820152600f60248201526e45786365656473206d61782062707360881b6044820152606401610b59565b60007f995f01bd2df7283cdccde6ac870b4e9dc366a11c2005b318f39305029bc84a2380546001600160a01b0385166001600160b01b03199091168117600160a01b61ffff861602178255604051848152919250907f90d7ec04bcb8978719414f82e52e4cb651db41d0e6f8cea6118c2191e6183adb9060200160405180910390a2505050565b7f52513acdf273074fe51c68a52514ea5eabc2d36eb91435d5799fc3f9adc3053080546001600160a01b0319166001600160a01b03831690811782556040517f299d17e95023f496e0ffc4909cff1a61f74bb5eb18de6f900f4155bfa1b3b33390600090a25050565b6115cf612693565b565b606061111b8383604051806060016040528060278152602001613cee60279139612716565b60008061164f816116056127f3565b60009182527fd0ebebe8e6445c62babf8fef767eb39f1002bb957bb5b83258275a4e46428ed5602090815260408084206001600160a01b0393909316845291905290205460ff1690565b91505090565b600061165f6110e0565b82515190915061166f828261110f565b61168b5760405162461bcd60e51b8152600401610b5990613c19565b6000826002018260405161169f9190613a9c565b9081526040805191829003602001909120600201548551909101516001600160a01b039182169250168114156117295760405162461bcd60e51b815260206004820152602960248201527f457874656e73696f6e53746174653a2072652d616464696e672073616d6520656044820152683c3a32b739b4b7b71760b91b6064820152608401610b59565b8351604051600285019061173e908590613a9c565b9081526040516020918190038201902082518051919261176392849290910190612df5565b50602082810151805161177c9260018501920190612df5565b50604091820151600291820180546001600160a01b0319166001600160a01b0390921691909117905590516000918501906117b8908590613a9c565b9081526020016040518091039020600301805480602002602001604051908101604052809291908181526020016000905b828210156118c65760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b0319168252600181018054929391929184019161183590613738565b80601f016020809104026020016040519081016040528092919081815260200182805461186190613738565b80156118ae5780601f10611883576101008083540402835291602001916118ae565b820191906000526020600020905b81548152906001019060200180831161189157829003601f168201915b505050505081525050815260200190600101906117e9565b50505050905060008151905084600201846040516118e49190613a9c565b908152602001604051809103902060030160006119019190612e79565b60005b818110156119885785600301600084838151811061192457611924613a41565b602090810291909101810151516001600160e01b03191682528101919091526040016000908120906119568282612e9a565b611964600183016000612e9a565b5060020180546001600160a01b0319169055611981600182613a6d565b9050611904565b5060208601515160005b81811015611c1557876020015181815181106119b0576119b0613a41565b6020026020010151602001516040516020016119cc9190613a9c565b604051602081830303815290604052805190602001206001600160e01b03191688602001518281518110611a0257611a02613a41565b6020026020010151600001516001600160e01b03191614611a355760405162461bcd60e51b8152600401610b5990613c62565b87600001518760030160008a602001518481518110611a5657611a56613a41565b602090810291909101810151516001600160e01b031916825281810192909252604001600020825180519192611a9192849290910190612df5565b506020828101518051611aaa9260018501920190612df5565b50604091820151600291820180546001600160a01b0319166001600160a01b03909216919091179055905190880190611ae4908890613a9c565b908152602001604051809103902060030188602001518281518110611b0b57611b0b613a41565b6020908102919091018101518254600180820185556000948552938390208251600290920201805463ffffffff191660e09290921c91909117815581830151805192949193611b609392850192910190612df5565b50505087602001518181518110611b7957611b79613a41565b6020026020010151600001516001600160e01b0319168860000151604001516001600160a01b0316866001600160a01b03167f7f4649aa14a7e9abd7f21a02ea35b32c907d59bb701c52c0e028ddf57533c74c8b602001518581518110611be257611be2613a41565b602002602001015160200151604051611bfb9190613b20565b60405180910390a4611c0e600182613a6d565b9050611992565b5050505050505050565b6000611c296110e0565b825151909150611c398282612815565b611c975760405162461bcd60e51b815260206004820152602960248201527f457874656e73696f6e53746174653a20657874656e73696f6e20616c726561646044820152683c9032bc34b9ba399760b91b6064820152608401610b59565b82516040516002840190611cac908490613a9c565b90815260405160209181900382019020825180519192611cd192849290910190612df5565b506020828101518051611cea9260018501920190612df5565b5060409182015160029190910180546001600160a01b0319166001600160a01b0392831617905584519091015116611d855760405162461bcd60e51b815260206004820152603860248201527f457874656e73696f6e53746174653a20616464696e6720657874656e73696f6e604482015277103bb4ba3437baba1034b6b83632b6b2b73a30ba34b7b71760411b6064820152608401610b59565b60208301515160005b818110156120cc5784602001518181518110611dac57611dac613a41565b602002602001015160200151604051602001611dc89190613a9c565b604051602081830303815290604052805190602001206001600160e01b03191685602001518281518110611dfe57611dfe613a41565b6020026020010151600001516001600160e01b03191614611e315760405162461bcd60e51b8152600401610b5990613c62565b60006001600160a01b031684600301600087602001518481518110611e5857611e58613a41565b602090810291909101810151516001600160e01b0319168252810191909152604001600020600201546001600160a01b031614611ef65760405162461bcd60e51b815260206004820152603660248201527f457874656e73696f6e53746174653a20657874656e73696f6e20616c726561646044820152753c9032bc34b9ba39903337b910333ab731ba34b7b71760511b6064820152608401610b59565b846000015184600301600087602001518481518110611f1757611f17613a41565b602090810291909101810151516001600160e01b031916825281810192909252604001600020825180519192611f5292849290910190612df5565b506020828101518051611f6b9260018501920190612df5565b50604091820151600291820180546001600160a01b0319166001600160a01b03909216919091179055905190850190611fa5908590613a9c565b908152602001604051809103902060030185602001518281518110611fcc57611fcc613a41565b6020908102919091018101518254600180820185556000948552938390208251600290920201805463ffffffff191660e09290921c919091178155818301518051929491936120219392850192910190612df5565b5050508460200151818151811061203a5761203a613a41565b6020026020010151600001516001600160e01b0319168560000151604001516001600160a01b03167fb5a3e9571e367979a4a14de42b248d0837c26fd8e879846062abcf7cee1712738760200151848151811061209957612099613a41565b6020026020010151602001516040516120b29190613b20565b60405180910390a36120c5600182613a6d565b9050611d8e565b5050505050565b60006120dd6110e0565b90506120e98183612821565b6121055760405162461bcd60e51b8152600401610b5990613c19565b600081600201836040516121199190613a9c565b9081526040519081900360200181206002908101546001600160a01b031692506000919084019061214b908690613a9c565b9081526020016040518091039020600301805480602002602001604051908101604052809291908181526020016000905b828210156122595760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b031916825260018101805492939192918401916121c890613738565b80601f01602080910402602001604051908101604052809291908181526020018280546121f490613738565b80156122415780601f1061221657610100808354040283529160200191612241565b820191906000526020600020905b81548152906001019060200180831161222457829003601f168201915b5050505050815250508152602001906001019061217c565b50505050905082600201846040516122719190613a9c565b9081526040519081900360200190206000818161228e8282612e9a565b61229c600183016000612e9a565b5060020180546001600160a01b03191690556122bc600383016000612e79565b5050805160005b8181101561148b578281815181106122dd576122dd613a41565b6020026020010151600001516001600160e01b031916846001600160a01b03167f5968261591c9d57680edfe0bed3bb6a37ab7fb354578affd1e5be8ce18e6c9d385848151811061233057612330613a41565b6020026020010151602001516040516123499190613b20565b60405180910390a384600301600084838151811061236957612369613a41565b602090810291909101810151516001600160e01b031916825281019190915260400160009081209061239b8282612e9a565b6123a9600183016000612e9a565b5060020180546001600160a01b03191690556123c6600182613a6d565b90506122c3565b606081600001805480602002602001604051908101604052809291908181526020016000905b8282101561249f57838290600052602060002001805461241290613738565b80601f016020809104026020016040519081016040528092919081815260200182805461243e90613738565b801561248b5780601f106124605761010080835404028352916020019161248b565b820191906000526020600020905b81548152906001019060200180831161246e57829003601f168201915b5050505050815260200190600101906123f3565b505050509050919050565b600082600101826040516124be9190613a9c565b9081526040519081900360200190205415159392505050565b60006124e1611122565b8054909150610100900460ff1661250a5760405162461bcd60e51b8152600401610b5990613ba9565b7fa140e363058a6cf3ca062c5e378319d7ddd21cedfbdca620f1c65b05028f156c60005b835181101561259557600182600001600086848151811061255157612551613a41565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff19169115159190911790558061258d81613b05565b91505061252e565b50505050565b60006125a5611122565b8054909150610100900460ff166125ce5760405162461bcd60e51b8152600401610b5990613ba9565b82517f5aa52bc3377dec757a2280f415d89b13ba8cd01bf969ccb7487e8a4fba742be390612622907f5aa52bc3377dec757a2280f415d89b13ba8cd01bf969ccb7487e8a4fba742be5906020870190612df5565b5082516126389060038301906020860190612df5565b5060009055505050565b600061264c611122565b8054909150610100900460ff166126755760405162461bcd60e51b8152600401610b5990613ba9565b61032d838361282d565b61268982826128b9565b6111828282612935565b6126b2733cc6cdda760b79bafa08df41ecfa224f810dceb660016129c3565b7f54378f4d3b8673acfc5119539edbb9597399240ea9418c2c01cf8d1dcb71133c8054600160ff199091168117825560408051918252517f38475885990d8dfe9ca01f0ef160a1b5514426eab9ddbc953a3353410ba780969181900360200190a150565b60606001600160a01b0384163b61277e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610b59565b600080856001600160a01b0316856040516127999190613a9c565b600060405180830381855af49150503d80600081146127d4576040519150601f19603f3d011682016040523d82523d6000602084013e6127d9565b606091505b50915091506127e9828286612b40565b9695505050505050565b60006127fe33610a62565b15612810575060131936013560601c90565b503390565b600061111b8383612b79565b600061111b8383612be5565b6000612837611122565b8054909150610100900460ff166128605760405162461bcd60e51b8152600401610b5990613ba9565b508151602092830120815191909201207f3f47c9d66c3eff2e63eabde79dec55c2d44646dfc30710e2c69bf9c420c1ade8919091557f3f47c9d66c3eff2e63eabde79dec55c2d44646dfc30710e2c69bf9c420c1ade955565b60008281527fd0ebebe8e6445c62babf8fef767eb39f1002bb957bb5b83258275a4e46428ed5602081815260408084206001600160a01b0386168086529252808420805460ff19166001179055519192339286917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d91a4505050565b60008281527f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c60208190526040822080549192600191906129768385613a6d565b909155505060009384526020918252604080852082865260018101845281862080546001600160a01b039096166001600160a01b0319909616861790559385526002909301909152912055565b6daaeb6d7670e522a718067333cd4e3b156111825760405163c3c5a54760e01b81526daaeb6d7670e522a718067333cd4e9063c3c5a54790612a09903090600401613127565b6020604051808303816000875af1158015612a28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a4c9190613cb5565b611182578015612ac057604051633e9f1edf60e11b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e90637d3e3dbe906044015b600060405180830381600087803b158015612aac57600080fd5b505af115801561148b573d6000803e3d6000fd5b6001600160a01b03821615612b0f5760405163a0af290360e01b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e9063a0af290390604401612a92565b604051632210724360e11b81526daaeb6d7670e522a718067333cd4e90634420e48690612a92903090600401613127565b60608315612b4f57508161111b565b825115612b5f5782518084602001fd5b8160405162461bcd60e51b8152600401610b599190613b20565b6000612b8583836124aa565b612bdd57825460018101845560008481526020908190208451612baf939190910191850190612df5565b5082546040516001850190612bc5908590613a9c565b90815260405190819003602001902055506001610d17565b506000610d17565b6000808360010183604051612bfa9190613a9c565b908152602001604051809103902054905080600014612da1576000612c20600183613a85565b8554909150600090612c3490600190613a85565b9050818114612d42576000866000018281548110612c5457612c54613a41565b906000526020600020018054612c6990613738565b80601f0160208091040260200160405190810160405280929190818152602001828054612c9590613738565b8015612ce25780601f10612cb757610100808354040283529160200191612ce2565b820191906000526020600020905b815481529060010190602001808311612cc557829003601f168201915b5050505050905080876000018481548110612cff57612cff613a41565b906000526020600020019080519060200190612d1c929190612df5565b50838760010182604051612d309190613a9c565b90815260405190819003602001902055505b8554869080612d5357612d53613cd7565b600190038181906000526020600020016000612d6f9190612e9a565b90558560010185604051612d839190613a9c565b90815260200160405180910390206000905560019350505050610d17565b6000915050610d17565b6040518060600160405280606081526020016060815260200160006001600160a01b031681525090565b6040518060400160405280612de8612dab565b8152602001606081525090565b828054612e0190613738565b90600052602060002090601f016020900481019282612e235760008555612e69565b82601f10612e3c57805160ff1916838001178555612e69565b82800160010185558215612e69579182015b82811115612e69578251825591602001919060010190612e4e565b50612e75929150612ed0565b5090565b50805460008255600202906000526020600020908101906110839190612ee5565b508054612ea690613738565b6000825580601f10612eb6575050565b601f01602090049060005260206000209081019061108391905b5b80821115612e755760008155600101612ed1565b80821115612e7557805463ffffffff191681556000612f076001830182612e9a565b50600201612ee5565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715612f4857612f48612f10565b60405290565b604051606081016001600160401b0381118282101715612f4857612f48612f10565b604051601f8201601f191681016001600160401b0381118282101715612f9857612f98612f10565b604052919050565b60006001600160401b03821115612fb957612fb9612f10565b50601f01601f191660200190565b600082601f830112612fd857600080fd5b8135612feb612fe682612fa0565b612f70565b81815284602083860101111561300057600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561302f57600080fd5b81356001600160401b0381111561304557600080fd5b61104e84828501612fc7565b60005b8381101561306c578181015183820152602001613054565b838111156125955750506000910152565b60008151808452613095816020860160208601613051565b601f01601f19169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561311957888303603f19018552815180516001600160e01b03191684528701518784018790526131068785018261307d565b95880195935050908601906001016130d0565b509098975050505050505050565b6001600160a01b0391909116815260200190565b6001600160e01b03198116811461108357600080fd5b60006020828403121561316357600080fd5b813561111b8161313b565b6000815160608452613183606085018261307d565b90506020830151848203602086015261319c828261307d565b6040948501516001600160a01b03169590940194909452509092915050565b60208152600061111b602083018461316e565b6000604082518185526131e38286018261316e565b9050602080850151868303828801528281518085528385019150838160051b860101848401935060005b8281101561325657868203601f19018452845180516001600160e01b03191683528601518683018990526132438984018261307d565b958701959487019492505060010161320d565b509998505050505050505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156132b957603f198886030184526132a78583516131ce565b9450928501929085019060010161328b565b5092979650505050505050565b6001600160a01b038116811461108357600080fd5b80356132e6816132c6565b919050565b6000602082840312156132fd57600080fd5b813561111b816132c6565b60006001600160401b0382111561332157613321612f10565b5060051b60200190565b600082601f83011261333c57600080fd5b8135602061334c612fe683613308565b82815260059290921b8401810191818101908684111561336b57600080fd5b8286015b8481101561338f578035613382816132c6565b835291830191830161336f565b509695505050505050565b803561ffff811681146132e657600080fd5b600080600080600080600080610100898b0312156133c957600080fd5b6133d2896132db565b975060208901356001600160401b03808211156133ee57600080fd5b6133fa8c838d01612fc7565b985060408b013591508082111561341057600080fd5b61341c8c838d01612fc7565b975060608b013591508082111561343257600080fd5b61343e8c838d01612fc7565b965060808b013591508082111561345457600080fd5b506134618b828c0161332b565b94505061347060a08a016132db565b925061347e60c08a016132db565b915061348c60e08a0161339a565b90509295985092959890939650565b600080602083850312156134ae57600080fd5b82356001600160401b03808211156134c557600080fd5b818501915085601f8301126134d957600080fd5b8135818111156134e857600080fd5b8660208260051b85010111156134fd57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156132b957603f1988860301845261355285835161307d565b94509285019290850190600101613536565b60208152600061111b60208301846131ce565b600082601f83011261358857600080fd5b81356020613598612fe683613308565b82815260059290921b840181019181810190868411156135b757600080fd5b8286015b8481101561338f5780356001600160401b03808211156135db5760008081fd5b908801906040828b03601f19018113156135f55760008081fd5b6135fd612f26565b8784013561360a8161313b565b815290830135908282111561361f5760008081fd5b61362d8c8984870101612fc7565b8189015286525050509183019183016135bb565b60006020828403121561365357600080fd5b81356001600160401b038082111561366a57600080fd5b908301906040828603121561367e57600080fd5b613686612f26565b82358281111561369557600080fd5b8301606081880312156136a757600080fd5b6136af612f4e565b8135848111156136be57600080fd5b6136ca89828501612fc7565b8252506020820135848111156136df57600080fd5b6136eb89828501612fc7565b60208301525060408201359150613701826132c6565b6040810191909152815260208301358281111561371d57600080fd5b61372987828601613577565b60208301525095945050505050565b600181811c9082168061374c57607f821691505b6020821081141561376d57634e487b7160e01b600052602260045260246000fd5b50919050565b600082601f83011261378457600080fd5b8151613792612fe682612fa0565b8181528460208386010111156137a757600080fd5b61104e826020830160208701613051565b6000606082840312156137ca57600080fd5b6137d2612f4e565b905081516001600160401b03808211156137eb57600080fd5b6137f785838601613773565b8352602084015191508082111561380d57600080fd5b5061381a84828501613773565b602083015250604082015161382e816132c6565b604082015292915050565b60006020828403121561384b57600080fd5b81516001600160401b0381111561386157600080fd5b61104e848285016137b8565b6000604080838503121561388057600080fd5b613888612f26565b915082516001600160401b03808211156138a157600080fd5b6138ad868387016137b8565b84526020915081850151818111156138c457600080fd5b8501601f810187136138d557600080fd5b80516138e3612fe682613308565b81815260059190911b8201840190848101908983111561390257600080fd5b8584015b8381101561397e5780518681111561391e5760008081fd5b8501808c03601f19018913156139345760008081fd5b61393c612f26565b888201516139498161313b565b8152818a01518881111561395d5760008081fd5b61396b8e8b83860101613773565b828b015250845250918601918601613906565b5080868901525050505050505092915050565b600060208083850312156139a457600080fd5b82516001600160401b03808211156139bb57600080fd5b818501915085601f8301126139cf57600080fd5b81516139dd612fe682613308565b81815260059190911b830184019084810190888311156139fc57600080fd5b8585015b83811015613a3457805185811115613a185760008081fd5b613a268b89838a010161386d565b845250918601918601613a00565b5098975050505050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60008219821115613a8057613a80613a57565b500190565b600082821015613a9757613a97613a57565b500390565b60008251613aae818460208701613051565b9190910192915050565b6000808335601e19843603018112613acf57600080fd5b8301803591506001600160401b03821115613ae957600080fd5b602001915036819003821315613afe57600080fd5b9250929050565b6000600019821415613b1957613b19613a57565b5060010190565b60208152600061111b602083018461307d565b600060208284031215613b4557600080fd5b81516001600160401b03811115613b5b57600080fd5b61104e8482850161386d565b60208082526022908201527f42617365526f757465723a2063616c6c6572206e6f7420617574686f72697a65604082015261321760f11b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b604081526000613c07604083018561307d565b8281036020840152610570818561307d565b60208082526029908201527f457874656e73696f6e53746174653a20657874656e73696f6e20646f6573206e60408201526837ba1032bc34b9ba1760b91b606082015260800190565b60208082526033908201527f457874656e73696f6e53746174653a20666e2073656c6563746f7220616e642060408201527239b4b3b730ba3ab9329036b4b9b6b0ba31b41760691b606082015260800190565b600060208284031215613cc757600080fd5b8151801515811461111b57600080fd5b634e487b7160e01b600052603160045260246000fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220291bdb7a40c33f494d0052d081d90369530d06c36dd342d2fa0c882fb51facc464736f6c634300080c0033608060405234801561001057600080fd5b50600080546001600160a01b031916331790556117be806100326000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c8063012b872914610067578063212f6912146100905780634a00cc48146100b05780637c3b1137146100c5578063c22707ee146100f0578063fdc9f25714610110575b600080fd5b61007a610075366004611299565b610125565b60405161008791906113a4565b60405180910390f35b6100a361009e3660046113d4565b61013a565b604051610087919061143c565b6100b861032f565b6040516100879190611486565b6100d86100d3366004611299565b61066f565b6040516001600160a01b039091168152602001610087565b6101036100fe366004611299565b610685565b60405161008791906114e8565b61012361011e3660046115de565b610981565b005b606061013082610685565b6020015192915050565b6101426110b7565b600061014c6109f9565b6001600160e01b0319841660009081526003820160205260408082208151606081019092528054939450919290919082908290610188906116e2565b80601f01602080910402602001604051908101604052809291908181526020018280546101b4906116e2565b80156102015780601f106101d657610100808354040283529160200191610201565b820191906000526020600020905b8154815290600101906020018083116101e457829003601f168201915b5050505050815260200160018201805461021a906116e2565b80601f0160208091040260200160405190810160405280929190818152602001828054610246906116e2565b80156102935780601f1061026857610100808354040283529160200191610293565b820191906000526020600020905b81548152906001019060200180831161027657829003601f168201915b5050509183525050600291909101546001600160a01b039081166020909201919091526040820151919250166103285760405162461bcd60e51b815260206004820152602f60248201527f44656661756c74457874656e73696f6e5365743a206e6f20657874656e73696f60448201526e37103337b910333ab731ba34b7b71760891b60648201526084015b60405180910390fd5b9392505050565b6060600061033b6109f9565b9050600061034882610a1d565b8051909150806001600160401b038111156103655761036561119a565b60405190808252806020026020018201604052801561039e57816020015b61038b6110e1565b8152602001906001900390816103835790505b50935060005b8181101561066857836002018382815181106103c2576103c261171d565b60200260200101516040516103d79190611733565b9081526040805191829003602001822060a08301825280549091839190820190839082908290610406906116e2565b80601f0160208091040260200160405190810160405280929190818152602001828054610432906116e2565b801561047f5780601f106104545761010080835404028352916020019161047f565b820191906000526020600020905b81548152906001019060200180831161046257829003601f168201915b50505050508152602001600182018054610498906116e2565b80601f01602080910402602001604051908101604052809291908181526020018280546104c4906116e2565b80156105115780601f106104e657610100808354040283529160200191610511565b820191906000526020600020905b8154815290600101906020018083116104f457829003601f168201915b5050509183525050600291909101546001600160a01b03166020918201529082526003830180546040805182850281018501909152818152938301939260009084015b828210156106315760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b031916825260018101805492939192918401916105a0906116e2565b80601f01602080910402602001604051908101604052809291908181526020018280546105cc906116e2565b80156106195780601f106105ee57610100808354040283529160200191610619565b820191906000526020600020905b8154815290600101906020018083116105fc57829003601f168201915b50505050508152505081526020019060010190610554565b505050508152505085828151811061064b5761064b61171d565b602090810291909101015261066160018261174f565b90506103a4565b5050505090565b600061067a82610685565b516040015192915050565b61068d6110e1565b60006106976109f9565b90506106a38184610a2e565b6107065760405162461bcd60e51b815260206004820152602e60248201527f44656661756c74457874656e73696f6e5365743a20657874656e73696f6e206460448201526d37b2b9903737ba1032bc34b9ba1760911b606482015260840161031f565b80600201836040516107189190611733565b9081526040805191829003602001822060a08301825280549091839190820190839082908290610747906116e2565b80601f0160208091040260200160405190810160405280929190818152602001828054610773906116e2565b80156107c05780601f10610795576101008083540402835291602001916107c0565b820191906000526020600020905b8154815290600101906020018083116107a357829003601f168201915b505050505081526020016001820180546107d9906116e2565b80601f0160208091040260200160405190810160405280929190818152602001828054610805906116e2565b80156108525780601f1061082757610100808354040283529160200191610852565b820191906000526020600020905b81548152906001019060200180831161083557829003601f168201915b5050509183525050600291909101546001600160a01b03166020918201529082526003830180546040805182850281018501909152818152938301939260009084015b828210156109725760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b031916825260018101805492939192918401916108e1906116e2565b80601f016020809104026020016040519081016040528092919081815260200182805461090d906116e2565b801561095a5780601f1061092f5761010080835404028352916020019161095a565b820191906000526020600020905b81548152906001019060200180831161093d57829003601f168201915b50505050508152505081526020019060010190610895565b50505091525090949350505050565b6000546001600160a01b031633146109ed5760405162461bcd60e51b815260206004820152602960248201527f44656661756c74457874656e73696f6e5365743a20756e617574686f72697a65604482015268321031b0b63632b91760b91b606482015260840161031f565b6109f681610a3a565b50565b7f1a039940024227c284ceea7ab90e5603ce17de27c93816eef22d65b14ee0087390565b6060610a2882610f3a565b92915050565b60006103288383611017565b6000610a446109f9565b825151909150610a548282611044565b610ab25760405162461bcd60e51b815260206004820152602960248201527f457874656e73696f6e53746174653a20657874656e73696f6e20616c726561646044820152683c9032bc34b9ba399760b91b606482015260840161031f565b82516040516002840190610ac7908490611733565b90815260405160209181900382019020825180519192610aec92849290910190611101565b506020828101518051610b059260018501920190611101565b5060409182015160029190910180546001600160a01b0319166001600160a01b0392831617905584519091015116610ba05760405162461bcd60e51b815260206004820152603860248201527f457874656e73696f6e53746174653a20616464696e6720657874656e73696f6e604482015277103bb4ba3437baba1034b6b83632b6b2b73a30ba34b7b71760411b606482015260840161031f565b60208301515160005b81811015610f335784602001518181518110610bc757610bc761171d565b602002602001015160200151604051602001610be39190611733565b604051602081830303815290604052805190602001206001600160e01b03191685602001518281518110610c1957610c1961171d565b6020026020010151600001516001600160e01b03191614610c985760405162461bcd60e51b815260206004820152603360248201527f457874656e73696f6e53746174653a20666e2073656c6563746f7220616e642060448201527239b4b3b730ba3ab9329036b4b9b6b0ba31b41760691b606482015260840161031f565b60006001600160a01b031684600301600087602001518481518110610cbf57610cbf61171d565b602090810291909101810151516001600160e01b0319168252810191909152604001600020600201546001600160a01b031614610d5d5760405162461bcd60e51b815260206004820152603660248201527f457874656e73696f6e53746174653a20657874656e73696f6e20616c726561646044820152753c9032bc34b9ba39903337b910333ab731ba34b7b71760511b606482015260840161031f565b846000015184600301600087602001518481518110610d7e57610d7e61171d565b602090810291909101810151516001600160e01b031916825281810192909252604001600020825180519192610db992849290910190611101565b506020828101518051610dd29260018501920190611101565b50604091820151600291820180546001600160a01b0319166001600160a01b03909216919091179055905190850190610e0c908590611733565b908152602001604051809103902060030185602001518281518110610e3357610e3361171d565b6020908102919091018101518254600180820185556000948552938390208251600290920201805463ffffffff191660e09290921c91909117815581830151805192949193610e889392850192910190611101565b50505084602001518181518110610ea157610ea161171d565b6020026020010151600001516001600160e01b0319168560000151604001516001600160a01b03167fb5a3e9571e367979a4a14de42b248d0837c26fd8e879846062abcf7cee17127387602001518481518110610f0057610f0061171d565b602002602001015160200151604051610f199190611775565b60405180910390a3610f2c60018261174f565b9050610ba9565b5050505050565b606081600001805480602002602001604051908101604052809291908181526020016000905b8282101561100c578382906000526020600020018054610f7f906116e2565b80601f0160208091040260200160405190810160405280929190818152602001828054610fab906116e2565b8015610ff85780601f10610fcd57610100808354040283529160200191610ff8565b820191906000526020600020905b815481529060010190602001808311610fdb57829003601f168201915b505050505081526020019060010190610f60565b505050509050919050565b6000826001018260405161102b9190611733565b9081526040519081900360200190205415159392505050565b6000610328838360006110578383611017565b6110af57825460018101845560008481526020908190208451611081939190910191850190611101565b5082546040516001850190611097908590611733565b90815260405190819003602001902055506001610a28565b506000610a28565b6040518060600160405280606081526020016060815260200160006001600160a01b031681525090565b60405180604001604052806110f46110b7565b8152602001606081525090565b82805461110d906116e2565b90600052602060002090601f01602090048101928261112f5760008555611175565b82601f1061114857805160ff1916838001178555611175565b82800160010185558215611175579182015b8281111561117557825182559160200191906001019061115a565b50611181929150611185565b5090565b5b808211156111815760008155600101611186565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156111d2576111d261119a565b60405290565b604051606081016001600160401b03811182821017156111d2576111d261119a565b604051601f8201601f191681016001600160401b03811182821017156112225761122261119a565b604052919050565b600082601f83011261123b57600080fd5b81356001600160401b038111156112545761125461119a565b611267601f8201601f19166020016111fa565b81815284602083860101111561127c57600080fd5b816020850160208301376000918101602001919091529392505050565b6000602082840312156112ab57600080fd5b81356001600160401b038111156112c157600080fd5b6112cd8482850161122a565b949350505050565b60005b838110156112f05781810151838201526020016112d8565b838111156112ff576000848401525b50505050565b6000815180845261131d8160208601602086016112d5565b601f01601f19169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b85811015611397578284038952815180516001600160e01b0319168552850151604086860181905261138381870183611305565b9a87019a955050509084019060010161134f565b5091979650505050505050565b6020815260006103286020830184611331565b80356001600160e01b0319811681146113cf57600080fd5b919050565b6000602082840312156113e657600080fd5b610328826113b7565b60008151606084526114046060850182611305565b90506020830151848203602086015261141d8282611305565b6040948501516001600160a01b03169590940194909452509092915050565b60208152600061032860208301846113ef565b600081516040845261146460408501826113ef565b90506020830151848203602086015261147d8282611331565b95945050505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156114db57603f198886030184526114c985835161144f565b945092850192908501906001016114ad565b5092979650505050505050565b602081526000610328602083018461144f565b600082601f83011261150c57600080fd5b813560206001600160401b03808311156115285761152861119a565b8260051b6115378382016111fa565b938452858101830193838101908886111561155157600080fd5b84880192505b858310156115d25782358481111561156f5760008081fd5b88016040818b03601f19018113156115875760008081fd5b61158f6111b0565b61159a8884016113b7565b81529082013590868211156115af5760008081fd5b6115bd8c898486010161122a565b81890152845250509184019190840190611557565b98975050505050505050565b6000602082840312156115f057600080fd5b81356001600160401b038082111561160757600080fd5b908301906040828603121561161b57600080fd5b6116236111b0565b82358281111561163257600080fd5b83016060818803121561164457600080fd5b61164c6111d8565b81358481111561165b57600080fd5b6116678982850161122a565b82525060208201358481111561167c57600080fd5b6116888982850161122a565b60208301525060409190910135906001600160a01b03821682146116ab57600080fd5b604081019190915281526020830135828111156116c757600080fd5b6116d3878286016114fb565b60208301525095945050505050565b600181811c908216806116f657607f821691505b6020821081141561171757634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b600082516117458184602087016112d5565b9190910192915050565b6000821982111561177057634e487b7160e01b600052601160045260246000fd5b500190565b602081526000610328602083018461130556fea2646970667358221220c45038cc24192d6a337d9d8c41071cd8cf4ace74197d7b536eede65374bb62d964736f6c634300080c00330000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001fa000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000e1fdf867e65b3b080b3f774b8453826acfdbc490000000000000000000000000000000000000000000000000000000000000000f54696572656444726f704c6f67696300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d58336353585867475159753743714d574c48464379594e635271427631363447507069476f487543766e63670000000000000000000000000000000000000000000000000000000000000000000000000000000000002e00000000000000000000000000000000000000000000000000000000000005c0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000006c0000000000000000000000000000000000000000000000000000000000000074000000000000000000000000000000000000000000000000000000000000007e0000000000000000000000000000000000000000000000000000000000000086000000000000000000000000000000000000000000000000000000000000008e0000000000000000000000000000000000000000000000000000000000000096000000000000000000000000000000000000000000000000000000000000009e00000000000000000000000000000000000000000000000000000000000000a600000000000000000000000000000000000000000000000000000000000000ae00000000000000000000000000000000000000000000000000000000000000b600000000000000000000000000000000000000000000000000000000000000be00000000000000000000000000000000000000000000000000000000000000c600000000000000000000000000000000000000000000000000000000000000ce00000000000000000000000000000000000000000000000000000000000000d600000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f200000000000000000000000000000000000000000000000000000000000000fa0000000000000000000000000000000000000000000000000000000000000102000000000000000000000000000000000000000000000000000000000000010c0000000000000000000000000000000000000000000000000000000000000114000000000000000000000000000000000000000000000000000000000000011c0000000000000000000000000000000000000000000000000000000000000124000000000000000000000000000000000000000000000000000000000000012c0000000000000000000000000000000000000000000000000000000000000134000000000000000000000000000000000000000000000000000000000000013c0000000000000000000000000000000000000000000000000000000000000144000000000000000000000000000000000000000000000000000000000000014c0000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000017a0000000000000000000000000000000000000000000000000000000000000182000000000000000000000000000000000000000000000000000000000000018a0000000000000000000000000000000000000000000000000000000000000192000000000000000000000000000000000000000000000000000000000000019c00000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001bc00000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001d60095ea7b30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000018617070726f766528616464726573732c75696e7432353629000000000000000070a08231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001262616c616e63654f66286164647265737329000000000000000000000000000042966c68000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000d6275726e2875696e7432353629000000000000000000000000000000000000007a70a8950000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000039636c61696d576974685369676e6174757265282875696e743132382c75696e743132382c627974657333322c6279746573292c62797465732900000000000000e8a3d485000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000d636f6e7472616374555249282900000000000000000000000000000000000000e7150322000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001b656e6372797074446563727970742862797465732c6279746573290000000000a05112fc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000016656e63727970746564446174612875696e743235362900000000000000000000081812fc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000014676574417070726f7665642875696e743235362900000000000000000000000063b45e2d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001167657442617365555249436f756e7428290000000000000000000000000000002419f51b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001a676574426174636849644174496e6465782875696e7432353629000000000000b24f2d39000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001767657444656661756c74526f79616c7479496e666f2829000000000000000000502eff7100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000186765744d65746164617461466f72416c6c5469657273282900000000000000009fc4d68f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001b67657452657665616c5552492875696e743235362c62797465732900000000004cc157df000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001f676574526f79616c7479496e666f466f72546f6b656e2875696e7432353629005e73ff93000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001867657454696572466f72546f6b656e2875696e7432353629000000000000000051c6a0650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000027676574546f6b656e73496e5469657228737472696e672c75696e743235362c75696e7432353629000000000000000000000000000000000000000000000000009d63e4a30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000014676574546f6b656e73496e546965724c656e2829000000000000000000000000e985e9c500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000216973417070726f766564466f72416c6c28616464726573732c616464726573732900000000000000000000000000000000000000000000000000000000000000492e224b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000196973456e6372797074656442617463682875696e743235362900000000000000572b6c05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001b697354727573746564466f727761726465722861646472657373290000000000e28411ea00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000256c617a794d696e742875696e743235362c737472696e672c737472696e672c62797465732900000000000000000000000000000000000000000000000000000006fdde0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000066e616d65282900000000000000000000000000000000000000000000000000003b1475a700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000136e657874546f6b656e4964546f4d696e74282900000000000000000000000000504c6e0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000156f70657261746f725265737472696374696f6e282900000000000000000000008da5cb5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000076f776e65722829000000000000000000000000000000000000000000000000006352211e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000106f776e65724f662875696e743235362900000000000000000000000000000000079fe40e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000167072696d61727953616c65526563697069656e74282900000000000000000000ce805642000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001572657665616c2875696e743235362c62797465732900000000000000000000002a55205a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c726f79616c7479496e666f2875696e743235362c75696e74323536290000000042842e0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000029736166655472616e7366657246726f6d28616464726573732c616464726573732c75696e74323536290000000000000000000000000000000000000000000000b88d4fde000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f736166655472616e7366657246726f6d28616464726573732c616464726573732c75696e743235362c6279746573290000000000000000000000000000000000a22cb465000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001f736574417070726f76616c466f72416c6c28616464726573732c626f6f6c2900938e3d7b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000016736574436f6e747261637455524928737472696e672900000000000000000000600dd5ea000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002673657444656661756c74526f79616c7479496e666f28616464726573732c75696e7432353629000000000000000000000000000000000000000000000000000032f0cd64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c7365744f70657261746f725265737472696374696f6e28626f6f6c290000000013af403500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000117365744f776e65722861646472657373290000000000000000000000000000006f4f283700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000207365745072696d61727953616c65526563697069656e742861646472657373299bcf7a15000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f736574526f79616c7479496e666f466f72546f6b656e2875696e743235362c616464726573732c75696e7432353629000000000000000000000000000000000001ffc9a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000019737570706f727473496e7465726661636528627974657334290000000000000095d89b41000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000873796d626f6c2829000000000000000000000000000000000000000000000000c87b56dd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000011746f6b656e5552492875696e7432353629000000000000000000000000000000a2309ff8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000d746f74616c4d696e746564282900000000000000000000000000000000000000b6d142300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000019746f74616c4d696e746564496e5469657228737472696e67290000000000000018160ddd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000d746f74616c537570706c7928290000000000000000000000000000000000000023b872dd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000257472616e7366657246726f6d28616464726573732c616464726573732c75696e7432353629000000000000000000000000000000000000000000000000000000c4376dd7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002d766572696679282875696e743132382c75696e743132382c627974657333322c6279746573292c6279746573290000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000f7469c633bfa27978fcad60c94833afb8bbcb29000000000000000000000000000000000000000000000000000000000000000155065726d697373696f6e73456e756d657261626c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d656576387843746b356d597a706f7171375a56536e31617a43327274364a38745a4432557644324c31634d4d00000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000000000000000000000000000000000000000000540a217fddf000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001444454641554c545f41444d494e5f524f4c452829000000000000000000000000248a9ca30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000015676574526f6c6541646d696e28627974657333322900000000000000000000009010d07c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e676574526f6c654d656d62657228627974657333322c75696e74323536290000ca15c873000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001b676574526f6c654d656d626572436f756e7428627974657333322900000000002f2ff15d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001a6772616e74526f6c6528627974657333322c616464726573732900000000000091d148540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000018686173526f6c6528627974657333322c61646472657373290000000000000000a32fa5b30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000022686173526f6c655769746853776974636828627974657333322c616464726573732900000000000000000000000000000000000000000000000000000000000036568abe000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001d72656e6f756e6365526f6c6528627974657333322c6164647265737329000000d547741f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001b7265766f6b65526f6c6528627974657333322c61646472657373290000000000
Deployed Bytecode
0x6080604052600436106100b65760003560e01c8063a79602ee1161006f578063a79602ee146101f8578063ac9650d81461021a578063c22707ee14610247578063c54c07e114610274578063ce0b601314610294578063e05688fe146102b4578063ee7d2adf146102d4576100bd565b8063012b8729146100e25780631ee8b41b14610118578063212f6912146101595780634a00cc4814610186578063572b6c05146101a85780637c3b1137146101d8576100bd565b366100bd57005b60006100d46000356001600160e01b0319166102f4565b90506100df81610309565b50005b3480156100ee57600080fd5b506101026100fd36600461301d565b610332565b60405161010f91906130a9565b60405180910390f35b34801561012457600080fd5b5061014c7f0000000000000000000000002991630ca06923c88a43704c6203b166d65d877581565b60405161010f9190613127565b34801561016557600080fd5b50610179610174366004613151565b610347565b60405161010f91906131bb565b34801561019257600080fd5b5061019b610579565b60405161010f9190613264565b3480156101b457600080fd5b506101c86101c33660046132eb565b610a62565b604051901515815260200161010f565b3480156101e457600080fd5b5061014c6101f336600461301d565b610a9f565b34801561020457600080fd5b506102186102133660046133ac565b610ab5565b005b34801561022657600080fd5b5061023a61023536600461349b565b610c28565b60405161010f919061350f565b34801561025357600080fd5b5061026761026236600461301d565b610d1d565b60405161010f9190613564565b34801561028057600080fd5b5061021861028f366004613641565b611056565b3480156102a057600080fd5b5061014c6102af366004613151565b6102f4565b3480156102c057600080fd5b506102186102cf366004613641565b611086565b3480156102e057600080fd5b506102186102ef36600461301d565b6110b3565b60006102ff82610347565b6040015192915050565b3660008037600080366000845af43d6000803e808015610328573d6000f35b3d6000fd5b505050565b606061033d82610d1d565b6020015192915050565b61034f612dab565b60006103596110e0565b6001600160e01b031984166000908152600382016020526040808220815160608101909252805493945091929091908290829061039590613738565b80601f01602080910402602001604051908101604052809291908181526020018280546103c190613738565b801561040e5780601f106103e35761010080835404028352916020019161040e565b820191906000526020600020905b8154815290600101906020018083116103f157829003601f168201915b5050505050815260200160018201805461042790613738565b80601f016020809104026020016040519081016040528092919081815260200182805461045390613738565b80156104a05780601f10610475576101008083540402835291602001916104a0565b820191906000526020600020905b81548152906001019060200180831161048357829003601f168201915b5050509183525050600291909101546001600160a01b0390811660209092019190915260408201519192501615158061056e57604051631097b48960e11b81526001600160e01b0319861660048201527f0000000000000000000000002991630ca06923c88a43704c6203b166d65d87756001600160a01b03169063212f691290602401600060405180830381865afa158015610541573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105699190810190613839565b610570565b815b95945050505050565b606060007f0000000000000000000000002991630ca06923c88a43704c6203b166d65d87756001600160a01b0316634a00cc486040518163ffffffff1660e01b8152600401600060405180830381865afa1580156105db573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106039190810190613991565b805190915060006106126110e0565b9050600061061f82611104565b80519091506000805b8581101561067e5761065987828151811061064557610645613a41565b60209081029190910101515151869061110f565b1561066c57610669600183613a6d565b91505b610677600182613a6d565b9050610628565b5060008161068c8785613a6d565b6106969190613a85565b9050806001600160401b038111156106b0576106b0612f10565b6040519080825280602002602001820160405280156106e957816020015b6106d6612dd5565b8152602001906001900390816106ce5790505b5097506000805b8781101561078157600089828151811061070c5761070c613a41565b602090810291909101015151519050610725888261110f565b61076e5789828151811061073b5761073b613a41565b60200260200101518b848151811061075557610755613a41565b602090810291909101015261076b600184613a6d565b92505b5061077a600182613a6d565b90506106f0565b5060005b84811015610a5657866002018682815181106107a3576107a3613a41565b60200260200101516040516107b89190613a9c565b9081526040805191829003602001822060a083018252805490918391908201908390829082906107e790613738565b80601f016020809104026020016040519081016040528092919081815260200182805461081390613738565b80156108605780601f1061083557610100808354040283529160200191610860565b820191906000526020600020905b81548152906001019060200180831161084357829003601f168201915b5050505050815260200160018201805461087990613738565b80601f01602080910402602001604051908101604052809291908181526020018280546108a590613738565b80156108f25780601f106108c7576101008083540402835291602001916108f2565b820191906000526020600020905b8154815290600101906020018083116108d557829003601f168201915b5050509183525050600291909101546001600160a01b03166020918201529082526003830180546040805182850281018501909152818152938301939260009084015b82821015610a125760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b0319168252600181018054929391929184019161098190613738565b80601f01602080910402602001604051908101604052809291908181526020018280546109ad90613738565b80156109fa5780601f106109cf576101008083540402835291602001916109fa565b820191906000526020600020905b8154815290600101906020018083116109dd57829003601f168201915b50505050508152505081526020019060010190610935565b50505050815250508a8381518110610a2c57610a2c613a41565b6020908102919091010152610a42600183613a6d565b9150610a4f600182613a6d565b9050610785565b50505050505050505090565b6001600160a01b031660009081527fa140e363058a6cf3ca062c5e378319d7ddd21cedfbdca620f1c65b05028f156c602052604090205460ff1690565b6000610aaa82610d1d565b516040015192915050565b6000610abf611122565b805490915060ff808216916101009004168015808015610ae2575060018360ff16105b80610afa5750303b158015610afa57508260ff166001145b610b625760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b835460ff191660011784558015610b8157835461ff0019166101001784555b610b8a88611146565b610b948b8b611186565b610b9c6111c3565b610ba589611240565b610bae8c611344565b610bb78c6113b5565b610bc5868661ffff16611493565b610bce8761155e565b610bd66115c7565b8015610c1a57835461ff0019168455604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050505050505050565b6060816001600160401b03811115610c4257610c42612f10565b604051908082528060200260200182016040528015610c7557816020015b6060815260200190600190039081610c605790505b50905060005b82811015610d1557610ce530858584818110610c9957610c99613a41565b9050602002810190610cab9190613ab8565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506115d192505050565b828281518110610cf757610cf7613a41565b60200260200101819052508080610d0d90613b05565b915050610c7b565b505b92915050565b610d25612dd5565b6000610d2f6110e0565b90506000610d3d828561110f565b905080610dda5760405163611383f760e11b81526001600160a01b037f0000000000000000000000002991630ca06923c88a43704c6203b166d65d8775169063c22707ee90610d90908790600401613b20565b600060405180830381865afa158015610dad573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610dd59190810190613b33565b61104e565b8160020184604051610dec9190613a9c565b9081526040805191829003602001822060a08301825280549091839190820190839082908290610e1b90613738565b80601f0160208091040260200160405190810160405280929190818152602001828054610e4790613738565b8015610e945780601f10610e6957610100808354040283529160200191610e94565b820191906000526020600020905b815481529060010190602001808311610e7757829003601f168201915b50505050508152602001600182018054610ead90613738565b80601f0160208091040260200160405190810160405280929190818152602001828054610ed990613738565b8015610f265780601f10610efb57610100808354040283529160200191610f26565b820191906000526020600020905b815481529060010190602001808311610f0957829003601f168201915b5050509183525050600291909101546001600160a01b03166020918201529082526003830180546040805182850281018501909152818152938301939260009084015b828210156110465760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b03191682526001810180549293919291840191610fb590613738565b80601f0160208091040260200160405190810160405280929190818152602001828054610fe190613738565b801561102e5780601f106110035761010080835404028352916020019161102e565b820191906000526020600020905b81548152906001019060200180831161101157829003601f168201915b50505050508152505081526020019060010190610f69565b505050915250505b949350505050565b61105e6115f6565b61107a5760405162461bcd60e51b8152600401610b5990613b67565b61108381611655565b50565b61108e6115f6565b6110aa5760405162461bcd60e51b8152600401610b5990613b67565b61108381611c1f565b6110bb6115f6565b6110d75760405162461bcd60e51b8152600401610b5990613b67565b611083816120d3565b7f1a039940024227c284ceea7ab90e5603ce17de27c93816eef22d65b14ee0087390565b6060610d17826123cd565b600061111b83836124aa565b9392505050565b7f627d6cbb4eb558f37de3c2ec08b04710e54e06be936a302f087f7bfb80f39ae090565b6000611150611122565b8054909150610100900460ff166111795760405162461bcd60e51b8152600401610b5990613ba9565b611182826124d7565b5050565b6000611190611122565b8054909150610100900460ff166111b95760405162461bcd60e51b8152600401610b5990613ba9565b61032d838361259b565b60006111cd611122565b8054909150610100900460ff166111f65760405162461bcd60e51b8152600401610b5990613ba9565b6110836040518060400160405280600f81526020016e29b4b3b730ba3ab932a0b1ba34b7b760891b815250604051806040016040528060018152602001603160f81b815250612642565b7fa7d40346e44ca145e94a946aa34a7d4a67245577dc18699a626fe0ffc6ce32818054600090829061127190613738565b80601f016020809104026020016040519081016040528092919081815260200182805461129d90613738565b80156112ea5780601f106112bf576101008083540402835291602001916112ea565b820191906000526020600020905b8154815290600101906020018083116112cd57829003601f168201915b50508651939450611305938693506020880192509050612df5565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a168184604051611337929190613bf4565b60405180910390a1505050565b7ffa02b2ade2dba28b48a24f204a68d8c0005ca2ccfd58c765cdddd023319a9b3f80546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a3505050565b60006113bf611122565b8054909150610100900460ff166113e85760405162461bcd60e51b8152600401610b5990613ba9565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b9297f8502233096d909befbda0999bb8ea2f3a6be3c138b9fbf003752a4c8bce86f6c7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a66000611457818761267f565b611461828761267f565b61146b838761267f565b61147683600061267f565b611480848761267f565b61148b84600061267f565b505050505050565b6127108111156114d75760405162461bcd60e51b815260206004820152600f60248201526e45786365656473206d61782062707360881b6044820152606401610b59565b60007f995f01bd2df7283cdccde6ac870b4e9dc366a11c2005b318f39305029bc84a2380546001600160a01b0385166001600160b01b03199091168117600160a01b61ffff861602178255604051848152919250907f90d7ec04bcb8978719414f82e52e4cb651db41d0e6f8cea6118c2191e6183adb9060200160405180910390a2505050565b7f52513acdf273074fe51c68a52514ea5eabc2d36eb91435d5799fc3f9adc3053080546001600160a01b0319166001600160a01b03831690811782556040517f299d17e95023f496e0ffc4909cff1a61f74bb5eb18de6f900f4155bfa1b3b33390600090a25050565b6115cf612693565b565b606061111b8383604051806060016040528060278152602001613cee60279139612716565b60008061164f816116056127f3565b60009182527fd0ebebe8e6445c62babf8fef767eb39f1002bb957bb5b83258275a4e46428ed5602090815260408084206001600160a01b0393909316845291905290205460ff1690565b91505090565b600061165f6110e0565b82515190915061166f828261110f565b61168b5760405162461bcd60e51b8152600401610b5990613c19565b6000826002018260405161169f9190613a9c565b9081526040805191829003602001909120600201548551909101516001600160a01b039182169250168114156117295760405162461bcd60e51b815260206004820152602960248201527f457874656e73696f6e53746174653a2072652d616464696e672073616d6520656044820152683c3a32b739b4b7b71760b91b6064820152608401610b59565b8351604051600285019061173e908590613a9c565b9081526040516020918190038201902082518051919261176392849290910190612df5565b50602082810151805161177c9260018501920190612df5565b50604091820151600291820180546001600160a01b0319166001600160a01b0390921691909117905590516000918501906117b8908590613a9c565b9081526020016040518091039020600301805480602002602001604051908101604052809291908181526020016000905b828210156118c65760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b0319168252600181018054929391929184019161183590613738565b80601f016020809104026020016040519081016040528092919081815260200182805461186190613738565b80156118ae5780601f10611883576101008083540402835291602001916118ae565b820191906000526020600020905b81548152906001019060200180831161189157829003601f168201915b505050505081525050815260200190600101906117e9565b50505050905060008151905084600201846040516118e49190613a9c565b908152602001604051809103902060030160006119019190612e79565b60005b818110156119885785600301600084838151811061192457611924613a41565b602090810291909101810151516001600160e01b03191682528101919091526040016000908120906119568282612e9a565b611964600183016000612e9a565b5060020180546001600160a01b0319169055611981600182613a6d565b9050611904565b5060208601515160005b81811015611c1557876020015181815181106119b0576119b0613a41565b6020026020010151602001516040516020016119cc9190613a9c565b604051602081830303815290604052805190602001206001600160e01b03191688602001518281518110611a0257611a02613a41565b6020026020010151600001516001600160e01b03191614611a355760405162461bcd60e51b8152600401610b5990613c62565b87600001518760030160008a602001518481518110611a5657611a56613a41565b602090810291909101810151516001600160e01b031916825281810192909252604001600020825180519192611a9192849290910190612df5565b506020828101518051611aaa9260018501920190612df5565b50604091820151600291820180546001600160a01b0319166001600160a01b03909216919091179055905190880190611ae4908890613a9c565b908152602001604051809103902060030188602001518281518110611b0b57611b0b613a41565b6020908102919091018101518254600180820185556000948552938390208251600290920201805463ffffffff191660e09290921c91909117815581830151805192949193611b609392850192910190612df5565b50505087602001518181518110611b7957611b79613a41565b6020026020010151600001516001600160e01b0319168860000151604001516001600160a01b0316866001600160a01b03167f7f4649aa14a7e9abd7f21a02ea35b32c907d59bb701c52c0e028ddf57533c74c8b602001518581518110611be257611be2613a41565b602002602001015160200151604051611bfb9190613b20565b60405180910390a4611c0e600182613a6d565b9050611992565b5050505050505050565b6000611c296110e0565b825151909150611c398282612815565b611c975760405162461bcd60e51b815260206004820152602960248201527f457874656e73696f6e53746174653a20657874656e73696f6e20616c726561646044820152683c9032bc34b9ba399760b91b6064820152608401610b59565b82516040516002840190611cac908490613a9c565b90815260405160209181900382019020825180519192611cd192849290910190612df5565b506020828101518051611cea9260018501920190612df5565b5060409182015160029190910180546001600160a01b0319166001600160a01b0392831617905584519091015116611d855760405162461bcd60e51b815260206004820152603860248201527f457874656e73696f6e53746174653a20616464696e6720657874656e73696f6e604482015277103bb4ba3437baba1034b6b83632b6b2b73a30ba34b7b71760411b6064820152608401610b59565b60208301515160005b818110156120cc5784602001518181518110611dac57611dac613a41565b602002602001015160200151604051602001611dc89190613a9c565b604051602081830303815290604052805190602001206001600160e01b03191685602001518281518110611dfe57611dfe613a41565b6020026020010151600001516001600160e01b03191614611e315760405162461bcd60e51b8152600401610b5990613c62565b60006001600160a01b031684600301600087602001518481518110611e5857611e58613a41565b602090810291909101810151516001600160e01b0319168252810191909152604001600020600201546001600160a01b031614611ef65760405162461bcd60e51b815260206004820152603660248201527f457874656e73696f6e53746174653a20657874656e73696f6e20616c726561646044820152753c9032bc34b9ba39903337b910333ab731ba34b7b71760511b6064820152608401610b59565b846000015184600301600087602001518481518110611f1757611f17613a41565b602090810291909101810151516001600160e01b031916825281810192909252604001600020825180519192611f5292849290910190612df5565b506020828101518051611f6b9260018501920190612df5565b50604091820151600291820180546001600160a01b0319166001600160a01b03909216919091179055905190850190611fa5908590613a9c565b908152602001604051809103902060030185602001518281518110611fcc57611fcc613a41565b6020908102919091018101518254600180820185556000948552938390208251600290920201805463ffffffff191660e09290921c919091178155818301518051929491936120219392850192910190612df5565b5050508460200151818151811061203a5761203a613a41565b6020026020010151600001516001600160e01b0319168560000151604001516001600160a01b03167fb5a3e9571e367979a4a14de42b248d0837c26fd8e879846062abcf7cee1712738760200151848151811061209957612099613a41565b6020026020010151602001516040516120b29190613b20565b60405180910390a36120c5600182613a6d565b9050611d8e565b5050505050565b60006120dd6110e0565b90506120e98183612821565b6121055760405162461bcd60e51b8152600401610b5990613c19565b600081600201836040516121199190613a9c565b9081526040519081900360200181206002908101546001600160a01b031692506000919084019061214b908690613a9c565b9081526020016040518091039020600301805480602002602001604051908101604052809291908181526020016000905b828210156122595760008481526020908190206040805180820190915260028502909101805460e01b6001600160e01b031916825260018101805492939192918401916121c890613738565b80601f01602080910402602001604051908101604052809291908181526020018280546121f490613738565b80156122415780601f1061221657610100808354040283529160200191612241565b820191906000526020600020905b81548152906001019060200180831161222457829003601f168201915b5050505050815250508152602001906001019061217c565b50505050905082600201846040516122719190613a9c565b9081526040519081900360200190206000818161228e8282612e9a565b61229c600183016000612e9a565b5060020180546001600160a01b03191690556122bc600383016000612e79565b5050805160005b8181101561148b578281815181106122dd576122dd613a41565b6020026020010151600001516001600160e01b031916846001600160a01b03167f5968261591c9d57680edfe0bed3bb6a37ab7fb354578affd1e5be8ce18e6c9d385848151811061233057612330613a41565b6020026020010151602001516040516123499190613b20565b60405180910390a384600301600084838151811061236957612369613a41565b602090810291909101810151516001600160e01b031916825281019190915260400160009081209061239b8282612e9a565b6123a9600183016000612e9a565b5060020180546001600160a01b03191690556123c6600182613a6d565b90506122c3565b606081600001805480602002602001604051908101604052809291908181526020016000905b8282101561249f57838290600052602060002001805461241290613738565b80601f016020809104026020016040519081016040528092919081815260200182805461243e90613738565b801561248b5780601f106124605761010080835404028352916020019161248b565b820191906000526020600020905b81548152906001019060200180831161246e57829003601f168201915b5050505050815260200190600101906123f3565b505050509050919050565b600082600101826040516124be9190613a9c565b9081526040519081900360200190205415159392505050565b60006124e1611122565b8054909150610100900460ff1661250a5760405162461bcd60e51b8152600401610b5990613ba9565b7fa140e363058a6cf3ca062c5e378319d7ddd21cedfbdca620f1c65b05028f156c60005b835181101561259557600182600001600086848151811061255157612551613a41565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff19169115159190911790558061258d81613b05565b91505061252e565b50505050565b60006125a5611122565b8054909150610100900460ff166125ce5760405162461bcd60e51b8152600401610b5990613ba9565b82517f5aa52bc3377dec757a2280f415d89b13ba8cd01bf969ccb7487e8a4fba742be390612622907f5aa52bc3377dec757a2280f415d89b13ba8cd01bf969ccb7487e8a4fba742be5906020870190612df5565b5082516126389060038301906020860190612df5565b5060009055505050565b600061264c611122565b8054909150610100900460ff166126755760405162461bcd60e51b8152600401610b5990613ba9565b61032d838361282d565b61268982826128b9565b6111828282612935565b6126b2733cc6cdda760b79bafa08df41ecfa224f810dceb660016129c3565b7f54378f4d3b8673acfc5119539edbb9597399240ea9418c2c01cf8d1dcb71133c8054600160ff199091168117825560408051918252517f38475885990d8dfe9ca01f0ef160a1b5514426eab9ddbc953a3353410ba780969181900360200190a150565b60606001600160a01b0384163b61277e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610b59565b600080856001600160a01b0316856040516127999190613a9c565b600060405180830381855af49150503d80600081146127d4576040519150601f19603f3d011682016040523d82523d6000602084013e6127d9565b606091505b50915091506127e9828286612b40565b9695505050505050565b60006127fe33610a62565b15612810575060131936013560601c90565b503390565b600061111b8383612b79565b600061111b8383612be5565b6000612837611122565b8054909150610100900460ff166128605760405162461bcd60e51b8152600401610b5990613ba9565b508151602092830120815191909201207f3f47c9d66c3eff2e63eabde79dec55c2d44646dfc30710e2c69bf9c420c1ade8919091557f3f47c9d66c3eff2e63eabde79dec55c2d44646dfc30710e2c69bf9c420c1ade955565b60008281527fd0ebebe8e6445c62babf8fef767eb39f1002bb957bb5b83258275a4e46428ed5602081815260408084206001600160a01b0386168086529252808420805460ff19166001179055519192339286917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d91a4505050565b60008281527f0c4ba382c0009cf238e4c1ca1a52f51c61e6248a70bdfb34e5ed49d5578a5c0c60208190526040822080549192600191906129768385613a6d565b909155505060009384526020918252604080852082865260018101845281862080546001600160a01b039096166001600160a01b0319909616861790559385526002909301909152912055565b6daaeb6d7670e522a718067333cd4e3b156111825760405163c3c5a54760e01b81526daaeb6d7670e522a718067333cd4e9063c3c5a54790612a09903090600401613127565b6020604051808303816000875af1158015612a28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a4c9190613cb5565b611182578015612ac057604051633e9f1edf60e11b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e90637d3e3dbe906044015b600060405180830381600087803b158015612aac57600080fd5b505af115801561148b573d6000803e3d6000fd5b6001600160a01b03821615612b0f5760405163a0af290360e01b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e9063a0af290390604401612a92565b604051632210724360e11b81526daaeb6d7670e522a718067333cd4e90634420e48690612a92903090600401613127565b60608315612b4f57508161111b565b825115612b5f5782518084602001fd5b8160405162461bcd60e51b8152600401610b599190613b20565b6000612b8583836124aa565b612bdd57825460018101845560008481526020908190208451612baf939190910191850190612df5565b5082546040516001850190612bc5908590613a9c565b90815260405190819003602001902055506001610d17565b506000610d17565b6000808360010183604051612bfa9190613a9c565b908152602001604051809103902054905080600014612da1576000612c20600183613a85565b8554909150600090612c3490600190613a85565b9050818114612d42576000866000018281548110612c5457612c54613a41565b906000526020600020018054612c6990613738565b80601f0160208091040260200160405190810160405280929190818152602001828054612c9590613738565b8015612ce25780601f10612cb757610100808354040283529160200191612ce2565b820191906000526020600020905b815481529060010190602001808311612cc557829003601f168201915b5050505050905080876000018481548110612cff57612cff613a41565b906000526020600020019080519060200190612d1c929190612df5565b50838760010182604051612d309190613a9c565b90815260405190819003602001902055505b8554869080612d5357612d53613cd7565b600190038181906000526020600020016000612d6f9190612e9a565b90558560010185604051612d839190613a9c565b90815260200160405180910390206000905560019350505050610d17565b6000915050610d17565b6040518060600160405280606081526020016060815260200160006001600160a01b031681525090565b6040518060400160405280612de8612dab565b8152602001606081525090565b828054612e0190613738565b90600052602060002090601f016020900481019282612e235760008555612e69565b82601f10612e3c57805160ff1916838001178555612e69565b82800160010185558215612e69579182015b82811115612e69578251825591602001919060010190612e4e565b50612e75929150612ed0565b5090565b50805460008255600202906000526020600020908101906110839190612ee5565b508054612ea690613738565b6000825580601f10612eb6575050565b601f01602090049060005260206000209081019061108391905b5b80821115612e755760008155600101612ed1565b80821115612e7557805463ffffffff191681556000612f076001830182612e9a565b50600201612ee5565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715612f4857612f48612f10565b60405290565b604051606081016001600160401b0381118282101715612f4857612f48612f10565b604051601f8201601f191681016001600160401b0381118282101715612f9857612f98612f10565b604052919050565b60006001600160401b03821115612fb957612fb9612f10565b50601f01601f191660200190565b600082601f830112612fd857600080fd5b8135612feb612fe682612fa0565b612f70565b81815284602083860101111561300057600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561302f57600080fd5b81356001600160401b0381111561304557600080fd5b61104e84828501612fc7565b60005b8381101561306c578181015183820152602001613054565b838111156125955750506000910152565b60008151808452613095816020860160208601613051565b601f01601f19169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561311957888303603f19018552815180516001600160e01b03191684528701518784018790526131068785018261307d565b95880195935050908601906001016130d0565b509098975050505050505050565b6001600160a01b0391909116815260200190565b6001600160e01b03198116811461108357600080fd5b60006020828403121561316357600080fd5b813561111b8161313b565b6000815160608452613183606085018261307d565b90506020830151848203602086015261319c828261307d565b6040948501516001600160a01b03169590940194909452509092915050565b60208152600061111b602083018461316e565b6000604082518185526131e38286018261316e565b9050602080850151868303828801528281518085528385019150838160051b860101848401935060005b8281101561325657868203601f19018452845180516001600160e01b03191683528601518683018990526132438984018261307d565b958701959487019492505060010161320d565b509998505050505050505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156132b957603f198886030184526132a78583516131ce565b9450928501929085019060010161328b565b5092979650505050505050565b6001600160a01b038116811461108357600080fd5b80356132e6816132c6565b919050565b6000602082840312156132fd57600080fd5b813561111b816132c6565b60006001600160401b0382111561332157613321612f10565b5060051b60200190565b600082601f83011261333c57600080fd5b8135602061334c612fe683613308565b82815260059290921b8401810191818101908684111561336b57600080fd5b8286015b8481101561338f578035613382816132c6565b835291830191830161336f565b509695505050505050565b803561ffff811681146132e657600080fd5b600080600080600080600080610100898b0312156133c957600080fd5b6133d2896132db565b975060208901356001600160401b03808211156133ee57600080fd5b6133fa8c838d01612fc7565b985060408b013591508082111561341057600080fd5b61341c8c838d01612fc7565b975060608b013591508082111561343257600080fd5b61343e8c838d01612fc7565b965060808b013591508082111561345457600080fd5b506134618b828c0161332b565b94505061347060a08a016132db565b925061347e60c08a016132db565b915061348c60e08a0161339a565b90509295985092959890939650565b600080602083850312156134ae57600080fd5b82356001600160401b03808211156134c557600080fd5b818501915085601f8301126134d957600080fd5b8135818111156134e857600080fd5b8660208260051b85010111156134fd57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156132b957603f1988860301845261355285835161307d565b94509285019290850190600101613536565b60208152600061111b60208301846131ce565b600082601f83011261358857600080fd5b81356020613598612fe683613308565b82815260059290921b840181019181810190868411156135b757600080fd5b8286015b8481101561338f5780356001600160401b03808211156135db5760008081fd5b908801906040828b03601f19018113156135f55760008081fd5b6135fd612f26565b8784013561360a8161313b565b815290830135908282111561361f5760008081fd5b61362d8c8984870101612fc7565b8189015286525050509183019183016135bb565b60006020828403121561365357600080fd5b81356001600160401b038082111561366a57600080fd5b908301906040828603121561367e57600080fd5b613686612f26565b82358281111561369557600080fd5b8301606081880312156136a757600080fd5b6136af612f4e565b8135848111156136be57600080fd5b6136ca89828501612fc7565b8252506020820135848111156136df57600080fd5b6136eb89828501612fc7565b60208301525060408201359150613701826132c6565b6040810191909152815260208301358281111561371d57600080fd5b61372987828601613577565b60208301525095945050505050565b600181811c9082168061374c57607f821691505b6020821081141561376d57634e487b7160e01b600052602260045260246000fd5b50919050565b600082601f83011261378457600080fd5b8151613792612fe682612fa0565b8181528460208386010111156137a757600080fd5b61104e826020830160208701613051565b6000606082840312156137ca57600080fd5b6137d2612f4e565b905081516001600160401b03808211156137eb57600080fd5b6137f785838601613773565b8352602084015191508082111561380d57600080fd5b5061381a84828501613773565b602083015250604082015161382e816132c6565b604082015292915050565b60006020828403121561384b57600080fd5b81516001600160401b0381111561386157600080fd5b61104e848285016137b8565b6000604080838503121561388057600080fd5b613888612f26565b915082516001600160401b03808211156138a157600080fd5b6138ad868387016137b8565b84526020915081850151818111156138c457600080fd5b8501601f810187136138d557600080fd5b80516138e3612fe682613308565b81815260059190911b8201840190848101908983111561390257600080fd5b8584015b8381101561397e5780518681111561391e5760008081fd5b8501808c03601f19018913156139345760008081fd5b61393c612f26565b888201516139498161313b565b8152818a01518881111561395d5760008081fd5b61396b8e8b83860101613773565b828b015250845250918601918601613906565b5080868901525050505050505092915050565b600060208083850312156139a457600080fd5b82516001600160401b03808211156139bb57600080fd5b818501915085601f8301126139cf57600080fd5b81516139dd612fe682613308565b81815260059190911b830184019084810190888311156139fc57600080fd5b8585015b83811015613a3457805185811115613a185760008081fd5b613a268b89838a010161386d565b845250918601918601613a00565b5098975050505050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60008219821115613a8057613a80613a57565b500190565b600082821015613a9757613a97613a57565b500390565b60008251613aae818460208701613051565b9190910192915050565b6000808335601e19843603018112613acf57600080fd5b8301803591506001600160401b03821115613ae957600080fd5b602001915036819003821315613afe57600080fd5b9250929050565b6000600019821415613b1957613b19613a57565b5060010190565b60208152600061111b602083018461307d565b600060208284031215613b4557600080fd5b81516001600160401b03811115613b5b57600080fd5b61104e8482850161386d565b60208082526022908201527f42617365526f757465723a2063616c6c6572206e6f7420617574686f72697a65604082015261321760f11b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b604081526000613c07604083018561307d565b8281036020840152610570818561307d565b60208082526029908201527f457874656e73696f6e53746174653a20657874656e73696f6e20646f6573206e60408201526837ba1032bc34b9ba1760b91b606082015260800190565b60208082526033908201527f457874656e73696f6e53746174653a20666e2073656c6563746f7220616e642060408201527239b4b3b730ba3ab9329036b4b9b6b0ba31b41760691b606082015260800190565b600060208284031215613cc757600080fd5b8151801515811461111b57600080fd5b634e487b7160e01b600052603160045260246000fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220291bdb7a40c33f494d0052d081d90369530d06c36dd342d2fa0c882fb51facc464736f6c634300080c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001fa000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000e1fdf867e65b3b080b3f774b8453826acfdbc490000000000000000000000000000000000000000000000000000000000000000f54696572656444726f704c6f67696300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d58336353585867475159753743714d574c48464379594e635271427631363447507069476f487543766e63670000000000000000000000000000000000000000000000000000000000000000000000000000000000002e00000000000000000000000000000000000000000000000000000000000005c0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000006c0000000000000000000000000000000000000000000000000000000000000074000000000000000000000000000000000000000000000000000000000000007e0000000000000000000000000000000000000000000000000000000000000086000000000000000000000000000000000000000000000000000000000000008e0000000000000000000000000000000000000000000000000000000000000096000000000000000000000000000000000000000000000000000000000000009e00000000000000000000000000000000000000000000000000000000000000a600000000000000000000000000000000000000000000000000000000000000ae00000000000000000000000000000000000000000000000000000000000000b600000000000000000000000000000000000000000000000000000000000000be00000000000000000000000000000000000000000000000000000000000000c600000000000000000000000000000000000000000000000000000000000000ce00000000000000000000000000000000000000000000000000000000000000d600000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000e800000000000000000000000000000000000000000000000000000000000000f200000000000000000000000000000000000000000000000000000000000000fa0000000000000000000000000000000000000000000000000000000000000102000000000000000000000000000000000000000000000000000000000000010c0000000000000000000000000000000000000000000000000000000000000114000000000000000000000000000000000000000000000000000000000000011c0000000000000000000000000000000000000000000000000000000000000124000000000000000000000000000000000000000000000000000000000000012c0000000000000000000000000000000000000000000000000000000000000134000000000000000000000000000000000000000000000000000000000000013c0000000000000000000000000000000000000000000000000000000000000144000000000000000000000000000000000000000000000000000000000000014c0000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000017a0000000000000000000000000000000000000000000000000000000000000182000000000000000000000000000000000000000000000000000000000000018a0000000000000000000000000000000000000000000000000000000000000192000000000000000000000000000000000000000000000000000000000000019c00000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001bc00000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001d60095ea7b30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000018617070726f766528616464726573732c75696e7432353629000000000000000070a08231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001262616c616e63654f66286164647265737329000000000000000000000000000042966c68000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000d6275726e2875696e7432353629000000000000000000000000000000000000007a70a8950000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000039636c61696d576974685369676e6174757265282875696e743132382c75696e743132382c627974657333322c6279746573292c62797465732900000000000000e8a3d485000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000d636f6e7472616374555249282900000000000000000000000000000000000000e7150322000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001b656e6372797074446563727970742862797465732c6279746573290000000000a05112fc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000016656e63727970746564446174612875696e743235362900000000000000000000081812fc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000014676574417070726f7665642875696e743235362900000000000000000000000063b45e2d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001167657442617365555249436f756e7428290000000000000000000000000000002419f51b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001a676574426174636849644174496e6465782875696e7432353629000000000000b24f2d39000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001767657444656661756c74526f79616c7479496e666f2829000000000000000000502eff7100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000186765744d65746164617461466f72416c6c5469657273282900000000000000009fc4d68f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001b67657452657665616c5552492875696e743235362c62797465732900000000004cc157df000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001f676574526f79616c7479496e666f466f72546f6b656e2875696e7432353629005e73ff93000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001867657454696572466f72546f6b656e2875696e7432353629000000000000000051c6a0650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000027676574546f6b656e73496e5469657228737472696e672c75696e743235362c75696e7432353629000000000000000000000000000000000000000000000000009d63e4a30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000014676574546f6b656e73496e546965724c656e2829000000000000000000000000e985e9c500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000216973417070726f766564466f72416c6c28616464726573732c616464726573732900000000000000000000000000000000000000000000000000000000000000492e224b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000196973456e6372797074656442617463682875696e743235362900000000000000572b6c05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001b697354727573746564466f727761726465722861646472657373290000000000e28411ea00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000256c617a794d696e742875696e743235362c737472696e672c737472696e672c62797465732900000000000000000000000000000000000000000000000000000006fdde0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000066e616d65282900000000000000000000000000000000000000000000000000003b1475a700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000136e657874546f6b656e4964546f4d696e74282900000000000000000000000000504c6e0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000156f70657261746f725265737472696374696f6e282900000000000000000000008da5cb5b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000076f776e65722829000000000000000000000000000000000000000000000000006352211e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000106f776e65724f662875696e743235362900000000000000000000000000000000079fe40e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000167072696d61727953616c65526563697069656e74282900000000000000000000ce805642000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001572657665616c2875696e743235362c62797465732900000000000000000000002a55205a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c726f79616c7479496e666f2875696e743235362c75696e74323536290000000042842e0e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000029736166655472616e7366657246726f6d28616464726573732c616464726573732c75696e74323536290000000000000000000000000000000000000000000000b88d4fde000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f736166655472616e7366657246726f6d28616464726573732c616464726573732c75696e743235362c6279746573290000000000000000000000000000000000a22cb465000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001f736574417070726f76616c466f72416c6c28616464726573732c626f6f6c2900938e3d7b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000016736574436f6e747261637455524928737472696e672900000000000000000000600dd5ea000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002673657444656661756c74526f79616c7479496e666f28616464726573732c75696e7432353629000000000000000000000000000000000000000000000000000032f0cd64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c7365744f70657261746f725265737472696374696f6e28626f6f6c290000000013af403500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000117365744f776e65722861646472657373290000000000000000000000000000006f4f283700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000207365745072696d61727953616c65526563697069656e742861646472657373299bcf7a15000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f736574526f79616c7479496e666f466f72546f6b656e2875696e743235362c616464726573732c75696e7432353629000000000000000000000000000000000001ffc9a70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000019737570706f727473496e7465726661636528627974657334290000000000000095d89b41000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000873796d626f6c2829000000000000000000000000000000000000000000000000c87b56dd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000011746f6b656e5552492875696e7432353629000000000000000000000000000000a2309ff8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000d746f74616c4d696e746564282900000000000000000000000000000000000000b6d142300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000019746f74616c4d696e746564496e5469657228737472696e67290000000000000018160ddd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000d746f74616c537570706c7928290000000000000000000000000000000000000023b872dd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000257472616e7366657246726f6d28616464726573732c616464726573732c75696e7432353629000000000000000000000000000000000000000000000000000000c4376dd7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002d766572696679282875696e743132382c75696e743132382c627974657333322c6279746573292c6279746573290000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000f7469c633bfa27978fcad60c94833afb8bbcb29000000000000000000000000000000000000000000000000000000000000000155065726d697373696f6e73456e756d657261626c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d656576387843746b356d597a706f7171375a56536e31617a43327274364a38745a4432557644324c31634d4d00000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000000000000000000000000000000000000000000540a217fddf000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001444454641554c545f41444d494e5f524f4c452829000000000000000000000000248a9ca30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000015676574526f6c6541646d696e28627974657333322900000000000000000000009010d07c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e676574526f6c654d656d62657228627974657333322c75696e74323536290000ca15c873000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001b676574526f6c654d656d626572436f756e7428627974657333322900000000002f2ff15d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001a6772616e74526f6c6528627974657333322c616464726573732900000000000091d148540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000018686173526f6c6528627974657333322c61646472657373290000000000000000a32fa5b30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000022686173526f6c655769746853776974636828627974657333322c616464726573732900000000000000000000000000000000000000000000000000000000000036568abe000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001d72656e6f756e6365526f6c6528627974657333322c6164647265737329000000d547741f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001b7265766f6b65526f6c6528627974657333322c61646472657373290000000000
-----Decoded View---------------
Arg [0] : _extensions (tuple[]):
Arg [1] : metadata (tuple):
Arg [1] : name (string): TieredDropLogic
Arg [2] : metadataURI (string): ipfs://QmX3cSXXgGQYu7CqMWLHFCyYNcRqBv164GPpiGoHuCvncg
Arg [3] : implementation (address): 0xe1fDf867E65b3b080B3f774B8453826ACfDbC490
Arg [2] : functions (tuple[]):
Arg [1] : functionSelector (bytes4): 0x095ea7b3
Arg [2] : functionSignature (string): approve(address,uint256)
,
Arg [1] : functionSelector (bytes4): 0x70a08231
Arg [2] : functionSignature (string): balanceOf(address)
,
Arg [1] : functionSelector (bytes4): 0x42966c68
Arg [2] : functionSignature (string): burn(uint256)
,
Arg [1] : functionSelector (bytes4): 0x7a70a895
Arg [2] : functionSignature (string): claimWithSignature((uint128,uint128,bytes32,bytes),bytes)
,
Arg [1] : functionSelector (bytes4): 0xe8a3d485
Arg [2] : functionSignature (string): contractURI()
,
Arg [1] : functionSelector (bytes4): 0xe7150322
Arg [2] : functionSignature (string): encryptDecrypt(bytes,bytes)
,
Arg [1] : functionSelector (bytes4): 0xa05112fc
Arg [2] : functionSignature (string): encryptedData(uint256)
,
Arg [1] : functionSelector (bytes4): 0x081812fc
Arg [2] : functionSignature (string): getApproved(uint256)
,
Arg [1] : functionSelector (bytes4): 0x63b45e2d
Arg [2] : functionSignature (string): getBaseURICount()
,
Arg [1] : functionSelector (bytes4): 0x2419f51b
Arg [2] : functionSignature (string): getBatchIdAtIndex(uint256)
,
Arg [1] : functionSelector (bytes4): 0xb24f2d39
Arg [2] : functionSignature (string): getDefaultRoyaltyInfo()
,
Arg [1] : functionSelector (bytes4): 0x502eff71
Arg [2] : functionSignature (string): getMetadataForAllTiers()
,
Arg [1] : functionSelector (bytes4): 0x9fc4d68f
Arg [2] : functionSignature (string): getRevealURI(uint256,bytes)
,
Arg [1] : functionSelector (bytes4): 0x4cc157df
Arg [2] : functionSignature (string): getRoyaltyInfoForToken(uint256)
,
Arg [1] : functionSelector (bytes4): 0x5e73ff93
Arg [2] : functionSignature (string): getTierForToken(uint256)
,
Arg [1] : functionSelector (bytes4): 0x51c6a065
Arg [2] : functionSignature (string): getTokensInTier(string,uint256,uint256)
,
Arg [1] : functionSelector (bytes4): 0x9d63e4a3
Arg [2] : functionSignature (string): getTokensInTierLen()
,
Arg [1] : functionSelector (bytes4): 0xe985e9c5
Arg [2] : functionSignature (string): isApprovedForAll(address,address)
,
Arg [1] : functionSelector (bytes4): 0x492e224b
Arg [2] : functionSignature (string): isEncryptedBatch(uint256)
,
Arg [1] : functionSelector (bytes4): 0x572b6c05
Arg [2] : functionSignature (string): isTrustedForwarder(address)
,
Arg [1] : functionSelector (bytes4): 0xe28411ea
Arg [2] : functionSignature (string): lazyMint(uint256,string,string,bytes)
,
Arg [1] : functionSelector (bytes4): 0x06fdde03
Arg [2] : functionSignature (string): name()
,
Arg [1] : functionSelector (bytes4): 0x3b1475a7
Arg [2] : functionSignature (string): nextTokenIdToMint()
,
Arg [1] : functionSelector (bytes4): 0x504c6e01
Arg [2] : functionSignature (string): operatorRestriction()
,
Arg [1] : functionSelector (bytes4): 0x8da5cb5b
Arg [2] : functionSignature (string): owner()
,
Arg [1] : functionSelector (bytes4): 0x6352211e
Arg [2] : functionSignature (string): ownerOf(uint256)
,
Arg [1] : functionSelector (bytes4): 0x079fe40e
Arg [2] : functionSignature (string): primarySaleRecipient()
,
Arg [1] : functionSelector (bytes4): 0xce805642
Arg [2] : functionSignature (string): reveal(uint256,bytes)
,
Arg [1] : functionSelector (bytes4): 0x2a55205a
Arg [2] : functionSignature (string): royaltyInfo(uint256,uint256)
,
Arg [1] : functionSelector (bytes4): 0x42842e0e
Arg [2] : functionSignature (string): safeTransferFrom(address,address,uint256)
,
Arg [1] : functionSelector (bytes4): 0xb88d4fde
Arg [2] : functionSignature (string): safeTransferFrom(address,address,uint256,bytes)
,
Arg [1] : functionSelector (bytes4): 0xa22cb465
Arg [2] : functionSignature (string): setApprovalForAll(address,bool)
,
Arg [1] : functionSelector (bytes4): 0x938e3d7b
Arg [2] : functionSignature (string): setContractURI(string)
,
Arg [1] : functionSelector (bytes4): 0x600dd5ea
Arg [2] : functionSignature (string): setDefaultRoyaltyInfo(address,uint256)
,
Arg [1] : functionSelector (bytes4): 0x32f0cd64
Arg [2] : functionSignature (string): setOperatorRestriction(bool)
,
Arg [1] : functionSelector (bytes4): 0x13af4035
Arg [2] : functionSignature (string): setOwner(address)
,
Arg [1] : functionSelector (bytes4): 0x6f4f2837
Arg [2] : functionSignature (string): setPrimarySaleRecipient(address)
,
Arg [1] : functionSelector (bytes4): 0x9bcf7a15
Arg [2] : functionSignature (string): setRoyaltyInfoForToken(uint256,address,uint256)
,
Arg [1] : functionSelector (bytes4): 0x01ffc9a7
Arg [2] : functionSignature (string): supportsInterface(bytes4)
,
Arg [1] : functionSelector (bytes4): 0x95d89b41
Arg [2] : functionSignature (string): symbol()
,
Arg [1] : functionSelector (bytes4): 0xc87b56dd
Arg [2] : functionSignature (string): tokenURI(uint256)
,
Arg [1] : functionSelector (bytes4): 0xa2309ff8
Arg [2] : functionSignature (string): totalMinted()
,
Arg [1] : functionSelector (bytes4): 0xb6d14230
Arg [2] : functionSignature (string): totalMintedInTier(string)
,
Arg [1] : functionSelector (bytes4): 0x18160ddd
Arg [2] : functionSignature (string): totalSupply()
,
Arg [1] : functionSelector (bytes4): 0x23b872dd
Arg [2] : functionSignature (string): transferFrom(address,address,uint256)
,
Arg [1] : functionSelector (bytes4): 0xc4376dd7
Arg [2] : functionSignature (string): verify((uint128,uint128,bytes32,bytes),bytes)
Arg [1] : metadata (tuple):
Arg [1] : name (string): PermissionsEnumerable
Arg [2] : metadataURI (string): ipfs://Qmeev8xCtk5mYzpoqq7ZVSn1azC2rt6J8tZD2UvD2L1cMM
Arg [3] : implementation (address): 0xF7469C633bfA27978fCad60c94833aFb8BbCB290
Arg [2] : functions (tuple[]):
Arg [1] : functionSelector (bytes4): 0xa217fddf
Arg [2] : functionSignature (string): DEFAULT_ADMIN_ROLE()
,
Arg [1] : functionSelector (bytes4): 0x248a9ca3
Arg [2] : functionSignature (string): getRoleAdmin(bytes32)
,
Arg [1] : functionSelector (bytes4): 0x9010d07c
Arg [2] : functionSignature (string): getRoleMember(bytes32,uint256)
,
Arg [1] : functionSelector (bytes4): 0xca15c873
Arg [2] : functionSignature (string): getRoleMemberCount(bytes32)
,
Arg [1] : functionSelector (bytes4): 0x2f2ff15d
Arg [2] : functionSignature (string): grantRole(bytes32,address)
,
Arg [1] : functionSelector (bytes4): 0x91d14854
Arg [2] : functionSignature (string): hasRole(bytes32,address)
,
Arg [1] : functionSelector (bytes4): 0xa32fa5b3
Arg [2] : functionSignature (string): hasRoleWithSwitch(bytes32,address)
,
Arg [1] : functionSelector (bytes4): 0x36568abe
Arg [2] : functionSignature (string): renounceRole(bytes32,address)
,
Arg [1] : functionSelector (bytes4): 0xd547741f
Arg [2] : functionSignature (string): revokeRole(bytes32,address)
-----Encoded View---------------
312 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [3] : 0000000000000000000000000000000000000000000000000000000000001fa0
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [7] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [8] : 000000000000000000000000e1fdf867e65b3b080b3f774b8453826acfdbc490
Arg [9] : 000000000000000000000000000000000000000000000000000000000000000f
Arg [10] : 54696572656444726f704c6f6769630000000000000000000000000000000000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000035
Arg [12] : 697066733a2f2f516d58336353585867475159753743714d574c48464379594e
Arg [13] : 635271427631363447507069476f487543766e63670000000000000000000000
Arg [14] : 000000000000000000000000000000000000000000000000000000000000002e
Arg [15] : 00000000000000000000000000000000000000000000000000000000000005c0
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000640
Arg [17] : 00000000000000000000000000000000000000000000000000000000000006c0
Arg [18] : 0000000000000000000000000000000000000000000000000000000000000740
Arg [19] : 00000000000000000000000000000000000000000000000000000000000007e0
Arg [20] : 0000000000000000000000000000000000000000000000000000000000000860
Arg [21] : 00000000000000000000000000000000000000000000000000000000000008e0
Arg [22] : 0000000000000000000000000000000000000000000000000000000000000960
Arg [23] : 00000000000000000000000000000000000000000000000000000000000009e0
Arg [24] : 0000000000000000000000000000000000000000000000000000000000000a60
Arg [25] : 0000000000000000000000000000000000000000000000000000000000000ae0
Arg [26] : 0000000000000000000000000000000000000000000000000000000000000b60
Arg [27] : 0000000000000000000000000000000000000000000000000000000000000be0
Arg [28] : 0000000000000000000000000000000000000000000000000000000000000c60
Arg [29] : 0000000000000000000000000000000000000000000000000000000000000ce0
Arg [30] : 0000000000000000000000000000000000000000000000000000000000000d60
Arg [31] : 0000000000000000000000000000000000000000000000000000000000000e00
Arg [32] : 0000000000000000000000000000000000000000000000000000000000000e80
Arg [33] : 0000000000000000000000000000000000000000000000000000000000000f20
Arg [34] : 0000000000000000000000000000000000000000000000000000000000000fa0
Arg [35] : 0000000000000000000000000000000000000000000000000000000000001020
Arg [36] : 00000000000000000000000000000000000000000000000000000000000010c0
Arg [37] : 0000000000000000000000000000000000000000000000000000000000001140
Arg [38] : 00000000000000000000000000000000000000000000000000000000000011c0
Arg [39] : 0000000000000000000000000000000000000000000000000000000000001240
Arg [40] : 00000000000000000000000000000000000000000000000000000000000012c0
Arg [41] : 0000000000000000000000000000000000000000000000000000000000001340
Arg [42] : 00000000000000000000000000000000000000000000000000000000000013c0
Arg [43] : 0000000000000000000000000000000000000000000000000000000000001440
Arg [44] : 00000000000000000000000000000000000000000000000000000000000014c0
Arg [45] : 0000000000000000000000000000000000000000000000000000000000001560
Arg [46] : 0000000000000000000000000000000000000000000000000000000000001600
Arg [47] : 0000000000000000000000000000000000000000000000000000000000001680
Arg [48] : 0000000000000000000000000000000000000000000000000000000000001700
Arg [49] : 00000000000000000000000000000000000000000000000000000000000017a0
Arg [50] : 0000000000000000000000000000000000000000000000000000000000001820
Arg [51] : 00000000000000000000000000000000000000000000000000000000000018a0
Arg [52] : 0000000000000000000000000000000000000000000000000000000000001920
Arg [53] : 00000000000000000000000000000000000000000000000000000000000019c0
Arg [54] : 0000000000000000000000000000000000000000000000000000000000001a40
Arg [55] : 0000000000000000000000000000000000000000000000000000000000001ac0
Arg [56] : 0000000000000000000000000000000000000000000000000000000000001b40
Arg [57] : 0000000000000000000000000000000000000000000000000000000000001bc0
Arg [58] : 0000000000000000000000000000000000000000000000000000000000001c40
Arg [59] : 0000000000000000000000000000000000000000000000000000000000001cc0
Arg [60] : 0000000000000000000000000000000000000000000000000000000000001d60
Arg [61] : 095ea7b300000000000000000000000000000000000000000000000000000000
Arg [62] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [63] : 0000000000000000000000000000000000000000000000000000000000000018
Arg [64] : 617070726f766528616464726573732c75696e74323536290000000000000000
Arg [65] : 70a0823100000000000000000000000000000000000000000000000000000000
Arg [66] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [67] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [68] : 62616c616e63654f662861646472657373290000000000000000000000000000
Arg [69] : 42966c6800000000000000000000000000000000000000000000000000000000
Arg [70] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [71] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [72] : 6275726e2875696e743235362900000000000000000000000000000000000000
Arg [73] : 7a70a89500000000000000000000000000000000000000000000000000000000
Arg [74] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [75] : 0000000000000000000000000000000000000000000000000000000000000039
Arg [76] : 636c61696d576974685369676e6174757265282875696e743132382c75696e74
Arg [77] : 3132382c627974657333322c6279746573292c62797465732900000000000000
Arg [78] : e8a3d48500000000000000000000000000000000000000000000000000000000
Arg [79] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [80] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [81] : 636f6e7472616374555249282900000000000000000000000000000000000000
Arg [82] : e715032200000000000000000000000000000000000000000000000000000000
Arg [83] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [84] : 000000000000000000000000000000000000000000000000000000000000001b
Arg [85] : 656e6372797074446563727970742862797465732c6279746573290000000000
Arg [86] : a05112fc00000000000000000000000000000000000000000000000000000000
Arg [87] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [88] : 0000000000000000000000000000000000000000000000000000000000000016
Arg [89] : 656e63727970746564446174612875696e743235362900000000000000000000
Arg [90] : 081812fc00000000000000000000000000000000000000000000000000000000
Arg [91] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [92] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [93] : 676574417070726f7665642875696e7432353629000000000000000000000000
Arg [94] : 63b45e2d00000000000000000000000000000000000000000000000000000000
Arg [95] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [96] : 0000000000000000000000000000000000000000000000000000000000000011
Arg [97] : 67657442617365555249436f756e742829000000000000000000000000000000
Arg [98] : 2419f51b00000000000000000000000000000000000000000000000000000000
Arg [99] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [100] : 000000000000000000000000000000000000000000000000000000000000001a
Arg [101] : 676574426174636849644174496e6465782875696e7432353629000000000000
Arg [102] : b24f2d3900000000000000000000000000000000000000000000000000000000
Arg [103] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [104] : 0000000000000000000000000000000000000000000000000000000000000017
Arg [105] : 67657444656661756c74526f79616c7479496e666f2829000000000000000000
Arg [106] : 502eff7100000000000000000000000000000000000000000000000000000000
Arg [107] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [108] : 0000000000000000000000000000000000000000000000000000000000000018
Arg [109] : 6765744d65746164617461466f72416c6c546965727328290000000000000000
Arg [110] : 9fc4d68f00000000000000000000000000000000000000000000000000000000
Arg [111] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [112] : 000000000000000000000000000000000000000000000000000000000000001b
Arg [113] : 67657452657665616c5552492875696e743235362c6279746573290000000000
Arg [114] : 4cc157df00000000000000000000000000000000000000000000000000000000
Arg [115] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [116] : 000000000000000000000000000000000000000000000000000000000000001f
Arg [117] : 676574526f79616c7479496e666f466f72546f6b656e2875696e743235362900
Arg [118] : 5e73ff9300000000000000000000000000000000000000000000000000000000
Arg [119] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [120] : 0000000000000000000000000000000000000000000000000000000000000018
Arg [121] : 67657454696572466f72546f6b656e2875696e74323536290000000000000000
Arg [122] : 51c6a06500000000000000000000000000000000000000000000000000000000
Arg [123] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [124] : 0000000000000000000000000000000000000000000000000000000000000027
Arg [125] : 676574546f6b656e73496e5469657228737472696e672c75696e743235362c75
Arg [126] : 696e743235362900000000000000000000000000000000000000000000000000
Arg [127] : 9d63e4a300000000000000000000000000000000000000000000000000000000
Arg [128] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [129] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [130] : 676574546f6b656e73496e546965724c656e2829000000000000000000000000
Arg [131] : e985e9c500000000000000000000000000000000000000000000000000000000
Arg [132] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [133] : 0000000000000000000000000000000000000000000000000000000000000021
Arg [134] : 6973417070726f766564466f72416c6c28616464726573732c61646472657373
Arg [135] : 2900000000000000000000000000000000000000000000000000000000000000
Arg [136] : 492e224b00000000000000000000000000000000000000000000000000000000
Arg [137] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [138] : 0000000000000000000000000000000000000000000000000000000000000019
Arg [139] : 6973456e6372797074656442617463682875696e743235362900000000000000
Arg [140] : 572b6c0500000000000000000000000000000000000000000000000000000000
Arg [141] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [142] : 000000000000000000000000000000000000000000000000000000000000001b
Arg [143] : 697354727573746564466f727761726465722861646472657373290000000000
Arg [144] : e28411ea00000000000000000000000000000000000000000000000000000000
Arg [145] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [146] : 0000000000000000000000000000000000000000000000000000000000000025
Arg [147] : 6c617a794d696e742875696e743235362c737472696e672c737472696e672c62
Arg [148] : 7974657329000000000000000000000000000000000000000000000000000000
Arg [149] : 06fdde0300000000000000000000000000000000000000000000000000000000
Arg [150] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [151] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [152] : 6e616d6528290000000000000000000000000000000000000000000000000000
Arg [153] : 3b1475a700000000000000000000000000000000000000000000000000000000
Arg [154] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [155] : 0000000000000000000000000000000000000000000000000000000000000013
Arg [156] : 6e657874546f6b656e4964546f4d696e74282900000000000000000000000000
Arg [157] : 504c6e0100000000000000000000000000000000000000000000000000000000
Arg [158] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [159] : 0000000000000000000000000000000000000000000000000000000000000015
Arg [160] : 6f70657261746f725265737472696374696f6e28290000000000000000000000
Arg [161] : 8da5cb5b00000000000000000000000000000000000000000000000000000000
Arg [162] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [163] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [164] : 6f776e6572282900000000000000000000000000000000000000000000000000
Arg [165] : 6352211e00000000000000000000000000000000000000000000000000000000
Arg [166] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [167] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [168] : 6f776e65724f662875696e743235362900000000000000000000000000000000
Arg [169] : 079fe40e00000000000000000000000000000000000000000000000000000000
Arg [170] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [171] : 0000000000000000000000000000000000000000000000000000000000000016
Arg [172] : 7072696d61727953616c65526563697069656e74282900000000000000000000
Arg [173] : ce80564200000000000000000000000000000000000000000000000000000000
Arg [174] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [175] : 0000000000000000000000000000000000000000000000000000000000000015
Arg [176] : 72657665616c2875696e743235362c6279746573290000000000000000000000
Arg [177] : 2a55205a00000000000000000000000000000000000000000000000000000000
Arg [178] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [179] : 000000000000000000000000000000000000000000000000000000000000001c
Arg [180] : 726f79616c7479496e666f2875696e743235362c75696e743235362900000000
Arg [181] : 42842e0e00000000000000000000000000000000000000000000000000000000
Arg [182] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [183] : 0000000000000000000000000000000000000000000000000000000000000029
Arg [184] : 736166655472616e7366657246726f6d28616464726573732c61646472657373
Arg [185] : 2c75696e74323536290000000000000000000000000000000000000000000000
Arg [186] : b88d4fde00000000000000000000000000000000000000000000000000000000
Arg [187] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [188] : 000000000000000000000000000000000000000000000000000000000000002f
Arg [189] : 736166655472616e7366657246726f6d28616464726573732c61646472657373
Arg [190] : 2c75696e743235362c6279746573290000000000000000000000000000000000
Arg [191] : a22cb46500000000000000000000000000000000000000000000000000000000
Arg [192] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [193] : 000000000000000000000000000000000000000000000000000000000000001f
Arg [194] : 736574417070726f76616c466f72416c6c28616464726573732c626f6f6c2900
Arg [195] : 938e3d7b00000000000000000000000000000000000000000000000000000000
Arg [196] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [197] : 0000000000000000000000000000000000000000000000000000000000000016
Arg [198] : 736574436f6e747261637455524928737472696e672900000000000000000000
Arg [199] : 600dd5ea00000000000000000000000000000000000000000000000000000000
Arg [200] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [201] : 0000000000000000000000000000000000000000000000000000000000000026
Arg [202] : 73657444656661756c74526f79616c7479496e666f28616464726573732c7569
Arg [203] : 6e74323536290000000000000000000000000000000000000000000000000000
Arg [204] : 32f0cd6400000000000000000000000000000000000000000000000000000000
Arg [205] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [206] : 000000000000000000000000000000000000000000000000000000000000001c
Arg [207] : 7365744f70657261746f725265737472696374696f6e28626f6f6c2900000000
Arg [208] : 13af403500000000000000000000000000000000000000000000000000000000
Arg [209] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [210] : 0000000000000000000000000000000000000000000000000000000000000011
Arg [211] : 7365744f776e6572286164647265737329000000000000000000000000000000
Arg [212] : 6f4f283700000000000000000000000000000000000000000000000000000000
Arg [213] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [214] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [215] : 7365745072696d61727953616c65526563697069656e74286164647265737329
Arg [216] : 9bcf7a1500000000000000000000000000000000000000000000000000000000
Arg [217] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [218] : 000000000000000000000000000000000000000000000000000000000000002f
Arg [219] : 736574526f79616c7479496e666f466f72546f6b656e2875696e743235362c61
Arg [220] : 6464726573732c75696e74323536290000000000000000000000000000000000
Arg [221] : 01ffc9a700000000000000000000000000000000000000000000000000000000
Arg [222] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [223] : 0000000000000000000000000000000000000000000000000000000000000019
Arg [224] : 737570706f727473496e74657266616365286279746573342900000000000000
Arg [225] : 95d89b4100000000000000000000000000000000000000000000000000000000
Arg [226] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [227] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [228] : 73796d626f6c2829000000000000000000000000000000000000000000000000
Arg [229] : c87b56dd00000000000000000000000000000000000000000000000000000000
Arg [230] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [231] : 0000000000000000000000000000000000000000000000000000000000000011
Arg [232] : 746f6b656e5552492875696e7432353629000000000000000000000000000000
Arg [233] : a2309ff800000000000000000000000000000000000000000000000000000000
Arg [234] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [235] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [236] : 746f74616c4d696e746564282900000000000000000000000000000000000000
Arg [237] : b6d1423000000000000000000000000000000000000000000000000000000000
Arg [238] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [239] : 0000000000000000000000000000000000000000000000000000000000000019
Arg [240] : 746f74616c4d696e746564496e5469657228737472696e672900000000000000
Arg [241] : 18160ddd00000000000000000000000000000000000000000000000000000000
Arg [242] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [243] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [244] : 746f74616c537570706c79282900000000000000000000000000000000000000
Arg [245] : 23b872dd00000000000000000000000000000000000000000000000000000000
Arg [246] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [247] : 0000000000000000000000000000000000000000000000000000000000000025
Arg [248] : 7472616e7366657246726f6d28616464726573732c616464726573732c75696e
Arg [249] : 7432353629000000000000000000000000000000000000000000000000000000
Arg [250] : c4376dd700000000000000000000000000000000000000000000000000000000
Arg [251] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [252] : 000000000000000000000000000000000000000000000000000000000000002d
Arg [253] : 766572696679282875696e743132382c75696e743132382c627974657333322c
Arg [254] : 6279746573292c62797465732900000000000000000000000000000000000000
Arg [255] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [256] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [257] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [258] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [259] : 000000000000000000000000f7469c633bfa27978fcad60c94833afb8bbcb290
Arg [260] : 0000000000000000000000000000000000000000000000000000000000000015
Arg [261] : 5065726d697373696f6e73456e756d657261626c650000000000000000000000
Arg [262] : 0000000000000000000000000000000000000000000000000000000000000035
Arg [263] : 697066733a2f2f516d656576387843746b356d597a706f7171375a56536e3161
Arg [264] : 7a43327274364a38745a4432557644324c31634d4d0000000000000000000000
Arg [265] : 0000000000000000000000000000000000000000000000000000000000000009
Arg [266] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [267] : 00000000000000000000000000000000000000000000000000000000000001a0
Arg [268] : 0000000000000000000000000000000000000000000000000000000000000220
Arg [269] : 00000000000000000000000000000000000000000000000000000000000002a0
Arg [270] : 0000000000000000000000000000000000000000000000000000000000000320
Arg [271] : 00000000000000000000000000000000000000000000000000000000000003a0
Arg [272] : 0000000000000000000000000000000000000000000000000000000000000420
Arg [273] : 00000000000000000000000000000000000000000000000000000000000004c0
Arg [274] : 0000000000000000000000000000000000000000000000000000000000000540
Arg [275] : a217fddf00000000000000000000000000000000000000000000000000000000
Arg [276] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [277] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [278] : 44454641554c545f41444d494e5f524f4c452829000000000000000000000000
Arg [279] : 248a9ca300000000000000000000000000000000000000000000000000000000
Arg [280] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [281] : 0000000000000000000000000000000000000000000000000000000000000015
Arg [282] : 676574526f6c6541646d696e2862797465733332290000000000000000000000
Arg [283] : 9010d07c00000000000000000000000000000000000000000000000000000000
Arg [284] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [285] : 000000000000000000000000000000000000000000000000000000000000001e
Arg [286] : 676574526f6c654d656d62657228627974657333322c75696e74323536290000
Arg [287] : ca15c87300000000000000000000000000000000000000000000000000000000
Arg [288] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [289] : 000000000000000000000000000000000000000000000000000000000000001b
Arg [290] : 676574526f6c654d656d626572436f756e742862797465733332290000000000
Arg [291] : 2f2ff15d00000000000000000000000000000000000000000000000000000000
Arg [292] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [293] : 000000000000000000000000000000000000000000000000000000000000001a
Arg [294] : 6772616e74526f6c6528627974657333322c6164647265737329000000000000
Arg [295] : 91d1485400000000000000000000000000000000000000000000000000000000
Arg [296] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [297] : 0000000000000000000000000000000000000000000000000000000000000018
Arg [298] : 686173526f6c6528627974657333322c61646472657373290000000000000000
Arg [299] : a32fa5b300000000000000000000000000000000000000000000000000000000
Arg [300] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [301] : 0000000000000000000000000000000000000000000000000000000000000022
Arg [302] : 686173526f6c655769746853776974636828627974657333322c616464726573
Arg [303] : 7329000000000000000000000000000000000000000000000000000000000000
Arg [304] : 36568abe00000000000000000000000000000000000000000000000000000000
Arg [305] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [306] : 000000000000000000000000000000000000000000000000000000000000001d
Arg [307] : 72656e6f756e6365526f6c6528627974657333322c6164647265737329000000
Arg [308] : d547741f00000000000000000000000000000000000000000000000000000000
Arg [309] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [310] : 000000000000000000000000000000000000000000000000000000000000001b
Arg [311] : 7265766f6b65526f6c6528627974657333322c61646472657373290000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 33 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.