Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- NFTMarketOffers
- Optimization enabled
- false
- Compiler version
- v0.8.6+commit.11564f7e
- EVM Version
- default
- Verified at
- 2023-06-16T12:31:25.153423Z
Constructor Arguments
0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cdba97dc6c7e9609512d79d88f5ec6c4d2857637
src/NFTMarketOffers.sol
// SPDX-License-Identifier: MIT
// Used as some other regular ERC20 token in unit tests
pragma solidity ^0.8.6;
import './MarketTools.sol';
/**
* @title Marketplace contract for arbitrary offers for NFTs
*/
contract NFTMarketOffers is MarketTools {
using Counters for Counters.Counter;
using ERC165Checker for address;
mapping(uint256 => Offer) public offers;
Counters.Counter private _offerIds;
struct Offer {
address offerer;
address nftContract;
uint256 tokenId;
uint256 quantity;
address erc20Address;
uint256 singleOfferPrice;
uint256 deadline;
}
event OfferCreated(uint256 indexed offerId);
event OfferAccepted(uint256 indexed offerId, uint256 acceptQuantity);
event OfferCancelled(uint256 indexed offerId);
/**
* @dev Initializes the contract
* @param erc20TokenAddresses List of ERC20 tokens to be whitelisted initially
*/
constructor(address[] memory erc20TokenAddresses)
MarketTools(erc20TokenAddresses)
{}
/**
* @dev Makes an offer on an arbitrary NFT
* @param nftContract Address of the NFT contract
* @param tokenId Token ID of the NFT
* @param quantity Number of NFTs to make an offer on (always 1 for ERC-721)
* @param offerERC20Address Address of the ERC20 used for pricing
* @param singleOfferPrice Offered price for buying a single NFT
* @param offerDeadline Timestamp when the offer is no longer valid
*/
function offerOnNft(
address nftContract,
uint256 tokenId,
uint256 quantity,
address offerERC20Address,
uint256 singleOfferPrice,
uint256 offerDeadline
) external whenNotPaused {
require(whitelistedERC20[offerERC20Address], 'Invalid price token');
uint256 givenAllowance = IERC20(offerERC20Address).allowance(
msg.sender,
address(this)
);
require(
givenAllowance >= singleOfferPrice * quantity,
'Not enough allowance'
);
require(singleOfferPrice > 0, 'Must offer something');
require(offerDeadline > block.timestamp, 'Deadline must be in the future');
require(quantity > 0, 'Must offer on some amount of NFTs');
require(
!is721Type(nftContract) || quantity == 1,
'ERC-721 can have only quantity of 1'
);
_offerIds.increment();
uint256 offerId = _offerIds.current();
Offer memory offer = Offer(
msg.sender,
nftContract,
tokenId,
quantity,
offerERC20Address,
singleOfferPrice,
offerDeadline
);
offers[offerId] = offer;
emit OfferCreated(offerId);
}
/**
* @dev Accepts a previously made offer fully or partially
* @param offerId ID of the offer
* @param acceptQuantity How many NFTs to sell
*/
function acceptOffer(uint256 offerId, uint256 acceptQuantity)
external
whenNotPaused
{
Offer storage offer = offers[offerId];
require(offer.offerer != address(0x0), 'No offer found');
uint256 givenAllowance = IERC20(offer.erc20Address).allowance(
offer.offerer,
address(this)
);
require(
givenAllowance >= offer.singleOfferPrice * acceptQuantity,
'Not enough allowance'
);
require(block.timestamp < offer.deadline, 'The offer has expired');
require(acceptQuantity > 0, 'Should accept something');
require(offer.quantity >= acceptQuantity, 'Offer quantity exhausted');
// Check that the seller has enough of the NFT
if (is721Type(offer.nftContract)) {
address nftOwner = IERC721(offer.nftContract).ownerOf(offer.tokenId);
require(nftOwner == msg.sender, 'Only owner can accept offer');
} else {
uint256 senderBalance = IERC1155(offer.nftContract).balanceOf(
msg.sender,
offer.tokenId
);
require(senderBalance >= acceptQuantity, 'Not enough balance');
}
offer.quantity -= acceptQuantity;
uint256 commission = getPriceAfterPercent(
offer.singleOfferPrice,
acceptQuantity,
commissionPercent
);
// Transfers royalty
uint256 royalty = handleErc20Royalty(
offer.nftContract,
offer.tokenId,
offer.erc20Address,
offer.offerer,
acceptQuantity * offer.singleOfferPrice
);
// Transfers price
IERC20(offer.erc20Address).transferFrom(
offer.offerer,
msg.sender,
acceptQuantity * offer.singleOfferPrice - commission - royalty
);
// Transfers commission
IERC20(offer.erc20Address).transferFrom(offer.offerer, owner(), commission);
// transfer the nfts from owner to offerer
transferNFT(
offer.nftContract,
msg.sender,
offer.offerer,
offer.tokenId,
acceptQuantity
);
emit OfferAccepted(offerId, acceptQuantity);
}
/**
* @dev Cancels a previously made offer
* @param offerId ID of the offer
*/
function cancelOffer(uint256 offerId) external whenNotPaused {
Offer storage offer = offers[offerId];
require(offer.offerer != address(0x0), 'No offer found');
require(offer.offerer == msg.sender, 'Only offerer can cancel');
require(offer.quantity > 0, 'Nothing to cancel');
offer.quantity = 0;
emit OfferCancelled(offerId);
}
}
@openzeppelin/contracts/access/Ownable.sol
// 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);
}
}
@openzeppelin/contracts/interfaces/IERC2981.sol
// 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);
}
@openzeppelin/contracts/security/Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
@openzeppelin/contracts/token/ERC1155/ERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.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 nor 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 nor 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;
}
}
@openzeppelin/contracts/token/ERC1155/IERC1155.sol
// 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;
}
@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol
// 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);
}
@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol
// 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);
}
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
@openzeppelin/contracts/token/ERC721/IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
@openzeppelin/contracts/utils/Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.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 functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
@openzeppelin/contracts/utils/Context.sol
// 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;
}
}
@openzeppelin/contracts/utils/Counters.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)
pragma solidity ^0.8.0;
/**
* @title Counters
* @author Matt Condon (@shrugs)
* @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
* of elements in a mapping, issuing ERC721 ids, or counting request ids.
*
* Include with `using Counters for Counters.Counter;`
*/
library Counters {
struct Counter {
// This variable should never be directly accessed by users of the library: interactions must be restricted to
// the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
// this feature: see https://github.com/ethereum/solidity/issues/4637
uint256 _value; // default: 0
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
unchecked {
counter._value += 1;
}
}
function decrement(Counter storage counter) internal {
uint256 value = counter._value;
require(value > 0, "Counter: decrement overflow");
unchecked {
counter._value = value - 1;
}
}
function reset(Counter storage counter) internal {
counter._value = 0;
}
}
@openzeppelin/contracts/utils/introspection/ERC165.sol
// 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;
}
}
@openzeppelin/contracts/utils/introspection/ERC165Checker.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Checker.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Library used to query support of an interface declared via {IERC165}.
*
* Note that these functions return the actual result of the query: they do not
* `revert` if an interface is not supported. It is up to the caller to decide
* what to do in these cases.
*/
library ERC165Checker {
// As per the EIP-165 spec, no interface should ever match 0xffffffff
bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
/**
* @dev Returns true if `account` supports the {IERC165} interface,
*/
function supportsERC165(address account) internal view returns (bool) {
// Any contract that implements ERC165 must explicitly indicate support of
// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
return
_supportsERC165Interface(account, type(IERC165).interfaceId) &&
!_supportsERC165Interface(account, _INTERFACE_ID_INVALID);
}
/**
* @dev Returns true if `account` supports the interface defined by
* `interfaceId`. Support for {IERC165} itself is queried automatically.
*
* See {IERC165-supportsInterface}.
*/
function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
// query support of both ERC165 as per the spec and support of _interfaceId
return supportsERC165(account) && _supportsERC165Interface(account, interfaceId);
}
/**
* @dev Returns a boolean array where each value corresponds to the
* interfaces passed in and whether they're supported or not. This allows
* you to batch check interfaces for a contract where your expectation
* is that some interfaces may not be supported.
*
* See {IERC165-supportsInterface}.
*
* _Available since v3.4._
*/
function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)
internal
view
returns (bool[] memory)
{
// an array of booleans corresponding to interfaceIds and whether they're supported or not
bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
// query support of ERC165 itself
if (supportsERC165(account)) {
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]);
}
}
return interfaceIdsSupported;
}
/**
* @dev Returns true if `account` supports all the interfaces defined in
* `interfaceIds`. Support for {IERC165} itself is queried automatically.
*
* Batch-querying can lead to gas savings by skipping repeated checks for
* {IERC165} support.
*
* See {IERC165-supportsInterface}.
*/
function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
// query support of ERC165 itself
if (!supportsERC165(account)) {
return false;
}
// query support of each interface in _interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
if (!_supportsERC165Interface(account, interfaceIds[i])) {
return false;
}
}
// all interfaces supported
return true;
}
/**
* @notice Query if a contract implements an interface, does not check ERC165 support
* @param account The address of the contract to query for support of an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @return true if the contract at account indicates support of the interface with
* identifier interfaceId, false otherwise
* @dev Assumes that account contains a contract that supports ERC165, otherwise
* the behavior of this method is undefined. This precondition can be checked
* with {supportsERC165}.
* Interface identification is specified in ERC-165.
*/
function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {
bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);
(bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams);
if (result.length < 32) return false;
return success && abi.decode(result, (bool));
}
}
@openzeppelin/contracts/utils/introspection/IERC165.sol
// 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);
}
src/IPartialNFT.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
interface IPartialNFT {
function isApprovedForAll(address account, address operator)
external
view
returns (bool);
}
src/MarketTools.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
import '@openzeppelin/contracts/token/ERC1155/ERC1155.sol';
import '@openzeppelin/contracts/token/ERC1155/IERC1155.sol';
import '@openzeppelin/contracts/token/ERC721/IERC721.sol';
import '@openzeppelin/contracts/utils/Counters.sol';
import '@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/security/Pausable.sol';
import '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';
import '@openzeppelin/contracts/interfaces/IERC2981.sol';
import './IPartialNFT.sol';
/**
@title Common functionality for all marketplace contracts
*/
abstract contract MarketTools is Ownable, Pausable {
using Counters for Counters.Counter;
using ERC165Checker for address;
// Amount of tokens a user has for sale, per contract and per tokenId
mapping(address => mapping(address => mapping(uint256 => uint256)))
public userListedTokens;
Counters.Counter internal _listingIds;
// Commission percentage for simple market
uint8 public commissionPercentSimple = 2;
// Commission percentage for auctions and offers sales
uint8 public commissionPercent = 2;
// List of ERC20 token addresses which are allowed to be used
mapping(address => bool) public whitelistedERC20;
bytes4 internal InterfaceId_ERC721 = 0x80ac58cd; // The ERC-165 identifier for 721
bytes4 internal InterfaceId_ERC1155 = 0xd9b67a26; // The ERC-165 identifier for 1155
bytes4 internal InterfaceId_ERC2981 = 0x2a55205a; // The ERC-165 identifier for 2981
/**
* @dev Initializes the contract
* @param erc20TokenAddresses List of ERC20 tokens to be whitelisted initially
*/
constructor(address[] memory erc20TokenAddresses) {
for (uint256 i = 0; i < erc20TokenAddresses.length; i++) {
whitelistedERC20[erc20TokenAddresses[i]] = true;
}
}
/**
* @dev Adds an ERC20 token to the whitelist
* @param erc20TokenAddress The address of the token
*/
function addToWhitelist(address erc20TokenAddress) public onlyOwner {
whitelistedERC20[erc20TokenAddress] = true;
}
/**
* @dev Removes an ERC20 token from the whitelist
* @param erc20TokenAddress The address of the token
*/
function removeFromWhitelist(address erc20TokenAddress) public onlyOwner {
whitelistedERC20[erc20TokenAddress] = false;
}
/**
* @dev Gets the latest listingId used in the contract
* @return uint256 listingId
*/
function getLatestListItemId() public view returns (uint256) {
return _listingIds.current();
}
/**
* @dev Returns the price after the given percentage has been deducted
* @param price The original price
* @param quantity How many times the price should be used
* @param percent How big percentage should be deducted
*/
function getPriceAfterPercent(
uint256 price,
uint256 quantity,
uint256 percent
) public pure returns (uint256) {
uint256 _percent = percent;
return ((price * quantity) * _percent) / 100;
}
/**
* @dev Makes sure the sender has given allowance for this contract to manage their NFTs
* @param nftContract Address of the NFT contract for which to check for allowance
*/
function checkNFTAllowance(address nftContract) internal view {
// Make sure the owner has given allowance
bool givenAllowance = IPartialNFT(nftContract).isApprovedForAll(
msg.sender,
address(this)
);
require(givenAllowance, 'Not allowed to manage tokens');
}
/**
* @dev Checks how many NFTs the given owner has
* @param nftContract Address of the NFT contract for which to check for allowance
* @param tokenId Which NFT token ID to check
* @param nftOwner Address of the owner
* @return uint256 The amount of NFTs the owner has. For ERC721, this is always 0 or 1.
*/
function getNFTOwnerAmount(
address nftContract,
uint256 tokenId,
address nftOwner
) internal view returns (uint256) {
if (is721Type(nftContract)) {
return IERC721(nftContract).ownerOf(tokenId) == nftOwner ? 1 : 0;
} else {
return IERC1155(nftContract).balanceOf(nftOwner, tokenId);
}
}
/**
* @dev Transfers an NFT
* @param nftContract Address of the NFT contract
* @param sender Sender of the NFT
* @param receiver Receiver of the NFT
* @param nftTokenId NFT token ID
* @param amount How many NFTs to transfer
*/
function transferNFT(
address nftContract,
address sender,
address receiver,
uint256 nftTokenId,
uint256 amount
) internal {
if (is721Type(nftContract)) {
IERC721(nftContract).safeTransferFrom(sender, receiver, nftTokenId);
} else {
IERC1155(nftContract).safeTransferFrom(
sender,
receiver,
nftTokenId,
amount,
''
);
}
}
/**
* @dev Checks the type of the given NFT. Reverts if it's not supported
* @param addr Address of the NFT contract
* @return bool true if it's ERC721, false if ERC1155
*/
function is721Type(address addr) internal view returns (bool) {
if (addr.supportsInterface(InterfaceId_ERC721)) {
return true;
} else if (addr.supportsInterface(InterfaceId_ERC1155)) {
return false;
} else {
revert('Not supported');
}
}
/**
* @dev Sends out royalties for ERC20 priced sales if the NFT supports royalties
* @param nftContract The NFT contract address
* @param tokenId NFT token ID
* @param priceTokenAddress The ERC20 token contract address
* @param royaltyFrom From which address to take the ERC20 tokens for royalty
* @param price Sale price, from which the royalty is to be calculated
* @return royalty The calculated and transferred royalty
*/
function handleErc20Royalty(
address nftContract,
uint256 tokenId,
address priceTokenAddress,
address royaltyFrom,
uint256 price
) internal returns (uint256 royalty) {
if (nftContract.supportsInterface(InterfaceId_ERC2981)) {
(address receiver, uint256 royaltyAmount) = IERC2981(nftContract)
.royaltyInfo(tokenId, price);
if (receiver != address(0x0) && royaltyAmount > 0) {
IERC20(priceTokenAddress).transferFrom(
royaltyFrom,
receiver,
royaltyAmount
);
return royaltyAmount;
}
}
return 0;
}
function pause() external onlyOwner {
_pause();
}
function unpause() external onlyOwner {
_unpause();
}
function setCommisionPercent(uint8 percent) external onlyOwner {
require(percent >= 0, "Service fee cannot be negative");
require(percent <= 5, "Service fee cannot be bigger than 5");
commissionPercent = percent;
}
function setSimpleCommisionPercent(uint8 percent) external onlyOwner {
require(percent >= 0, "Service fee cannot be negative");
require(percent <= 5, "Service fee cannot be bigger than 5");
commissionPercentSimple = percent;
}
}
Compiler Settings
{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers"]}},"optimizer":{"runs":200,"enabled":false},"libraries":{}}
Contract ABI
[{"type":"constructor","inputs":[{"type":"address[]","name":"erc20TokenAddresses","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"acceptOffer","inputs":[{"type":"uint256","name":"offerId","internalType":"uint256"},{"type":"uint256","name":"acceptQuantity","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addToWhitelist","inputs":[{"type":"address","name":"erc20TokenAddress","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelOffer","inputs":[{"type":"uint256","name":"offerId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"commissionPercent","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"commissionPercentSimple","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getLatestListItemId","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getPriceAfterPercent","inputs":[{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"uint256","name":"percent","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"offerOnNft","inputs":[{"type":"address","name":"nftContract","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"address","name":"offerERC20Address","internalType":"address"},{"type":"uint256","name":"singleOfferPrice","internalType":"uint256"},{"type":"uint256","name":"offerDeadline","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"offerer","internalType":"address"},{"type":"address","name":"nftContract","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"quantity","internalType":"uint256"},{"type":"address","name":"erc20Address","internalType":"address"},{"type":"uint256","name":"singleOfferPrice","internalType":"uint256"},{"type":"uint256","name":"deadline","internalType":"uint256"}],"name":"offers","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"pause","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"paused","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeFromWhitelist","inputs":[{"type":"address","name":"erc20TokenAddress","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setCommisionPercent","inputs":[{"type":"uint8","name":"percent","internalType":"uint8"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setSimpleCommisionPercent","inputs":[{"type":"uint8","name":"percent","internalType":"uint8"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unpause","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"userListedTokens","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"whitelistedERC20","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"event","name":"OfferAccepted","inputs":[{"type":"uint256","name":"offerId","indexed":true},{"type":"uint256","name":"acceptQuantity","indexed":false}],"anonymous":false},{"type":"event","name":"OfferCancelled","inputs":[{"type":"uint256","name":"offerId","indexed":true}],"anonymous":false},{"type":"event","name":"OfferCreated","inputs":[{"type":"uint256","name":"offerId","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":true},{"type":"address","name":"newOwner","indexed":true}],"anonymous":false},{"type":"event","name":"Paused","inputs":[{"type":"address","name":"account","indexed":false}],"anonymous":false},{"type":"event","name":"Unpaused","inputs":[{"type":"address","name":"account","indexed":false}],"anonymous":false}]
Contract Creation Code
0x60806040526002600360006101000a81548160ff021916908360ff1602179055506002600360016101000a81548160ff021916908360ff1602179055506380ac58cd60e01b600560006101000a81548163ffffffff021916908360e01c021790555063d9b67a2660e01b600560046101000a81548163ffffffff021916908360e01c0217905550632a55205a60e01b600560086101000a81548163ffffffff021916908360e01c0217905550348015620000b857600080fd5b5060405162003611380380620036118339818101604052810190620000de91906200034b565b80620000ff620000f3620001ba60201b60201c565b620001c260201b60201c565b60008060146101000a81548160ff02191690831515021790555060005b8151811015620001b157600160046000848481518110620001425762000141620004e5565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508080620001a89062000468565b9150506200011c565b50505062000582565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60006200029d6200029784620003c5565b6200039c565b90508083825260208201905082856020860282011115620002c357620002c262000548565b5b60005b85811015620002f75781620002dc888262000301565b845260208401935060208301925050600181019050620002c6565b5050509392505050565b600081519050620003128162000568565b92915050565b600082601f83011262000330576200032f62000543565b5b81516200034284826020860162000286565b91505092915050565b60006020828403121562000364576200036362000552565b5b600082015167ffffffffffffffff8111156200038557620003846200054d565b5b620003938482850162000318565b91505092915050565b6000620003a8620003bb565b9050620003b6828262000432565b919050565b6000604051905090565b600067ffffffffffffffff821115620003e357620003e262000514565b5b602082029050602081019050919050565b6000620004018262000408565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6200043d8262000557565b810181811067ffffffffffffffff821117156200045f576200045e62000514565b5b80604052505050565b6000620004758262000428565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415620004ab57620004aa620004b6565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b6200057381620003f4565b81146200057f57600080fd5b50565b61307f80620005926000396000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c80638a72ea6a116100ad578063b65fbaf711610071578063b65fbaf7146102ff578063c46968b91461031b578063e43252d714610337578063ef706adf14610353578063f2fde38b1461036f5761012c565b80638a72ea6a1461022f5780638ab1d681146102655780638da5cb5b14610281578063992cfdc31461029f578063b370fa71146102cf5761012c565b80636ebd7ea5116100f45780636ebd7ea5146101c5578063715018a6146101e157806377d3550b146101eb57806381257bd5146102095780638456cb59146102255761012c565b80630eb06ff114610131578063367005021461014f5780633f4ba83a1461017f57806347ba713a146101895780635c975abb146101a7575b600080fd5b61013961038b565b6040516101469190612988565b60405180910390f35b61016960048036038101906101649190611ef1565b61039c565b60405161017691906126b2565b60405180910390f35b6101876103bc565b005b6101916103ce565b60405161019e91906129cc565b60405180910390f35b6101af6103e1565b6040516101bc91906126b2565b60405180910390f35b6101df60048036038101906101da9190612185565b6103f7565b005b6101e96104ab565b005b6101f36104bf565b60405161020091906129cc565b60405180910390f35b610223600480360381019061021e91906120f2565b6104d2565b005b61022d610d19565b005b61024960048036038101906102449190612098565b610d2b565b60405161025c97969594939291906125c2565b60405180910390f35b61027f600480360381019061027a9190611ef1565b610dcd565b005b610289610e30565b6040516102969190612547565b60405180910390f35b6102b960048036038101906102b49190612132565b610e59565b6040516102c69190612988565b60405180910390f35b6102e960048036038101906102e49190611f4b565b610e8c565b6040516102f69190612988565b60405180910390f35b61031960048036038101906103149190611fde565b610ebe565b005b61033560048036038101906103309190612185565b611328565b005b610351600480360381019061034c9190611ef1565b6113dc565b005b61036d60048036038101906103689190612098565b61143f565b005b61038960048036038101906103849190611ef1565b611606565b005b6000610397600261168a565b905090565b60046020528060005260406000206000915054906101000a900460ff1681565b6103c4611698565b6103cc611716565b565b600360009054906101000a900460ff1681565b60008060149054906101000a900460ff16905090565b6103ff611698565b60008160ff161015610446576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043d906127a8565b60405180910390fd5b60058160ff16111561048d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161048490612788565b60405180910390fd5b80600360016101000a81548160ff021916908360ff16021790555050565b6104b3611698565b6104bd6000611778565b565b600360019054906101000a900460ff1681565b6104da61183c565b6000600660008481526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff168160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610585576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161057c90612728565b60405180910390fd5b60008160040160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e8360000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16306040518363ffffffff1660e01b815260040161060a929190612562565b60206040518083038186803b15801561062257600080fd5b505afa158015610636573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061065a91906120c5565b905082826005015461066c9190612a50565b8110156106ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106a590612888565b60405180910390fd5b816006015442106106f4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106eb90612968565b60405180910390fd5b60008311610737576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072e90612828565b60405180910390fd5b828260030154101561077e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161077590612928565b60405180910390fd5b6107ab8260010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611886565b156108d95760008260010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636352211e84600201546040518263ffffffff1660e01b81526004016108139190612988565b60206040518083038186803b15801561082b57600080fd5b505afa15801561083f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108639190611f1e565b90503373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146108d3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108ca906128a8565b60405180910390fd5b506109d4565b60008260010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1662fdd58e3385600201546040518363ffffffff1660e01b815260040161093d929190612689565b60206040518083038186803b15801561095557600080fd5b505afa158015610969573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098d91906120c5565b9050838110156109d2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109c9906127e8565b60405180910390fd5b505b828260030160008282546109e89190612aaa565b925050819055506000610a12836005015485600360019054906101000a900460ff1660ff16610e59565b90506000610aa28460010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1685600201548660040160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168760000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1688600501548a610a9d9190612a50565b611954565b90508360040160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd8560000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1633848689600501548b610b1c9190612a50565b610b269190612aaa565b610b309190612aaa565b6040518463ffffffff1660e01b8152600401610b4e9392919061258b565b602060405180830381600087803b158015610b6857600080fd5b505af1158015610b7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba0919061206b565b508360040160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd8560000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16610c0e610e30565b856040518463ffffffff1660e01b8152600401610c2d9392919061258b565b602060405180830381600087803b158015610c4757600080fd5b505af1158015610c5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7f919061206b565b50610cd98460010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16338660000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16876002015489611b11565b857f397f87b3946767b09967764d50032941de13a2606bcb39dfed61d7b1ed0192cc86604051610d099190612988565b60405180910390a2505050505050565b610d21611698565b610d29611c0c565b565b60066020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020154908060030154908060040160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060050154908060060154905087565b610dd5611698565b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000808290506064818587610e6e9190612a50565b610e789190612a50565b610e829190612a1f565b9150509392505050565b600160205282600052604060002060205281600052604060002060205280600052604060002060009250925050505481565b610ec661183c565b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610f52576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f4990612708565b60405180910390fd5b60008373ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff1660e01b8152600401610f8f929190612562565b60206040518083038186803b158015610fa757600080fd5b505afa158015610fbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fdf91906120c5565b90508483610fed9190612a50565b81101561102f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161102690612888565b60405180910390fd5b60008311611072576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161106990612768565b60405180910390fd5b4282116110b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110ab906128e8565b60405180910390fd5b600085116110f7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110ee90612848565b60405180910390fd5b61110087611886565b158061110c5750600185145b61114b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161114290612908565b60405180910390fd5b6111556007611c6f565b6000611161600761168a565b905060006040518060e001604052803373ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018881526020018773ffffffffffffffffffffffffffffffffffffffff168152602001868152602001858152509050806006600084815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550604082015181600201556060820151816003015560808201518160040160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a0820151816005015560c08201518160060155905050817f682fd9923da5632e7c7702dabcfa626195d5f444833bc25f94e418e258e7918660405160405180910390a2505050505050505050565b611330611698565b60008160ff161015611377576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161136e906127a8565b60405180910390fd5b60058160ff1611156113be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113b590612788565b60405180910390fd5b80600360006101000a81548160ff021916908360ff16021790555050565b6113e4611698565b6001600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b61144761183c565b6000600660008381526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff168160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156114f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114e990612728565b60405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff168160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611584576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161157b906128c8565b60405180910390fd5b60008160030154116115cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115c2906127c8565b60405180910390fd5b60008160030181905550817fc28b4aed030bfacc245c0501326e1beb8c0ef0d60e4edc21067fdeb52da2a7aa60405160405180910390a25050565b61160e611698565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561167e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161167590612748565b60405180910390fd5b61168781611778565b50565b600081600001549050919050565b6116a0611c85565b73ffffffffffffffffffffffffffffffffffffffff166116be610e30565b73ffffffffffffffffffffffffffffffffffffffff1614611714576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161170b90612868565b60405180910390fd5b565b61171e611c8d565b60008060146101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa611761611c85565b60405161176e9190612547565b60405180910390a1565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6118446103e1565b15611884576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161187b90612808565b60405180910390fd5b565b60006118c0600560009054906101000a900460e01b8373ffffffffffffffffffffffffffffffffffffffff16611cd690919063ffffffff16565b156118ce576001905061194f565b611906600560049054906101000a900460e01b8373ffffffffffffffffffffffffffffffffffffffff16611cd690919063ffffffff16565b15611914576000905061194f565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161194690612948565b60405180910390fd5b919050565b600061198e600560089054906101000a900460e01b8773ffffffffffffffffffffffffffffffffffffffff16611cd690919063ffffffff16565b15611b03576000808773ffffffffffffffffffffffffffffffffffffffff16632a55205a88866040518363ffffffff1660e01b81526004016119d19291906129a3565b604080518083038186803b1580156119e857600080fd5b505afa1580156119fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a209190611f9e565b91509150600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015611a615750600081115b15611b00578573ffffffffffffffffffffffffffffffffffffffff166323b872dd8684846040518463ffffffff1660e01b8152600401611aa39392919061258b565b602060405180830381600087803b158015611abd57600080fd5b505af1158015611ad1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af5919061206b565b508092505050611b08565b50505b600090505b95945050505050565b611b1a85611886565b15611b93578473ffffffffffffffffffffffffffffffffffffffff166342842e0e8585856040518463ffffffff1660e01b8152600401611b5c9392919061258b565b600060405180830381600087803b158015611b7657600080fd5b505af1158015611b8a573d6000803e3d6000fd5b50505050611c05565b8473ffffffffffffffffffffffffffffffffffffffff1663f242432a858585856040518563ffffffff1660e01b8152600401611bd29493929190612631565b600060405180830381600087803b158015611bec57600080fd5b505af1158015611c00573d6000803e3d6000fd5b505050505b5050505050565b611c1461183c565b6001600060146101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611c58611c85565b604051611c659190612547565b60405180910390a1565b6001816000016000828254019250508190555050565b600033905090565b611c956103e1565b611cd4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ccb906126e8565b60405180910390fd5b565b6000611ce183611cfb565b8015611cf35750611cf28383611d48565b5b905092915050565b6000611d27827f01ffc9a700000000000000000000000000000000000000000000000000000000611d48565b8015611d415750611d3f8263ffffffff60e01b611d48565b155b9050919050565b6000806301ffc9a760e01b83604051602401611d6491906126cd565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000808573ffffffffffffffffffffffffffffffffffffffff1661753084604051611dee9190612530565b6000604051808303818686fa925050503d8060008114611e2a576040519150601f19603f3d011682016040523d82523d6000602084013e611e2f565b606091505b5091509150602081511015611e4a5760009350505050611e6d565b818015611e67575080806020019051810190611e66919061206b565b5b93505050505b92915050565b600081359050611e8281612fed565b92915050565b600081519050611e9781612fed565b92915050565b600081519050611eac81613004565b92915050565b600081359050611ec18161301b565b92915050565b600081519050611ed68161301b565b92915050565b600081359050611eeb81613032565b92915050565b600060208284031215611f0757611f06612bf0565b5b6000611f1584828501611e73565b91505092915050565b600060208284031215611f3457611f33612bf0565b5b6000611f4284828501611e88565b91505092915050565b600080600060608486031215611f6457611f63612bf0565b5b6000611f7286828701611e73565b9350506020611f8386828701611e73565b9250506040611f9486828701611eb2565b9150509250925092565b60008060408385031215611fb557611fb4612bf0565b5b6000611fc385828601611e88565b9250506020611fd485828601611ec7565b9150509250929050565b60008060008060008060c08789031215611ffb57611ffa612bf0565b5b600061200989828a01611e73565b965050602061201a89828a01611eb2565b955050604061202b89828a01611eb2565b945050606061203c89828a01611e73565b935050608061204d89828a01611eb2565b92505060a061205e89828a01611eb2565b9150509295509295509295565b60006020828403121561208157612080612bf0565b5b600061208f84828501611e9d565b91505092915050565b6000602082840312156120ae576120ad612bf0565b5b60006120bc84828501611eb2565b91505092915050565b6000602082840312156120db576120da612bf0565b5b60006120e984828501611ec7565b91505092915050565b6000806040838503121561210957612108612bf0565b5b600061211785828601611eb2565b925050602061212885828601611eb2565b9150509250929050565b60008060006060848603121561214b5761214a612bf0565b5b600061215986828701611eb2565b935050602061216a86828701611eb2565b925050604061217b86828701611eb2565b9150509250925092565b60006020828403121561219b5761219a612bf0565b5b60006121a984828501611edc565b91505092915050565b6121bb81612ade565b82525050565b6121ca81612af0565b82525050565b6121d981612afc565b82525050565b60006121ea826129e7565b6121f48185612a03565b9350612204818560208601612b5f565b80840191505092915050565b600061221d601483612a0e565b915061222882612bf5565b602082019050919050565b6000612240601383612a0e565b915061224b82612c1e565b602082019050919050565b6000612263600e83612a0e565b915061226e82612c47565b602082019050919050565b6000612286602683612a0e565b915061229182612c70565b604082019050919050565b60006122a9601483612a0e565b91506122b482612cbf565b602082019050919050565b60006122cc602383612a0e565b91506122d782612ce8565b604082019050919050565b60006122ef601e83612a0e565b91506122fa82612d37565b602082019050919050565b6000612312601183612a0e565b915061231d82612d60565b602082019050919050565b6000612335601283612a0e565b915061234082612d89565b602082019050919050565b6000612358601083612a0e565b915061236382612db2565b602082019050919050565b600061237b601783612a0e565b915061238682612ddb565b602082019050919050565b600061239e602183612a0e565b91506123a982612e04565b604082019050919050565b60006123c1602083612a0e565b91506123cc82612e53565b602082019050919050565b60006123e4601483612a0e565b91506123ef82612e7c565b602082019050919050565b6000612407601b83612a0e565b915061241282612ea5565b602082019050919050565b600061242a601783612a0e565b915061243582612ece565b602082019050919050565b600061244d6000836129f2565b915061245882612ef7565b600082019050919050565b6000612470601e83612a0e565b915061247b82612efa565b602082019050919050565b6000612493602383612a0e565b915061249e82612f23565b604082019050919050565b60006124b6601883612a0e565b91506124c182612f72565b602082019050919050565b60006124d9600d83612a0e565b91506124e482612f9b565b602082019050919050565b60006124fc601583612a0e565b915061250782612fc4565b602082019050919050565b61251b81612b48565b82525050565b61252a81612b52565b82525050565b600061253c82846121df565b915081905092915050565b600060208201905061255c60008301846121b2565b92915050565b600060408201905061257760008301856121b2565b61258460208301846121b2565b9392505050565b60006060820190506125a060008301866121b2565b6125ad60208301856121b2565b6125ba6040830184612512565b949350505050565b600060e0820190506125d7600083018a6121b2565b6125e460208301896121b2565b6125f16040830188612512565b6125fe6060830187612512565b61260b60808301866121b2565b61261860a0830185612512565b61262560c0830184612512565b98975050505050505050565b600060a08201905061264660008301876121b2565b61265360208301866121b2565b6126606040830185612512565b61266d6060830184612512565b818103608083015261267e81612440565b905095945050505050565b600060408201905061269e60008301856121b2565b6126ab6020830184612512565b9392505050565b60006020820190506126c760008301846121c1565b92915050565b60006020820190506126e260008301846121d0565b92915050565b6000602082019050818103600083015261270181612210565b9050919050565b6000602082019050818103600083015261272181612233565b9050919050565b6000602082019050818103600083015261274181612256565b9050919050565b6000602082019050818103600083015261276181612279565b9050919050565b600060208201905081810360008301526127818161229c565b9050919050565b600060208201905081810360008301526127a1816122bf565b9050919050565b600060208201905081810360008301526127c1816122e2565b9050919050565b600060208201905081810360008301526127e181612305565b9050919050565b6000602082019050818103600083015261280181612328565b9050919050565b600060208201905081810360008301526128218161234b565b9050919050565b600060208201905081810360008301526128418161236e565b9050919050565b6000602082019050818103600083015261286181612391565b9050919050565b60006020820190508181036000830152612881816123b4565b9050919050565b600060208201905081810360008301526128a1816123d7565b9050919050565b600060208201905081810360008301526128c1816123fa565b9050919050565b600060208201905081810360008301526128e18161241d565b9050919050565b6000602082019050818103600083015261290181612463565b9050919050565b6000602082019050818103600083015261292181612486565b9050919050565b60006020820190508181036000830152612941816124a9565b9050919050565b60006020820190508181036000830152612961816124cc565b9050919050565b60006020820190508181036000830152612981816124ef565b9050919050565b600060208201905061299d6000830184612512565b92915050565b60006040820190506129b86000830185612512565b6129c56020830184612512565b9392505050565b60006020820190506129e16000830184612521565b92915050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b6000612a2a82612b48565b9150612a3583612b48565b925082612a4557612a44612bc1565b5b828204905092915050565b6000612a5b82612b48565b9150612a6683612b48565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612a9f57612a9e612b92565b5b828202905092915050565b6000612ab582612b48565b9150612ac083612b48565b925082821015612ad357612ad2612b92565b5b828203905092915050565b6000612ae982612b28565b9050919050565b60008115159050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b60005b83811015612b7d578082015181840152602081019050612b62565b83811115612b8c576000848401525b50505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600080fd5b7f5061757361626c653a206e6f7420706175736564000000000000000000000000600082015250565b7f496e76616c696420707269636520746f6b656e00000000000000000000000000600082015250565b7f4e6f206f6666657220666f756e64000000000000000000000000000000000000600082015250565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b7f4d757374206f6666657220736f6d657468696e67000000000000000000000000600082015250565b7f53657276696365206665652063616e6e6f74206265206269676765722074686160008201527f6e20350000000000000000000000000000000000000000000000000000000000602082015250565b7f53657276696365206665652063616e6e6f74206265206e656761746976650000600082015250565b7f4e6f7468696e6720746f2063616e63656c000000000000000000000000000000600082015250565b7f4e6f7420656e6f7567682062616c616e63650000000000000000000000000000600082015250565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b7f53686f756c642061636365707420736f6d657468696e67000000000000000000600082015250565b7f4d757374206f66666572206f6e20736f6d6520616d6f756e74206f66204e465460008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b7f4e6f7420656e6f75676820616c6c6f77616e6365000000000000000000000000600082015250565b7f4f6e6c79206f776e65722063616e20616363657074206f666665720000000000600082015250565b7f4f6e6c79206f6666657265722063616e2063616e63656c000000000000000000600082015250565b50565b7f446561646c696e65206d75737420626520696e20746865206675747572650000600082015250565b7f4552432d3732312063616e2068617665206f6e6c79207175616e74697479206f60008201527f6620310000000000000000000000000000000000000000000000000000000000602082015250565b7f4f66666572207175616e74697479206578686175737465640000000000000000600082015250565b7f4e6f7420737570706f7274656400000000000000000000000000000000000000600082015250565b7f546865206f666665722068617320657870697265640000000000000000000000600082015250565b612ff681612ade565b811461300157600080fd5b50565b61300d81612af0565b811461301857600080fd5b50565b61302481612b48565b811461302f57600080fd5b50565b61303b81612b52565b811461304657600080fd5b5056fea2646970667358221220399d432edfb584a163434710f43d10a28a32a65bfae79ce383a15195a7e267a864736f6c6343000806003300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cdba97dc6c7e9609512d79d88f5ec6c4d2857637
Deployed ByteCode
0x608060405234801561001057600080fd5b506004361061012c5760003560e01c80638a72ea6a116100ad578063b65fbaf711610071578063b65fbaf7146102ff578063c46968b91461031b578063e43252d714610337578063ef706adf14610353578063f2fde38b1461036f5761012c565b80638a72ea6a1461022f5780638ab1d681146102655780638da5cb5b14610281578063992cfdc31461029f578063b370fa71146102cf5761012c565b80636ebd7ea5116100f45780636ebd7ea5146101c5578063715018a6146101e157806377d3550b146101eb57806381257bd5146102095780638456cb59146102255761012c565b80630eb06ff114610131578063367005021461014f5780633f4ba83a1461017f57806347ba713a146101895780635c975abb146101a7575b600080fd5b61013961038b565b6040516101469190612988565b60405180910390f35b61016960048036038101906101649190611ef1565b61039c565b60405161017691906126b2565b60405180910390f35b6101876103bc565b005b6101916103ce565b60405161019e91906129cc565b60405180910390f35b6101af6103e1565b6040516101bc91906126b2565b60405180910390f35b6101df60048036038101906101da9190612185565b6103f7565b005b6101e96104ab565b005b6101f36104bf565b60405161020091906129cc565b60405180910390f35b610223600480360381019061021e91906120f2565b6104d2565b005b61022d610d19565b005b61024960048036038101906102449190612098565b610d2b565b60405161025c97969594939291906125c2565b60405180910390f35b61027f600480360381019061027a9190611ef1565b610dcd565b005b610289610e30565b6040516102969190612547565b60405180910390f35b6102b960048036038101906102b49190612132565b610e59565b6040516102c69190612988565b60405180910390f35b6102e960048036038101906102e49190611f4b565b610e8c565b6040516102f69190612988565b60405180910390f35b61031960048036038101906103149190611fde565b610ebe565b005b61033560048036038101906103309190612185565b611328565b005b610351600480360381019061034c9190611ef1565b6113dc565b005b61036d60048036038101906103689190612098565b61143f565b005b61038960048036038101906103849190611ef1565b611606565b005b6000610397600261168a565b905090565b60046020528060005260406000206000915054906101000a900460ff1681565b6103c4611698565b6103cc611716565b565b600360009054906101000a900460ff1681565b60008060149054906101000a900460ff16905090565b6103ff611698565b60008160ff161015610446576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043d906127a8565b60405180910390fd5b60058160ff16111561048d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161048490612788565b60405180910390fd5b80600360016101000a81548160ff021916908360ff16021790555050565b6104b3611698565b6104bd6000611778565b565b600360019054906101000a900460ff1681565b6104da61183c565b6000600660008481526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff168160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610585576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161057c90612728565b60405180910390fd5b60008160040160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e8360000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16306040518363ffffffff1660e01b815260040161060a929190612562565b60206040518083038186803b15801561062257600080fd5b505afa158015610636573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061065a91906120c5565b905082826005015461066c9190612a50565b8110156106ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106a590612888565b60405180910390fd5b816006015442106106f4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106eb90612968565b60405180910390fd5b60008311610737576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072e90612828565b60405180910390fd5b828260030154101561077e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161077590612928565b60405180910390fd5b6107ab8260010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611886565b156108d95760008260010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636352211e84600201546040518263ffffffff1660e01b81526004016108139190612988565b60206040518083038186803b15801561082b57600080fd5b505afa15801561083f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108639190611f1e565b90503373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146108d3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108ca906128a8565b60405180910390fd5b506109d4565b60008260010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1662fdd58e3385600201546040518363ffffffff1660e01b815260040161093d929190612689565b60206040518083038186803b15801561095557600080fd5b505afa158015610969573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098d91906120c5565b9050838110156109d2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109c9906127e8565b60405180910390fd5b505b828260030160008282546109e89190612aaa565b925050819055506000610a12836005015485600360019054906101000a900460ff1660ff16610e59565b90506000610aa28460010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1685600201548660040160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168760000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1688600501548a610a9d9190612a50565b611954565b90508360040160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd8560000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1633848689600501548b610b1c9190612a50565b610b269190612aaa565b610b309190612aaa565b6040518463ffffffff1660e01b8152600401610b4e9392919061258b565b602060405180830381600087803b158015610b6857600080fd5b505af1158015610b7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba0919061206b565b508360040160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd8560000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16610c0e610e30565b856040518463ffffffff1660e01b8152600401610c2d9392919061258b565b602060405180830381600087803b158015610c4757600080fd5b505af1158015610c5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7f919061206b565b50610cd98460010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16338660000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16876002015489611b11565b857f397f87b3946767b09967764d50032941de13a2606bcb39dfed61d7b1ed0192cc86604051610d099190612988565b60405180910390a2505050505050565b610d21611698565b610d29611c0c565b565b60066020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020154908060030154908060040160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060050154908060060154905087565b610dd5611698565b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000808290506064818587610e6e9190612a50565b610e789190612a50565b610e829190612a1f565b9150509392505050565b600160205282600052604060002060205281600052604060002060205280600052604060002060009250925050505481565b610ec661183c565b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16610f52576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f4990612708565b60405180910390fd5b60008373ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff1660e01b8152600401610f8f929190612562565b60206040518083038186803b158015610fa757600080fd5b505afa158015610fbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fdf91906120c5565b90508483610fed9190612a50565b81101561102f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161102690612888565b60405180910390fd5b60008311611072576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161106990612768565b60405180910390fd5b4282116110b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110ab906128e8565b60405180910390fd5b600085116110f7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110ee90612848565b60405180910390fd5b61110087611886565b158061110c5750600185145b61114b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161114290612908565b60405180910390fd5b6111556007611c6f565b6000611161600761168a565b905060006040518060e001604052803373ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018881526020018773ffffffffffffffffffffffffffffffffffffffff168152602001868152602001858152509050806006600084815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550604082015181600201556060820151816003015560808201518160040160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a0820151816005015560c08201518160060155905050817f682fd9923da5632e7c7702dabcfa626195d5f444833bc25f94e418e258e7918660405160405180910390a2505050505050505050565b611330611698565b60008160ff161015611377576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161136e906127a8565b60405180910390fd5b60058160ff1611156113be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113b590612788565b60405180910390fd5b80600360006101000a81548160ff021916908360ff16021790555050565b6113e4611698565b6001600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b61144761183c565b6000600660008381526020019081526020016000209050600073ffffffffffffffffffffffffffffffffffffffff168160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156114f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114e990612728565b60405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff168160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611584576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161157b906128c8565b60405180910390fd5b60008160030154116115cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115c2906127c8565b60405180910390fd5b60008160030181905550817fc28b4aed030bfacc245c0501326e1beb8c0ef0d60e4edc21067fdeb52da2a7aa60405160405180910390a25050565b61160e611698565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561167e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161167590612748565b60405180910390fd5b61168781611778565b50565b600081600001549050919050565b6116a0611c85565b73ffffffffffffffffffffffffffffffffffffffff166116be610e30565b73ffffffffffffffffffffffffffffffffffffffff1614611714576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161170b90612868565b60405180910390fd5b565b61171e611c8d565b60008060146101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa611761611c85565b60405161176e9190612547565b60405180910390a1565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6118446103e1565b15611884576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161187b90612808565b60405180910390fd5b565b60006118c0600560009054906101000a900460e01b8373ffffffffffffffffffffffffffffffffffffffff16611cd690919063ffffffff16565b156118ce576001905061194f565b611906600560049054906101000a900460e01b8373ffffffffffffffffffffffffffffffffffffffff16611cd690919063ffffffff16565b15611914576000905061194f565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161194690612948565b60405180910390fd5b919050565b600061198e600560089054906101000a900460e01b8773ffffffffffffffffffffffffffffffffffffffff16611cd690919063ffffffff16565b15611b03576000808773ffffffffffffffffffffffffffffffffffffffff16632a55205a88866040518363ffffffff1660e01b81526004016119d19291906129a3565b604080518083038186803b1580156119e857600080fd5b505afa1580156119fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a209190611f9e565b91509150600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015611a615750600081115b15611b00578573ffffffffffffffffffffffffffffffffffffffff166323b872dd8684846040518463ffffffff1660e01b8152600401611aa39392919061258b565b602060405180830381600087803b158015611abd57600080fd5b505af1158015611ad1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af5919061206b565b508092505050611b08565b50505b600090505b95945050505050565b611b1a85611886565b15611b93578473ffffffffffffffffffffffffffffffffffffffff166342842e0e8585856040518463ffffffff1660e01b8152600401611b5c9392919061258b565b600060405180830381600087803b158015611b7657600080fd5b505af1158015611b8a573d6000803e3d6000fd5b50505050611c05565b8473ffffffffffffffffffffffffffffffffffffffff1663f242432a858585856040518563ffffffff1660e01b8152600401611bd29493929190612631565b600060405180830381600087803b158015611bec57600080fd5b505af1158015611c00573d6000803e3d6000fd5b505050505b5050505050565b611c1461183c565b6001600060146101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611c58611c85565b604051611c659190612547565b60405180910390a1565b6001816000016000828254019250508190555050565b600033905090565b611c956103e1565b611cd4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ccb906126e8565b60405180910390fd5b565b6000611ce183611cfb565b8015611cf35750611cf28383611d48565b5b905092915050565b6000611d27827f01ffc9a700000000000000000000000000000000000000000000000000000000611d48565b8015611d415750611d3f8263ffffffff60e01b611d48565b155b9050919050565b6000806301ffc9a760e01b83604051602401611d6491906126cd565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000808573ffffffffffffffffffffffffffffffffffffffff1661753084604051611dee9190612530565b6000604051808303818686fa925050503d8060008114611e2a576040519150601f19603f3d011682016040523d82523d6000602084013e611e2f565b606091505b5091509150602081511015611e4a5760009350505050611e6d565b818015611e67575080806020019051810190611e66919061206b565b5b93505050505b92915050565b600081359050611e8281612fed565b92915050565b600081519050611e9781612fed565b92915050565b600081519050611eac81613004565b92915050565b600081359050611ec18161301b565b92915050565b600081519050611ed68161301b565b92915050565b600081359050611eeb81613032565b92915050565b600060208284031215611f0757611f06612bf0565b5b6000611f1584828501611e73565b91505092915050565b600060208284031215611f3457611f33612bf0565b5b6000611f4284828501611e88565b91505092915050565b600080600060608486031215611f6457611f63612bf0565b5b6000611f7286828701611e73565b9350506020611f8386828701611e73565b9250506040611f9486828701611eb2565b9150509250925092565b60008060408385031215611fb557611fb4612bf0565b5b6000611fc385828601611e88565b9250506020611fd485828601611ec7565b9150509250929050565b60008060008060008060c08789031215611ffb57611ffa612bf0565b5b600061200989828a01611e73565b965050602061201a89828a01611eb2565b955050604061202b89828a01611eb2565b945050606061203c89828a01611e73565b935050608061204d89828a01611eb2565b92505060a061205e89828a01611eb2565b9150509295509295509295565b60006020828403121561208157612080612bf0565b5b600061208f84828501611e9d565b91505092915050565b6000602082840312156120ae576120ad612bf0565b5b60006120bc84828501611eb2565b91505092915050565b6000602082840312156120db576120da612bf0565b5b60006120e984828501611ec7565b91505092915050565b6000806040838503121561210957612108612bf0565b5b600061211785828601611eb2565b925050602061212885828601611eb2565b9150509250929050565b60008060006060848603121561214b5761214a612bf0565b5b600061215986828701611eb2565b935050602061216a86828701611eb2565b925050604061217b86828701611eb2565b9150509250925092565b60006020828403121561219b5761219a612bf0565b5b60006121a984828501611edc565b91505092915050565b6121bb81612ade565b82525050565b6121ca81612af0565b82525050565b6121d981612afc565b82525050565b60006121ea826129e7565b6121f48185612a03565b9350612204818560208601612b5f565b80840191505092915050565b600061221d601483612a0e565b915061222882612bf5565b602082019050919050565b6000612240601383612a0e565b915061224b82612c1e565b602082019050919050565b6000612263600e83612a0e565b915061226e82612c47565b602082019050919050565b6000612286602683612a0e565b915061229182612c70565b604082019050919050565b60006122a9601483612a0e565b91506122b482612cbf565b602082019050919050565b60006122cc602383612a0e565b91506122d782612ce8565b604082019050919050565b60006122ef601e83612a0e565b91506122fa82612d37565b602082019050919050565b6000612312601183612a0e565b915061231d82612d60565b602082019050919050565b6000612335601283612a0e565b915061234082612d89565b602082019050919050565b6000612358601083612a0e565b915061236382612db2565b602082019050919050565b600061237b601783612a0e565b915061238682612ddb565b602082019050919050565b600061239e602183612a0e565b91506123a982612e04565b604082019050919050565b60006123c1602083612a0e565b91506123cc82612e53565b602082019050919050565b60006123e4601483612a0e565b91506123ef82612e7c565b602082019050919050565b6000612407601b83612a0e565b915061241282612ea5565b602082019050919050565b600061242a601783612a0e565b915061243582612ece565b602082019050919050565b600061244d6000836129f2565b915061245882612ef7565b600082019050919050565b6000612470601e83612a0e565b915061247b82612efa565b602082019050919050565b6000612493602383612a0e565b915061249e82612f23565b604082019050919050565b60006124b6601883612a0e565b91506124c182612f72565b602082019050919050565b60006124d9600d83612a0e565b91506124e482612f9b565b602082019050919050565b60006124fc601583612a0e565b915061250782612fc4565b602082019050919050565b61251b81612b48565b82525050565b61252a81612b52565b82525050565b600061253c82846121df565b915081905092915050565b600060208201905061255c60008301846121b2565b92915050565b600060408201905061257760008301856121b2565b61258460208301846121b2565b9392505050565b60006060820190506125a060008301866121b2565b6125ad60208301856121b2565b6125ba6040830184612512565b949350505050565b600060e0820190506125d7600083018a6121b2565b6125e460208301896121b2565b6125f16040830188612512565b6125fe6060830187612512565b61260b60808301866121b2565b61261860a0830185612512565b61262560c0830184612512565b98975050505050505050565b600060a08201905061264660008301876121b2565b61265360208301866121b2565b6126606040830185612512565b61266d6060830184612512565b818103608083015261267e81612440565b905095945050505050565b600060408201905061269e60008301856121b2565b6126ab6020830184612512565b9392505050565b60006020820190506126c760008301846121c1565b92915050565b60006020820190506126e260008301846121d0565b92915050565b6000602082019050818103600083015261270181612210565b9050919050565b6000602082019050818103600083015261272181612233565b9050919050565b6000602082019050818103600083015261274181612256565b9050919050565b6000602082019050818103600083015261276181612279565b9050919050565b600060208201905081810360008301526127818161229c565b9050919050565b600060208201905081810360008301526127a1816122bf565b9050919050565b600060208201905081810360008301526127c1816122e2565b9050919050565b600060208201905081810360008301526127e181612305565b9050919050565b6000602082019050818103600083015261280181612328565b9050919050565b600060208201905081810360008301526128218161234b565b9050919050565b600060208201905081810360008301526128418161236e565b9050919050565b6000602082019050818103600083015261286181612391565b9050919050565b60006020820190508181036000830152612881816123b4565b9050919050565b600060208201905081810360008301526128a1816123d7565b9050919050565b600060208201905081810360008301526128c1816123fa565b9050919050565b600060208201905081810360008301526128e18161241d565b9050919050565b6000602082019050818103600083015261290181612463565b9050919050565b6000602082019050818103600083015261292181612486565b9050919050565b60006020820190508181036000830152612941816124a9565b9050919050565b60006020820190508181036000830152612961816124cc565b9050919050565b60006020820190508181036000830152612981816124ef565b9050919050565b600060208201905061299d6000830184612512565b92915050565b60006040820190506129b86000830185612512565b6129c56020830184612512565b9392505050565b60006020820190506129e16000830184612521565b92915050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b6000612a2a82612b48565b9150612a3583612b48565b925082612a4557612a44612bc1565b5b828204905092915050565b6000612a5b82612b48565b9150612a6683612b48565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612a9f57612a9e612b92565b5b828202905092915050565b6000612ab582612b48565b9150612ac083612b48565b925082821015612ad357612ad2612b92565b5b828203905092915050565b6000612ae982612b28565b9050919050565b60008115159050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b60005b83811015612b7d578082015181840152602081019050612b62565b83811115612b8c576000848401525b50505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600080fd5b7f5061757361626c653a206e6f7420706175736564000000000000000000000000600082015250565b7f496e76616c696420707269636520746f6b656e00000000000000000000000000600082015250565b7f4e6f206f6666657220666f756e64000000000000000000000000000000000000600082015250565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b7f4d757374206f6666657220736f6d657468696e67000000000000000000000000600082015250565b7f53657276696365206665652063616e6e6f74206265206269676765722074686160008201527f6e20350000000000000000000000000000000000000000000000000000000000602082015250565b7f53657276696365206665652063616e6e6f74206265206e656761746976650000600082015250565b7f4e6f7468696e6720746f2063616e63656c000000000000000000000000000000600082015250565b7f4e6f7420656e6f7567682062616c616e63650000000000000000000000000000600082015250565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b7f53686f756c642061636365707420736f6d657468696e67000000000000000000600082015250565b7f4d757374206f66666572206f6e20736f6d6520616d6f756e74206f66204e465460008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b7f4e6f7420656e6f75676820616c6c6f77616e6365000000000000000000000000600082015250565b7f4f6e6c79206f776e65722063616e20616363657074206f666665720000000000600082015250565b7f4f6e6c79206f6666657265722063616e2063616e63656c000000000000000000600082015250565b50565b7f446561646c696e65206d75737420626520696e20746865206675747572650000600082015250565b7f4552432d3732312063616e2068617665206f6e6c79207175616e74697479206f60008201527f6620310000000000000000000000000000000000000000000000000000000000602082015250565b7f4f66666572207175616e74697479206578686175737465640000000000000000600082015250565b7f4e6f7420737570706f7274656400000000000000000000000000000000000000600082015250565b7f546865206f666665722068617320657870697265640000000000000000000000600082015250565b612ff681612ade565b811461300157600080fd5b50565b61300d81612af0565b811461301857600080fd5b50565b61302481612b48565b811461302f57600080fd5b50565b61303b81612b52565b811461304657600080fd5b5056fea2646970667358221220399d432edfb584a163434710f43d10a28a32a65bfae79ce383a15195a7e267a864736f6c63430008060033