Overview
APE Balance
APE Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Multichain Info
Latest 25 from a total of 914 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Set Approval For... | 32739396 | 5 days ago | IN | 0 APE | 0.00473984 | ||||
| Set Approval For... | 32490197 | 12 days ago | IN | 0 APE | 0.00474838 | ||||
| Set Approval For... | 32017359 | 24 days ago | IN | 0 APE | 0.00473984 | ||||
| Set Approval For... | 31988278 | 25 days ago | IN | 0 APE | 0.00474838 | ||||
| Safe Transfer Fr... | 31951291 | 26 days ago | IN | 0 APE | 0.00526869 | ||||
| Safe Transfer Fr... | 31820853 | 29 days ago | IN | 0 APE | 0.00652183 | ||||
| Set Approval For... | 31711838 | 31 days ago | IN | 0 APE | 0.00473984 | ||||
| Set Approval For... | 30518424 | 52 days ago | IN | 0 APE | 0.00118747 | ||||
| Safe Transfer Fr... | 30034449 | 56 days ago | IN | 0 APE | 0.00163104 | ||||
| Set Approval For... | 29067277 | 64 days ago | IN | 0 APE | 0.00118747 | ||||
| Set Approval For... | 28257257 | 72 days ago | IN | 0 APE | 0.00062832 | ||||
| Set Approval For... | 28138249 | 73 days ago | IN | 0 APE | 0.00118747 | ||||
| Safe Transfer Fr... | 28087083 | 73 days ago | IN | 0 APE | 0.00163104 | ||||
| Set Approval For... | 27792128 | 75 days ago | IN | 0 APE | 0.0011875 | ||||
| Set Approval For... | 26520625 | 82 days ago | IN | 0 APE | 0.00118747 | ||||
| Set Approval For... | 26412082 | 83 days ago | IN | 0 APE | 0.00118747 | ||||
| Set Approval For... | 26283779 | 84 days ago | IN | 0 APE | 0.00118747 | ||||
| Set Approval For... | 26072977 | 87 days ago | IN | 0 APE | 0.00062832 | ||||
| Set Approval For... | 26028387 | 87 days ago | IN | 0 APE | 0.00118747 | ||||
| Set Approval For... | 25795732 | 91 days ago | IN | 0 APE | 0.00118747 | ||||
| Set Approval For... | 25744830 | 91 days ago | IN | 0 APE | 0.00118747 | ||||
| Safe Transfer Fr... | 25646748 | 93 days ago | IN | 0 APE | 0.00119634 | ||||
| Safe Transfer Fr... | 25646606 | 93 days ago | IN | 0 APE | 0.00119637 | ||||
| Set Approval For... | 25646581 | 93 days ago | IN | 0 APE | 0.00118747 | ||||
| Safe Transfer Fr... | 25572680 | 94 days ago | IN | 0 APE | 0.00119637 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | ||||
|---|---|---|---|---|---|---|---|
| 31951291 | 26 days ago | 0 APE | |||||
| 31820853 | 29 days ago | 0 APE | |||||
| 30034449 | 56 days ago | 0 APE | |||||
| 28117345 | 73 days ago | 0 APE | |||||
| 28117345 | 73 days ago | 0 APE | |||||
| 28087083 | 73 days ago | 0 APE | |||||
| 28085813 | 73 days ago | 0 APE | |||||
| 28085813 | 73 days ago | 0 APE | |||||
| 26005949 | 88 days ago | 0 APE | |||||
| 26005949 | 88 days ago | 0 APE | |||||
| 25646748 | 93 days ago | 0 APE | |||||
| 25646606 | 93 days ago | 0 APE | |||||
| 25572680 | 94 days ago | 0 APE | |||||
| 25572132 | 94 days ago | 0 APE | |||||
| 25482349 | 96 days ago | 0 APE | |||||
| 25443835 | 97 days ago | 0 APE | |||||
| 25239166 | 101 days ago | 0 APE | |||||
| 25239166 | 101 days ago | 0 APE | |||||
| 25191963 | 102 days ago | 0 APE | |||||
| 25191963 | 102 days ago | 0 APE | |||||
| 25143592 | 103 days ago | 0 APE | |||||
| 25143592 | 103 days ago | 0 APE | |||||
| 25115796 | 104 days ago | 0 APE | |||||
| 25110429 | 104 days ago | 0 APE | |||||
| 25110429 | 104 days ago | 0 APE |
Cross-Chain Transactions
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@limitbreak/creator-token-standards/src/access/OwnableBasic.sol";
import "@limitbreak/creator-token-standards/src/erc1155c/ERC1155C.sol";
import "@limitbreak/creator-token-standards/src/programmable-royalties/BasicRoyalties.sol";
/**
* @title GobsEditions
* @notice ERC1155 contract for Gobs Editions - supports multiple artworks/editions
*/
contract GobsEditions is
ERC1155C,
OwnableBasic,
BasicRoyalties
{
// Authorized minters (e.g., marketplace contract, admin)
mapping(address => bool) public authorizedMinters;
string public name;
string public symbol;
// Token ID counter for creating new editions
uint256 private _currentTokenId;
// Mapping from token ID to its URI
mapping(uint256 => string) private _tokenURIs;
// Mapping from token ID to max supply (0 = unlimited)
mapping(uint256 => uint256) public maxSupply;
// Mapping from token ID to current supply
mapping(uint256 => uint256) public currentSupply;
// Mapping from token ID to onchain data (SVG or base64 encoded metadata)
mapping(uint256 => string) private _onchainData;
// Mapping to track if token uses onchain storage
mapping(uint256 => bool) public isOnchain;
// Per-token royalty tracking
mapping(uint256 => address) private _tokenRoyaltyReceivers;
mapping(uint256 => uint96) private _tokenRoyaltyFees;
constructor(
address royaltyReceiver,
uint96 royaltyFeeNumerator
)
ERC1155OpenZeppelin("")
BasicRoyalties(royaltyReceiver, royaltyFeeNumerator)
{
_transferOwnership(msg.sender);
authorizedMinters[msg.sender] = true;
name = "Gobs Editions";
symbol = "GE";
}
/**
* @dev See {IERC165-supportsInterface}
* @param interfaceId The interface identifier to check
* @return bool True if the contract supports the interface
*/
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ERC1155C, ERC2981) returns (bool) {
return
ERC1155C.supportsInterface(interfaceId) ||
ERC2981.supportsInterface(interfaceId);
}
// --- Royalty Management ---
/**
* @notice Sets a custom royalty for a specific token ID
* @param tokenId The token ID to set royalty for
* @param receiver The address that will receive royalties
* @param feeNumerator The royalty fee in basis points (e.g., 500 = 5%)
*/
function setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) external onlyOwner {
require(tokenId < _currentTokenId, "Edition does not exist");
require(feeNumerator <= 10000, "Royalty fee too high");
require(receiver != address(0), "Invalid receiver address");
_tokenRoyaltyReceivers[tokenId] = receiver;
_tokenRoyaltyFees[tokenId] = feeNumerator;
}
/**
* @notice Gets the royalty info for a specific token and sale price
* @dev Checks for token-specific royalty first, falls back to default
* @param tokenId The token ID being sold
* @param salePrice The sale price of the token
* @return receiver The address to receive royalties
* @return royaltyAmount The amount of royalties to pay
*/
function royaltyInfo(uint256 tokenId, uint256 salePrice)
public
view
virtual
override
returns (address receiver, uint256 royaltyAmount)
{
receiver = _tokenRoyaltyReceivers[tokenId];
uint96 fee = _tokenRoyaltyFees[tokenId];
// If no token-specific royalty set, use default from BasicRoyalties
if (receiver == address(0)) {
return super.royaltyInfo(tokenId, salePrice);
}
royaltyAmount = (salePrice * fee) / 10000;
return (receiver, royaltyAmount);
}
/**
* @notice Gets the token-specific royalty info if set
* @param tokenId The token ID to query
* @return receiver The royalty receiver (address(0) if using default)
* @return feeNumerator The royalty fee in basis points
*/
function getTokenRoyalty(uint256 tokenId) external view returns (address receiver, uint96 feeNumerator) {
return (_tokenRoyaltyReceivers[tokenId], _tokenRoyaltyFees[tokenId]);
}
// --- Access Control ---
function setAuthorizedMinter(address minter, bool authorized) external onlyOwner {
authorizedMinters[minter] = authorized;
}
function isAuthorizedMinter(address minter) public view returns (bool) {
return authorizedMinters[minter];
}
// --- Edition Management ---
/**
* @notice Creates a new edition with optional onchain storage
* @param uri_ The metadata URI (or empty string if storing onchain)
* @param maxSupply_ Maximum supply for this edition (0 = unlimited)
* @param onchainData_ Optional onchain SVG/base64 data
* @param storeOnchain_ Whether to store art onchain
* @return tokenId The ID of the newly created edition
*/
function createEdition(
string memory uri_,
uint256 maxSupply_,
string memory onchainData_,
bool storeOnchain_
) external onlyOwner returns (uint256) {
uint256 tokenId = _currentTokenId;
_currentTokenId++;
if (storeOnchain_) {
_onchainData[tokenId] = onchainData_;
isOnchain[tokenId] = true;
} else {
_tokenURIs[tokenId] = uri_;
}
maxSupply[tokenId] = maxSupply_;
return tokenId;
}
/**
* @notice Updates the URI for an existing edition
* @param tokenId The token ID to update
* @param uri_ The new metadata URI
*/
function setTokenURI(uint256 tokenId, string memory uri_) external onlyOwner {
require(bytes(_tokenURIs[tokenId]).length > 0 || tokenId < _currentTokenId, "Edition does not exist");
require(!isOnchain[tokenId], "Cannot set URI for onchain edition");
_tokenURIs[tokenId] = uri_;
}
/**
* @notice Sets onchain data for an edition (SVG or base64 encoded metadata)
* @param tokenId The token ID to update
* @param data_ The onchain SVG or base64 data
*/
function setOnchainData(uint256 tokenId, string memory data_) external onlyOwner {
require(tokenId < _currentTokenId, "Edition does not exist");
_onchainData[tokenId] = data_;
isOnchain[tokenId] = true;
}
/**
* @notice Returns the URI for a specific token ID
* @param tokenId The token ID to query
* @return The metadata URI or onchain data URI for the token
*/
function uri(uint256 tokenId) public view override returns (string memory) {
if (isOnchain[tokenId]) {
// Return data URI for onchain storage
return string(abi.encodePacked("data:application/json;base64,", _onchainData[tokenId]));
}
return _tokenURIs[tokenId];
}
/**
* @notice Gets the raw onchain data for a token
* @param tokenId The token ID to query
* @return The raw onchain data (SVG or base64)
*/
function getOnchainData(uint256 tokenId) external view returns (string memory) {
require(isOnchain[tokenId], "Token does not use onchain storage");
return _onchainData[tokenId];
}
// --- Minting Functions ---
/**
* @notice Mints tokens of a specific edition to an address
* @param to The address to mint to
* @param tokenId The edition ID to mint
* @param amount The amount to mint
*/
function mint(address to, uint256 tokenId, uint256 amount) external {
require(authorizedMinters[msg.sender] || msg.sender == owner(), "Not authorized to mint");
require(tokenId < _currentTokenId, "Edition does not exist");
// Check max supply if set
if (maxSupply[tokenId] > 0) {
require(currentSupply[tokenId] + amount <= maxSupply[tokenId], "Exceeds max supply");
}
currentSupply[tokenId] += amount;
_mint(to, tokenId, amount, "");
}
/**
* @notice Mints multiple editions to an address
* @param to The address to mint to
* @param tokenIds Array of edition IDs to mint
* @param amounts Array of amounts to mint for each edition
*/
function mintBatch(address to, uint256[] memory tokenIds, uint256[] memory amounts) external {
require(authorizedMinters[msg.sender] || msg.sender == owner(), "Not authorized to mint");
require(tokenIds.length == amounts.length, "Array length mismatch");
for (uint256 i = 0; i < tokenIds.length; i++) {
require(tokenIds[i] < _currentTokenId, "Edition does not exist");
// Check max supply if set
if (maxSupply[tokenIds[i]] > 0) {
require(currentSupply[tokenIds[i]] + amounts[i] <= maxSupply[tokenIds[i]], "Exceeds max supply");
}
currentSupply[tokenIds[i]] += amounts[i];
}
_mintBatch(to, tokenIds, amounts, "");
}
/**
* @notice Gets the total number of editions created
* @return The total number of editions
*/
function totalEditions() external view returns (uint256) {
return _currentTokenId;
}
// --- Burn Functionality ---
/**
* @notice Burns `value` tokens of token type `id` from `account`.
* @dev Caller must be `account` or be approved to operate on behalf of `account`.
* @param account The address whose tokens are to be burned.
* @param id The ID of the token type to burn.
* @param value The amount of tokens to burn.
*/
function burn(address account, uint256 id, uint256 value) public virtual {
require(
msg.sender == account || isApprovedForAll(account, msg.sender),
"ERC1155: caller is not token owner nor approved"
);
_burn(account, id, value);
}
/**
* @notice Burns `values` tokens of token types `ids` from `account`.
* @dev Caller must be `account` or be approved to operate on behalf of `account`.
* @param account The address whose tokens are to be burned.
* @param ids The IDs of the token types to burn.
* @param values The amounts of tokens to burn for each type.
*/
function burnBatch(address account, uint256[] memory ids, uint256[] memory values) public virtual {
require(
msg.sender == account || isApprovedForAll(account, msg.sender),
"ERC1155: caller is not token owner nor approved"
);
_burnBatch(account, ids, values);
}
// --- End Burn Functionality ---
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./OwnablePermissions.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
abstract contract OwnableBasic is OwnablePermissions, Ownable {
function _requireCallerIsContractOwner() internal view virtual override {
_checkOwner();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/Context.sol";
abstract contract OwnablePermissions is Context {
function _requireCallerIsContractOwner() internal view virtual;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../utils/AutomaticValidatorTransferApproval.sol";
import "../utils/CreatorTokenBase.sol";
import "../token/erc1155/ERC1155OpenZeppelin.sol";
import {TOKEN_TYPE_ERC1155} from "@limitbreak/permit-c/src/Constants.sol";
/**
* @title ERC1155C
* @author Limit Break, Inc.
* @notice Extends OpenZeppelin's ERC1155 implementation with Creator Token functionality, which
* allows the contract owner to update the transfer validation logic by managing a security policy in
* an external transfer validation security policy registry. See {CreatorTokenTransferValidator}.
*/
abstract contract ERC1155C is ERC1155OpenZeppelin, CreatorTokenBase, AutomaticValidatorTransferApproval {
/**
* @notice Overrides behavior of isApprovedFor all such that if an operator is not explicitly approved
* for all, the contract owner can optionally auto-approve the 721-C transfer validator for transfers.
*/
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool isApproved) {
isApproved = super.isApprovedForAll(owner, operator);
if (!isApproved) {
if (autoApproveTransfersFromValidator) {
isApproved = operator == address(getTransferValidator());
}
}
}
/**
* @notice Indicates whether the contract implements the specified interface.
* @dev Overrides supportsInterface in ERC165.
* @param interfaceId The interface id
* @return true if the contract implements the specified interface, false otherwise
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
interfaceId == type(ICreatorToken).interfaceId ||
interfaceId == type(ICreatorTokenLegacy).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @notice Returns the function selector for the transfer validator's validation function to be called
* @notice for transaction simulation.
*/
function getTransferValidationFunction() external pure returns (bytes4 functionSignature, bool isViewFunction) {
functionSignature = bytes4(keccak256("validateTransfer(address,address,address,uint256,uint256)"));
isViewFunction = false;
}
/// @dev Ties the open-zeppelin _beforeTokenTransfer hook to more granular transfer validation logic
function _beforeTokenTransfer(
address /*operator*/,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory /*data*/
) internal virtual override {
uint256 idsArrayLength = ids.length;
for (uint256 i = 0; i < idsArrayLength;) {
_validateBeforeTransfer(from, to, ids[i], amounts[i]);
unchecked {
++i;
}
}
}
/// @dev Ties the open-zeppelin _afterTokenTransfer hook to more granular transfer validation logic
function _afterTokenTransfer(
address /*operator*/,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory /*data*/
) internal virtual override {
uint256 idsArrayLength = ids.length;
for (uint256 i = 0; i < idsArrayLength;) {
_validateAfterTransfer(from, to, ids[i], amounts[i]);
unchecked {
++i;
}
}
}
function _tokenType() internal pure override returns(uint16) {
return uint16(TOKEN_TYPE_ERC1155);
}
}
/**
* @title ERC1155CInitializable
* @author Limit Break, Inc.
* @notice Initializable implementation of ERC1155C to allow for EIP-1167 proxy clones.
*/
abstract contract ERC1155CInitializable is ERC1155OpenZeppelinInitializable, CreatorTokenBase, AutomaticValidatorTransferApproval {
function initializeERC1155(string memory uri_) public override {
super.initializeERC1155(uri_);
_emitDefaultTransferValidator();
_registerTokenType(getTransferValidator());
}
/**
* @notice Overrides behavior of isApprovedFor all such that if an operator is not explicitly approved
* for all, the contract owner can optionally auto-approve the 721-C transfer validator for transfers.
*/
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool isApproved) {
isApproved = super.isApprovedForAll(owner, operator);
if (!isApproved) {
if (autoApproveTransfersFromValidator) {
isApproved = operator == address(getTransferValidator());
}
}
}
/**
* @notice Indicates whether the contract implements the specified interface.
* @dev Overrides supportsInterface in ERC165.
* @param interfaceId The interface id
* @return true if the contract implements the specified interface, false otherwise
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
interfaceId == type(ICreatorToken).interfaceId ||
interfaceId == type(ICreatorTokenLegacy).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @notice Returns the function selector for the transfer validator's validation function to be called
* @notice for transaction simulation.
*/
function getTransferValidationFunction() external pure returns (bytes4 functionSignature, bool isViewFunction) {
functionSignature = bytes4(keccak256("validateTransfer(address,address,address,uint256,uint256)"));
isViewFunction = false;
}
/// @dev Ties the open-zeppelin _beforeTokenTransfer hook to more granular transfer validation logic
function _beforeTokenTransfer(
address /*operator*/,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory /*data*/
) internal virtual override {
uint256 idsArrayLength = ids.length;
for (uint256 i = 0; i < idsArrayLength;) {
_validateBeforeTransfer(from, to, ids[i], amounts[i]);
unchecked {
++i;
}
}
}
/// @dev Ties the open-zeppelin _afterTokenTransfer hook to more granular transfer validation logic
function _afterTokenTransfer(
address /*operator*/,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory /*data*/
) internal virtual override {
uint256 idsArrayLength = ids.length;
for (uint256 i = 0; i < idsArrayLength;) {
_validateAfterTransfer(from, to, ids[i], amounts[i]);
unchecked {
++i;
}
}
}
function _tokenType() internal pure override returns(uint16) {
return uint16(TOKEN_TYPE_ERC1155);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface ICreatorToken {
event TransferValidatorUpdated(address oldValidator, address newValidator);
function getTransferValidator() external view returns (address validator);
function setTransferValidator(address validator) external;
function getTransferValidationFunction() external view returns (bytes4 functionSignature, bool isViewFunction);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface ICreatorTokenLegacy {
event TransferValidatorUpdated(address oldValidator, address newValidator);
function getTransferValidator() external view returns (address validator);
function setTransferValidator(address validator) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface ITransferValidator {
function applyCollectionTransferPolicy(address caller, address from, address to) external view;
function validateTransfer(address caller, address from, address to) external view;
function validateTransfer(address caller, address from, address to, uint256 tokenId) external view;
function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount) external;
function beforeAuthorizedTransfer(address operator, address token, uint256 tokenId) external;
function afterAuthorizedTransfer(address token, uint256 tokenId) external;
function beforeAuthorizedTransfer(address operator, address token) external;
function afterAuthorizedTransfer(address token) external;
function beforeAuthorizedTransfer(address token, uint256 tokenId) external;
function beforeAuthorizedTransferWithAmount(address token, uint256 tokenId, uint256 amount) external;
function afterAuthorizedTransferWithAmount(address token, uint256 tokenId) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface ITransferValidatorSetTokenType {
function setTokenTypeOfCollection(address collection, uint16 tokenType) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/common/ERC2981.sol";
/**
* @title BasicRoyaltiesBase
* @author Limit Break, Inc.
* @dev Base functionality of an NFT mix-in contract implementing the most basic form of programmable royalties.
*/
abstract contract BasicRoyaltiesBase is ERC2981 {
event DefaultRoyaltySet(address indexed receiver, uint96 feeNumerator);
event TokenRoyaltySet(uint256 indexed tokenId, address indexed receiver, uint96 feeNumerator);
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual override {
super._setDefaultRoyalty(receiver, feeNumerator);
emit DefaultRoyaltySet(receiver, feeNumerator);
}
function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual override {
super._setTokenRoyalty(tokenId, receiver, feeNumerator);
emit TokenRoyaltySet(tokenId, receiver, feeNumerator);
}
}
/**
* @title BasicRoyalties
* @author Limit Break, Inc.
* @notice Constructable BasicRoyalties Contract implementation.
*/
abstract contract BasicRoyalties is BasicRoyaltiesBase {
constructor(address receiver, uint96 feeNumerator) {
_setDefaultRoyalty(receiver, feeNumerator);
}
}
/**
* @title BasicRoyaltiesInitializable
* @author Limit Break, Inc.
* @notice Initializable BasicRoyalties Contract implementation to allow for EIP-1167 clones.
*/
abstract contract BasicRoyaltiesInitializable is BasicRoyaltiesBase {}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../../access/OwnablePermissions.sol";
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
abstract contract ERC1155OpenZeppelinBase is ERC1155 {
}
abstract contract ERC1155OpenZeppelin is ERC1155OpenZeppelinBase {
constructor(string memory uri_) ERC1155(uri_) {}
}
abstract contract ERC1155OpenZeppelinInitializable is OwnablePermissions, ERC1155OpenZeppelinBase {
error ERC1155OpenZeppelinInitializable__AlreadyInitializedERC1155();
bool private _erc1155Initialized;
function initializeERC1155(string memory uri_) public virtual {
_requireCallerIsContractOwner();
if(_erc1155Initialized) {
revert ERC1155OpenZeppelinInitializable__AlreadyInitializedERC1155();
}
_erc1155Initialized = true;
_setURI(uri_);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../access/OwnablePermissions.sol";
/**
* @title AutomaticValidatorTransferApproval
* @author Limit Break, Inc.
* @notice Base contract mix-in that provides boilerplate code giving the contract owner the
* option to automatically approve a 721-C transfer validator implementation for transfers.
*/
abstract contract AutomaticValidatorTransferApproval is OwnablePermissions {
/// @dev Emitted when the automatic approval flag is modified by the creator.
event AutomaticApprovalOfTransferValidatorSet(bool autoApproved);
/// @dev If true, the collection's transfer validator is automatically approved to transfer holder's tokens.
bool public autoApproveTransfersFromValidator;
/**
* @notice Sets if the transfer validator is automatically approved as an operator for all token owners.
*
* @dev Throws when the caller is not the contract owner.
*
* @param autoApprove If true, the collection's transfer validator will be automatically approved to
* transfer holder's tokens.
*/
function setAutomaticApprovalOfTransfersFromValidator(bool autoApprove) external {
_requireCallerIsContractOwner();
autoApproveTransfersFromValidator = autoApprove;
emit AutomaticApprovalOfTransferValidatorSet(autoApprove);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../access/OwnablePermissions.sol";
import "../interfaces/ICreatorToken.sol";
import "../interfaces/ICreatorTokenLegacy.sol";
import "../interfaces/ITransferValidator.sol";
import "./TransferValidation.sol";
import "../interfaces/ITransferValidatorSetTokenType.sol";
/**
* @title CreatorTokenBase
* @author Limit Break, Inc.
* @notice CreatorTokenBaseV3 is an abstract contract that provides basic functionality for managing token
* transfer policies through an implementation of ICreatorTokenTransferValidator/ICreatorTokenTransferValidatorV2/ICreatorTokenTransferValidatorV3.
* This contract is intended to be used as a base for creator-specific token contracts, enabling customizable transfer
* restrictions and security policies.
*
* <h4>Features:</h4>
* <ul>Ownable: This contract can have an owner who can set and update the transfer validator.</ul>
* <ul>TransferValidation: Implements the basic token transfer validation interface.</ul>
*
* <h4>Benefits:</h4>
* <ul>Provides a flexible and modular way to implement custom token transfer restrictions and security policies.</ul>
* <ul>Allows creators to enforce policies such as account and codehash blacklists, whitelists, and graylists.</ul>
* <ul>Can be easily integrated into other token contracts as a base contract.</ul>
*
* <h4>Intended Usage:</h4>
* <ul>Use as a base contract for creator token implementations that require advanced transfer restrictions and
* security policies.</ul>
* <ul>Set and update the ICreatorTokenTransferValidator implementation contract to enforce desired policies for the
* creator token.</ul>
*
* <h4>Compatibility:</h4>
* <ul>Backward and Forward Compatible - V1/V2/V3 Creator Token Base will work with V1/V2/V3 Transfer Validators.</ul>
*/
abstract contract CreatorTokenBase is OwnablePermissions, TransferValidation, ICreatorToken {
/// @dev Thrown when setting a transfer validator address that has no deployed code.
error CreatorTokenBase__InvalidTransferValidatorContract();
/// @dev The default transfer validator that will be used if no transfer validator has been set by the creator.
address public constant DEFAULT_TRANSFER_VALIDATOR = address(0x721C002B0059009a671D00aD1700c9748146cd1B);
/// @dev Used to determine if the default transfer validator is applied.
/// @dev Set to true when the creator sets a transfer validator address.
bool private isValidatorInitialized;
/// @dev Address of the transfer validator to apply to transactions.
address private transferValidator;
constructor() {
_emitDefaultTransferValidator();
_registerTokenType(DEFAULT_TRANSFER_VALIDATOR);
}
/**
* @notice Sets the transfer validator for the token contract.
*
* @dev Throws when provided validator contract is not the zero address and does not have code.
* @dev Throws when the caller is not the contract owner.
*
* @dev <h4>Postconditions:</h4>
* 1. The transferValidator address is updated.
* 2. The `TransferValidatorUpdated` event is emitted.
*
* @param transferValidator_ The address of the transfer validator contract.
*/
function setTransferValidator(address transferValidator_) public {
_requireCallerIsContractOwner();
bool isValidTransferValidator = transferValidator_.code.length > 0;
if(transferValidator_ != address(0) && !isValidTransferValidator) {
revert CreatorTokenBase__InvalidTransferValidatorContract();
}
emit TransferValidatorUpdated(address(getTransferValidator()), transferValidator_);
isValidatorInitialized = true;
transferValidator = transferValidator_;
_registerTokenType(transferValidator_);
}
/**
* @notice Returns the transfer validator contract address for this token contract.
*/
function getTransferValidator() public view override returns (address validator) {
validator = transferValidator;
if (validator == address(0)) {
if (!isValidatorInitialized) {
validator = DEFAULT_TRANSFER_VALIDATOR;
}
}
}
/**
* @dev Pre-validates a token transfer, reverting if the transfer is not allowed by this token's security policy.
* Inheriting contracts are responsible for overriding the _beforeTokenTransfer function, or its equivalent
* and calling _validateBeforeTransfer so that checks can be properly applied during token transfers.
*
* @dev Be aware that if the msg.sender is the transfer validator, the transfer is automatically permitted, as the
* transfer validator is expected to pre-validate the transfer.
*
* @dev Throws when the transfer doesn't comply with the collection's transfer policy, if the transferValidator is
* set to a non-zero address.
*
* @param caller The address of the caller.
* @param from The address of the sender.
* @param to The address of the receiver.
* @param tokenId The token id being transferred.
*/
function _preValidateTransfer(
address caller,
address from,
address to,
uint256 tokenId,
uint256 /*value*/) internal virtual override {
address validator = getTransferValidator();
if (validator != address(0)) {
if (msg.sender == validator) {
return;
}
ITransferValidator(validator).validateTransfer(caller, from, to, tokenId);
}
}
/**
* @dev Pre-validates a token transfer, reverting if the transfer is not allowed by this token's security policy.
* Inheriting contracts are responsible for overriding the _beforeTokenTransfer function, or its equivalent
* and calling _validateBeforeTransfer so that checks can be properly applied during token transfers.
*
* @dev Be aware that if the msg.sender is the transfer validator, the transfer is automatically permitted, as the
* transfer validator is expected to pre-validate the transfer.
*
* @dev Used for ERC20 and ERC1155 token transfers which have an amount value to validate in the transfer validator.
* @dev The `tokenId` for ERC20 tokens should be set to `0`.
*
* @dev Throws when the transfer doesn't comply with the collection's transfer policy, if the transferValidator is
* set to a non-zero address.
*
* @param caller The address of the caller.
* @param from The address of the sender.
* @param to The address of the receiver.
* @param tokenId The token id being transferred.
* @param amount The amount of token being transferred.
*/
function _preValidateTransfer(
address caller,
address from,
address to,
uint256 tokenId,
uint256 amount,
uint256 /*value*/) internal virtual override {
address validator = getTransferValidator();
if (validator != address(0)) {
if (msg.sender == validator) {
return;
}
ITransferValidator(validator).validateTransfer(caller, from, to, tokenId, amount);
}
}
function _tokenType() internal virtual pure returns(uint16);
function _registerTokenType(address validator) internal {
if (validator != address(0)) {
uint256 validatorCodeSize;
assembly {
validatorCodeSize := extcodesize(validator)
}
if(validatorCodeSize > 0) {
try ITransferValidatorSetTokenType(validator).setTokenTypeOfCollection(address(this), _tokenType()) {
} catch { }
}
}
}
/**
* @dev Used during contract deployment for constructable and cloneable creator tokens
* @dev to emit the `TransferValidatorUpdated` event signaling the validator for the contract
* @dev is the default transfer validator.
*/
function _emitDefaultTransferValidator() internal {
emit TransferValidatorUpdated(address(0), DEFAULT_TRANSFER_VALIDATOR);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/Context.sol";
/**
* @title TransferValidation
* @author Limit Break, Inc.
* @notice A mix-in that can be combined with ERC-721 contracts to provide more granular hooks.
* Openzeppelin's ERC721 contract only provides hooks for before and after transfer. This allows
* developers to validate or customize transfers within the context of a mint, a burn, or a transfer.
*/
abstract contract TransferValidation is Context {
/// @dev Thrown when the from and to address are both the zero address.
error ShouldNotMintToBurnAddress();
/*************************************************************************/
/* Transfers Without Amounts */
/*************************************************************************/
/// @dev Inheriting contracts should call this function in the _beforeTokenTransfer function to get more granular hooks.
function _validateBeforeTransfer(address from, address to, uint256 tokenId) internal virtual {
bool fromZeroAddress = from == address(0);
bool toZeroAddress = to == address(0);
if(fromZeroAddress && toZeroAddress) {
revert ShouldNotMintToBurnAddress();
} else if(fromZeroAddress) {
_preValidateMint(_msgSender(), to, tokenId, msg.value);
} else if(toZeroAddress) {
_preValidateBurn(_msgSender(), from, tokenId, msg.value);
} else {
_preValidateTransfer(_msgSender(), from, to, tokenId, msg.value);
}
}
/// @dev Inheriting contracts should call this function in the _afterTokenTransfer function to get more granular hooks.
function _validateAfterTransfer(address from, address to, uint256 tokenId) internal virtual {
bool fromZeroAddress = from == address(0);
bool toZeroAddress = to == address(0);
if(fromZeroAddress && toZeroAddress) {
revert ShouldNotMintToBurnAddress();
} else if(fromZeroAddress) {
_postValidateMint(_msgSender(), to, tokenId, msg.value);
} else if(toZeroAddress) {
_postValidateBurn(_msgSender(), from, tokenId, msg.value);
} else {
_postValidateTransfer(_msgSender(), from, to, tokenId, msg.value);
}
}
/// @dev Optional validation hook that fires before a mint
function _preValidateMint(address caller, address to, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires after a mint
function _postValidateMint(address caller, address to, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires before a burn
function _preValidateBurn(address caller, address from, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires after a burn
function _postValidateBurn(address caller, address from, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires before a transfer
function _preValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires after a transfer
function _postValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 value) internal virtual {}
/*************************************************************************/
/* Transfers With Amounts */
/*************************************************************************/
/// @dev Inheriting contracts should call this function in the _beforeTokenTransfer function to get more granular hooks.
function _validateBeforeTransfer(address from, address to, uint256 tokenId, uint256 amount) internal virtual {
bool fromZeroAddress = from == address(0);
bool toZeroAddress = to == address(0);
if(fromZeroAddress && toZeroAddress) {
revert ShouldNotMintToBurnAddress();
} else if(fromZeroAddress) {
_preValidateMint(_msgSender(), to, tokenId, amount, msg.value);
} else if(toZeroAddress) {
_preValidateBurn(_msgSender(), from, tokenId, amount, msg.value);
} else {
_preValidateTransfer(_msgSender(), from, to, tokenId, amount, msg.value);
}
}
/// @dev Inheriting contracts should call this function in the _afterTokenTransfer function to get more granular hooks.
function _validateAfterTransfer(address from, address to, uint256 tokenId, uint256 amount) internal virtual {
bool fromZeroAddress = from == address(0);
bool toZeroAddress = to == address(0);
if(fromZeroAddress && toZeroAddress) {
revert ShouldNotMintToBurnAddress();
} else if(fromZeroAddress) {
_postValidateMint(_msgSender(), to, tokenId, amount, msg.value);
} else if(toZeroAddress) {
_postValidateBurn(_msgSender(), from, tokenId, amount, msg.value);
} else {
_postValidateTransfer(_msgSender(), from, to, tokenId, amount, msg.value);
}
}
/// @dev Optional validation hook that fires before a mint
function _preValidateMint(address caller, address to, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires after a mint
function _postValidateMint(address caller, address to, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires before a burn
function _preValidateBurn(address caller, address from, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires after a burn
function _postValidateBurn(address caller, address from, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires before a transfer
function _preValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires after a transfer
function _postValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @dev Constant bytes32 value of 0x000...000
bytes32 constant ZERO_BYTES32 = bytes32(0);
/// @dev Constant value of 0
uint256 constant ZERO = 0;
/// @dev Constant value of 1
uint256 constant ONE = 1;
/// @dev Constant value representing an open order in storage
uint8 constant ORDER_STATE_OPEN = 0;
/// @dev Constant value representing a filled order in storage
uint8 constant ORDER_STATE_FILLED = 1;
/// @dev Constant value representing a cancelled order in storage
uint8 constant ORDER_STATE_CANCELLED = 2;
/// @dev Constant value representing the ERC721 token type for signatures and transfer hooks
uint256 constant TOKEN_TYPE_ERC721 = 721;
/// @dev Constant value representing the ERC1155 token type for signatures and transfer hooks
uint256 constant TOKEN_TYPE_ERC1155 = 1155;
/// @dev Constant value representing the ERC20 token type for signatures and transfer hooks
uint256 constant TOKEN_TYPE_ERC20 = 20;
/// @dev Constant value to mask the upper bits of a signature that uses a packed `vs` value to extract `s`
bytes32 constant UPPER_BIT_MASK = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
/// @dev EIP-712 typehash used for validating signature based stored approvals
bytes32 constant UPDATE_APPROVAL_TYPEHASH =
keccak256("UpdateApprovalBySignature(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 approvalExpiration,uint256 sigDeadline,uint256 masterNonce)");
/// @dev EIP-712 typehash used for validating a single use permit without additional data
bytes32 constant SINGLE_USE_PERMIT_TYPEHASH =
keccak256("PermitTransferFrom(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 expiration,uint256 masterNonce)");
/// @dev EIP-712 typehash used for validating a single use permit with additional data
string constant SINGLE_USE_PERMIT_TRANSFER_ADVANCED_TYPEHASH_STUB =
"PermitTransferFromWithAdditionalData(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 expiration,uint256 masterNonce,";
/// @dev EIP-712 typehash used for validating an order permit that updates storage as it fills
string constant PERMIT_ORDER_ADVANCED_TYPEHASH_STUB =
"PermitOrderWithAdditionalData(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 salt,address operator,uint256 expiration,uint256 masterNonce,";
/// @dev Pausable flag for stored approval transfers of ERC721 assets
uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC721 = 1 << 0;
/// @dev Pausable flag for stored approval transfers of ERC1155 assets
uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC1155 = 1 << 1;
/// @dev Pausable flag for stored approval transfers of ERC20 assets
uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC20 = 1 << 2;
/// @dev Pausable flag for single use permit transfers of ERC721 assets
uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC721 = 1 << 3;
/// @dev Pausable flag for single use permit transfers of ERC1155 assets
uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC1155 = 1 << 4;
/// @dev Pausable flag for single use permit transfers of ERC20 assets
uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC20 = 1 << 5;
/// @dev Pausable flag for order fill transfers of ERC1155 assets
uint256 constant PAUSABLE_ORDER_TRANSFER_FROM_ERC1155 = 1 << 6;
/// @dev Pausable flag for order fill transfers of ERC20 assets
uint256 constant PAUSABLE_ORDER_TRANSFER_FROM_ERC20 = 1 << 7;// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol)
pragma solidity ^0.8.0;
import "../utils/introspection/IERC165.sol";
/**
* @dev Interface for the NFT Royalty Standard.
*
* A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
* support for royalty payments across all NFT marketplaces and ecosystem participants.
*
* _Available since v4.5._
*/
interface IERC2981 is IERC165 {
/**
* @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
* exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
*/
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external
view
returns (address receiver, uint256 royaltyAmount);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/common/ERC2981.sol)
pragma solidity ^0.8.0;
import "../../interfaces/IERC2981.sol";
import "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
*
* Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
* specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
*
* Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
* fee is specified in basis points by default.
*
* IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
* https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
* voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
*
* _Available since v4.5._
*/
abstract contract ERC2981 is IERC2981, ERC165 {
struct RoyaltyInfo {
address receiver;
uint96 royaltyFraction;
}
RoyaltyInfo private _defaultRoyaltyInfo;
mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc IERC2981
*/
function royaltyInfo(uint256 _tokenId, uint256 _salePrice) public view virtual override returns (address, uint256) {
RoyaltyInfo memory royalty = _tokenRoyaltyInfo[_tokenId];
if (royalty.receiver == address(0)) {
royalty = _defaultRoyaltyInfo;
}
uint256 royaltyAmount = (_salePrice * royalty.royaltyFraction) / _feeDenominator();
return (royalty.receiver, royaltyAmount);
}
/**
* @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
* fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
* override.
*/
function _feeDenominator() internal pure virtual returns (uint96) {
return 10000;
}
/**
* @dev Sets the royalty information that all ids in this contract will default to.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: invalid receiver");
_defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Removes default royalty information.
*/
function _deleteDefaultRoyalty() internal virtual {
delete _defaultRoyaltyInfo;
}
/**
* @dev Sets the royalty information for a specific token id, overriding the global default.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setTokenRoyalty(
uint256 tokenId,
address receiver,
uint96 feeNumerator
) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: Invalid parameters");
_tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Resets royalty information for the token id back to the global default.
*/
function _resetTokenRoyalty(uint256 tokenId) internal virtual {
delete _tokenRoyaltyInfo[tokenId];
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol)
pragma solidity ^0.8.0;
import "./IERC1155.sol";
import "./IERC1155Receiver.sol";
import "./extensions/IERC1155MetadataURI.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the basic standard multi-token.
* See https://eips.ethereum.org/EIPS/eip-1155
* Originally based on code by Enjin: https://github.com/enjin/erc-1155
*
* _Available since v3.1._
*/
contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
using Address for address;
// Mapping from token ID to account balances
mapping(uint256 => mapping(address => uint256)) private _balances;
// Mapping from account to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
// Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
string private _uri;
/**
* @dev See {_setURI}.
*/
constructor(string memory uri_) {
_setURI(uri_);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC1155MetadataURI-uri}.
*
* This implementation returns the same URI for *all* token types. It relies
* on the token type ID substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* Clients calling this function must replace the `\{id\}` substring with the
* actual token type ID.
*/
function uri(uint256) public view virtual override returns (string memory) {
return _uri;
}
/**
* @dev See {IERC1155-balanceOf}.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
require(account != address(0), "ERC1155: address zero is not a valid owner");
return _balances[id][account];
}
/**
* @dev See {IERC1155-balanceOfBatch}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
public
view
virtual
override
returns (uint256[] memory)
{
require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");
uint256[] memory batchBalances = new uint256[](accounts.length);
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts[i], ids[i]);
}
return batchBalances;
}
/**
* @dev See {IERC1155-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC1155-isApprovedForAll}.
*/
function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
return _operatorApprovals[account][operator];
}
/**
* @dev See {IERC1155-safeTransferFrom}.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
_safeTransferFrom(from, to, id, amount, data);
}
/**
* @dev See {IERC1155-safeBatchTransferFrom}.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
_safeBatchTransferFrom(from, to, ids, amounts, data);
}
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
emit TransferSingle(operator, from, to, id, amount);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
}
emit TransferBatch(operator, from, to, ids, amounts);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
}
/**
* @dev Sets a new URI for all token types, by relying on the token type ID
* substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* By this mechanism, any occurrence of the `\{id\}` substring in either the
* URI or any of the amounts in the JSON file at said URI will be replaced by
* clients with the token type ID.
*
* For example, the `https://token-cdn-domain/\{id\}.json` URI would be
* interpreted by clients as
* `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
* for token type ID 0x4cce0.
*
* See {uri}.
*
* Because these URIs cannot be meaningfully represented by the {URI} event,
* this function emits no events.
*/
function _setURI(string memory newuri) internal virtual {
_uri = newuri;
}
/**
* @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _mint(
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
_balances[id][to] += amount;
emit TransferSingle(operator, address(0), to, id, amount);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _mintBatch(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; i++) {
_balances[ids[i]][to] += amounts[i];
}
emit TransferBatch(operator, address(0), to, ids, amounts);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
}
/**
* @dev Destroys `amount` tokens of token type `id` from `from`
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `from` must have at least `amount` tokens of token type `id`.
*/
function _burn(
address from,
uint256 id,
uint256 amount
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
emit TransferSingle(operator, from, address(0), id, amount);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
*/
function _burnBatch(
address from,
uint256[] memory ids,
uint256[] memory amounts
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
for (uint256 i = 0; i < ids.length; i++) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
}
emit TransferBatch(operator, from, address(0), ids, amounts);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Emits an {ApprovalForAll} event.
*/
function _setApprovalForAll(
address owner,
address operator,
bool approved
) internal virtual {
require(owner != operator, "ERC1155: setting approval status for self");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Hook that is called before any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `ids` and `amounts` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
/**
* @dev Hook that is called after any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `id` and `amount` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
if (response != IERC1155Receiver.onERC1155Received.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function _doSafeBatchTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
bytes4 response
) {
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
uint256[] memory array = new uint256[](1);
array[0] = element;
return array;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)
pragma solidity ^0.8.0;
import "../IERC1155.sol";
/**
* @dev Interface of the optional ERC1155MetadataExtension interface, as defined
* in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
*
* _Available since v3.1._
*/
interface IERC1155MetadataURI is IERC1155 {
/**
* @dev Returns the URI for token type `id`.
*
* If the `\{id\}` substring is present in the URI, it must be replaced by
* clients with the actual token type ID.
*/
function uri(uint256 id) external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
external
view
returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev _Available since v3.1._
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://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 functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts 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 v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./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
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}{
"evmVersion": "paris",
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"royaltyReceiver","type":"address"},{"internalType":"uint96","name":"royaltyFeeNumerator","type":"uint96"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CreatorTokenBase__InvalidTransferValidatorContract","type":"error"},{"inputs":[],"name":"ShouldNotMintToBurnAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"autoApproved","type":"bool"}],"name":"AutomaticApprovalOfTransferValidatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"DefaultRoyaltySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"TokenRoyaltySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValidator","type":"address"},{"indexed":false,"internalType":"address","name":"newValidator","type":"address"}],"name":"TransferValidatorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[],"name":"DEFAULT_TRANSFER_VALIDATOR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"authorizedMinters","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"autoApproveTransfersFromValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"burnBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"uri_","type":"string"},{"internalType":"uint256","name":"maxSupply_","type":"uint256"},{"internalType":"string","name":"onchainData_","type":"string"},{"internalType":"bool","name":"storeOnchain_","type":"bool"}],"name":"createEdition","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"currentSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getOnchainData","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getTokenRoyalty","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransferValidationFunction","outputs":[{"internalType":"bytes4","name":"functionSignature","type":"bytes4"},{"internalType":"bool","name":"isViewFunction","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTransferValidator","outputs":[{"internalType":"address","name":"validator","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"isApproved","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"}],"name":"isAuthorizedMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"isOnchain","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"mintBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"},{"internalType":"bool","name":"authorized","type":"bool"}],"name":"setAuthorizedMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"autoApprove","type":"bool"}],"name":"setAutomaticApprovalOfTransfersFromValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"data_","type":"string"}],"name":"setOnchainData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"setTokenRoyalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"uri_","type":"string"}],"name":"setTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transferValidator_","type":"address"}],"name":"setTransferValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalEditions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b50604051616b20380380616b2083398181016040528101906100329190610653565b81816040518060200160405280600081525080610054816101ad60201b60201c565b50506100646101c060201b60201c565b61008773721c002b0059009a671d00ad1700c9748146cd1b61021060201b60201c565b6100a36100986102cd60201b60201c565b6102d560201b60201c565b6100b3828261039b60201b60201c565b50506100c4336102d560201b60201c565b6001600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506040518060400160405280600d81526020017f476f62732045646974696f6e73000000000000000000000000000000000000008152506008908161016091906108e3565b506040518060400160405280600281526020017f4745000000000000000000000000000000000000000000000000000000000000815250600990816101a591906108e3565b505050610b6c565b80600290816101bc91906108e3565b5050565b7fcc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aac600073721c002b0059009a671d00ad1700c9748146cd1b6040516102069291906109c4565b60405180910390a1565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146102ca576000813b905060008111156102c8578173ffffffffffffffffffffffffffffffffffffffff1663fb2de5d73061027e6103fd60201b60201c565b6040518363ffffffff1660e01b815260040161029b929190610a0a565b600060405180830381600087803b1580156102b557600080fd5b505af19250505080156102c6575060015b505b505b50565b600033905090565b6000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6103ab828261040760201b60201c565b8173ffffffffffffffffffffffffffffffffffffffff167f8a8bae378cb731c5c40b632330c6836c2f916f48edb967699c86736f9a6a76ef826040516103f19190610a42565b60405180910390a25050565b6000610483905090565b6104156105a260201b60201c565b6bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610473576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161046a90610ae0565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036104e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104d990610b4c565b60405180910390fd5b60405180604001604052808373ffffffffffffffffffffffffffffffffffffffff168152602001826bffffffffffffffffffffffff16815250600560008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055509050505050565b6000612710905090565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006105dc826105b1565b9050919050565b6105ec816105d1565b81146105f757600080fd5b50565b600081519050610609816105e3565b92915050565b60006bffffffffffffffffffffffff82169050919050565b6106308161060f565b811461063b57600080fd5b50565b60008151905061064d81610627565b92915050565b6000806040838503121561066a576106696105ac565b5b6000610678858286016105fa565b92505060206106898582860161063e565b9150509250929050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061071457607f821691505b602082108103610727576107266106cd565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b60006008830261078f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610752565b6107998683610752565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006107e06107db6107d6846107b1565b6107bb565b6107b1565b9050919050565b6000819050919050565b6107fa836107c5565b61080e610806826107e7565b84845461075f565b825550505050565b600090565b610823610816565b61082e8184846107f1565b505050565b5b818110156108525761084760008261081b565b600181019050610834565b5050565b601f821115610897576108688161072d565b61087184610742565b81016020851015610880578190505b61089461088c85610742565b830182610833565b50505b505050565b600082821c905092915050565b60006108ba6000198460080261089c565b1980831691505092915050565b60006108d383836108a9565b9150826002028217905092915050565b6108ec82610693565b67ffffffffffffffff8111156109055761090461069e565b5b61090f82546106fc565b61091a828285610856565b600060209050601f83116001811461094d576000841561093b578287015190505b61094585826108c7565b8655506109ad565b601f19841661095b8661072d565b60005b828110156109835784890151825560018201915060208501945060208101905061095e565b868310156109a0578489015161099c601f8916826108a9565b8355505b6001600288020188555050505b505050505050565b6109be816105d1565b82525050565b60006040820190506109d960008301856109b5565b6109e660208301846109b5565b9392505050565b600061ffff82169050919050565b610a04816109ed565b82525050565b6000604082019050610a1f60008301856109b5565b610a2c60208301846109fb565b9392505050565b610a3c8161060f565b82525050565b6000602082019050610a576000830184610a33565b92915050565b600082825260208201905092915050565b7f455243323938313a20726f79616c7479206665652077696c6c2065786365656460008201527f2073616c65507269636500000000000000000000000000000000000000000000602082015250565b6000610aca602a83610a5d565b9150610ad582610a6e565b604082019050919050565b60006020820190508181036000830152610af981610abd565b9050919050565b7f455243323938313a20696e76616c696420726563656976657200000000000000600082015250565b6000610b36601983610a5d565b9150610b4182610b00565b602082019050919050565b60006020820190508181036000830152610b6581610b29565b9050919050565b615fa580610b7b6000396000f3fe608060405234801561001057600080fd5b50600436106102265760003560e01c80635b746077116101305780639e05d240116100b8578063e985e9c51161007c578063e985e9c5146106b0578063ed58bad8146106e0578063f242432a146106fc578063f2fde38b14610718578063f5298aca1461073457610226565b80639e05d24014610610578063a22cb4651461062c578063a9fc664e14610648578063aa2fe91b14610664578063d81d0a151461069457610226565b8063833b7b78116100ff578063833b7b7814610543578063842392c214610574578063869f7594146105a45780638da5cb5b146105d457806395d89b41146105f257610226565b80635b746077146104cf5780636221d13c146104ff5780636b20c4541461051d578063715018a61461053957610226565b806323b01cfa116101b35780633d96004c116101825780633d96004c146104195780634e1273f414610435578063503b3f6c1461046557806351d329dc146104955780635944c753146104b357610226565b806323b01cfa1461036c5780632a55205a1461039c5780632ce0ff5f146103cd5780632eb2c2d6146103fd57610226565b8063098144d4116101fa578063098144d4146102c75780630d705df6146102e55780630e89341c14610304578063156e29f614610334578063162094c41461035057610226565b8062fdd58e1461022b578063014635461461025b57806301ffc9a71461027957806306fdde03146102a9575b600080fd5b61024560048036038101906102409190613e2f565b610750565b6040516102529190613e7e565b60405180910390f35b610263610818565b6040516102709190613ea8565b60405180910390f35b610293600480360381019061028e9190613f1b565b610830565b6040516102a09190613f63565b60405180910390f35b6102b1610852565b6040516102be919061400e565b60405180910390f35b6102cf6108e0565b6040516102dc9190613ea8565b60405180910390f35b6102ed61096b565b6040516102fb92919061403f565b60405180910390f35b61031e60048036038101906103199190614068565b610999565b60405161032b919061400e565b60405180910390f35b61034e60048036038101906103499190614095565b610a9e565b005b61036a6004803603810190610365919061421d565b610c86565b005b61038660048036038101906103819190614068565b610d82565b6040516103939190613f63565b60405180910390f35b6103b660048036038101906103b19190614279565b610da2565b6040516103c49291906142b9565b60405180910390f35b6103e760048036038101906103e29190614068565b610e85565b6040516103f4919061400e565b60405180910390f35b6104176004803603810190610412919061444b565b610f8a565b005b610433600480360381019061042e919061421d565b61102b565b005b61044f600480360381019061044a91906145dd565b6110c8565b60405161045c9190614713565b60405180910390f35b61047f600480360381019061047a9190614761565b6111db565b60405161048c9190613e7e565b60405180910390f35b61049d6112a2565b6040516104aa9190613e7e565b60405180910390f35b6104cd60048036038101906104c89190614844565b6112ac565b005b6104e960048036038101906104e49190614068565b611453565b6040516104f69190613e7e565b60405180910390f35b61050761146b565b6040516105149190613f63565b60405180910390f35b61053760048036038101906105329190614897565b61147e565b005b61054161150d565b005b61055d60048036038101906105589190614068565b611521565b60405161056b929190614931565b60405180910390f35b61058e6004803603810190610589919061495a565b61158d565b60405161059b9190613f63565b60405180910390f35b6105be60048036038101906105b99190614068565b6115e3565b6040516105cb9190613e7e565b60405180910390f35b6105dc6115fb565b6040516105e99190613ea8565b60405180910390f35b6105fa611625565b604051610607919061400e565b60405180910390f35b61062a60048036038101906106259190614987565b6116b3565b005b610646600480360381019061064191906149b4565b61170f565b005b610662600480360381019061065d919061495a565b611725565b005b61067e6004803603810190610679919061495a565b611866565b60405161068b9190613f63565b60405180910390f35b6106ae60048036038101906106a99190614897565b611886565b005b6106ca60048036038101906106c591906149f4565b611b82565b6040516106d79190613f63565b60405180910390f35b6106fa60048036038101906106f591906149b4565b611bea565b005b61071660048036038101906107119190614a34565b611c4d565b005b610732600480360381019061072d919061495a565b611cee565b005b61074e60048036038101906107499190614095565b611d71565b005b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036107c0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107b790614b3d565b60405180910390fd5b60008083815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b73721c002b0059009a671d00ad1700c9748146cd1b81565b600061083b82611e00565b8061084b575061084a82611ee2565b5b9050919050565b6008805461085f90614b8c565b80601f016020809104026020016040519081016040528092919081815260200182805461088b90614b8c565b80156108d85780601f106108ad576101008083540402835291602001916108d8565b820191906000526020600020905b8154815290600101906020018083116108bb57829003601f168201915b505050505081565b6000600360019054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361096857600360009054906101000a900460ff166109675773721c002b0059009a671d00ad1700c9748146cd1b90505b5b90565b6000807f1854b24168de2a3561e8caaa0770d8257ca046fb64fc845e3cd163acfc66770c9150600090509091565b6060600f600083815260200190815260200160002060009054906101000a900460ff16156109fa57600e60008381526020019081526020016000206040516020016109e49190614cac565b6040516020818303038152906040529050610a99565b600b60008381526020019081526020016000208054610a1890614b8c565b80601f0160208091040260200160405190810160405280929190818152602001828054610a4490614b8c565b8015610a915780601f10610a6657610100808354040283529160200191610a91565b820191906000526020600020905b815481529060010190602001808311610a7457829003601f168201915b505050505090505b919050565b600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1680610b285750610af96115fb565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b610b67576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b5e90614d1a565b60405180910390fd5b600a548210610bab576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ba290614d86565b60405180910390fd5b6000600c6000848152602001908152602001600020541115610c3c57600c60008381526020019081526020016000205481600d600085815260200190815260200160002054610bfa9190614dd5565b1115610c3b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c3290614e55565b60405180910390fd5b5b80600d60008481526020019081526020016000206000828254610c5f9190614dd5565b92505081905550610c8183838360405180602001604052806000815250611f5c565b505050565b610c8e61210c565b6000600b60008481526020019081526020016000208054610cae90614b8c565b90501180610cbd5750600a5482105b610cfc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cf390614d86565b60405180910390fd5b600f600083815260200190815260200160002060009054906101000a900460ff1615610d5d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d5490614ee7565b60405180910390fd5b80600b60008481526020019081526020016000209081610d7d919061509e565b505050565b600f6020528060005260406000206000915054906101000a900460ff1681565b6000806010600085815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16915060006011600086815260200190815260200160002060009054906101000a90046bffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610e5357610e49858561218a565b9250925050610e7e565b612710816bffffffffffffffffffffffff1685610e709190615170565b610e7a91906151e1565b9150505b9250929050565b6060600f600083815260200190815260200160002060009054906101000a900460ff16610ee7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ede90615284565b60405180910390fd5b600e60008381526020019081526020016000208054610f0590614b8c565b80601f0160208091040260200160405190810160405280929190818152602001828054610f3190614b8c565b8015610f7e5780601f10610f5357610100808354040283529160200191610f7e565b820191906000526020600020905b815481529060010190602001808311610f6157829003601f168201915b50505050509050919050565b610f92612374565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480610fd85750610fd785610fd2612374565b611b82565b5b611017576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161100e90615316565b60405180910390fd5b611024858585858561237c565b5050505050565b61103361210c565b600a548210611077576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161106e90614d86565b60405180910390fd5b80600e60008481526020019081526020016000209081611097919061509e565b506001600f600084815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b6060815183511461110e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611105906153a8565b60405180910390fd5b6000835167ffffffffffffffff81111561112b5761112a6140f2565b5b6040519080825280602002602001820160405280156111595781602001602082028036833780820191505090505b50905060005b84518110156111d0576111a685828151811061117e5761117d6153c8565b5b6020026020010151858381518110611199576111986153c8565b5b6020026020010151610750565b8282815181106111b9576111b86153c8565b5b60200260200101818152505080600101905061115f565b508091505092915050565b60006111e561210c565b6000600a549050600a60008154809291906111ff906153f7565b9190505550821561125c5783600e6000838152602001908152602001600020908161122a919061509e565b506001600f600083815260200190815260200160002060006101000a81548160ff02191690831515021790555061127e565b85600b6000838152602001908152602001600020908161127c919061509e565b505b84600c60008381526020019081526020016000208190555080915050949350505050565b6000600a54905090565b6112b461210c565b600a5483106112f8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112ef90614d86565b60405180910390fd5b612710816bffffffffffffffffffffffff16111561134b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113429061548b565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036113ba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113b1906154f7565b60405180910390fd5b816010600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550806011600085815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505050565b600d6020528060005260406000206000915090505481565b600360159054906101000a900460ff1681565b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806114be57506114bd8333611b82565b5b6114fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114f490615589565b60405180910390fd5b611508838383612697565b505050565b61151561210c565b61151f600061295f565b565b6000806010600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166011600085815260200190815260200160002060009054906101000a90046bffffffffffffffffffffffff1691509150915091565b6000600760008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b600c6020528060005260406000206000915090505481565b6000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6009805461163290614b8c565b80601f016020809104026020016040519081016040528092919081815260200182805461165e90614b8c565b80156116ab5780601f10611680576101008083540402835291602001916116ab565b820191906000526020600020905b81548152906001019060200180831161168e57829003601f168201915b505050505081565b6116bb612a25565b80600360156101000a81548160ff0219169083151502179055507f6787c7f9a80aa0f5ceddab2c54f1f5169c0b88e75dd5e19d5e858a64144c7dbc816040516117049190613f63565b60405180910390a150565b61172161171a612374565b8383612a2f565b5050565b61172d612a25565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015611786575080155b156117bd576040517f32483afb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fcc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aac6117e66108e0565b836040516117f59291906155a9565b60405180910390a16001600360006101000a81548160ff02191690831515021790555081600360016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061186282612b9b565b5050565b60076020528060005260406000206000915054906101000a900460ff1681565b600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff168061191057506118e16115fb565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b61194f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161194690614d1a565b60405180910390fd5b8051825114611993576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161198a9061561e565b60405180910390fd5b60005b8251811015611b6157600a548382815181106119b5576119b46153c8565b5b6020026020010151106119fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119f490614d86565b60405180910390fd5b6000600c6000858481518110611a1657611a156153c8565b5b60200260200101518152602001908152602001600020541115611af657600c6000848381518110611a4a57611a496153c8565b5b6020026020010151815260200190815260200160002054828281518110611a7457611a736153c8565b5b6020026020010151600d6000868581518110611a9357611a926153c8565b5b6020026020010151815260200190815260200160002054611ab49190614dd5565b1115611af5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611aec90614e55565b60405180910390fd5b5b818181518110611b0957611b086153c8565b5b6020026020010151600d6000858481518110611b2857611b276153c8565b5b602002602001015181526020019081526020016000206000828254611b4d9190614dd5565b925050819055508080600101915050611996565b50611b7d83838360405180602001604052806000815250612c52565b505050565b6000611b8e8383612e78565b905080611be457600360159054906101000a900460ff1615611be357611bb26108e0565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161490505b5b92915050565b611bf261210c565b80600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b611c55612374565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480611c9b5750611c9a85611c95612374565b611b82565b5b611cda576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cd190615316565b60405180910390fd5b611ce78585858585612f0c565b5050505050565b611cf661210c565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611d65576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d5c906156b0565b60405180910390fd5b611d6e8161295f565b50565b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480611db15750611db08333611b82565b5b611df0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611de790615589565b60405180910390fd5b611dfb8383836131a7565b505050565b60007fad0d7f6c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480611ecb57507fa07d229a000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80611edb5750611eda826133ed565b5b9050919050565b60007f2a55205a000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480611f555750611f5482611e00565b5b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603611fcb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fc290615742565b60405180910390fd5b6000611fd5612374565b90506000611fe2856134cf565b90506000611fef856134cf565b905061200083600089858589613549565b8460008088815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461205f9190614dd5565b925050819055508673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6289896040516120dd929190615762565b60405180910390a46120f4836000898585896135af565b61210383600089898989613615565b50505050505050565b612114612374565b73ffffffffffffffffffffffffffffffffffffffff166121326115fb565b73ffffffffffffffffffffffffffffffffffffffff1614612188576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161217f906157d7565b60405180910390fd5b565b6000806000600660008681526020019081526020016000206040518060400160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815250509050600073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff160361231f5760056040518060400160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff168152505090505b60006123296137ec565b6bffffffffffffffffffffffff1682602001516bffffffffffffffffffffffff16866123559190615170565b61235f91906151e1565b90508160000151819350935050509250929050565b600033905090565b81518351146123c0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123b790615869565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361242f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612426906158fb565b60405180910390fd5b6000612439612374565b9050612449818787878787613549565b60005b84518110156125f457600085828151811061246a576124696153c8565b5b602002602001015190506000858381518110612489576124886153c8565b5b60200260200101519050600080600084815260200190815260200160002060008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490508181101561252a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125219061598d565b60405180910390fd5b81810360008085815260200190815260200160002060008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508160008085815260200190815260200160002060008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546125df9190614dd5565b9250508190555050505080600101905061244c565b508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb878760405161266b9291906159ad565b60405180910390a46126818187878787876135af565b61268f8187878787876137f6565b505050505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612706576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126fd90615a56565b60405180910390fd5b805182511461274a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161274190615869565b60405180910390fd5b6000612754612374565b905061277481856000868660405180602001604052806000815250613549565b60005b83518110156128bb576000848281518110612795576127946153c8565b5b6020026020010151905060008483815181106127b4576127b36153c8565b5b60200260200101519050600080600084815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015612855576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161284c90615ae8565b60405180910390fd5b81810360008085815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505050508080600101915050612777565b50600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb86866040516129339291906159ad565b60405180910390a4612959818560008686604051806020016040528060008152506135af565b50505050565b6000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b612a2d61210c565b565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612a9d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a9490615b7a565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051612b8e9190613f63565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612c4f576000813b90506000811115612c4d578173ffffffffffffffffffffffffffffffffffffffff1663fb2de5d730612c036139cd565b6040518363ffffffff1660e01b8152600401612c20929190615bb7565b600060405180830381600087803b158015612c3a57600080fd5b505af1925050508015612c4b575060015b505b505b50565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603612cc1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cb890615742565b60405180910390fd5b8151835114612d05576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cfc90615869565b60405180910390fd5b6000612d0f612374565b9050612d2081600087878787613549565b60005b8451811015612dd357838181518110612d3f57612d3e6153c8565b5b6020026020010151600080878481518110612d5d57612d5c6153c8565b5b6020026020010151815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254612dbf9190614dd5565b925050819055508080600101915050612d23565b508473ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8787604051612e4b9291906159ad565b60405180910390a4612e62816000878787876135af565b612e71816000878787876137f6565b5050505050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603612f7b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f72906158fb565b60405180910390fd5b6000612f85612374565b90506000612f92856134cf565b90506000612f9f856134cf565b9050612faf838989858589613549565b600080600088815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905085811015613046576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161303d9061598d565b60405180910390fd5b85810360008089815260200190815260200160002060008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508560008089815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546130fb9190614dd5565b925050819055508773ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628a8a604051613178929190615762565b60405180910390a461318e848a8a86868a6135af565b61319c848a8a8a8a8a613615565b505050505050505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603613216576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161320d90615a56565b60405180910390fd5b6000613220612374565b9050600061322d846134cf565b9050600061323a846134cf565b905061325a83876000858560405180602001604052806000815250613549565b600080600087815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050848110156132f1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016132e890615ae8565b60405180910390fd5b84810360008088815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6289896040516133be929190615762565b60405180910390a46133e4848860008686604051806020016040528060008152506135af565b50505050505050565b60007fd9b67a26000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806134b857507f0e89341c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806134c857506134c7826139d7565b5b9050919050565b60606000600167ffffffffffffffff8111156134ee576134ed6140f2565b5b60405190808252806020026020018201604052801561351c5781602001602082028036833780820191505090505b5090508281600081518110613534576135336153c8565b5b60200260200101818152505080915050919050565b60008351905060005b818110156135a55761359a8787878481518110613572576135716153c8565b5b602002602001015187858151811061358d5761358c6153c8565b5b6020026020010151613a41565b806001019050613552565b5050505050505050565b60008351905060005b8181101561360b5761360087878784815181106135d8576135d76153c8565b5b60200260200101518785815181106135f3576135f26153c8565b5b6020026020010151613b45565b8060010190506135b8565b5050505050505050565b6136348473ffffffffffffffffffffffffffffffffffffffff16613c49565b156137e4578373ffffffffffffffffffffffffffffffffffffffff1663f23a6e6187878686866040518663ffffffff1660e01b815260040161367a959493929190615c35565b6020604051808303816000875af19250505080156136b657506040513d601f19601f820116820180604052508101906136b39190615ca4565b60015b61375b576136c2615cde565b806308c379a00361371e57506136d6615d00565b806136e15750613720565b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613715919061400e565b60405180910390fd5b505b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161375290615e02565b60405180910390fd5b63f23a6e6160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146137e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137d990615e94565b60405180910390fd5b505b505050505050565b6000612710905090565b6138158473ffffffffffffffffffffffffffffffffffffffff16613c49565b156139c5578373ffffffffffffffffffffffffffffffffffffffff1663bc197c8187878686866040518663ffffffff1660e01b815260040161385b959493929190615eb4565b6020604051808303816000875af192505050801561389757506040513d601f19601f820116820180604052508101906138949190615ca4565b60015b61393c576138a3615cde565b806308c379a0036138ff57506138b7615d00565b806138c25750613901565b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016138f6919061400e565b60405180910390fd5b505b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161393390615e02565b60405180910390fd5b63bc197c8160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146139c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016139ba90615e94565b60405180910390fd5b505b505050505050565b6000610483905090565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614905060008073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16149050818015613ab15750805b15613ae8576040517f5cbd944100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8115613b0757613b02613af9612374565b86868634613c6c565b613b3d565b8015613b2657613b21613b18612374565b87868634613c73565b613b3c565b613b3b613b31612374565b8787878734613c7a565b5b5b505050505050565b60008073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614905060008073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16149050818015613bb55750805b15613bec576040517f5cbd944100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8115613c0b57613c06613bfd612374565b86868634613d71565b613c41565b8015613c2a57613c25613c1c612374565b87868634613d78565b613c40565b613c3f613c35612374565b8787878734613d7f565b5b5b505050505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b5050505050565b5050505050565b6000613c846108e0565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614613d67578073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1603613cf35750613d69565b8073ffffffffffffffffffffffffffffffffffffffff16631854b24188888888886040518663ffffffff1660e01b8152600401613d34959493929190615f1c565b600060405180830381600087803b158015613d4e57600080fd5b505af1158015613d62573d6000803e3d6000fd5b505050505b505b505050505050565b5050505050565b5050505050565b505050505050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613dc682613d9b565b9050919050565b613dd681613dbb565b8114613de157600080fd5b50565b600081359050613df381613dcd565b92915050565b6000819050919050565b613e0c81613df9565b8114613e1757600080fd5b50565b600081359050613e2981613e03565b92915050565b60008060408385031215613e4657613e45613d91565b5b6000613e5485828601613de4565b9250506020613e6585828601613e1a565b9150509250929050565b613e7881613df9565b82525050565b6000602082019050613e936000830184613e6f565b92915050565b613ea281613dbb565b82525050565b6000602082019050613ebd6000830184613e99565b92915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613ef881613ec3565b8114613f0357600080fd5b50565b600081359050613f1581613eef565b92915050565b600060208284031215613f3157613f30613d91565b5b6000613f3f84828501613f06565b91505092915050565b60008115159050919050565b613f5d81613f48565b82525050565b6000602082019050613f786000830184613f54565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015613fb8578082015181840152602081019050613f9d565b60008484015250505050565b6000601f19601f8301169050919050565b6000613fe082613f7e565b613fea8185613f89565b9350613ffa818560208601613f9a565b61400381613fc4565b840191505092915050565b600060208201905081810360008301526140288184613fd5565b905092915050565b61403981613ec3565b82525050565b60006040820190506140546000830185614030565b6140616020830184613f54565b9392505050565b60006020828403121561407e5761407d613d91565b5b600061408c84828501613e1a565b91505092915050565b6000806000606084860312156140ae576140ad613d91565b5b60006140bc86828701613de4565b93505060206140cd86828701613e1a565b92505060406140de86828701613e1a565b9150509250925092565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61412a82613fc4565b810181811067ffffffffffffffff82111715614149576141486140f2565b5b80604052505050565b600061415c613d87565b90506141688282614121565b919050565b600067ffffffffffffffff821115614188576141876140f2565b5b61419182613fc4565b9050602081019050919050565b82818337600083830152505050565b60006141c06141bb8461416d565b614152565b9050828152602081018484840111156141dc576141db6140ed565b5b6141e784828561419e565b509392505050565b600082601f830112614204576142036140e8565b5b81356142148482602086016141ad565b91505092915050565b6000806040838503121561423457614233613d91565b5b600061424285828601613e1a565b925050602083013567ffffffffffffffff81111561426357614262613d96565b5b61426f858286016141ef565b9150509250929050565b600080604083850312156142905761428f613d91565b5b600061429e85828601613e1a565b92505060206142af85828601613e1a565b9150509250929050565b60006040820190506142ce6000830185613e99565b6142db6020830184613e6f565b9392505050565b600067ffffffffffffffff8211156142fd576142fc6140f2565b5b602082029050602081019050919050565b600080fd5b6000614326614321846142e2565b614152565b905080838252602082019050602084028301858111156143495761434861430e565b5b835b81811015614372578061435e8882613e1a565b84526020840193505060208101905061434b565b5050509392505050565b600082601f830112614391576143906140e8565b5b81356143a1848260208601614313565b91505092915050565b600067ffffffffffffffff8211156143c5576143c46140f2565b5b6143ce82613fc4565b9050602081019050919050565b60006143ee6143e9846143aa565b614152565b90508281526020810184848401111561440a576144096140ed565b5b61441584828561419e565b509392505050565b600082601f830112614432576144316140e8565b5b81356144428482602086016143db565b91505092915050565b600080600080600060a0868803121561446757614466613d91565b5b600061447588828901613de4565b955050602061448688828901613de4565b945050604086013567ffffffffffffffff8111156144a7576144a6613d96565b5b6144b38882890161437c565b935050606086013567ffffffffffffffff8111156144d4576144d3613d96565b5b6144e08882890161437c565b925050608086013567ffffffffffffffff81111561450157614500613d96565b5b61450d8882890161441d565b9150509295509295909350565b600067ffffffffffffffff821115614535576145346140f2565b5b602082029050602081019050919050565b60006145596145548461451a565b614152565b9050808382526020820190506020840283018581111561457c5761457b61430e565b5b835b818110156145a557806145918882613de4565b84526020840193505060208101905061457e565b5050509392505050565b600082601f8301126145c4576145c36140e8565b5b81356145d4848260208601614546565b91505092915050565b600080604083850312156145f4576145f3613d91565b5b600083013567ffffffffffffffff81111561461257614611613d96565b5b61461e858286016145af565b925050602083013567ffffffffffffffff81111561463f5761463e613d96565b5b61464b8582860161437c565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61468a81613df9565b82525050565b600061469c8383614681565b60208301905092915050565b6000602082019050919050565b60006146c082614655565b6146ca8185614660565b93506146d583614671565b8060005b838110156147065781516146ed8882614690565b97506146f8836146a8565b9250506001810190506146d9565b5085935050505092915050565b6000602082019050818103600083015261472d81846146b5565b905092915050565b61473e81613f48565b811461474957600080fd5b50565b60008135905061475b81614735565b92915050565b6000806000806080858703121561477b5761477a613d91565b5b600085013567ffffffffffffffff81111561479957614798613d96565b5b6147a5878288016141ef565b94505060206147b687828801613e1a565b935050604085013567ffffffffffffffff8111156147d7576147d6613d96565b5b6147e3878288016141ef565b92505060606147f48782880161474c565b91505092959194509250565b60006bffffffffffffffffffffffff82169050919050565b61482181614800565b811461482c57600080fd5b50565b60008135905061483e81614818565b92915050565b60008060006060848603121561485d5761485c613d91565b5b600061486b86828701613e1a565b935050602061487c86828701613de4565b925050604061488d8682870161482f565b9150509250925092565b6000806000606084860312156148b0576148af613d91565b5b60006148be86828701613de4565b935050602084013567ffffffffffffffff8111156148df576148de613d96565b5b6148eb8682870161437c565b925050604084013567ffffffffffffffff81111561490c5761490b613d96565b5b6149188682870161437c565b9150509250925092565b61492b81614800565b82525050565b60006040820190506149466000830185613e99565b6149536020830184614922565b9392505050565b6000602082840312156149705761496f613d91565b5b600061497e84828501613de4565b91505092915050565b60006020828403121561499d5761499c613d91565b5b60006149ab8482850161474c565b91505092915050565b600080604083850312156149cb576149ca613d91565b5b60006149d985828601613de4565b92505060206149ea8582860161474c565b9150509250929050565b60008060408385031215614a0b57614a0a613d91565b5b6000614a1985828601613de4565b9250506020614a2a85828601613de4565b9150509250929050565b600080600080600060a08688031215614a5057614a4f613d91565b5b6000614a5e88828901613de4565b9550506020614a6f88828901613de4565b9450506040614a8088828901613e1a565b9350506060614a9188828901613e1a565b925050608086013567ffffffffffffffff811115614ab257614ab1613d96565b5b614abe8882890161441d565b9150509295509295909350565b7f455243313135353a2061646472657373207a65726f206973206e6f742061207660008201527f616c6964206f776e657200000000000000000000000000000000000000000000602082015250565b6000614b27602a83613f89565b9150614b3282614acb565b604082019050919050565b60006020820190508181036000830152614b5681614b1a565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680614ba457607f821691505b602082108103614bb757614bb6614b5d565b5b50919050565b600081905092915050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000600082015250565b6000614bfe601d83614bbd565b9150614c0982614bc8565b601d82019050919050565b60008190508160005260206000209050919050565b60008154614c3681614b8c565b614c408186614bbd565b94506001821660008114614c5b5760018114614c7057614ca3565b60ff1983168652811515820286019350614ca3565b614c7985614c14565b60005b83811015614c9b57815481890152600182019150602081019050614c7c565b838801955050505b50505092915050565b6000614cb782614bf1565b9150614cc38284614c29565b915081905092915050565b7f4e6f7420617574686f72697a656420746f206d696e7400000000000000000000600082015250565b6000614d04601683613f89565b9150614d0f82614cce565b602082019050919050565b60006020820190508181036000830152614d3381614cf7565b9050919050565b7f45646974696f6e20646f6573206e6f7420657869737400000000000000000000600082015250565b6000614d70601683613f89565b9150614d7b82614d3a565b602082019050919050565b60006020820190508181036000830152614d9f81614d63565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000614de082613df9565b9150614deb83613df9565b9250828201905080821115614e0357614e02614da6565b5b92915050565b7f45786365656473206d617820737570706c790000000000000000000000000000600082015250565b6000614e3f601283613f89565b9150614e4a82614e09565b602082019050919050565b60006020820190508181036000830152614e6e81614e32565b9050919050565b7f43616e6e6f74207365742055524920666f72206f6e636861696e20656469746960008201527f6f6e000000000000000000000000000000000000000000000000000000000000602082015250565b6000614ed1602283613f89565b9150614edc82614e75565b604082019050919050565b60006020820190508181036000830152614f0081614ec4565b9050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302614f547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614f17565b614f5e8683614f17565b95508019841693508086168417925050509392505050565b6000819050919050565b6000614f9b614f96614f9184613df9565b614f76565b613df9565b9050919050565b6000819050919050565b614fb583614f80565b614fc9614fc182614fa2565b848454614f24565b825550505050565b600090565b614fde614fd1565b614fe9818484614fac565b505050565b5b8181101561500d57615002600082614fd6565b600181019050614fef565b5050565b601f8211156150525761502381614c14565b61502c84614f07565b8101602085101561503b578190505b61504f61504785614f07565b830182614fee565b50505b505050565b600082821c905092915050565b600061507560001984600802615057565b1980831691505092915050565b600061508e8383615064565b9150826002028217905092915050565b6150a782613f7e565b67ffffffffffffffff8111156150c0576150bf6140f2565b5b6150ca8254614b8c565b6150d5828285615011565b600060209050601f83116001811461510857600084156150f6578287015190505b6151008582615082565b865550615168565b601f19841661511686614c14565b60005b8281101561513e57848901518255600182019150602085019450602081019050615119565b8683101561515b5784890151615157601f891682615064565b8355505b6001600288020188555050505b505050505050565b600061517b82613df9565b915061518683613df9565b925082820261519481613df9565b915082820484148315176151ab576151aa614da6565b5b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006151ec82613df9565b91506151f783613df9565b925082615207576152066151b2565b5b828204905092915050565b7f546f6b656e20646f6573206e6f7420757365206f6e636861696e2073746f726160008201527f6765000000000000000000000000000000000000000000000000000000000000602082015250565b600061526e602283613f89565b915061527982615212565b604082019050919050565b6000602082019050818103600083015261529d81615261565b9050919050565b7f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60008201527f6572206f7220617070726f766564000000000000000000000000000000000000602082015250565b6000615300602e83613f89565b915061530b826152a4565b604082019050919050565b6000602082019050818103600083015261532f816152f3565b9050919050565b7f455243313135353a206163636f756e747320616e6420696473206c656e67746860008201527f206d69736d617463680000000000000000000000000000000000000000000000602082015250565b6000615392602983613f89565b915061539d82615336565b604082019050919050565b600060208201905081810360008301526153c181615385565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600061540282613df9565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361543457615433614da6565b5b600182019050919050565b7f526f79616c74792066656520746f6f2068696768000000000000000000000000600082015250565b6000615475601483613f89565b91506154808261543f565b602082019050919050565b600060208201905081810360008301526154a481615468565b9050919050565b7f496e76616c696420726563656976657220616464726573730000000000000000600082015250565b60006154e1601883613f89565b91506154ec826154ab565b602082019050919050565b60006020820190508181036000830152615510816154d4565b9050919050565b7f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60008201527f6572206e6f7220617070726f7665640000000000000000000000000000000000602082015250565b6000615573602f83613f89565b915061557e82615517565b604082019050919050565b600060208201905081810360008301526155a281615566565b9050919050565b60006040820190506155be6000830185613e99565b6155cb6020830184613e99565b9392505050565b7f4172726179206c656e677468206d69736d617463680000000000000000000000600082015250565b6000615608601583613f89565b9150615613826155d2565b602082019050919050565b60006020820190508181036000830152615637816155fb565b9050919050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b600061569a602683613f89565b91506156a58261563e565b604082019050919050565b600060208201905081810360008301526156c98161568d565b9050919050565b7f455243313135353a206d696e7420746f20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b600061572c602183613f89565b9150615737826156d0565b604082019050919050565b6000602082019050818103600083015261575b8161571f565b9050919050565b60006040820190506157776000830185613e6f565b6157846020830184613e6f565b9392505050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b60006157c1602083613f89565b91506157cc8261578b565b602082019050919050565b600060208201905081810360008301526157f0816157b4565b9050919050565b7f455243313135353a2069647320616e6420616d6f756e7473206c656e6774682060008201527f6d69736d61746368000000000000000000000000000000000000000000000000602082015250565b6000615853602883613f89565b915061585e826157f7565b604082019050919050565b6000602082019050818103600083015261588281615846565b9050919050565b7f455243313135353a207472616e7366657220746f20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b60006158e5602583613f89565b91506158f082615889565b604082019050919050565b60006020820190508181036000830152615914816158d8565b9050919050565b7f455243313135353a20696e73756666696369656e742062616c616e636520666f60008201527f72207472616e7366657200000000000000000000000000000000000000000000602082015250565b6000615977602a83613f89565b91506159828261591b565b604082019050919050565b600060208201905081810360008301526159a68161596a565b9050919050565b600060408201905081810360008301526159c781856146b5565b905081810360208301526159db81846146b5565b90509392505050565b7f455243313135353a206275726e2066726f6d20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b6000615a40602383613f89565b9150615a4b826159e4565b604082019050919050565b60006020820190508181036000830152615a6f81615a33565b9050919050565b7f455243313135353a206275726e20616d6f756e7420657863656564732062616c60008201527f616e636500000000000000000000000000000000000000000000000000000000602082015250565b6000615ad2602483613f89565b9150615add82615a76565b604082019050919050565b60006020820190508181036000830152615b0181615ac5565b9050919050565b7f455243313135353a2073657474696e6720617070726f76616c2073746174757360008201527f20666f722073656c660000000000000000000000000000000000000000000000602082015250565b6000615b64602983613f89565b9150615b6f82615b08565b604082019050919050565b60006020820190508181036000830152615b9381615b57565b9050919050565b600061ffff82169050919050565b615bb181615b9a565b82525050565b6000604082019050615bcc6000830185613e99565b615bd96020830184615ba8565b9392505050565b600081519050919050565b600082825260208201905092915050565b6000615c0782615be0565b615c118185615beb565b9350615c21818560208601613f9a565b615c2a81613fc4565b840191505092915050565b600060a082019050615c4a6000830188613e99565b615c576020830187613e99565b615c646040830186613e6f565b615c716060830185613e6f565b8181036080830152615c838184615bfc565b90509695505050505050565b600081519050615c9e81613eef565b92915050565b600060208284031215615cba57615cb9613d91565b5b6000615cc884828501615c8f565b91505092915050565b60008160e01c9050919050565b600060033d1115615cfd5760046000803e615cfa600051615cd1565b90505b90565b600060443d10615d8d57615d12613d87565b60043d036004823e80513d602482011167ffffffffffffffff82111715615d3a575050615d8d565b808201805167ffffffffffffffff811115615d585750505050615d8d565b80602083010160043d038501811115615d75575050505050615d8d565b615d8482602001850186614121565b82955050505050505b90565b7f455243313135353a207472616e7366657220746f206e6f6e2d4552433131353560008201527f526563656976657220696d706c656d656e746572000000000000000000000000602082015250565b6000615dec603483613f89565b9150615df782615d90565b604082019050919050565b60006020820190508181036000830152615e1b81615ddf565b9050919050565b7f455243313135353a204552433131353552656365697665722072656a6563746560008201527f6420746f6b656e73000000000000000000000000000000000000000000000000602082015250565b6000615e7e602883613f89565b9150615e8982615e22565b604082019050919050565b60006020820190508181036000830152615ead81615e71565b9050919050565b600060a082019050615ec96000830188613e99565b615ed66020830187613e99565b8181036040830152615ee881866146b5565b90508181036060830152615efc81856146b5565b90508181036080830152615f108184615bfc565b90509695505050505050565b600060a082019050615f316000830188613e99565b615f3e6020830187613e99565b615f4b6040830186613e99565b615f586060830185613e6f565b615f656080830184613e6f565b969550505050505056fea2646970667358221220a55f03d6d0379b077f4adb8f38cac5a70672968443a0e594956222668aa2cb6a64736f6c634300081c00330000000000000000000000006ff5104460c815c838b8dbe9e93c3ce17a2528bd00000000000000000000000000000000000000000000000000000000000001f4
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102265760003560e01c80635b746077116101305780639e05d240116100b8578063e985e9c51161007c578063e985e9c5146106b0578063ed58bad8146106e0578063f242432a146106fc578063f2fde38b14610718578063f5298aca1461073457610226565b80639e05d24014610610578063a22cb4651461062c578063a9fc664e14610648578063aa2fe91b14610664578063d81d0a151461069457610226565b8063833b7b78116100ff578063833b7b7814610543578063842392c214610574578063869f7594146105a45780638da5cb5b146105d457806395d89b41146105f257610226565b80635b746077146104cf5780636221d13c146104ff5780636b20c4541461051d578063715018a61461053957610226565b806323b01cfa116101b35780633d96004c116101825780633d96004c146104195780634e1273f414610435578063503b3f6c1461046557806351d329dc146104955780635944c753146104b357610226565b806323b01cfa1461036c5780632a55205a1461039c5780632ce0ff5f146103cd5780632eb2c2d6146103fd57610226565b8063098144d4116101fa578063098144d4146102c75780630d705df6146102e55780630e89341c14610304578063156e29f614610334578063162094c41461035057610226565b8062fdd58e1461022b578063014635461461025b57806301ffc9a71461027957806306fdde03146102a9575b600080fd5b61024560048036038101906102409190613e2f565b610750565b6040516102529190613e7e565b60405180910390f35b610263610818565b6040516102709190613ea8565b60405180910390f35b610293600480360381019061028e9190613f1b565b610830565b6040516102a09190613f63565b60405180910390f35b6102b1610852565b6040516102be919061400e565b60405180910390f35b6102cf6108e0565b6040516102dc9190613ea8565b60405180910390f35b6102ed61096b565b6040516102fb92919061403f565b60405180910390f35b61031e60048036038101906103199190614068565b610999565b60405161032b919061400e565b60405180910390f35b61034e60048036038101906103499190614095565b610a9e565b005b61036a6004803603810190610365919061421d565b610c86565b005b61038660048036038101906103819190614068565b610d82565b6040516103939190613f63565b60405180910390f35b6103b660048036038101906103b19190614279565b610da2565b6040516103c49291906142b9565b60405180910390f35b6103e760048036038101906103e29190614068565b610e85565b6040516103f4919061400e565b60405180910390f35b6104176004803603810190610412919061444b565b610f8a565b005b610433600480360381019061042e919061421d565b61102b565b005b61044f600480360381019061044a91906145dd565b6110c8565b60405161045c9190614713565b60405180910390f35b61047f600480360381019061047a9190614761565b6111db565b60405161048c9190613e7e565b60405180910390f35b61049d6112a2565b6040516104aa9190613e7e565b60405180910390f35b6104cd60048036038101906104c89190614844565b6112ac565b005b6104e960048036038101906104e49190614068565b611453565b6040516104f69190613e7e565b60405180910390f35b61050761146b565b6040516105149190613f63565b60405180910390f35b61053760048036038101906105329190614897565b61147e565b005b61054161150d565b005b61055d60048036038101906105589190614068565b611521565b60405161056b929190614931565b60405180910390f35b61058e6004803603810190610589919061495a565b61158d565b60405161059b9190613f63565b60405180910390f35b6105be60048036038101906105b99190614068565b6115e3565b6040516105cb9190613e7e565b60405180910390f35b6105dc6115fb565b6040516105e99190613ea8565b60405180910390f35b6105fa611625565b604051610607919061400e565b60405180910390f35b61062a60048036038101906106259190614987565b6116b3565b005b610646600480360381019061064191906149b4565b61170f565b005b610662600480360381019061065d919061495a565b611725565b005b61067e6004803603810190610679919061495a565b611866565b60405161068b9190613f63565b60405180910390f35b6106ae60048036038101906106a99190614897565b611886565b005b6106ca60048036038101906106c591906149f4565b611b82565b6040516106d79190613f63565b60405180910390f35b6106fa60048036038101906106f591906149b4565b611bea565b005b61071660048036038101906107119190614a34565b611c4d565b005b610732600480360381019061072d919061495a565b611cee565b005b61074e60048036038101906107499190614095565b611d71565b005b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036107c0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107b790614b3d565b60405180910390fd5b60008083815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b73721c002b0059009a671d00ad1700c9748146cd1b81565b600061083b82611e00565b8061084b575061084a82611ee2565b5b9050919050565b6008805461085f90614b8c565b80601f016020809104026020016040519081016040528092919081815260200182805461088b90614b8c565b80156108d85780601f106108ad576101008083540402835291602001916108d8565b820191906000526020600020905b8154815290600101906020018083116108bb57829003601f168201915b505050505081565b6000600360019054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361096857600360009054906101000a900460ff166109675773721c002b0059009a671d00ad1700c9748146cd1b90505b5b90565b6000807f1854b24168de2a3561e8caaa0770d8257ca046fb64fc845e3cd163acfc66770c9150600090509091565b6060600f600083815260200190815260200160002060009054906101000a900460ff16156109fa57600e60008381526020019081526020016000206040516020016109e49190614cac565b6040516020818303038152906040529050610a99565b600b60008381526020019081526020016000208054610a1890614b8c565b80601f0160208091040260200160405190810160405280929190818152602001828054610a4490614b8c565b8015610a915780601f10610a6657610100808354040283529160200191610a91565b820191906000526020600020905b815481529060010190602001808311610a7457829003601f168201915b505050505090505b919050565b600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1680610b285750610af96115fb565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b610b67576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b5e90614d1a565b60405180910390fd5b600a548210610bab576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ba290614d86565b60405180910390fd5b6000600c6000848152602001908152602001600020541115610c3c57600c60008381526020019081526020016000205481600d600085815260200190815260200160002054610bfa9190614dd5565b1115610c3b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c3290614e55565b60405180910390fd5b5b80600d60008481526020019081526020016000206000828254610c5f9190614dd5565b92505081905550610c8183838360405180602001604052806000815250611f5c565b505050565b610c8e61210c565b6000600b60008481526020019081526020016000208054610cae90614b8c565b90501180610cbd5750600a5482105b610cfc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cf390614d86565b60405180910390fd5b600f600083815260200190815260200160002060009054906101000a900460ff1615610d5d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d5490614ee7565b60405180910390fd5b80600b60008481526020019081526020016000209081610d7d919061509e565b505050565b600f6020528060005260406000206000915054906101000a900460ff1681565b6000806010600085815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16915060006011600086815260200190815260200160002060009054906101000a90046bffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610e5357610e49858561218a565b9250925050610e7e565b612710816bffffffffffffffffffffffff1685610e709190615170565b610e7a91906151e1565b9150505b9250929050565b6060600f600083815260200190815260200160002060009054906101000a900460ff16610ee7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ede90615284565b60405180910390fd5b600e60008381526020019081526020016000208054610f0590614b8c565b80601f0160208091040260200160405190810160405280929190818152602001828054610f3190614b8c565b8015610f7e5780601f10610f5357610100808354040283529160200191610f7e565b820191906000526020600020905b815481529060010190602001808311610f6157829003601f168201915b50505050509050919050565b610f92612374565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480610fd85750610fd785610fd2612374565b611b82565b5b611017576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161100e90615316565b60405180910390fd5b611024858585858561237c565b5050505050565b61103361210c565b600a548210611077576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161106e90614d86565b60405180910390fd5b80600e60008481526020019081526020016000209081611097919061509e565b506001600f600084815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b6060815183511461110e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611105906153a8565b60405180910390fd5b6000835167ffffffffffffffff81111561112b5761112a6140f2565b5b6040519080825280602002602001820160405280156111595781602001602082028036833780820191505090505b50905060005b84518110156111d0576111a685828151811061117e5761117d6153c8565b5b6020026020010151858381518110611199576111986153c8565b5b6020026020010151610750565b8282815181106111b9576111b86153c8565b5b60200260200101818152505080600101905061115f565b508091505092915050565b60006111e561210c565b6000600a549050600a60008154809291906111ff906153f7565b9190505550821561125c5783600e6000838152602001908152602001600020908161122a919061509e565b506001600f600083815260200190815260200160002060006101000a81548160ff02191690831515021790555061127e565b85600b6000838152602001908152602001600020908161127c919061509e565b505b84600c60008381526020019081526020016000208190555080915050949350505050565b6000600a54905090565b6112b461210c565b600a5483106112f8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112ef90614d86565b60405180910390fd5b612710816bffffffffffffffffffffffff16111561134b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113429061548b565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036113ba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113b1906154f7565b60405180910390fd5b816010600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550806011600085815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505050565b600d6020528060005260406000206000915090505481565b600360159054906101000a900460ff1681565b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806114be57506114bd8333611b82565b5b6114fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114f490615589565b60405180910390fd5b611508838383612697565b505050565b61151561210c565b61151f600061295f565b565b6000806010600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166011600085815260200190815260200160002060009054906101000a90046bffffffffffffffffffffffff1691509150915091565b6000600760008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b600c6020528060005260406000206000915090505481565b6000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6009805461163290614b8c565b80601f016020809104026020016040519081016040528092919081815260200182805461165e90614b8c565b80156116ab5780601f10611680576101008083540402835291602001916116ab565b820191906000526020600020905b81548152906001019060200180831161168e57829003601f168201915b505050505081565b6116bb612a25565b80600360156101000a81548160ff0219169083151502179055507f6787c7f9a80aa0f5ceddab2c54f1f5169c0b88e75dd5e19d5e858a64144c7dbc816040516117049190613f63565b60405180910390a150565b61172161171a612374565b8383612a2f565b5050565b61172d612a25565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015611786575080155b156117bd576040517f32483afb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fcc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aac6117e66108e0565b836040516117f59291906155a9565b60405180910390a16001600360006101000a81548160ff02191690831515021790555081600360016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061186282612b9b565b5050565b60076020528060005260406000206000915054906101000a900460ff1681565b600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff168061191057506118e16115fb565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b61194f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161194690614d1a565b60405180910390fd5b8051825114611993576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161198a9061561e565b60405180910390fd5b60005b8251811015611b6157600a548382815181106119b5576119b46153c8565b5b6020026020010151106119fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119f490614d86565b60405180910390fd5b6000600c6000858481518110611a1657611a156153c8565b5b60200260200101518152602001908152602001600020541115611af657600c6000848381518110611a4a57611a496153c8565b5b6020026020010151815260200190815260200160002054828281518110611a7457611a736153c8565b5b6020026020010151600d6000868581518110611a9357611a926153c8565b5b6020026020010151815260200190815260200160002054611ab49190614dd5565b1115611af5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611aec90614e55565b60405180910390fd5b5b818181518110611b0957611b086153c8565b5b6020026020010151600d6000858481518110611b2857611b276153c8565b5b602002602001015181526020019081526020016000206000828254611b4d9190614dd5565b925050819055508080600101915050611996565b50611b7d83838360405180602001604052806000815250612c52565b505050565b6000611b8e8383612e78565b905080611be457600360159054906101000a900460ff1615611be357611bb26108e0565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161490505b5b92915050565b611bf261210c565b80600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b611c55612374565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480611c9b5750611c9a85611c95612374565b611b82565b5b611cda576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cd190615316565b60405180910390fd5b611ce78585858585612f0c565b5050505050565b611cf661210c565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611d65576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d5c906156b0565b60405180910390fd5b611d6e8161295f565b50565b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480611db15750611db08333611b82565b5b611df0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611de790615589565b60405180910390fd5b611dfb8383836131a7565b505050565b60007fad0d7f6c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480611ecb57507fa07d229a000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80611edb5750611eda826133ed565b5b9050919050565b60007f2a55205a000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480611f555750611f5482611e00565b5b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603611fcb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fc290615742565b60405180910390fd5b6000611fd5612374565b90506000611fe2856134cf565b90506000611fef856134cf565b905061200083600089858589613549565b8460008088815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461205f9190614dd5565b925050819055508673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6289896040516120dd929190615762565b60405180910390a46120f4836000898585896135af565b61210383600089898989613615565b50505050505050565b612114612374565b73ffffffffffffffffffffffffffffffffffffffff166121326115fb565b73ffffffffffffffffffffffffffffffffffffffff1614612188576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161217f906157d7565b60405180910390fd5b565b6000806000600660008681526020019081526020016000206040518060400160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815250509050600073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff160361231f5760056040518060400160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016000820160149054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff168152505090505b60006123296137ec565b6bffffffffffffffffffffffff1682602001516bffffffffffffffffffffffff16866123559190615170565b61235f91906151e1565b90508160000151819350935050509250929050565b600033905090565b81518351146123c0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123b790615869565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361242f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612426906158fb565b60405180910390fd5b6000612439612374565b9050612449818787878787613549565b60005b84518110156125f457600085828151811061246a576124696153c8565b5b602002602001015190506000858381518110612489576124886153c8565b5b60200260200101519050600080600084815260200190815260200160002060008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490508181101561252a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125219061598d565b60405180910390fd5b81810360008085815260200190815260200160002060008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508160008085815260200190815260200160002060008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546125df9190614dd5565b9250508190555050505080600101905061244c565b508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb878760405161266b9291906159ad565b60405180910390a46126818187878787876135af565b61268f8187878787876137f6565b505050505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612706576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126fd90615a56565b60405180910390fd5b805182511461274a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161274190615869565b60405180910390fd5b6000612754612374565b905061277481856000868660405180602001604052806000815250613549565b60005b83518110156128bb576000848281518110612795576127946153c8565b5b6020026020010151905060008483815181106127b4576127b36153c8565b5b60200260200101519050600080600084815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015612855576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161284c90615ae8565b60405180910390fd5b81810360008085815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505050508080600101915050612777565b50600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb86866040516129339291906159ad565b60405180910390a4612959818560008686604051806020016040528060008152506135af565b50505050565b6000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b612a2d61210c565b565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612a9d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a9490615b7a565b60405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051612b8e9190613f63565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612c4f576000813b90506000811115612c4d578173ffffffffffffffffffffffffffffffffffffffff1663fb2de5d730612c036139cd565b6040518363ffffffff1660e01b8152600401612c20929190615bb7565b600060405180830381600087803b158015612c3a57600080fd5b505af1925050508015612c4b575060015b505b505b50565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603612cc1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cb890615742565b60405180910390fd5b8151835114612d05576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cfc90615869565b60405180910390fd5b6000612d0f612374565b9050612d2081600087878787613549565b60005b8451811015612dd357838181518110612d3f57612d3e6153c8565b5b6020026020010151600080878481518110612d5d57612d5c6153c8565b5b6020026020010151815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254612dbf9190614dd5565b925050819055508080600101915050612d23565b508473ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8787604051612e4b9291906159ad565b60405180910390a4612e62816000878787876135af565b612e71816000878787876137f6565b5050505050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603612f7b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f72906158fb565b60405180910390fd5b6000612f85612374565b90506000612f92856134cf565b90506000612f9f856134cf565b9050612faf838989858589613549565b600080600088815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905085811015613046576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161303d9061598d565b60405180910390fd5b85810360008089815260200190815260200160002060008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508560008089815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546130fb9190614dd5565b925050819055508773ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628a8a604051613178929190615762565b60405180910390a461318e848a8a86868a6135af565b61319c848a8a8a8a8a613615565b505050505050505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603613216576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161320d90615a56565b60405180910390fd5b6000613220612374565b9050600061322d846134cf565b9050600061323a846134cf565b905061325a83876000858560405180602001604052806000815250613549565b600080600087815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050848110156132f1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016132e890615ae8565b60405180910390fd5b84810360008088815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6289896040516133be929190615762565b60405180910390a46133e4848860008686604051806020016040528060008152506135af565b50505050505050565b60007fd9b67a26000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806134b857507f0e89341c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806134c857506134c7826139d7565b5b9050919050565b60606000600167ffffffffffffffff8111156134ee576134ed6140f2565b5b60405190808252806020026020018201604052801561351c5781602001602082028036833780820191505090505b5090508281600081518110613534576135336153c8565b5b60200260200101818152505080915050919050565b60008351905060005b818110156135a55761359a8787878481518110613572576135716153c8565b5b602002602001015187858151811061358d5761358c6153c8565b5b6020026020010151613a41565b806001019050613552565b5050505050505050565b60008351905060005b8181101561360b5761360087878784815181106135d8576135d76153c8565b5b60200260200101518785815181106135f3576135f26153c8565b5b6020026020010151613b45565b8060010190506135b8565b5050505050505050565b6136348473ffffffffffffffffffffffffffffffffffffffff16613c49565b156137e4578373ffffffffffffffffffffffffffffffffffffffff1663f23a6e6187878686866040518663ffffffff1660e01b815260040161367a959493929190615c35565b6020604051808303816000875af19250505080156136b657506040513d601f19601f820116820180604052508101906136b39190615ca4565b60015b61375b576136c2615cde565b806308c379a00361371e57506136d6615d00565b806136e15750613720565b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613715919061400e565b60405180910390fd5b505b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161375290615e02565b60405180910390fd5b63f23a6e6160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146137e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137d990615e94565b60405180910390fd5b505b505050505050565b6000612710905090565b6138158473ffffffffffffffffffffffffffffffffffffffff16613c49565b156139c5578373ffffffffffffffffffffffffffffffffffffffff1663bc197c8187878686866040518663ffffffff1660e01b815260040161385b959493929190615eb4565b6020604051808303816000875af192505050801561389757506040513d601f19601f820116820180604052508101906138949190615ca4565b60015b61393c576138a3615cde565b806308c379a0036138ff57506138b7615d00565b806138c25750613901565b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016138f6919061400e565b60405180910390fd5b505b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161393390615e02565b60405180910390fd5b63bc197c8160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146139c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016139ba90615e94565b60405180910390fd5b505b505050505050565b6000610483905090565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614905060008073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16149050818015613ab15750805b15613ae8576040517f5cbd944100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8115613b0757613b02613af9612374565b86868634613c6c565b613b3d565b8015613b2657613b21613b18612374565b87868634613c73565b613b3c565b613b3b613b31612374565b8787878734613c7a565b5b5b505050505050565b60008073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614905060008073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16149050818015613bb55750805b15613bec576040517f5cbd944100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8115613c0b57613c06613bfd612374565b86868634613d71565b613c41565b8015613c2a57613c25613c1c612374565b87868634613d78565b613c40565b613c3f613c35612374565b8787878734613d7f565b5b5b505050505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b5050505050565b5050505050565b6000613c846108e0565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614613d67578073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1603613cf35750613d69565b8073ffffffffffffffffffffffffffffffffffffffff16631854b24188888888886040518663ffffffff1660e01b8152600401613d34959493929190615f1c565b600060405180830381600087803b158015613d4e57600080fd5b505af1158015613d62573d6000803e3d6000fd5b505050505b505b505050505050565b5050505050565b5050505050565b505050505050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613dc682613d9b565b9050919050565b613dd681613dbb565b8114613de157600080fd5b50565b600081359050613df381613dcd565b92915050565b6000819050919050565b613e0c81613df9565b8114613e1757600080fd5b50565b600081359050613e2981613e03565b92915050565b60008060408385031215613e4657613e45613d91565b5b6000613e5485828601613de4565b9250506020613e6585828601613e1a565b9150509250929050565b613e7881613df9565b82525050565b6000602082019050613e936000830184613e6f565b92915050565b613ea281613dbb565b82525050565b6000602082019050613ebd6000830184613e99565b92915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613ef881613ec3565b8114613f0357600080fd5b50565b600081359050613f1581613eef565b92915050565b600060208284031215613f3157613f30613d91565b5b6000613f3f84828501613f06565b91505092915050565b60008115159050919050565b613f5d81613f48565b82525050565b6000602082019050613f786000830184613f54565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015613fb8578082015181840152602081019050613f9d565b60008484015250505050565b6000601f19601f8301169050919050565b6000613fe082613f7e565b613fea8185613f89565b9350613ffa818560208601613f9a565b61400381613fc4565b840191505092915050565b600060208201905081810360008301526140288184613fd5565b905092915050565b61403981613ec3565b82525050565b60006040820190506140546000830185614030565b6140616020830184613f54565b9392505050565b60006020828403121561407e5761407d613d91565b5b600061408c84828501613e1a565b91505092915050565b6000806000606084860312156140ae576140ad613d91565b5b60006140bc86828701613de4565b93505060206140cd86828701613e1a565b92505060406140de86828701613e1a565b9150509250925092565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61412a82613fc4565b810181811067ffffffffffffffff82111715614149576141486140f2565b5b80604052505050565b600061415c613d87565b90506141688282614121565b919050565b600067ffffffffffffffff821115614188576141876140f2565b5b61419182613fc4565b9050602081019050919050565b82818337600083830152505050565b60006141c06141bb8461416d565b614152565b9050828152602081018484840111156141dc576141db6140ed565b5b6141e784828561419e565b509392505050565b600082601f830112614204576142036140e8565b5b81356142148482602086016141ad565b91505092915050565b6000806040838503121561423457614233613d91565b5b600061424285828601613e1a565b925050602083013567ffffffffffffffff81111561426357614262613d96565b5b61426f858286016141ef565b9150509250929050565b600080604083850312156142905761428f613d91565b5b600061429e85828601613e1a565b92505060206142af85828601613e1a565b9150509250929050565b60006040820190506142ce6000830185613e99565b6142db6020830184613e6f565b9392505050565b600067ffffffffffffffff8211156142fd576142fc6140f2565b5b602082029050602081019050919050565b600080fd5b6000614326614321846142e2565b614152565b905080838252602082019050602084028301858111156143495761434861430e565b5b835b81811015614372578061435e8882613e1a565b84526020840193505060208101905061434b565b5050509392505050565b600082601f830112614391576143906140e8565b5b81356143a1848260208601614313565b91505092915050565b600067ffffffffffffffff8211156143c5576143c46140f2565b5b6143ce82613fc4565b9050602081019050919050565b60006143ee6143e9846143aa565b614152565b90508281526020810184848401111561440a576144096140ed565b5b61441584828561419e565b509392505050565b600082601f830112614432576144316140e8565b5b81356144428482602086016143db565b91505092915050565b600080600080600060a0868803121561446757614466613d91565b5b600061447588828901613de4565b955050602061448688828901613de4565b945050604086013567ffffffffffffffff8111156144a7576144a6613d96565b5b6144b38882890161437c565b935050606086013567ffffffffffffffff8111156144d4576144d3613d96565b5b6144e08882890161437c565b925050608086013567ffffffffffffffff81111561450157614500613d96565b5b61450d8882890161441d565b9150509295509295909350565b600067ffffffffffffffff821115614535576145346140f2565b5b602082029050602081019050919050565b60006145596145548461451a565b614152565b9050808382526020820190506020840283018581111561457c5761457b61430e565b5b835b818110156145a557806145918882613de4565b84526020840193505060208101905061457e565b5050509392505050565b600082601f8301126145c4576145c36140e8565b5b81356145d4848260208601614546565b91505092915050565b600080604083850312156145f4576145f3613d91565b5b600083013567ffffffffffffffff81111561461257614611613d96565b5b61461e858286016145af565b925050602083013567ffffffffffffffff81111561463f5761463e613d96565b5b61464b8582860161437c565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61468a81613df9565b82525050565b600061469c8383614681565b60208301905092915050565b6000602082019050919050565b60006146c082614655565b6146ca8185614660565b93506146d583614671565b8060005b838110156147065781516146ed8882614690565b97506146f8836146a8565b9250506001810190506146d9565b5085935050505092915050565b6000602082019050818103600083015261472d81846146b5565b905092915050565b61473e81613f48565b811461474957600080fd5b50565b60008135905061475b81614735565b92915050565b6000806000806080858703121561477b5761477a613d91565b5b600085013567ffffffffffffffff81111561479957614798613d96565b5b6147a5878288016141ef565b94505060206147b687828801613e1a565b935050604085013567ffffffffffffffff8111156147d7576147d6613d96565b5b6147e3878288016141ef565b92505060606147f48782880161474c565b91505092959194509250565b60006bffffffffffffffffffffffff82169050919050565b61482181614800565b811461482c57600080fd5b50565b60008135905061483e81614818565b92915050565b60008060006060848603121561485d5761485c613d91565b5b600061486b86828701613e1a565b935050602061487c86828701613de4565b925050604061488d8682870161482f565b9150509250925092565b6000806000606084860312156148b0576148af613d91565b5b60006148be86828701613de4565b935050602084013567ffffffffffffffff8111156148df576148de613d96565b5b6148eb8682870161437c565b925050604084013567ffffffffffffffff81111561490c5761490b613d96565b5b6149188682870161437c565b9150509250925092565b61492b81614800565b82525050565b60006040820190506149466000830185613e99565b6149536020830184614922565b9392505050565b6000602082840312156149705761496f613d91565b5b600061497e84828501613de4565b91505092915050565b60006020828403121561499d5761499c613d91565b5b60006149ab8482850161474c565b91505092915050565b600080604083850312156149cb576149ca613d91565b5b60006149d985828601613de4565b92505060206149ea8582860161474c565b9150509250929050565b60008060408385031215614a0b57614a0a613d91565b5b6000614a1985828601613de4565b9250506020614a2a85828601613de4565b9150509250929050565b600080600080600060a08688031215614a5057614a4f613d91565b5b6000614a5e88828901613de4565b9550506020614a6f88828901613de4565b9450506040614a8088828901613e1a565b9350506060614a9188828901613e1a565b925050608086013567ffffffffffffffff811115614ab257614ab1613d96565b5b614abe8882890161441d565b9150509295509295909350565b7f455243313135353a2061646472657373207a65726f206973206e6f742061207660008201527f616c6964206f776e657200000000000000000000000000000000000000000000602082015250565b6000614b27602a83613f89565b9150614b3282614acb565b604082019050919050565b60006020820190508181036000830152614b5681614b1a565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680614ba457607f821691505b602082108103614bb757614bb6614b5d565b5b50919050565b600081905092915050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000600082015250565b6000614bfe601d83614bbd565b9150614c0982614bc8565b601d82019050919050565b60008190508160005260206000209050919050565b60008154614c3681614b8c565b614c408186614bbd565b94506001821660008114614c5b5760018114614c7057614ca3565b60ff1983168652811515820286019350614ca3565b614c7985614c14565b60005b83811015614c9b57815481890152600182019150602081019050614c7c565b838801955050505b50505092915050565b6000614cb782614bf1565b9150614cc38284614c29565b915081905092915050565b7f4e6f7420617574686f72697a656420746f206d696e7400000000000000000000600082015250565b6000614d04601683613f89565b9150614d0f82614cce565b602082019050919050565b60006020820190508181036000830152614d3381614cf7565b9050919050565b7f45646974696f6e20646f6573206e6f7420657869737400000000000000000000600082015250565b6000614d70601683613f89565b9150614d7b82614d3a565b602082019050919050565b60006020820190508181036000830152614d9f81614d63565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000614de082613df9565b9150614deb83613df9565b9250828201905080821115614e0357614e02614da6565b5b92915050565b7f45786365656473206d617820737570706c790000000000000000000000000000600082015250565b6000614e3f601283613f89565b9150614e4a82614e09565b602082019050919050565b60006020820190508181036000830152614e6e81614e32565b9050919050565b7f43616e6e6f74207365742055524920666f72206f6e636861696e20656469746960008201527f6f6e000000000000000000000000000000000000000000000000000000000000602082015250565b6000614ed1602283613f89565b9150614edc82614e75565b604082019050919050565b60006020820190508181036000830152614f0081614ec4565b9050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302614f547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614f17565b614f5e8683614f17565b95508019841693508086168417925050509392505050565b6000819050919050565b6000614f9b614f96614f9184613df9565b614f76565b613df9565b9050919050565b6000819050919050565b614fb583614f80565b614fc9614fc182614fa2565b848454614f24565b825550505050565b600090565b614fde614fd1565b614fe9818484614fac565b505050565b5b8181101561500d57615002600082614fd6565b600181019050614fef565b5050565b601f8211156150525761502381614c14565b61502c84614f07565b8101602085101561503b578190505b61504f61504785614f07565b830182614fee565b50505b505050565b600082821c905092915050565b600061507560001984600802615057565b1980831691505092915050565b600061508e8383615064565b9150826002028217905092915050565b6150a782613f7e565b67ffffffffffffffff8111156150c0576150bf6140f2565b5b6150ca8254614b8c565b6150d5828285615011565b600060209050601f83116001811461510857600084156150f6578287015190505b6151008582615082565b865550615168565b601f19841661511686614c14565b60005b8281101561513e57848901518255600182019150602085019450602081019050615119565b8683101561515b5784890151615157601f891682615064565b8355505b6001600288020188555050505b505050505050565b600061517b82613df9565b915061518683613df9565b925082820261519481613df9565b915082820484148315176151ab576151aa614da6565b5b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006151ec82613df9565b91506151f783613df9565b925082615207576152066151b2565b5b828204905092915050565b7f546f6b656e20646f6573206e6f7420757365206f6e636861696e2073746f726160008201527f6765000000000000000000000000000000000000000000000000000000000000602082015250565b600061526e602283613f89565b915061527982615212565b604082019050919050565b6000602082019050818103600083015261529d81615261565b9050919050565b7f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60008201527f6572206f7220617070726f766564000000000000000000000000000000000000602082015250565b6000615300602e83613f89565b915061530b826152a4565b604082019050919050565b6000602082019050818103600083015261532f816152f3565b9050919050565b7f455243313135353a206163636f756e747320616e6420696473206c656e67746860008201527f206d69736d617463680000000000000000000000000000000000000000000000602082015250565b6000615392602983613f89565b915061539d82615336565b604082019050919050565b600060208201905081810360008301526153c181615385565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600061540282613df9565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361543457615433614da6565b5b600182019050919050565b7f526f79616c74792066656520746f6f2068696768000000000000000000000000600082015250565b6000615475601483613f89565b91506154808261543f565b602082019050919050565b600060208201905081810360008301526154a481615468565b9050919050565b7f496e76616c696420726563656976657220616464726573730000000000000000600082015250565b60006154e1601883613f89565b91506154ec826154ab565b602082019050919050565b60006020820190508181036000830152615510816154d4565b9050919050565b7f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60008201527f6572206e6f7220617070726f7665640000000000000000000000000000000000602082015250565b6000615573602f83613f89565b915061557e82615517565b604082019050919050565b600060208201905081810360008301526155a281615566565b9050919050565b60006040820190506155be6000830185613e99565b6155cb6020830184613e99565b9392505050565b7f4172726179206c656e677468206d69736d617463680000000000000000000000600082015250565b6000615608601583613f89565b9150615613826155d2565b602082019050919050565b60006020820190508181036000830152615637816155fb565b9050919050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b600061569a602683613f89565b91506156a58261563e565b604082019050919050565b600060208201905081810360008301526156c98161568d565b9050919050565b7f455243313135353a206d696e7420746f20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b600061572c602183613f89565b9150615737826156d0565b604082019050919050565b6000602082019050818103600083015261575b8161571f565b9050919050565b60006040820190506157776000830185613e6f565b6157846020830184613e6f565b9392505050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b60006157c1602083613f89565b91506157cc8261578b565b602082019050919050565b600060208201905081810360008301526157f0816157b4565b9050919050565b7f455243313135353a2069647320616e6420616d6f756e7473206c656e6774682060008201527f6d69736d61746368000000000000000000000000000000000000000000000000602082015250565b6000615853602883613f89565b915061585e826157f7565b604082019050919050565b6000602082019050818103600083015261588281615846565b9050919050565b7f455243313135353a207472616e7366657220746f20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b60006158e5602583613f89565b91506158f082615889565b604082019050919050565b60006020820190508181036000830152615914816158d8565b9050919050565b7f455243313135353a20696e73756666696369656e742062616c616e636520666f60008201527f72207472616e7366657200000000000000000000000000000000000000000000602082015250565b6000615977602a83613f89565b91506159828261591b565b604082019050919050565b600060208201905081810360008301526159a68161596a565b9050919050565b600060408201905081810360008301526159c781856146b5565b905081810360208301526159db81846146b5565b90509392505050565b7f455243313135353a206275726e2066726f6d20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b6000615a40602383613f89565b9150615a4b826159e4565b604082019050919050565b60006020820190508181036000830152615a6f81615a33565b9050919050565b7f455243313135353a206275726e20616d6f756e7420657863656564732062616c60008201527f616e636500000000000000000000000000000000000000000000000000000000602082015250565b6000615ad2602483613f89565b9150615add82615a76565b604082019050919050565b60006020820190508181036000830152615b0181615ac5565b9050919050565b7f455243313135353a2073657474696e6720617070726f76616c2073746174757360008201527f20666f722073656c660000000000000000000000000000000000000000000000602082015250565b6000615b64602983613f89565b9150615b6f82615b08565b604082019050919050565b60006020820190508181036000830152615b9381615b57565b9050919050565b600061ffff82169050919050565b615bb181615b9a565b82525050565b6000604082019050615bcc6000830185613e99565b615bd96020830184615ba8565b9392505050565b600081519050919050565b600082825260208201905092915050565b6000615c0782615be0565b615c118185615beb565b9350615c21818560208601613f9a565b615c2a81613fc4565b840191505092915050565b600060a082019050615c4a6000830188613e99565b615c576020830187613e99565b615c646040830186613e6f565b615c716060830185613e6f565b8181036080830152615c838184615bfc565b90509695505050505050565b600081519050615c9e81613eef565b92915050565b600060208284031215615cba57615cb9613d91565b5b6000615cc884828501615c8f565b91505092915050565b60008160e01c9050919050565b600060033d1115615cfd5760046000803e615cfa600051615cd1565b90505b90565b600060443d10615d8d57615d12613d87565b60043d036004823e80513d602482011167ffffffffffffffff82111715615d3a575050615d8d565b808201805167ffffffffffffffff811115615d585750505050615d8d565b80602083010160043d038501811115615d75575050505050615d8d565b615d8482602001850186614121565b82955050505050505b90565b7f455243313135353a207472616e7366657220746f206e6f6e2d4552433131353560008201527f526563656976657220696d706c656d656e746572000000000000000000000000602082015250565b6000615dec603483613f89565b9150615df782615d90565b604082019050919050565b60006020820190508181036000830152615e1b81615ddf565b9050919050565b7f455243313135353a204552433131353552656365697665722072656a6563746560008201527f6420746f6b656e73000000000000000000000000000000000000000000000000602082015250565b6000615e7e602883613f89565b9150615e8982615e22565b604082019050919050565b60006020820190508181036000830152615ead81615e71565b9050919050565b600060a082019050615ec96000830188613e99565b615ed66020830187613e99565b8181036040830152615ee881866146b5565b90508181036060830152615efc81856146b5565b90508181036080830152615f108184615bfc565b90509695505050505050565b600060a082019050615f316000830188613e99565b615f3e6020830187613e99565b615f4b6040830186613e99565b615f586060830185613e6f565b615f656080830184613e6f565b969550505050505056fea2646970667358221220a55f03d6d0379b077f4adb8f38cac5a70672968443a0e594956222668aa2cb6a64736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000006ff5104460c815c838b8dbe9e93c3ce17a2528bd00000000000000000000000000000000000000000000000000000000000001f4
-----Decoded View---------------
Arg [0] : royaltyReceiver (address): 0x6Ff5104460c815C838b8dBe9E93c3ce17A2528bd
Arg [1] : royaltyFeeNumerator (uint96): 500
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000006ff5104460c815c838b8dbe9e93c3ce17a2528bd
Arg [1] : 00000000000000000000000000000000000000000000000000000000000001f4
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.