Source Code
Overview
ETH Balance
0.0022947 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 40 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Set Profit Perce... | 2698760 | 137 days ago | IN | 0 ETH | 0 | ||||
Create Offer SC | 2698210 | 137 days ago | IN | 0 ETH | 0.00037267 | ||||
Create Offer SC | 2697801 | 137 days ago | IN | 0 ETH | 0.00037268 | ||||
Create Offer SC | 2697196 | 137 days ago | IN | 0 ETH | 0.0015319 | ||||
Create Offer SC | 2697187 | 137 days ago | IN | 0 ETH | 0.0003727 | ||||
Create Offer SC | 2697004 | 137 days ago | IN | 0 ETH | 0.00037267 | ||||
Set Profit Perce... | 2692519 | 138 days ago | IN | 0 ETH | 0.00000264 | ||||
Set Profit Perce... | 2692301 | 138 days ago | IN | 0 ETH | 0.00000264 | ||||
Set Profit Perce... | 2691939 | 138 days ago | IN | 0 ETH | 0.00000264 | ||||
Create Offer SC | 2691853 | 138 days ago | IN | 0 ETH | 0.00037267 | ||||
Set Profit Perce... | 2691851 | 138 days ago | IN | 0 ETH | 0.00000264 | ||||
Create Offer SC | 2691107 | 138 days ago | IN | 0 ETH | 0.00037267 | ||||
Set Profit Perce... | 2691095 | 138 days ago | IN | 0 ETH | 0.00000264 | ||||
Set Discount Val... | 2691005 | 138 days ago | IN | 0 ETH | 0.00000267 | ||||
Set Discount Val... | 2690997 | 138 days ago | IN | 0 ETH | 0.00000267 | ||||
Create Offer SC | 2690952 | 138 days ago | IN | 0 ETH | 0.0003727 | ||||
Set Discount Val... | 2690848 | 138 days ago | IN | 0 ETH | 0.00000239 | ||||
Set Discount Val... | 2690844 | 138 days ago | IN | 0 ETH | 0.00000267 | ||||
Set Profit Perce... | 2685947 | 139 days ago | IN | 0 ETH | 0.00000264 | ||||
Set Discount Val... | 2685452 | 139 days ago | IN | 0 ETH | 0.00000267 | ||||
Set Discount Val... | 2685425 | 139 days ago | IN | 0 ETH | 0.00000267 | ||||
Create Offer SC | 2685424 | 139 days ago | IN | 0 ETH | 0.00037267 | ||||
Set Profit Perce... | 2685421 | 139 days ago | IN | 0 ETH | 0.00000264 | ||||
Set Discount Val... | 2685393 | 139 days ago | IN | 0 ETH | 0.00000239 | ||||
Set Discount Val... | 2685380 | 139 days ago | IN | 0 ETH | 0.00000239 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
Transfer | 2698948 | 137 days ago | 0.00005 ETH | ||||
Transfer | 2698931 | 137 days ago | 0.0000005 ETH | ||||
0x60c06040 | 2698210 | 137 days ago | Contract Creation | 0 ETH | |||
Transfer | 2698040 | 137 days ago | 0.000001 ETH | ||||
Transfer | 2697816 | 137 days ago | 0.000001 ETH | ||||
0x60c06040 | 2697801 | 137 days ago | Contract Creation | 0 ETH | |||
0x60c06040 | 2697196 | 137 days ago | Contract Creation | 0 ETH | |||
0x60c06040 | 2697187 | 137 days ago | Contract Creation | 0 ETH | |||
Transfer | 2697034 | 137 days ago | 0.000005 ETH | ||||
Transfer | 2697027 | 137 days ago | 0.000005 ETH | ||||
0x60c06040 | 2697004 | 137 days ago | Contract Creation | 0 ETH | |||
Transfer | 2691880 | 138 days ago | 0.0000002 ETH | ||||
0x60c06040 | 2691853 | 138 days ago | Contract Creation | 0 ETH | |||
Transfer | 2691705 | 138 days ago | 0.000184 ETH | ||||
Transfer | 2691458 | 138 days ago | 0.0004 ETH | ||||
Transfer | 2691399 | 138 days ago | 0.0002 ETH | ||||
Transfer | 2691389 | 138 days ago | 0.0002 ETH | ||||
Transfer | 2691304 | 138 days ago | 0.0004 ETH | ||||
Transfer | 2691290 | 138 days ago | 0.000004 ETH | ||||
Transfer | 2691285 | 138 days ago | 0.000004 ETH | ||||
Transfer | 2691239 | 138 days ago | 0.0004 ETH | ||||
Transfer | 2691237 | 138 days ago | 0.0004 ETH | ||||
Transfer | 2691125 | 138 days ago | 0.00002 ETH | ||||
Transfer | 2691115 | 138 days ago | 0.00002 ETH | ||||
0x60c06040 | 2691107 | 138 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
OfferFactory
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.26; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {Offer} from "./Offer.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; error InfluencerExists(); error NoProfit(); error NotCorrectPercent(); contract OfferFactory is Ownable { /********************************************************* ========================= Events ========================= *********************************************************/ /** * @param offerAddress Address of created offer contract * @param owner Owner of created contract * @param _name Name of collection (contract) * @param _symbol Symbol of collection (contract) * @param _commissionPercent Commission percent of created contract * @param offer_id Id for backend */ event OfferCreated( address offerAddress, address owner, string _name, string _symbol, uint256 _commissionPercent, string offer_id ); /** * @dev Emitted after becoming refferal * @param refferal Address of refferal * @param influencer Address of influencer */ event BecameRefferal(address refferal, address influencer); /********************************************************** ======================== Variables ======================== **********************************************************/ /// @notice amount of discount for refferals uint16 public discount; /*********************************************************** ========================= Mappings ========================= ***********************************************************/ /// @notice address of refferal => address of influencer mapping(address => address) public refferalToInfluencer; /// @notice address of influencer => influencer profit percent mapping(address => uint16) public influencerProfitPercents; /************************************************************ ========================= Functions ========================= ************************************************************/ constructor( address initialOwner, uint16 _discount ) payable Ownable(initialOwner) { discount = _discount; } function createOfferSC( string calldata offer_id, address _initialOwner, string memory _name, string memory _symbol, uint16 _commissionPercent, uint16 _penaltyPercent, string memory _uriLink, address _marketplaceAddress ) public onlyOwner { Offer offerContract = new Offer( address(this), _initialOwner, _name, _symbol, _commissionPercent, _penaltyPercent, _uriLink, _marketplaceAddress ); emit OfferCreated( address(offerContract), msg.sender, _name, _symbol, _commissionPercent, offer_id ); } function setProfitPercent( uint8 _profitPercent, address _user ) external onlyOwner { if (_profitPercent > 100) revert NotCorrectPercent(); influencerProfitPercents[_user] = _profitPercent; } /** * @notice Function for setting discount value * @notice discount divides by 1000 * @param _discount Amount of commission discount */ function setDiscountValue(uint16 _discount) external onlyOwner { discount = _discount; } /** * @notice Function for becoming refferal and getting commission discount * @param influencer Address of user that gives refferal */ function becomeRefferal(address influencer) external { if (refferalToInfluencer[msg.sender] != address(0)) revert InfluencerExists(); refferalToInfluencer[msg.sender] = influencer; emit BecameRefferal(msg.sender, influencer); } /** * @notice Function for withdrawing commission * @param _to Address of withdrawer */ function withdraw(address _to) public payable onlyOwner { payable(_to).transfer(address(this).balance); } function withdrawERC20( address erc20Address, uint256 value ) public onlyOwner { IERC20(erc20Address).transferFrom(address(this), msg.sender, value); } receive() external payable {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../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. * * The initial owner is set to the address provided by the deployer. 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; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @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 { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling 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 { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) pragma solidity ^0.8.20; /** * @dev Standard ERC20 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens. */ interface IERC20Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC20InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC20InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. * @param spender Address that may be allowed to operate on tokens without being their owner. * @param allowance Amount of tokens a `spender` is allowed to operate with. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC20InvalidApprover(address approver); /** * @dev Indicates a failure with the `spender` to be approved. Used in approvals. * @param spender Address that may be allowed to operate on tokens without being their owner. */ error ERC20InvalidSpender(address spender); } /** * @dev Standard ERC721 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens. */ interface IERC721Errors { /** * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20. * Used in balance queries. * @param owner Address of the current owner of a token. */ error ERC721InvalidOwner(address owner); /** * @dev Indicates a `tokenId` whose `owner` is the zero address. * @param tokenId Identifier number of a token. */ error ERC721NonexistentToken(uint256 tokenId); /** * @dev Indicates an error related to the ownership over a particular token. Used in transfers. * @param sender Address whose tokens are being transferred. * @param tokenId Identifier number of a token. * @param owner Address of the current owner of a token. */ error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC721InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC721InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param tokenId Identifier number of a token. */ error ERC721InsufficientApproval(address operator, uint256 tokenId); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC721InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC721InvalidOperator(address operator); } /** * @dev Standard ERC1155 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens. */ interface IERC1155Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. * @param tokenId Identifier number of a token. */ error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC1155InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC1155InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param owner Address of the current owner of a token. */ error ERC1155MissingApprovalForAll(address operator, address owner); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC1155InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC1155InvalidOperator(address operator); /** * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. * Used in batch transfers. * @param idsLength Length of the array of token identifiers * @param valuesLength Length of the array of token amounts */ error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4906.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; import {IERC721} from "./IERC721.sol"; /// @title EIP-721 Metadata Update Extension interface IERC4906 is IERC165, IERC721 { /// @dev This event emits when the metadata of a token is changed. /// So that the third-party platforms such as NFT market could /// timely update the images and related attributes of the NFT. event MetadataUpdate(uint256 _tokenId); /// @dev This event emits when the metadata of a range of tokens is changed. /// So that the third-party platforms such as NFT market could /// timely update the images and related attributes of the NFTs. event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721.sol) pragma solidity ^0.8.20; import {IERC721} from "../token/ERC721/IERC721.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @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 value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` 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 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC20Permit} from "../extensions/IERC20Permit.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev An operation with an ERC20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data); if (returndata.length != 0 && !abi.decode(returndata, (bool))) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol) pragma solidity ^0.8.20; import {IERC721} from "./IERC721.sol"; import {IERC721Receiver} from "./IERC721Receiver.sol"; import {IERC721Metadata} from "./extensions/IERC721Metadata.sol"; import {Context} from "../../utils/Context.sol"; import {Strings} from "../../utils/Strings.sol"; import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol"; import {IERC721Errors} from "../../interfaces/draft-IERC6093.sol"; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including * the Metadata extension, but not including the Enumerable extension, which is available separately as * {ERC721Enumerable}. */ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Errors { using Strings for uint256; // Token name string private _name; // Token symbol string private _symbol; mapping(uint256 tokenId => address) private _owners; mapping(address owner => uint256) private _balances; mapping(uint256 tokenId => address) private _tokenApprovals; mapping(address owner => mapping(address operator => bool)) private _operatorApprovals; /** * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual returns (uint256) { if (owner == address(0)) { revert ERC721InvalidOwner(address(0)); } return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual returns (address) { return _requireOwned(tokenId); } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual returns (string memory) { _requireOwned(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string.concat(baseURI, tokenId.toString()) : ""; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ""; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual { _approve(to, tokenId, _msgSender()); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual returns (address) { _requireOwned(tokenId); return _getApproved(tokenId); } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom(address from, address to, uint256 tokenId) public virtual { if (to == address(0)) { revert ERC721InvalidReceiver(address(0)); } // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. address previousOwner = _update(to, tokenId, _msgSender()); if (previousOwner != from) { revert ERC721IncorrectOwner(from, tokenId, previousOwner); } } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom(address from, address to, uint256 tokenId) public { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual { transferFrom(from, to, tokenId); _checkOnERC721Received(from, to, tokenId, data); } /** * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist * * IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the * core ERC721 logic MUST be matched with the use of {_increaseBalance} to keep balances * consistent with ownership. The invariant to preserve is that for any address `a` the value returned by * `balanceOf(a)` must be equal to the number of tokens such that `_ownerOf(tokenId)` is `a`. */ function _ownerOf(uint256 tokenId) internal view virtual returns (address) { return _owners[tokenId]; } /** * @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted. */ function _getApproved(uint256 tokenId) internal view virtual returns (address) { return _tokenApprovals[tokenId]; } /** * @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in * particular (ignoring whether it is owned by `owner`). * * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this * assumption. */ function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) { return spender != address(0) && (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender); } /** * @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner. * Reverts if `spender` does not have approval from the provided `owner` for the given token or for all its assets * the `spender` for the specific `tokenId`. * * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this * assumption. */ function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual { if (!_isAuthorized(owner, spender, tokenId)) { if (owner == address(0)) { revert ERC721NonexistentToken(tokenId); } else { revert ERC721InsufficientApproval(spender, tokenId); } } } /** * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override. * * NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that * a uint256 would ever overflow from increments when these increments are bounded to uint128 values. * * WARNING: Increasing an account's balance using this function tends to be paired with an override of the * {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership * remain consistent with one another. */ function _increaseBalance(address account, uint128 value) internal virtual { unchecked { _balances[account] += value; } } /** * @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. * * The `auth` argument is optional. If the value passed is non 0, then this function will check that * `auth` is either the owner of the token, or approved to operate on the token (by the owner). * * Emits a {Transfer} event. * * NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}. */ function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) { address from = _ownerOf(tokenId); // Perform (optional) operator check if (auth != address(0)) { _checkAuthorized(from, auth, tokenId); } // Execute the update if (from != address(0)) { // Clear approval. No need to re-authorize or emit the Approval event _approve(address(0), tokenId, address(0), false); unchecked { _balances[from] -= 1; } } if (to != address(0)) { unchecked { _balances[to] += 1; } } _owners[tokenId] = to; emit Transfer(from, to, tokenId); return from; } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal { if (to == address(0)) { revert ERC721InvalidReceiver(address(0)); } address previousOwner = _update(to, tokenId, address(0)); if (previousOwner != address(0)) { revert ERC721InvalidSender(address(0)); } } /** * @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance. * * Requirements: * * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual { _mint(to, tokenId); _checkOnERC721Received(address(0), to, tokenId, data); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * This is an internal function that does not check if the sender is authorized to operate on the token. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal { address previousOwner = _update(address(0), tokenId, address(0)); if (previousOwner == address(0)) { revert ERC721NonexistentToken(tokenId); } } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer(address from, address to, uint256 tokenId) internal { if (to == address(0)) { revert ERC721InvalidReceiver(address(0)); } address previousOwner = _update(to, tokenId, address(0)); if (previousOwner == address(0)) { revert ERC721NonexistentToken(tokenId); } else if (previousOwner != from) { revert ERC721IncorrectOwner(from, tokenId, previousOwner); } } /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients * are aware of the ERC721 standard to prevent tokens from being forever locked. * * `data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is like {safeTransferFrom} in the sense that it invokes * {IERC721Receiver-onERC721Received} on the receiver, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `tokenId` token must exist and be owned by `from`. * - `to` cannot be the zero address. * - `from` cannot be the zero address. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer(address from, address to, uint256 tokenId) internal { _safeTransfer(from, to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual { _transfer(from, to, tokenId); _checkOnERC721Received(from, to, tokenId, data); } /** * @dev Approve `to` to operate on `tokenId` * * The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is * either the owner of the token, or approved to operate on all tokens held by this owner. * * Emits an {Approval} event. * * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. */ function _approve(address to, uint256 tokenId, address auth) internal { _approve(to, tokenId, auth, true); } /** * @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not * emitted in the context of transfers. */ function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual { // Avoid reading the owner unless necessary if (emitEvent || auth != address(0)) { address owner = _requireOwned(tokenId); // We do not use _isAuthorized because single-token approvals should not be able to call approve if (auth != address(0) && owner != auth && !isApprovedForAll(owner, auth)) { revert ERC721InvalidApprover(auth); } if (emitEvent) { emit Approval(owner, to, tokenId); } } _tokenApprovals[tokenId] = to; } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Requirements: * - operator can't be the address zero. * * Emits an {ApprovalForAll} event. */ function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { if (operator == address(0)) { revert ERC721InvalidOperator(operator); } _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned). * Returns the owner. * * Overrides to ownership logic should be done to {_ownerOf}. */ function _requireOwned(uint256 tokenId) internal view returns (address) { address owner = _ownerOf(tokenId); if (owner == address(0)) { revert ERC721NonexistentToken(tokenId); } return owner; } /** * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. This will revert if the * recipient doesn't accept the token transfer. The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param data bytes optional data to send along with the call */ function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data) private { if (to.code.length > 0) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { if (retval != IERC721Receiver.onERC721Received.selector) { revert ERC721InvalidReceiver(to); } } catch (bytes memory reason) { if (reason.length == 0) { revert ERC721InvalidReceiver(to); } else { /// @solidity memory-safe-assembly assembly { revert(add(32, reason), mload(reason)) } } } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721URIStorage.sol) pragma solidity ^0.8.20; import {ERC721} from "../ERC721.sol"; import {Strings} from "../../../utils/Strings.sol"; import {IERC4906} from "../../../interfaces/IERC4906.sol"; import {IERC165} from "../../../interfaces/IERC165.sol"; /** * @dev ERC721 token with storage based token URI management. */ abstract contract ERC721URIStorage is IERC4906, ERC721 { using Strings for uint256; // Interface ID as defined in ERC-4906. This does not correspond to a traditional interface ID as ERC-4906 only // defines events and does not include any external function. bytes4 private constant ERC4906_INTERFACE_ID = bytes4(0x49064906); // Optional mapping for token URIs mapping(uint256 tokenId => string) private _tokenURIs; /** * @dev See {IERC165-supportsInterface} */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, IERC165) returns (bool) { return interfaceId == ERC4906_INTERFACE_ID || super.supportsInterface(interfaceId); } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireOwned(tokenId); string memory _tokenURI = _tokenURIs[tokenId]; string memory base = _baseURI(); // If there is no base URI, return the token URI. if (bytes(base).length == 0) { return _tokenURI; } // If both are set, concatenate the baseURI and tokenURI (via string.concat). if (bytes(_tokenURI).length > 0) { return string.concat(base, _tokenURI); } return super.tokenURI(tokenId); } /** * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. * * Emits {MetadataUpdate}. */ function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { _tokenURIs[tokenId] = _tokenURI; emit MetadataUpdate(tokenId); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.20; import {IERC721} from "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or * {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the address zero. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.20; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be * reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @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 or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * 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. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @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`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert FailedInnerCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./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); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { uint256 localValue = value; bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal * representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.26; interface IOfferFactory { function refferalToInfluencer(address _refferal) external view returns (address); function influencerProfitPercents(address _influencer) external view returns (uint16); function discount() external view returns (uint16); }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.26; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {ERC721URIStorage, ERC721} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {OfferStorage} from "./OfferStorage.sol"; import {IOfferFactory} from "./interface/IOfferFactory.sol"; contract Offer is OfferStorage, ERC721URIStorage, Ownable { using SafeERC20 for IERC20Metadata; /// @notice Add payable modificator for reducing deployment gas cost constructor( address _withdrawalSCAddress, address _initialOwner, string memory _name, string memory _symbol, uint16 _commissionPercent, uint16 _penaltyPercent, string memory _uriLink, address _marketplaceAddress ) payable Ownable(_initialOwner) ERC721(_name, _symbol) { uriLink = _uriLink; commissionPercent = _commissionPercent; penaltyPercent = _penaltyPercent; marketplaceAddress = _marketplaceAddress; withdrawalSCAddress = _withdrawalSCAddress; } /************************************************************ ========================= Functions ========================= ************************************************************/ /** * @notice Function for adding seller lot * @param _amount Amount of erc20 tokens for future selling * @param _price Price of all amount of tokens in wei */ function addTokenTradeLot( uint256 _amount, uint256 _price ) external payable beforeLaunch { (uint256 commission, uint256 discount) = getCommissionAmount(_price); ( uint256 refferalsProfit, uint16 profitPercent, address influencer ) = getRefferalsInfo(commission); // checking checkValueWithCommission(_price); if (_amount > MAX_TOKEN_AMOUNT) revert MoreThanMaxAmountOfTokens(MAX_TOKEN_AMOUNT); payable(withdrawalSCAddress).transfer( commission - discount - refferalsProfit ); if (profitPercent > 0) payable(influencer).transfer(refferalsProfit); tradeLots[tradeLotId] = TradeLotInfo( _amount, _price, msg.sender, LotStatus.Created ); emit LotCreated( tradeLotId, _amount, _price, msg.sender, address(this), refferalsProfit ); ++tradeLotId; } /** * @notice Function for donating ERC20 tokens * @notice Returns to seller his `deposit - commision` and reward of purchase * @notice Needs preliminary `Approve` of user from `tokenAddress` * @param lotId Id of token lot */ function donateERC20Tokens(uint256 lotId) external payable { TradeLotInfo storage tradeLotInfo = tradeLots[lotId]; // checking if (isDeadline) revert DeadlineError(); if (tradeLotInfo.amount == 0) revert LotNotExists(lotId); if (tradeLotInfo.status != LotStatus.Bought) revert BuyerNotExists(); IERC20Metadata erc20Token = IERC20Metadata(tokenAddress); (uint256 commission, uint256 discount) = getCommissionAmount( tradeLotInfo.price ); ( uint256 refferalsProfit, uint16 profitPercent, address influencer ) = getRefferalsInfo(commission); tradeLotInfo.status = LotStatus.Donated; uint8 decimals = IERC20Metadata(tokenAddress).decimals(); erc20Token.safeTransferFrom( msg.sender, address(this), tradeLotInfo.amount * 10 ** decimals // tradeLotInfo.amount ); uint256 totalCommission = commission - discount; payable(msg.sender).transfer( tradeLotInfo.price + tradeLotInfo.price - totalCommission ); payable(withdrawalSCAddress).transfer( totalCommission - refferalsProfit ); if (profitPercent > 0) payable(influencer).transfer(refferalsProfit); emit TokensDonated( lotId, tradeLotInfo.amount, tradeLotInfo.price, msg.sender, address(this), refferalsProfit ); } /** * @notice Function for returning deposit * @param lotId Id of lot */ function sellerDepositReturning(uint256 lotId) external payable { TradeLotInfo memory tradeLotInfo = tradeLots[lotId]; (uint256 commission, uint256 discount) = getCommissionAmount( tradeLotInfo.price ); ( uint256 refferalsProfit, uint16 profitPercent, address influencer ) = getRefferalsInfo(commission); if (msg.sender != tradeLotInfo.seller) revert NotSeller(); if (tradeLotInfo.status == LotStatus.Withdrawed) revert AlreadyWithdrawed(); if (tradeLotInfo.status == LotStatus.Bought) revert DeadlineError(); if (tradeLotInfo.status == LotStatus.Canceled) revert Canceled(); if ( tradeLotInfo.status == LotStatus.Donated && msg.value != commission - discount ) revert NotCorrectValue( msg.value, tradeLotInfo.price, commission, discount ); tradeLots[lotId].status = LotStatus.Withdrawed; payable(withdrawalSCAddress).transfer( commission - discount - refferalsProfit ); if (profitPercent > 0) payable(influencer).transfer(refferalsProfit); totalProfit += commission - discount - refferalsProfit; uint256 sellerValue = tradeLotInfo.status == LotStatus.Donated ? (tradeLotInfo.price * 2) : tradeLotInfo.price; payable(msg.sender).transfer(sellerValue); emit DepReturnedBySeller(lotId, address(this), refferalsProfit); } /** * @notice Function for cancelling lot * @param lotId Id of lot */ function sellerCancelLot(uint256 lotId) external { TradeLotInfo memory tradeLotInfo = tradeLots[lotId]; if (msg.sender != tradeLotInfo.seller) revert NotSeller(); if (tradeLotInfo.status == LotStatus.Withdrawed) revert AlreadyWithdrawed(); if (tradeLotInfo.status == LotStatus.Canceled) revert Canceled(); if (tradeLotInfo.status != LotStatus.Bought) revert BuyerNotExists(); tradeLots[lotId].status = LotStatus.Canceled; emit LotCanceled(lotId, address(this)); } /** * @notice Function for purchase future ERC20 tokens and transferring NFT to buyer * @param lotId Id of lot */ function buy(uint256 lotId) external payable beforeLaunch { TradeLotInfo memory tradeLotInfo = tradeLots[lotId]; checkValueWithCommission(tradeLotInfo.price); if (tradeLots[lotId].status == LotStatus.Bought) revert AlreadyBought(); if (tradeLotInfo.status == LotStatus.Canceled) revert Canceled(); tradeLots[lotId].status = LotStatus.Bought; (uint256 commission, uint256 discount) = getCommissionAmount( tradeLotInfo.price ); ( uint256 refferalsProfit, uint16 profitPercent, address influencer ) = getRefferalsInfo(commission); payable(withdrawalSCAddress).transfer( commission - discount - refferalsProfit ); if (profitPercent > 0) payable(influencer).transfer(refferalsProfit); totalProfit += commission - discount - refferalsProfit; uint256 nftIdBeforeIncr = mintNFT( lotId, msg.sender, tradeLotInfo.amount ); emit NFTBoughtFromOffer( lotId, msg.sender, address(this), nftIdBeforeIncr, refferalsProfit ); } /** * @notice Function for buyer's claiming erc20 tokens * @param lotId Id of lot */ function buyerClaimsTokens(uint256 lotId, uint256 _nftId) external payable { address nftOwner = ownerOf(_nftId); TradeLotInfo memory tradeLotInfo = tradeLots[lotId]; PurchaseInfo memory purchaseInfo = purchases[lotId][_nftId]; // Checking if (tradeLotInfo.amount == 0) revert LotNotExists(lotId); if (nftOwner != msg.sender) revert NotNFTOwner(_nftId); if (tradeLotInfo.status == LotStatus.Bought && !isDeadline) revert NotAvailableForClaim(); _burn(_nftId); purchases[lotId][_nftId].isClaimed = true; uint256 percentPart = (purchaseInfo.tokensAmount * PERCENT_DIVIDER) / tradeLotInfo.amount; uint256 priceOfPart = (tradeLotInfo.price * percentPart) / PERCENT_DIVIDER; uint256 _refferalsProfit; if (tradeLotInfo.status == LotStatus.Donated) { // Seller donates tokens (uint256 commission, uint256 discount) = getCommissionAmount( priceOfPart ); ( uint256 refferalsProfit, uint16 profitPercent, address influencer ) = getRefferalsInfo(commission); _refferalsProfit = refferalsProfit; if (msg.value != commission - discount) revert NotCorrectValue( msg.value, priceOfPart, commission, discount ); payable(withdrawalSCAddress).transfer( commission - discount - refferalsProfit ); if (profitPercent > 0) payable(influencer).transfer(refferalsProfit); uint8 decimals = IERC20Metadata(tokenAddress).decimals(); bool success = IERC20Metadata(tokenAddress).transfer( nftOwner, purchaseInfo.tokensAmount * 10 ** decimals // purchaseInfo.tokensAmount ); if (!success) revert TransferFailed(); } else { // Seller doesn't donate tokens uint256 valueForSC = (priceOfPart * penaltyPercent) / MULTIPLIER; ( uint256 refferalsProfit, uint16 profitPercent, address influencer ) = getRefferalsInfo(valueForSC); _refferalsProfit = refferalsProfit; // Commision for withdrawal SC payable(withdrawalSCAddress).transfer(valueForSC - refferalsProfit); // Profit for influencer if (profitPercent > 0) payable(influencer).transfer(refferalsProfit); // Compensation for buyer payable(nftOwner).transfer( tradeLotInfo.price + priceOfPart - valueForSC ); } emit NFTReturnedFromOffer( lotId, purchaseInfo.tokensAmount, _nftId, nftOwner, address(this), _refferalsProfit ); } /** * @notice Function for splitting NFT * @notice This function burns original NFT and mints 2 new instead * @param _nftId Id of NFT * @param amountForBuyer Percent amount of ERC20 tokens that buyer receives * @param nftBuyer Address of NFT buyer * @param nftSeller Address of NFT seller */ function splitNFT( uint256 _nftId, uint256 amountForBuyer, address nftBuyer, address nftSeller ) public returns (uint256, uint256) { if (msg.sender != marketplaceAddress) revert OnlyForMarketplace(); uint256 _tradeLotId = nftIdToLotId[_nftId]; uint256 tokensAmount = nftIdToTokensAmount[_nftId]; // minting NFT and writting to mapping uint256 buyerNFTId = mintNFT(_tradeLotId, nftBuyer, amountForBuyer); uint256 sellerNFTId = mintNFT( _tradeLotId, nftSeller, tokensAmount - amountForBuyer ); // burning prev nft with removing purchase from mapping _burn(_nftId); delete purchases[_tradeLotId][_nftId]; delete nftIdToTokensAmount[_nftId]; return (buyerNFTId, sellerNFTId); } /** * @notice Function for minting NFT and writting to mapping * @param lotId Id of lot * @param buyer Address of buyer * @param tokensAmount Amount of ERC20 tokens */ function mintNFT( uint256 lotId, address buyer, uint256 tokensAmount ) private returns (uint256) { purchases[lotId][nftId] = PurchaseInfo(nftId, tokensAmount, false); nftIdToLotId[nftId] = lotId; nftIdToTokensAmount[nftId] = tokensAmount; string memory fileName = string.concat( uriLink, Strings.toString(nftId), ".json" ); // minting NFT and setting URI _mint(buyer, nftId); _setTokenURI(nftId, fileName); // id of current NFT uint256 idBeforeIncr = nftId; ++nftId; return idBeforeIncr; } /** * @notice Function for setting percent of commission * @param _commissionPercent percent of commission */ function setCommission(uint16 _commissionPercent) external onlyOwner { if (_commissionPercent >= MULTIPLIER) revert NotCorrectPercent(); commissionPercent = _commissionPercent; } function checkValueWithCommission(uint256 _price) private { (uint256 commission, uint256 discount) = getCommissionAmount(_price); if (msg.value != _price + (commission - discount)) revert NotCorrectValue(msg.value, _price, commission, discount); } /** * @notice Function for getting amount of commission * @param price Price of tokens */ function getCommissionAmount( uint256 price ) private view returns (uint256, uint256) { uint256 commission = (price * commissionPercent) / MULTIPLIER; uint256 discountValueFromFactory = IOfferFactory(withdrawalSCAddress) .discount(); address influencer = IOfferFactory(withdrawalSCAddress) .refferalToInfluencer(msg.sender); uint256 discount = influencer != address(0) ? (commission * discountValueFromFactory) / PERCENT_DIVIDER : 0; return (commission, discount); } /** * @notice Function for calculating profit from refferal and getting influencer * @param commission Value of commission */ function getRefferalsInfo( uint256 commission ) internal view returns (uint256, uint16, address) { IOfferFactory factory = IOfferFactory(withdrawalSCAddress); address influencer = factory.refferalToInfluencer(msg.sender); uint16 influencerProfitPercent = factory.influencerProfitPercents(influencer); uint256 profit = (commission * influencerProfitPercent) / MULTIPLIER; return (profit, influencerProfitPercent, influencer); } /** * @notice Function for setting token launch * @param _tokenAddress Address of ERC20 token */ function setTokenLaunch( address _tokenAddress, uint256 _decimalsMultiplier ) external onlyOwner { tokenAddress = _tokenAddress; decimalsMultiplier = _decimalsMultiplier; isTokenLaunched = true; emit TokenLaunchedOnOffer(address(this)); } /** * @notice Function for setting percent of deposit amount that platform * @notice takes if seller don't donate ERC20 tokens in time * @param _penaltyPercent Amount of percent */ function setPenaltyPercent(uint16 _penaltyPercent) external onlyOwner { if (_penaltyPercent >= MULTIPLIER) revert NotCorrectPercent(); penaltyPercent = _penaltyPercent; } /// @notice Function for setting deadline function setDeadline() external onlyOwner { if (!isTokenLaunched) revert TokenNotLaunched(); isDeadline = true; emit TokenDeadlineOnOffer(address(this)); } /// @notice Function for manual minting function setURILink(string calldata link) external onlyOwner { uriLink = link; } function transferToWithdrawalSC(uint256 _value) internal { payable(withdrawalSCAddress).transfer(_value); totalProfit += _value; } receive() external payable {} fallback() external payable {} }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.26; contract OfferStorage { error NotCorrectValue( uint256 value, uint256 price, uint256 commission, uint256 discount ); error NotDonated(); error NotSelled(uint256 id); error NotSeller(); error BuyerNotExists(); error BuyerExists(); error AlreadyBought(); error AlreadyClaimed(); error AlreadyWithdrawed(); error TokenNotLaunched(); error TokenLaunchedError(); error DeadlineError(); error NotCorrectURIsAmount(); error NotCorrectPercent(); error LotNotExists(uint256 lotId); error NotNFTOwner(uint256 nftId); error MoreThanMaxAmountOfTokens(uint32 maxAmount); error OnlyForMarketplace(); error TransferFailed(); error NotAvailableForClaim(); error Canceled(); /********************************************************* ========================= Events ========================= *********************************************************/ /** * @dev Emitted after creating trade lot * @param tradeLotId Id of trade lot * @param amount Amount of tokens for sell * @param price Price of all amount ot tokens for sell * @param seller Address of seller */ event LotCreated( uint256 tradeLotId, uint256 amount, uint256 price, address seller, address offer_address, uint256 refferalsProfit ); /** * @dev Emitted after donation tokens on contract * @param tradeLotId Id of trade lot * @param amount Amount of tokens for sell * @param price Price of all amount ot tokens for sell * @param seller Address of seller */ event TokensDonated( uint256 tradeLotId, uint256 amount, uint256 price, address seller, address offer_address, uint256 refferalsProfit ); /** * @dev Emitted after returning deposit to seller * @param tradeLotId Id of trade lot * @param offer_address Address of this contract */ event DepReturnedBySeller( uint256 tradeLotId, address offer_address, uint256 refferalsProfit ); /** * @dev Emitted after buying nft(lot) * @param tradeLotId Id of trade lot * @param buyer Address of buyer * @param offer_address Address of this contract * @param nftId Id of NFT */ event NFTBoughtFromOffer( uint256 tradeLotId, address buyer, address offer_address, uint256 nftId, uint256 refferalsProfit ); /** * @dev Emitted after cancelling lot * @param tradeLotId Id of trade lot * @param offer_address Address of this contract */ event LotCanceled(uint256 tradeLotId, address offer_address); /** * @dev Emitted after returning NFT * @param tradeLotId Id of trade lot * @param tokensAmount Amount of ERC20 tokens for claim * @param nftId Id of NFT * @param buyer Address of buyer * @param offer_address Address of this contract */ event NFTReturnedFromOffer( uint256 tradeLotId, uint256 tokensAmount, uint256 nftId, address buyer, address offer_address, uint256 refferalsProfit ); /** * @dev Emitted after token launching * @param offer_address Address of this contract */ event TokenLaunchedOnOffer(address offer_address); /** * @dev Emitted after ending of deadline * @param offer_address Address of this contract */ event TokenDeadlineOnOffer(address offer_address); /********************************************************** ========================= Structs ========================= **********************************************************/ /** * @param amount Amount of tokens for sell * @param price Price of all amount ot tokens * @param seller Address of seller * @param isDonated Flag indicates is tokens donated * @param isDepWithdrawed Flag indicates is deposit withdrawed */ struct TradeLotInfo { uint256 amount; uint256 price; address seller; LotStatus status; } /** * @param nftId Id of NFT * @param amount Amount of tokens for sell * @param isClaimed Flag indicates is buyer claimed erc20 tokens */ struct PurchaseInfo { uint256 nftId; uint256 tokensAmount; bool isClaimed; } /************************************************************ ========================= Constants ========================= ************************************************************/ /// @notice Max possible amount of ERC20 tokens for lot uint32 constant MAX_TOKEN_AMOUNT = 1_000_000_000; /// @notice Amount representing percent amount uint16 constant MULTIPLIER = 1000; uint8 constant PERCENT_DIVIDER = 100; /************************************************************ ========================= Variables ========================= ************************************************************/ /// @notice Id of current trade lot uint256 internal tradeLotId = 1; /// @notice Id of current NFT uint256 internal nftId = 1; /// @notice Total profit from commission uint256 public totalProfit = 0; /// @notice Address of token for sell address public tokenAddress; /// @notice Address of NFT marketplace address internal marketplaceAddress; /// @notice Percent amount of commission uint16 public commissionPercent = 1; /// @notice Flag for indication is token launched bool public isTokenLaunched = false; /// @notice Flag for indication is deadline end bool public isDeadline = false; /// @notice Address for commssion transfer address public immutable withdrawalSCAddress; /// @notice Percent amount that contract remains to himself uint16 public penaltyPercent = 1; /// @notice URI link with path to json metadata string uriLink = ""; /// @notice Multiplier for amount of ERC20 tokens uint256 internal decimalsMultiplier = 1; address internal immutable factoryAddress; /// @notice Status of trade lot enum LotStatus { Created, Bought, Donated, Withdrawed, Canceled } /*********************************************************** ========================= Mappings ========================= ***********************************************************/ /** * @notice List of trade lots of tokens * @notice lotId => TradeLotInfo */ mapping(uint256 => TradeLotInfo) public tradeLots; /** * @notice List of purchases * @notice lotId => nftId => PurchaseInfo */ mapping(uint256 => mapping(uint256 => PurchaseInfo)) public purchases; /// @notice List of lot ids for finding lot via nftId mapping(uint256 => uint256) public nftIdToLotId; /// @notice List of ERC20 tokens amount mapping(uint256 => uint256) public nftIdToTokensAmount; /************************************************************ ========================= Modifiers ========================= ************************************************************/ modifier beforeLaunch() { if (isTokenLaunched) revert TokenLaunchedError(); _; } }
{ "viaIR": true, "optimizer": { "enabled": true, "runs": 1000000 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract ABI
API[{"inputs":[{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"uint16","name":"_discount","type":"uint16"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"InfluencerExists","type":"error"},{"inputs":[],"name":"NotCorrectPercent","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"refferal","type":"address"},{"indexed":false,"internalType":"address","name":"influencer","type":"address"}],"name":"BecameRefferal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"offerAddress","type":"address"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"string","name":"_name","type":"string"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_commissionPercent","type":"uint256"},{"indexed":false,"internalType":"string","name":"offer_id","type":"string"}],"name":"OfferCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address","name":"influencer","type":"address"}],"name":"becomeRefferal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"offer_id","type":"string"},{"internalType":"address","name":"_initialOwner","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint16","name":"_commissionPercent","type":"uint16"},{"internalType":"uint16","name":"_penaltyPercent","type":"uint16"},{"internalType":"string","name":"_uriLink","type":"string"},{"internalType":"address","name":"_marketplaceAddress","type":"address"}],"name":"createOfferSC","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"discount","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"influencerProfitPercents","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"refferalToInfluencer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_discount","type":"uint16"}],"name":"setDiscountValue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_profitPercent","type":"uint8"},{"internalType":"address","name":"_user","type":"address"}],"name":"setProfitPercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"erc20Address","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"withdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6080601f61565f38819003918201601f19168301916001600160401b0383118484101760da57808492604094855283398101031260d55780516001600160a01b038116919082900360d557602001519061ffff8216820360d557801560bf5760005490604051928160018060a01b0384167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a36001600160b01b03199092161760a09190911b61ffff60a01b161760005561556e90816100f18239f35b631e4fbdf760e01b600052600060045260246000fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe608080604052600436101561001d575b50361561001b57600080fd5b005b60003560e01c90816323f6f968146109a75750806351cff8d9146109345780635d8162b0146108cb5780636b6f4a9d14610888578063715018a6146107ec5780638da5cb5b1461079a578063a1db9782146106be578063b915d1dd1461062e578063e04d70bc1461037d578063ec906f7614610274578063ef57e0b4146101a55763f2fde38b146100ae573861000f565b346101a05760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a05773ffffffffffffffffffffffffffffffffffffffff6100fa610a1e565b610102610b79565b1680156101715773ffffffffffffffffffffffffffffffffffffffff600054827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b7f1e4fbdf700000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b600080fd5b346101a05760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a05760043560ff81168091036101a0576101ea610a41565b6101f2610b79565b6064821161024a5773ffffffffffffffffffffffffffffffffffffffff1660005260026020526040600020907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000825416179055600080f35b7f3cb42c8a0000000000000000000000000000000000000000000000000000000060005260046000fd5b346101a05760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a0576102ab610a1e565b33600052600160205273ffffffffffffffffffffffffffffffffffffffff604060002054166103535760407ffe894b43a2eb942442ee61921094be387ddcdc3a20b3ef07188febf719a9eea69133600052600160205273ffffffffffffffffffffffffffffffffffffffff82600020911690817fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790558151903382526020820152a1005b7f336b2c1b0000000000000000000000000000000000000000000000000000000060005260046000fd5b346101a0576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a05760043567ffffffffffffffff81116101a057366023820112156101a057806004013567ffffffffffffffff81116101a05736602482840101116101a0576103f2610a41565b60443567ffffffffffffffff81116101a057610412903690600401610aa5565b9060643567ffffffffffffffff81116101a057610433903690600401610aa5565b906084359061ffff82168092036101a05760a43561ffff81168091036101a05760c43567ffffffffffffffff81116101a057610473903690600401610aa5565b9060e43573ffffffffffffffffffffffffffffffffffffffff81168091036101a05761049d610b79565b60405193614970908186019386851067ffffffffffffffff8611176105ff57869573ffffffffffffffffffffffffffffffffffffffff6105289360e095610bc98a39308852166020870152610100604087015261050f61050161010088018d610b1a565b87810360608901528b610b1a565b9189608088015260a087015285820360c0870152610b1a565b92015203906000f09182156105f357601f8573ffffffffffffffffffffffffffffffffffffffff9660247faad9ed14e5a3a1445c95acc441b3e0db97c4458cbaf66f3836aa43898be962e8996105cc7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0966105be60209b6040519d8e9c168c52338d8d015260c060408d015260c08c0190610b1a565b908a820360608c0152610b1a565b96608089015287870360a089015282875201878601376000868286010152011601030190a1005b6040513d6000823e3d90fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b346101a05760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a05760043561ffff811681036101a057610673610b79565b7fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff75ffff00000000000000000000000000000000000000006000549260a01b16911617600055600080f35b346101a05760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a0576000602073ffffffffffffffffffffffffffffffffffffffff6064610710610a1e565b610718610b79565b60405194859384927f23b872dd0000000000000000000000000000000000000000000000000000000084523060048501523360248501526024356044850152165af180156105f35761076657005b6020813d602011610792575b8161077f60209383610a64565b810103126101a05751801515036101a057005b3d9150610772565b346101a05760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a057602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b346101a05760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a057610823610b79565b600073ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346101a05760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a057602061ffff60005460a01c16604051908152f35b346101a05760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a05773ffffffffffffffffffffffffffffffffffffffff610917610a1e565b166000526002602052602061ffff60406000205416604051908152f35b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a057600080808061096b610a1e565b610973610b79565b47908290821561099d575b73ffffffffffffffffffffffffffffffffffffffff1690f1156105f357005b6108fc915061097e565b346101a05760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a05760209073ffffffffffffffffffffffffffffffffffffffff6109f6610a1e565b166000526001825273ffffffffffffffffffffffffffffffffffffffff604060002054168152f35b6004359073ffffffffffffffffffffffffffffffffffffffff821682036101a057565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101a057565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176105ff57604052565b81601f820112156101a05780359067ffffffffffffffff82116105ff5760405192610af860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8601160185610a64565b828452602083830101116101a057816000926020809301838601378301015290565b919082519283825260005b848110610b645750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b80602080928401015182828601015201610b25565b73ffffffffffffffffffffffffffffffffffffffff600054163303610b9a57565b7f118cdaa7000000000000000000000000000000000000000000000000000000006000523360045260246000fdfe60c06040526149708038038061001481610595565b928339810190610100818303126105905761002e816105ba565b9161003b602083016105ba565b60408301519092906001600160401b038111610590578261005d9183016105ce565b60608201519091906001600160401b038111610590578361007f9183016105ce565b9361008c60808301610639565b9461009960a08401610639565b60c084015190956001600160401b038211610590576100bf60e0916100c69387016105ce565b94016105ba565b600160008181559080556002556004805465ffffffffffff60a01b1916780100000001000000000000000000000000000000000000000017905560055490949061010f90610648565b601f811161056d575b50600060055560016006558051906001600160401b0382116103bd578190610141600b54610648565b601f811161051e575b50602090601f83116001146104b6576000926104ab575b50508160011b916000199060031b1c191617600b555b8051906001600160401b0382116103bd578190610195600c54610648565b601f811161045c575b50602090601f83116001146103f4576000926103e9575b50508160011b916000199060031b1c191617600c555b6001600160a01b031680156103d357601280546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a38051906001600160401b0382116103bd57819061023a600554610648565b601f811161037f575b50602090601f83116001146103175760009261030c575b50508160011b916000199060031b1c1916176005555b6004805460c09390931b61ffff60c01b16600163ffff000160b01b031990931660a09490941b61ffff60a01b1693909317919091176001600160a01b039091161790556080526040516142d6908161069a823960805181818161045301528181610b6f01528181611a1401528181611cfe01528181611fc0015281816122220152818161277f015281816136920152613801015260a051815050f35b01519050388061025a565b600560009081528281209350601f198516905b818110610367575090846001959493921061034e575b505050811b01600555610270565b015160001960f88460031b161c19169055388080610340565b9293602060018192878601518155019501930161032a565b6103ad9060056000526020600020601f850160051c810191602086106103b3575b601f0160051c0190610682565b38610243565b90915081906103a0565b634e487b7160e01b600052604160045260246000fd5b631e4fbdf760e01b600052600060045260246000fd5b0151905038806101b5565b600c60009081528281209350601f198516905b818110610444575090846001959493921061042b575b505050811b01600c556101cb565b015160001960f88460031b161c1916905538808061041d565b92936020600181928786015181550195019301610407565b600c6000526104a5907fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7601f850160051c810191602086106103b357601f0160051c0190610682565b3861019e565b015190503880610161565b600b60009081528281209350601f198516905b81811061050657509084600195949392106104ed575b505050811b01600b55610177565b015160001960f88460031b161c191690553880806104df565b929360206001819287860151815501950193016104c9565b600b600052610567907f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9601f850160051c810191602086106103b357601f0160051c0190610682565b3861014a565b61058a906005600052601f6020600020910160051c810190610682565b38610118565b600080fd5b6040519190601f01601f191682016001600160401b038111838210176103bd57604052565b51906001600160a01b038216820361059057565b81601f82011215610590578051906001600160401b0382116103bd576105fd601f8301601f1916602001610595565b92828452602083830101116105905760005b82811061062457505060206000918301015290565b8060208092840101518282870101520161060f565b519061ffff8216820361059057565b90600182811c92168015610678575b602083101461066257565b634e487b7160e01b600052602260045260246000fd5b91607f1691610657565b81811061068d575050565b6000815560010161068256fe608080604052600436101561001a575b50361561001857005b005b60003560e01c90816301ffc9a714612bf05750806306fdde0314612b29578063081812fc14612abf578063095ea7b314612939578063125ff95d1461255f578063161ba46a1461251c5780632372243b146124d857806323b872dd146124c15780632953e714146124355780632cbf8fb9146122465780633ced3171146121d757806342842e0e146121ad57806350bd305c14611f4c578063528a28b714611f08578063629b63071461182f5780636352211e146117d55780636cd3e830146116e457806370a082311461164a578063715018a6146115ac57806377d3550b14611569578063860015191461152d5780638da5cb5b146114db57806390e6871a1461149157806395d89b411461138757806399707f9c146112ab5780639a06b0b1146112615780639d76ea581461120f578063a22cb46514611102578063abc9104314610ebf578063b88d4fde14610e18578063bf96f31714610dc9578063c594cc6514610d2e578063c87b56dd14610cd9578063d96a094a146109f7578063e5e03c84146108b1578063e7fad70a146107e8578063e985e9c514610753578063f0e4d60e146102cb5763f2fde38b146101d4573861000f565b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65773ffffffffffffffffffffffffffffffffffffffff610220612d76565b610228613911565b1680156102975773ffffffffffffffffffffffffffffffffffffffff601254827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617601255167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b7f1e4fbdf700000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b600080fd5b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043580600052600760205260406000209073ffffffffffffffffffffffffffffffffffffffff6040519261032984612e62565b80548452600260018201549160208601928352015461035b60ff606060408801978685168952019260a01c16826132c2565b6103658251613662565b9095610370876137d2565b9891969092511633036107295783519760058910156106fa576003600099146106d25784516005811015610655576001146106aa57845160058110156106555760041461068257845160058110156106555760021480610642575b6105f3578890888252600760205260026040832001740300000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055818080806104348c61042f8b8a613003565b613003565b8181156105ea575b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690f1156105dd5761ffff889416610593575b50509061042f6104a09361049893613003565b600254613010565b60025551600581101561056657849060020361055c5750518060011b908082046002149015171561052f5783808080935b818115610526575b3390f11561051b577fafe5eb92bc7335536bafdb5ec3cc9545b5c1f06f5f3886690a8d6640084855a9916060916040519182523060208301526040820152a180f35b6040513d84823e3d90fd5b506108fc6104d9565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b80808093516104d1565b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526021600452fd5b818093948192829082156105d3575b73ffffffffffffffffffffffffffffffffffffffff1690f1156105c85784908789610485565b6040513d88823e3d90fd5b6108fc91506105a2565b50604051903d90823e3d90fd5b506108fc61043c565b5084516040517f42d45f780000000000000000000000000000000000000000000000000000000081523460048201526024810191909152604481019190915260648101839052608490fd5b0390fd5b5061064d8483613003565b3414156103cb565b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526021600452fd5b6004897f1afb0ae5000000000000000000000000000000000000000000000000000000008152fd5b6004897fb21ba927000000000000000000000000000000000000000000000000000000008152fd5b6004897f219055cc000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f5ec823510000000000000000000000000000000000000000000000000000000060005260046000fd5b346102c65760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65761078a612d76565b73ffffffffffffffffffffffffffffffffffffffff6107a7612d99565b9116600052601060205273ffffffffffffffffffffffffffffffffffffffff60406000209116600052602052602060ff604060002054166040519015158152f35b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043561ffff81168082036102c6576103e890610832613911565b1015610887577fffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffff79ffff0000000000000000000000000000000000000000000000006004549260c01b16911617600455600080f35b7f3cb42c8a0000000000000000000000000000000000000000000000000000000060005260046000fd5b346102c65760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043560443560243573ffffffffffffffffffffffffffffffffffffffff821682036102c6576064359273ffffffffffffffffffffffffffffffffffffffff841684036102c65773ffffffffffffffffffffffffffffffffffffffff6004541633036109cd5761098460409482600052600960205261097d86600020549484600052600a6020526109778189600020549888613b06565b96613003565b9084613b06565b9161098e826139d7565b60005260086020528360002081600052602052600060028582208281558260018201550155600052600a60205260008381205582519182526020820152f35b7fcf6b8f780000000000000000000000000000000000000000000000000000000060005260046000fd5b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043560ff60045460b01c16610caf5780600052600760205260406000209060405190610a4d82612e62565b82548252600260018401549360208401948552015473ffffffffffffffffffffffffffffffffffffffff81166040840152610a9260ff606085019260a01c16826132c2565b610a9c8451613960565b81600052600760205260ff60026040600020015460a01c1660058110156106fa57600114610c8557519260058410156106fa57600460009414610c5d57610b308491838352600760205260026040842001740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff82541617905551613662565b90610b3a816137d2565b9085808080610b508761042f8b8b9d9a9d613003565b818115610c54575b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690f11561051b5761ffff16610c05575b507fb72f862d94450c8b8e1ee32c6630970bee0e51cbfaffb8f401e6e312d6ece18060a08686610be58a610bda6104988461042f8c8c613003565b600255513384613b06565b60405192835233602084015230604084015260608301526080820152a180f35b81808681938299989799908215610c4a575b73ffffffffffffffffffffffffffffffffffffffff1690f115610c3f57858794929394610b9f565b6040513d87823e3d90fd5b6108fc9150610c17565b506108fc610b58565b6004847f1afb0ae5000000000000000000000000000000000000000000000000000000008152fd5b7f0b3465c20000000000000000000000000000000000000000000000000000000060005260046000fd5b7fd989c4ae0000000000000000000000000000000000000000000000000000000060005260046000fd5b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657610d2a610d166004356134d5565b604051918291602083526020830190612d33565b0390f35b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043561ffff81168082036102c6576103e890610d78613911565b1015610887577fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff75ffff00000000000000000000000000000000000000006004549260a01b16911617600455600080f35b346102c657610dd736612e2e565b9060005260086020526040600020906000526020526060604060002080549060ff600260018301549201541690604051928352602083015215156040820152f35b346102c65760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657610e4f612d76565b610e57612d99565b6064359167ffffffffffffffff83116102c657366023840112156102c657826004013591610e8483612f0a565b92610e926040519485612ec9565b80845236602482870101116102c65760208160009260246100189801838801378501015260443591613313565b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043580600052600760205260406000209073ffffffffffffffffffffffffffffffffffffffff600260405193610f2485612e62565b8054855260018101546020860152015492610f5260ff606060408401938588168552019560a01c16856132c2565b511633036107295781519160058310156106fa576003600093146110da57805160058110156110ad5760041461108557516005811015611058577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01611030576040817f9eb7657bef9907ba1467bb58e6f3b70349f0ee413302ab895acbc8bc225e4b219284526007602052600282852001740400000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff8254161790558151908152306020820152a180f35b6004827fdd980a31000000000000000000000000000000000000000000000000000000008152fd5b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526021600452fd5b6004837f1afb0ae5000000000000000000000000000000000000000000000000000000008152fd5b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526021600452fd5b6004837f219055cc000000000000000000000000000000000000000000000000000000008152fd5b346102c65760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657611139612d76565b60243590811515908183036102c65773ffffffffffffffffffffffffffffffffffffffff169182156111e1576111b39033600052601060205260406000208460005260205260406000209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b6040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b827f5b08ba180000000000000000000000000000000000000000000000000000000060005260045260246000fd5b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657602073ffffffffffffffffffffffffffffffffffffffff60035416604051908152f35b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657600435600052600a6020526020604060002054604051908152f35b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6576112e2613911565b60045460ff8160b01c161561135d577fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff770100000000000000000000000000000000000000000000009116176004557f206f7aa88b4936d5a9b98bed26f5f0d5e12c04b26ae217ebdb3a623a86a55f596020604051308152a1005b7fc79a5b5b0000000000000000000000000000000000000000000000000000000060005260046000fd5b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6576040516000600c546113c781612f44565b808452906001811690811561144f57506001146113ef575b610d2a83610d1681850382612ec9565b919050600c6000527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7916000905b80821061143557509091508101602001610d166113df565b91926001816020925483858801015201910190929161141d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b84019091019150610d1690506113df565b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043560005260096020526020604060002054604051908152f35b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657602073ffffffffffffffffffffffffffffffffffffffff60125416604051908152f35b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6576020600254604051908152f35b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657602061ffff60045460a01c16604051908152f35b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6576115e3613911565b600073ffffffffffffffffffffffffffffffffffffffff6012547fffffffffffffffffffffffff00000000000000000000000000000000000000008116601255167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65773ffffffffffffffffffffffffffffffffffffffff611696612d76565b1680156116b557600052600e6020526020604060002054604051908152f35b7f89c62b6400000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b346102c65760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65773ffffffffffffffffffffffffffffffffffffffff611730612d76565b611738613911565b167fffffffffffffffffffffffff000000000000000000000000000000000000000060035416176003556024356006557601000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff60045416176004557f3b11d3e657d8d514329702c63d255f4697baf18e6410e1f9072c93c731eb70326020604051308152a1005b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760206118116004356135bf565b73ffffffffffffffffffffffffffffffffffffffff60405191168152f35b61183836612e2e565b90611842826135bf565b918160005260076020526040600020926040519261185f84612e62565b8454845260026001860154956020860196875201549473ffffffffffffffffffffffffffffffffffffffff861660408601526118a560ff606087019760a01c16876132c2565b8160005260086020526040600020846000526020526040600020906040516118cc81612ead565b82548152604060ff6002600186015495602085019687520154161515910152855115611eda5773ffffffffffffffffffffffffffffffffffffffff841690338203611eac5787519660058810156106fa5760016000981480611e9c575b611e7457611936876139d7565b8488526008602052604088208789526020526002604089200160017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055835190606482029180830460641490151715611e475751908115611e1a576064916119a591048351612ff0565b0497516005811015611ded57600203611ca257506119c287613662565b906119cc816137d2565b93909192839b6119dc8383613003565b3403611c5a57508a806119f58661042f83968496613003565b818115611c51575b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690f115611c08579061ffff89939216611c13575b50505073ffffffffffffffffffffffffffffffffffffffff60035416906040517f313ce567000000000000000000000000000000000000000000000000000000008152602081600481865afa908115611c0857611abe602093926044928b91611bdb575b50611ab8875191612fb0565b90612ff0565b918960405195869485937fa9059cbb000000000000000000000000000000000000000000000000000000008552600485015260248401525af19081156105c8578691611bac575b5015611b845794611b7e917f7368bfddf54437295c38d71448fd337c832ab763b8d669fa154f59a111c5640a95965b5160408051928352602083019190915281019490945273ffffffffffffffffffffffffffffffffffffffff909216606084015230608084015260a0830191909152819060c0820190565b0390a180f35b6004857f90b8ec18000000000000000000000000000000000000000000000000000000008152fd5b611bce915060203d602011611bd4575b611bc68183612ec9565b8101906132fb565b87611b05565b503d611bbc565b611bfb9150853d8711611c01575b611bf38183612ec9565b810190612f97565b8c611aac565b503d611be9565b6040513d8a823e3d90fd5b82809291819282908215611c47575b73ffffffffffffffffffffffffffffffffffffffff1690f115610c3f57858880611a48565b6108fc9150611c22565b506108fc6119fd565b6040517f42d45f780000000000000000000000000000000000000000000000000000000081523460048201526024810191909152604481019190915260648101829052608490fd5b908697929396916103e8611cbf61ffff60045460c01c1686612ff0565b0491611cca836137d2565b9691809491949787808080611cdf868c613003565b818115611de4575b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690f115611dd95761ffff889616611d87575b5050839461042f859493611d449351613010565b90828215611d7e575bf115610c3f577f7368bfddf54437295c38d71448fd337c832ab763b8d669fa154f59a111c5640a94611b7e92611b34565b506108fc611d4d565b948080939594979692819382908215611dcf575b73ffffffffffffffffffffffffffffffffffffffff1690f115611dc45790928492938c80611d30565b6040513d86823e3d90fd5b6108fc9150611d9b565b6040513d89823e3d90fd5b506108fc611ce7565b6024887f4e487b710000000000000000000000000000000000000000000000000000000081526021600452fd5b6024897f4e487b710000000000000000000000000000000000000000000000000000000081526012600452fd5b6024897f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6004887f7361fc0c000000000000000000000000000000000000000000000000000000008152fd5b5060ff60045460b81c1615611929565b857fd64dfb010000000000000000000000000000000000000000000000000000000060005260045260246000fd5b827fc87c16410000000000000000000000000000000000000000000000000000000060005260045260246000fd5b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657602060ff60045460b81c166040519015158152f35b611f5536612e2e565b9060ff60045460b01c16610caf57611f6c82613662565b611f75826137d2565b91939092611f8287613960565b633b9aca00861161217b57600080611fa18761042f8396958496613003565b818115612172575b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690f11561215c5761ffff839216612128575b505060405161200081612e62565b8281526020810184815273ffffffffffffffffffffffffffffffffffffffff8060026040850194338652606081019460008652600054600052600760205260406000209151825551600182015501935116167fffffffffffffffffffffffff0000000000000000000000000000000000000000835416178255519360058510156106fa5781547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1660a095861b74ff000000000000000000000000000000000000000016179091556000805460408051828152602081019690965285019290925233606085015230608085015293830191909152612123917f8fd77df48aedff028372940389f8d7b6c07528858c2f7cc94e3c5ccd9fe2b2239060c090a16132ce565b815580f35b6000808093819382908215612168575b73ffffffffffffffffffffffffffffffffffffffff1690f11561215c578084611ff2565b6040513d6000823e3d90fd5b6108fc9150612138565b506108fc611fa9565b7f4e42c81400000000000000000000000000000000000000000000000000000000600052633b9aca0060045260246000fd5b346102c6576100186121be36612dbc565b90604051926121ce602085612ec9565b60008452613313565b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043567ffffffffffffffff81116102c657366023820112156102c657806004013567ffffffffffffffff81116102c65736602482840101116102c6576122ba613911565b6000906122c8600554612f44565b601f81116123ef575b5081601f8211600114612332578190839461231e9492612324575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b60055580f35b6024925001013584806122ec565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08216937f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db091845b8681106123d45750836001959610612399575b505050811b0160055580f35b01602401357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600384901b60f8161c1916905583808061238d565b9092602060018192602487870101358155019401910161237a565b6005835260208320601f830160051c8101916020841061242b575b601f0160051c01905b81811061242057506122d1565b838155600101612413565b909150819061240a565b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043560005260076020526040600020805473ffffffffffffffffffffffffffffffffffffffff6002600184015493015460ff8160a01c1693604051938452602084015216604082015260058210156106fa576080916060820152f35b346102c6576100186124d236612dbc565b9161301d565b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657602060ff60045460b01c166040519015158152f35b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657602061ffff60045460c01c16604051908152f35b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043580600052600760205260406000209060ff60045460b81c1661290f578154156128e2576002820160ff815460a01c1660058110156106fa576001036128b85773ffffffffffffffffffffffffffffffffffffffff600354169260018101916125f48354613662565b6125ff8293926137d2565b9491989093740200000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff8254161790556004602073ffffffffffffffffffffffffffffffffffffffff60035416604051928380927f313ce5670000000000000000000000000000000000000000000000000000000082525afa90811561215c5760006126af61270f9382938391612899575b50611ab88b5491612fb0565b60405160208101917f23b872dd0000000000000000000000000000000000000000000000000000000083523360248301523060448301526064820152606481526126fa608482612ec9565b519082865af1612708613ad6565b9083614203565b805190811515918261287e575b505061285157509061272d91613003565b60008080806127418561042f8b5480613010565b818115612848575b3390f11561215c57600080806127608a8295613003565b81811561283f575b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690f11561215c5761ffff16612802575b505490546040805193845260208401929092529082015233606082015230608082015260a08101919091527ffa9aad700273c94161651bdca5c167b4d924f83f2e832d88a861debed12438619060c090a1005b6000808087819482908215612835575b73ffffffffffffffffffffffffffffffffffffffff1690f11561215c57846127af565b6108fc9150612812565b506108fc612768565b506108fc612749565b7f5274afe70000000000000000000000000000000000000000000000000000000060005260045260246000fd5b61289192506020809183010191016132fb565b158a8061271c565b6128b2915060203d602011611c0157611bf38183612ec9565b8e6126a3565b7fdd980a310000000000000000000000000000000000000000000000000000000060005260046000fd5b7fc87c16410000000000000000000000000000000000000000000000000000000060005260045260246000fd5b7fb21ba9270000000000000000000000000000000000000000000000000000000060005260046000fd5b346102c65760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657612970612d76565b60243561297c816135bf565b33151580612a9f575b80612a4e575b612a2057819073ffffffffffffffffffffffffffffffffffffffff80851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a4600052600f60205273ffffffffffffffffffffffffffffffffffffffff604060002091167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055600080f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b5073ffffffffffffffffffffffffffffffffffffffff81166000526010602052604060002073ffffffffffffffffffffffffffffffffffffffff331660005260205260ff604060002054161561298b565b503373ffffffffffffffffffffffffffffffffffffffff82161415612985565b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657600435612afa816135bf565b50600052600f602052602073ffffffffffffffffffffffffffffffffffffffff60406000205416604051908152f35b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6576040516000600b54612b6981612f44565b808452906001811690811561144f5750600114612b9057610d2a83610d1681850382612ec9565b919050600b6000527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9916000905b808210612bd657509091508101602001610d166113df565b919260018160209254838588010152019101909291612bbe565b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036102c657817f490649060000000000000000000000000000000000000000000000000000000060209314908115612c82575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115612ce6575b8115612cbc575b5083612c7b565b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612cb5565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612cae565b60005b838110612d235750506000910152565b8181015183820152602001612d13565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093612d6f81518092818752878088019101612d10565b0116010190565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036102c657565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036102c657565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60609101126102c65760043573ffffffffffffffffffffffffffffffffffffffff811681036102c6579060243573ffffffffffffffffffffffffffffffffffffffff811681036102c6579060443590565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60409101126102c6576004359060243590565b6080810190811067ffffffffffffffff821117612e7e57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6060810190811067ffffffffffffffff821117612e7e57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117612e7e57604052565b67ffffffffffffffff8111612e7e57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b90600182811c92168015612f8d575b6020831014612f5e57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691612f53565b908160209103126102c6575160ff811681036102c65790565b60ff16604d8111612fc157600a0a90565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810292918115918404141715612fc157565b91908203918211612fc157565b91908201809211612fc157565b919073ffffffffffffffffffffffffffffffffffffffff1691821561329357600090828252600d6020528273ffffffffffffffffffffffffffffffffffffffff6040842054169485331515806131a5575b507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef73ffffffffffffffffffffffffffffffffffffffff9582613135575b838152600e6020526040812060018154019055848152600d60205260408120847fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905580a41680830361310257505050565b7f64283d7b0000000000000000000000000000000000000000000000000000000060005260045260245260445260646000fd5b61316e85600052600f60205260406000207fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055565b828152600e602052604081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81540190556130ac565b91939492505080613222575b156131c15791908390853861306e565b8390856131f3576024917f7e273289000000000000000000000000000000000000000000000000000000008252600452fd5b6044917f177e802f00000000000000000000000000000000000000000000000000000000825233600452602452fd5b50338514801561325d575b806131b15750838152600f6020523373ffffffffffffffffffffffffffffffffffffffff604083205416146131b1565b5084815260106020526040812073ffffffffffffffffffffffffffffffffffffffff3316825260205260ff60408220541661322d565b7f64a0ae9200000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b60058210156106fa5752565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114612fc15760010190565b908160209103126102c6575180151581036102c65790565b9061331f83828461301d565b803b61332c575b50505050565b60209161339873ffffffffffffffffffffffffffffffffffffffff8093169560405195869485947f150b7a020000000000000000000000000000000000000000000000000000000086523360048701521660248501526044840152608060648401526084830190612d33565b03816000865af18091600091613473575b50906133f357506133b8613ad6565b805190816133ee57827f64a0ae920000000000000000000000000000000000000000000000000000000060005260045260246000fd5b602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000007f150b7a0200000000000000000000000000000000000000000000000000000000911603613446575038808080613326565b7f64a0ae920000000000000000000000000000000000000000000000000000000060005260045260246000fd5b6020813d6020116134cd575b8161348c60209383612ec9565b810103126134c95751907fffffffff00000000000000000000000000000000000000000000000000000000821682036134c65750386133a9565b80fd5b5080fd5b3d915061347f565b6134de816135bf565b5060005260116020526040600020604051908160008254926134ff84612f44565b808452936001811690811561357f5750600114613538575b5061352492500382612ec9565b6000604051613534602082612ec9565b5290565b90506000929192526020600020906000915b8183106135635750509060206135249282010138613517565b602091935080600191548385880101520191019091839261354a565b602093506135249592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b82010138613517565b80600052600d60205273ffffffffffffffffffffffffffffffffffffffff604060002054169081156135ef575090565b7f7e2732890000000000000000000000000000000000000000000000000000000060005260045260246000fd5b908160209103126102c6575161ffff811681036102c65790565b908160209103126102c6575173ffffffffffffffffffffffffffffffffffffffff811681036102c65790565b6136796103e89161ffff60045460a01c1690612ff0565b049073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016604051907f6b6f4a9d000000000000000000000000000000000000000000000000000000008252602082600481845afa91821561215c5760009261379d575b506020602491604051928380927f23f6f9680000000000000000000000000000000000000000000000000000000082523360048301525afa801561215c5773ffffffffffffffffffffffffffffffffffffffff9160009161376e575b5016156137685761376461ffff6064921684612ff0565b0490565b50600090565b613790915060203d602011613796575b6137888183612ec9565b810190613636565b3861374d565b503d61377e565b60249192506137c3602091823d84116137cb575b6137bb8183612ec9565b81019061361c565b9291506136f1565b503d6137b1565b6040517f23f6f968000000000000000000000000000000000000000000000000000000008152336004820152917f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1691602084602481865afa92831561215c576024946000946138ef575b50602090604051958680927f5d8162b000000000000000000000000000000000000000000000000000000000825273ffffffffffffffffffffffffffffffffffffffff881660048301525afa93841561215c576000946138c6575b506138c06103e89161ffff861690612ff0565b04929190565b6103e89194506138e76138c09160203d6020116137cb576137bb8183612ec9565b9491506138ad565b602091945061390a90823d8411613796576137888183612ec9565b9390613852565b73ffffffffffffffffffffffffffffffffffffffff60125416330361393257565b7f118cdaa7000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b61396981613662565b61397e61397882849594613003565b83613010565b340361398957505050565b61063e906040519384937f42d45f7800000000000000000000000000000000000000000000000000000000855234600486019094939260609260808301968352602083015260408201520152565b6000818152600d60205273ffffffffffffffffffffffffffffffffffffffff604082205416828115928315613a66575b818152600d602052604081207fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4506135ef5750565b613a9f82600052600f60205260406000207fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055565b828152600e602052604081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8154019055613a07565b3d15613b01573d90613ae782612f0a565b91613af56040519384612ec9565b82523d6000602084013e565b606090565b92919092613b8b600154600260405191613b1f83612ead565b8083526020830186815260408401916000835286600052600860205260406000209060005260205260406000209351845551600184015551151591019060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b6001546000526009602052604060002055600154600052600a602052604060002055600154918290836000907a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008610156141db575b806d04ee2d6d415b85acef8100000000600a9210156141c0575b662386f26fc100008110156141ac575b6305f5e10081101561419b575b61271081101561418c575b606481101561417e575b1015614176575b6001810194600a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6021613c7a613c648a612f0a565b99613c726040519b8c612ec9565b808b52612f0a565b947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe060208b0196013687378901015b01917f30313233343536373839616263646566000000000000000000000000000000008282061a8353048015613d03577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600a9192613ca9565b5050604051948591600091600554613d1a81612f44565b906001811690811561413557506001146140d4575b509282613dad93613d5c60059473ffffffffffffffffffffffffffffffffffffffff989751938491612d10565b017f2e6a736f6e0000000000000000000000000000000000000000000000000000008152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe5810188520186612ec9565b16801561329357600091808352600d60205273ffffffffffffffffffffffffffffffffffffffff60408420541691827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8115159586614064575b838152600e6020526040812060018154019055848152600d60205260408120847fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905580a450614035576001548060005260116020526040600020835167ffffffffffffffff8111612e7e57613e818254612f44565b601f8111613fed575b506020601f8211600114613f2557816020949392613efe927ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79798600092613f1a5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b90555b604051908152a1600154613f14816132ce565b60015590565b0151905038806122ec565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082169583600052816000209660005b818110613fd5575096600192849260209796957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7999a10613f9e575b505050811b019055613f01565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c19169055388080613f91565b83830151895560019098019760209384019301613f55565b826000526020600020601f830160051c8101916020841061402b575b601f0160051c01905b81811061401f5750613e8a565b60008155600101614012565b9091508190614009565b7f73c6ac6e00000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b61409d85600052600f60205260406000207fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055565b828152600e602052604081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8154019055613e07565b9091925060056000527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db06000905b828210614119575050830160200191906005613d2f565b80546020838c018101919091528a965090910190600101614102565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166020808801919091528215159092028601909101935060059050613d2f565b600101613c2e565b606460029104920191613c27565b61271060049104920191613c1d565b6305f5e10060089104920191613c12565b662386f26fc1000060109104920191613c05565b6d04ee2d6d415b85acef810000000060209104920191613bf5565b50604090507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008504613bdb565b90614242575080511561421857805190602001fd5b7f1425ea420000000000000000000000000000000000000000000000000000000060005260046000fd5b81511580614297575b614253575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b50803b1561424b56fea2646970667358221220111cf0947d59636f65dfbc8bc0894c101c8d5d3ebbb44d9fe543e3ef97f6699a64736f6c634300081a0033a26469706673582212206f63e649585f826532accfb11c1f146c2e34c773a352fb9e6f78fd0add1cd1e464736f6c634300081a0033000000000000000000000000c946cb236481c159f460b212b34ab246dac37fcd000000000000000000000000000000000000000000000000000000000000000a
Deployed Bytecode
0x608080604052600436101561001d575b50361561001b57600080fd5b005b60003560e01c90816323f6f968146109a75750806351cff8d9146109345780635d8162b0146108cb5780636b6f4a9d14610888578063715018a6146107ec5780638da5cb5b1461079a578063a1db9782146106be578063b915d1dd1461062e578063e04d70bc1461037d578063ec906f7614610274578063ef57e0b4146101a55763f2fde38b146100ae573861000f565b346101a05760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a05773ffffffffffffffffffffffffffffffffffffffff6100fa610a1e565b610102610b79565b1680156101715773ffffffffffffffffffffffffffffffffffffffff600054827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b7f1e4fbdf700000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b600080fd5b346101a05760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a05760043560ff81168091036101a0576101ea610a41565b6101f2610b79565b6064821161024a5773ffffffffffffffffffffffffffffffffffffffff1660005260026020526040600020907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000825416179055600080f35b7f3cb42c8a0000000000000000000000000000000000000000000000000000000060005260046000fd5b346101a05760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a0576102ab610a1e565b33600052600160205273ffffffffffffffffffffffffffffffffffffffff604060002054166103535760407ffe894b43a2eb942442ee61921094be387ddcdc3a20b3ef07188febf719a9eea69133600052600160205273ffffffffffffffffffffffffffffffffffffffff82600020911690817fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790558151903382526020820152a1005b7f336b2c1b0000000000000000000000000000000000000000000000000000000060005260046000fd5b346101a0576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a05760043567ffffffffffffffff81116101a057366023820112156101a057806004013567ffffffffffffffff81116101a05736602482840101116101a0576103f2610a41565b60443567ffffffffffffffff81116101a057610412903690600401610aa5565b9060643567ffffffffffffffff81116101a057610433903690600401610aa5565b906084359061ffff82168092036101a05760a43561ffff81168091036101a05760c43567ffffffffffffffff81116101a057610473903690600401610aa5565b9060e43573ffffffffffffffffffffffffffffffffffffffff81168091036101a05761049d610b79565b60405193614970908186019386851067ffffffffffffffff8611176105ff57869573ffffffffffffffffffffffffffffffffffffffff6105289360e095610bc98a39308852166020870152610100604087015261050f61050161010088018d610b1a565b87810360608901528b610b1a565b9189608088015260a087015285820360c0870152610b1a565b92015203906000f09182156105f357601f8573ffffffffffffffffffffffffffffffffffffffff9660247faad9ed14e5a3a1445c95acc441b3e0db97c4458cbaf66f3836aa43898be962e8996105cc7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0966105be60209b6040519d8e9c168c52338d8d015260c060408d015260c08c0190610b1a565b908a820360608c0152610b1a565b96608089015287870360a089015282875201878601376000868286010152011601030190a1005b6040513d6000823e3d90fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b346101a05760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a05760043561ffff811681036101a057610673610b79565b7fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff75ffff00000000000000000000000000000000000000006000549260a01b16911617600055600080f35b346101a05760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a0576000602073ffffffffffffffffffffffffffffffffffffffff6064610710610a1e565b610718610b79565b60405194859384927f23b872dd0000000000000000000000000000000000000000000000000000000084523060048501523360248501526024356044850152165af180156105f35761076657005b6020813d602011610792575b8161077f60209383610a64565b810103126101a05751801515036101a057005b3d9150610772565b346101a05760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a057602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b346101a05760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a057610823610b79565b600073ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346101a05760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a057602061ffff60005460a01c16604051908152f35b346101a05760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a05773ffffffffffffffffffffffffffffffffffffffff610917610a1e565b166000526002602052602061ffff60406000205416604051908152f35b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a057600080808061096b610a1e565b610973610b79565b47908290821561099d575b73ffffffffffffffffffffffffffffffffffffffff1690f1156105f357005b6108fc915061097e565b346101a05760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101a05760209073ffffffffffffffffffffffffffffffffffffffff6109f6610a1e565b166000526001825273ffffffffffffffffffffffffffffffffffffffff604060002054168152f35b6004359073ffffffffffffffffffffffffffffffffffffffff821682036101a057565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101a057565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176105ff57604052565b81601f820112156101a05780359067ffffffffffffffff82116105ff5760405192610af860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8601160185610a64565b828452602083830101116101a057816000926020809301838601378301015290565b919082519283825260005b848110610b645750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b80602080928401015182828601015201610b25565b73ffffffffffffffffffffffffffffffffffffffff600054163303610b9a57565b7f118cdaa7000000000000000000000000000000000000000000000000000000006000523360045260246000fdfe60c06040526149708038038061001481610595565b928339810190610100818303126105905761002e816105ba565b9161003b602083016105ba565b60408301519092906001600160401b038111610590578261005d9183016105ce565b60608201519091906001600160401b038111610590578361007f9183016105ce565b9361008c60808301610639565b9461009960a08401610639565b60c084015190956001600160401b038211610590576100bf60e0916100c69387016105ce565b94016105ba565b600160008181559080556002556004805465ffffffffffff60a01b1916780100000001000000000000000000000000000000000000000017905560055490949061010f90610648565b601f811161056d575b50600060055560016006558051906001600160401b0382116103bd578190610141600b54610648565b601f811161051e575b50602090601f83116001146104b6576000926104ab575b50508160011b916000199060031b1c191617600b555b8051906001600160401b0382116103bd578190610195600c54610648565b601f811161045c575b50602090601f83116001146103f4576000926103e9575b50508160011b916000199060031b1c191617600c555b6001600160a01b031680156103d357601280546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a38051906001600160401b0382116103bd57819061023a600554610648565b601f811161037f575b50602090601f83116001146103175760009261030c575b50508160011b916000199060031b1c1916176005555b6004805460c09390931b61ffff60c01b16600163ffff000160b01b031990931660a09490941b61ffff60a01b1693909317919091176001600160a01b039091161790556080526040516142d6908161069a823960805181818161045301528181610b6f01528181611a1401528181611cfe01528181611fc0015281816122220152818161277f015281816136920152613801015260a051815050f35b01519050388061025a565b600560009081528281209350601f198516905b818110610367575090846001959493921061034e575b505050811b01600555610270565b015160001960f88460031b161c19169055388080610340565b9293602060018192878601518155019501930161032a565b6103ad9060056000526020600020601f850160051c810191602086106103b3575b601f0160051c0190610682565b38610243565b90915081906103a0565b634e487b7160e01b600052604160045260246000fd5b631e4fbdf760e01b600052600060045260246000fd5b0151905038806101b5565b600c60009081528281209350601f198516905b818110610444575090846001959493921061042b575b505050811b01600c556101cb565b015160001960f88460031b161c1916905538808061041d565b92936020600181928786015181550195019301610407565b600c6000526104a5907fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7601f850160051c810191602086106103b357601f0160051c0190610682565b3861019e565b015190503880610161565b600b60009081528281209350601f198516905b81811061050657509084600195949392106104ed575b505050811b01600b55610177565b015160001960f88460031b161c191690553880806104df565b929360206001819287860151815501950193016104c9565b600b600052610567907f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9601f850160051c810191602086106103b357601f0160051c0190610682565b3861014a565b61058a906005600052601f6020600020910160051c810190610682565b38610118565b600080fd5b6040519190601f01601f191682016001600160401b038111838210176103bd57604052565b51906001600160a01b038216820361059057565b81601f82011215610590578051906001600160401b0382116103bd576105fd601f8301601f1916602001610595565b92828452602083830101116105905760005b82811061062457505060206000918301015290565b8060208092840101518282870101520161060f565b519061ffff8216820361059057565b90600182811c92168015610678575b602083101461066257565b634e487b7160e01b600052602260045260246000fd5b91607f1691610657565b81811061068d575050565b6000815560010161068256fe608080604052600436101561001a575b50361561001857005b005b60003560e01c90816301ffc9a714612bf05750806306fdde0314612b29578063081812fc14612abf578063095ea7b314612939578063125ff95d1461255f578063161ba46a1461251c5780632372243b146124d857806323b872dd146124c15780632953e714146124355780632cbf8fb9146122465780633ced3171146121d757806342842e0e146121ad57806350bd305c14611f4c578063528a28b714611f08578063629b63071461182f5780636352211e146117d55780636cd3e830146116e457806370a082311461164a578063715018a6146115ac57806377d3550b14611569578063860015191461152d5780638da5cb5b146114db57806390e6871a1461149157806395d89b411461138757806399707f9c146112ab5780639a06b0b1146112615780639d76ea581461120f578063a22cb46514611102578063abc9104314610ebf578063b88d4fde14610e18578063bf96f31714610dc9578063c594cc6514610d2e578063c87b56dd14610cd9578063d96a094a146109f7578063e5e03c84146108b1578063e7fad70a146107e8578063e985e9c514610753578063f0e4d60e146102cb5763f2fde38b146101d4573861000f565b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65773ffffffffffffffffffffffffffffffffffffffff610220612d76565b610228613911565b1680156102975773ffffffffffffffffffffffffffffffffffffffff601254827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617601255167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b7f1e4fbdf700000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b600080fd5b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043580600052600760205260406000209073ffffffffffffffffffffffffffffffffffffffff6040519261032984612e62565b80548452600260018201549160208601928352015461035b60ff606060408801978685168952019260a01c16826132c2565b6103658251613662565b9095610370876137d2565b9891969092511633036107295783519760058910156106fa576003600099146106d25784516005811015610655576001146106aa57845160058110156106555760041461068257845160058110156106555760021480610642575b6105f3578890888252600760205260026040832001740300000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff825416179055818080806104348c61042f8b8a613003565b613003565b8181156105ea575b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690f1156105dd5761ffff889416610593575b50509061042f6104a09361049893613003565b600254613010565b60025551600581101561056657849060020361055c5750518060011b908082046002149015171561052f5783808080935b818115610526575b3390f11561051b577fafe5eb92bc7335536bafdb5ec3cc9545b5c1f06f5f3886690a8d6640084855a9916060916040519182523060208301526040820152a180f35b6040513d84823e3d90fd5b506108fc6104d9565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b80808093516104d1565b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526021600452fd5b818093948192829082156105d3575b73ffffffffffffffffffffffffffffffffffffffff1690f1156105c85784908789610485565b6040513d88823e3d90fd5b6108fc91506105a2565b50604051903d90823e3d90fd5b506108fc61043c565b5084516040517f42d45f780000000000000000000000000000000000000000000000000000000081523460048201526024810191909152604481019190915260648101839052608490fd5b0390fd5b5061064d8483613003565b3414156103cb565b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526021600452fd5b6004897f1afb0ae5000000000000000000000000000000000000000000000000000000008152fd5b6004897fb21ba927000000000000000000000000000000000000000000000000000000008152fd5b6004897f219055cc000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f5ec823510000000000000000000000000000000000000000000000000000000060005260046000fd5b346102c65760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65761078a612d76565b73ffffffffffffffffffffffffffffffffffffffff6107a7612d99565b9116600052601060205273ffffffffffffffffffffffffffffffffffffffff60406000209116600052602052602060ff604060002054166040519015158152f35b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043561ffff81168082036102c6576103e890610832613911565b1015610887577fffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffff79ffff0000000000000000000000000000000000000000000000006004549260c01b16911617600455600080f35b7f3cb42c8a0000000000000000000000000000000000000000000000000000000060005260046000fd5b346102c65760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043560443560243573ffffffffffffffffffffffffffffffffffffffff821682036102c6576064359273ffffffffffffffffffffffffffffffffffffffff841684036102c65773ffffffffffffffffffffffffffffffffffffffff6004541633036109cd5761098460409482600052600960205261097d86600020549484600052600a6020526109778189600020549888613b06565b96613003565b9084613b06565b9161098e826139d7565b60005260086020528360002081600052602052600060028582208281558260018201550155600052600a60205260008381205582519182526020820152f35b7fcf6b8f780000000000000000000000000000000000000000000000000000000060005260046000fd5b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043560ff60045460b01c16610caf5780600052600760205260406000209060405190610a4d82612e62565b82548252600260018401549360208401948552015473ffffffffffffffffffffffffffffffffffffffff81166040840152610a9260ff606085019260a01c16826132c2565b610a9c8451613960565b81600052600760205260ff60026040600020015460a01c1660058110156106fa57600114610c8557519260058410156106fa57600460009414610c5d57610b308491838352600760205260026040842001740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff82541617905551613662565b90610b3a816137d2565b9085808080610b508761042f8b8b9d9a9d613003565b818115610c54575b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690f11561051b5761ffff16610c05575b507fb72f862d94450c8b8e1ee32c6630970bee0e51cbfaffb8f401e6e312d6ece18060a08686610be58a610bda6104988461042f8c8c613003565b600255513384613b06565b60405192835233602084015230604084015260608301526080820152a180f35b81808681938299989799908215610c4a575b73ffffffffffffffffffffffffffffffffffffffff1690f115610c3f57858794929394610b9f565b6040513d87823e3d90fd5b6108fc9150610c17565b506108fc610b58565b6004847f1afb0ae5000000000000000000000000000000000000000000000000000000008152fd5b7f0b3465c20000000000000000000000000000000000000000000000000000000060005260046000fd5b7fd989c4ae0000000000000000000000000000000000000000000000000000000060005260046000fd5b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657610d2a610d166004356134d5565b604051918291602083526020830190612d33565b0390f35b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043561ffff81168082036102c6576103e890610d78613911565b1015610887577fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff75ffff00000000000000000000000000000000000000006004549260a01b16911617600455600080f35b346102c657610dd736612e2e565b9060005260086020526040600020906000526020526060604060002080549060ff600260018301549201541690604051928352602083015215156040820152f35b346102c65760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657610e4f612d76565b610e57612d99565b6064359167ffffffffffffffff83116102c657366023840112156102c657826004013591610e8483612f0a565b92610e926040519485612ec9565b80845236602482870101116102c65760208160009260246100189801838801378501015260443591613313565b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043580600052600760205260406000209073ffffffffffffffffffffffffffffffffffffffff600260405193610f2485612e62565b8054855260018101546020860152015492610f5260ff606060408401938588168552019560a01c16856132c2565b511633036107295781519160058310156106fa576003600093146110da57805160058110156110ad5760041461108557516005811015611058577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01611030576040817f9eb7657bef9907ba1467bb58e6f3b70349f0ee413302ab895acbc8bc225e4b219284526007602052600282852001740400000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff8254161790558151908152306020820152a180f35b6004827fdd980a31000000000000000000000000000000000000000000000000000000008152fd5b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526021600452fd5b6004837f1afb0ae5000000000000000000000000000000000000000000000000000000008152fd5b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526021600452fd5b6004837f219055cc000000000000000000000000000000000000000000000000000000008152fd5b346102c65760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657611139612d76565b60243590811515908183036102c65773ffffffffffffffffffffffffffffffffffffffff169182156111e1576111b39033600052601060205260406000208460005260205260406000209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b6040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b827f5b08ba180000000000000000000000000000000000000000000000000000000060005260045260246000fd5b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657602073ffffffffffffffffffffffffffffffffffffffff60035416604051908152f35b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657600435600052600a6020526020604060002054604051908152f35b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6576112e2613911565b60045460ff8160b01c161561135d577fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff770100000000000000000000000000000000000000000000009116176004557f206f7aa88b4936d5a9b98bed26f5f0d5e12c04b26ae217ebdb3a623a86a55f596020604051308152a1005b7fc79a5b5b0000000000000000000000000000000000000000000000000000000060005260046000fd5b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6576040516000600c546113c781612f44565b808452906001811690811561144f57506001146113ef575b610d2a83610d1681850382612ec9565b919050600c6000527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7916000905b80821061143557509091508101602001610d166113df565b91926001816020925483858801015201910190929161141d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b84019091019150610d1690506113df565b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043560005260096020526020604060002054604051908152f35b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657602073ffffffffffffffffffffffffffffffffffffffff60125416604051908152f35b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6576020600254604051908152f35b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657602061ffff60045460a01c16604051908152f35b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6576115e3613911565b600073ffffffffffffffffffffffffffffffffffffffff6012547fffffffffffffffffffffffff00000000000000000000000000000000000000008116601255167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65773ffffffffffffffffffffffffffffffffffffffff611696612d76565b1680156116b557600052600e6020526020604060002054604051908152f35b7f89c62b6400000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b346102c65760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65773ffffffffffffffffffffffffffffffffffffffff611730612d76565b611738613911565b167fffffffffffffffffffffffff000000000000000000000000000000000000000060035416176003556024356006557601000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff60045416176004557f3b11d3e657d8d514329702c63d255f4697baf18e6410e1f9072c93c731eb70326020604051308152a1005b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760206118116004356135bf565b73ffffffffffffffffffffffffffffffffffffffff60405191168152f35b61183836612e2e565b90611842826135bf565b918160005260076020526040600020926040519261185f84612e62565b8454845260026001860154956020860196875201549473ffffffffffffffffffffffffffffffffffffffff861660408601526118a560ff606087019760a01c16876132c2565b8160005260086020526040600020846000526020526040600020906040516118cc81612ead565b82548152604060ff6002600186015495602085019687520154161515910152855115611eda5773ffffffffffffffffffffffffffffffffffffffff841690338203611eac5787519660058810156106fa5760016000981480611e9c575b611e7457611936876139d7565b8488526008602052604088208789526020526002604089200160017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055835190606482029180830460641490151715611e475751908115611e1a576064916119a591048351612ff0565b0497516005811015611ded57600203611ca257506119c287613662565b906119cc816137d2565b93909192839b6119dc8383613003565b3403611c5a57508a806119f58661042f83968496613003565b818115611c51575b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690f115611c08579061ffff89939216611c13575b50505073ffffffffffffffffffffffffffffffffffffffff60035416906040517f313ce567000000000000000000000000000000000000000000000000000000008152602081600481865afa908115611c0857611abe602093926044928b91611bdb575b50611ab8875191612fb0565b90612ff0565b918960405195869485937fa9059cbb000000000000000000000000000000000000000000000000000000008552600485015260248401525af19081156105c8578691611bac575b5015611b845794611b7e917f7368bfddf54437295c38d71448fd337c832ab763b8d669fa154f59a111c5640a95965b5160408051928352602083019190915281019490945273ffffffffffffffffffffffffffffffffffffffff909216606084015230608084015260a0830191909152819060c0820190565b0390a180f35b6004857f90b8ec18000000000000000000000000000000000000000000000000000000008152fd5b611bce915060203d602011611bd4575b611bc68183612ec9565b8101906132fb565b87611b05565b503d611bbc565b611bfb9150853d8711611c01575b611bf38183612ec9565b810190612f97565b8c611aac565b503d611be9565b6040513d8a823e3d90fd5b82809291819282908215611c47575b73ffffffffffffffffffffffffffffffffffffffff1690f115610c3f57858880611a48565b6108fc9150611c22565b506108fc6119fd565b6040517f42d45f780000000000000000000000000000000000000000000000000000000081523460048201526024810191909152604481019190915260648101829052608490fd5b908697929396916103e8611cbf61ffff60045460c01c1686612ff0565b0491611cca836137d2565b9691809491949787808080611cdf868c613003565b818115611de4575b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690f115611dd95761ffff889616611d87575b5050839461042f859493611d449351613010565b90828215611d7e575bf115610c3f577f7368bfddf54437295c38d71448fd337c832ab763b8d669fa154f59a111c5640a94611b7e92611b34565b506108fc611d4d565b948080939594979692819382908215611dcf575b73ffffffffffffffffffffffffffffffffffffffff1690f115611dc45790928492938c80611d30565b6040513d86823e3d90fd5b6108fc9150611d9b565b6040513d89823e3d90fd5b506108fc611ce7565b6024887f4e487b710000000000000000000000000000000000000000000000000000000081526021600452fd5b6024897f4e487b710000000000000000000000000000000000000000000000000000000081526012600452fd5b6024897f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6004887f7361fc0c000000000000000000000000000000000000000000000000000000008152fd5b5060ff60045460b81c1615611929565b857fd64dfb010000000000000000000000000000000000000000000000000000000060005260045260246000fd5b827fc87c16410000000000000000000000000000000000000000000000000000000060005260045260246000fd5b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657602060ff60045460b81c166040519015158152f35b611f5536612e2e565b9060ff60045460b01c16610caf57611f6c82613662565b611f75826137d2565b91939092611f8287613960565b633b9aca00861161217b57600080611fa18761042f8396958496613003565b818115612172575b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690f11561215c5761ffff839216612128575b505060405161200081612e62565b8281526020810184815273ffffffffffffffffffffffffffffffffffffffff8060026040850194338652606081019460008652600054600052600760205260406000209151825551600182015501935116167fffffffffffffffffffffffff0000000000000000000000000000000000000000835416178255519360058510156106fa5781547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1660a095861b74ff000000000000000000000000000000000000000016179091556000805460408051828152602081019690965285019290925233606085015230608085015293830191909152612123917f8fd77df48aedff028372940389f8d7b6c07528858c2f7cc94e3c5ccd9fe2b2239060c090a16132ce565b815580f35b6000808093819382908215612168575b73ffffffffffffffffffffffffffffffffffffffff1690f11561215c578084611ff2565b6040513d6000823e3d90fd5b6108fc9150612138565b506108fc611fa9565b7f4e42c81400000000000000000000000000000000000000000000000000000000600052633b9aca0060045260246000fd5b346102c6576100186121be36612dbc565b90604051926121ce602085612ec9565b60008452613313565b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043567ffffffffffffffff81116102c657366023820112156102c657806004013567ffffffffffffffff81116102c65736602482840101116102c6576122ba613911565b6000906122c8600554612f44565b601f81116123ef575b5081601f8211600114612332578190839461231e9492612324575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b60055580f35b6024925001013584806122ec565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08216937f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db091845b8681106123d45750836001959610612399575b505050811b0160055580f35b01602401357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600384901b60f8161c1916905583808061238d565b9092602060018192602487870101358155019401910161237a565b6005835260208320601f830160051c8101916020841061242b575b601f0160051c01905b81811061242057506122d1565b838155600101612413565b909150819061240a565b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043560005260076020526040600020805473ffffffffffffffffffffffffffffffffffffffff6002600184015493015460ff8160a01c1693604051938452602084015216604082015260058210156106fa576080916060820152f35b346102c6576100186124d236612dbc565b9161301d565b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657602060ff60045460b01c166040519015158152f35b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657602061ffff60045460c01c16604051908152f35b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c65760043580600052600760205260406000209060ff60045460b81c1661290f578154156128e2576002820160ff815460a01c1660058110156106fa576001036128b85773ffffffffffffffffffffffffffffffffffffffff600354169260018101916125f48354613662565b6125ff8293926137d2565b9491989093740200000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff8254161790556004602073ffffffffffffffffffffffffffffffffffffffff60035416604051928380927f313ce5670000000000000000000000000000000000000000000000000000000082525afa90811561215c5760006126af61270f9382938391612899575b50611ab88b5491612fb0565b60405160208101917f23b872dd0000000000000000000000000000000000000000000000000000000083523360248301523060448301526064820152606481526126fa608482612ec9565b519082865af1612708613ad6565b9083614203565b805190811515918261287e575b505061285157509061272d91613003565b60008080806127418561042f8b5480613010565b818115612848575b3390f11561215c57600080806127608a8295613003565b81811561283f575b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690f11561215c5761ffff16612802575b505490546040805193845260208401929092529082015233606082015230608082015260a08101919091527ffa9aad700273c94161651bdca5c167b4d924f83f2e832d88a861debed12438619060c090a1005b6000808087819482908215612835575b73ffffffffffffffffffffffffffffffffffffffff1690f11561215c57846127af565b6108fc9150612812565b506108fc612768565b506108fc612749565b7f5274afe70000000000000000000000000000000000000000000000000000000060005260045260246000fd5b61289192506020809183010191016132fb565b158a8061271c565b6128b2915060203d602011611c0157611bf38183612ec9565b8e6126a3565b7fdd980a310000000000000000000000000000000000000000000000000000000060005260046000fd5b7fc87c16410000000000000000000000000000000000000000000000000000000060005260045260246000fd5b7fb21ba9270000000000000000000000000000000000000000000000000000000060005260046000fd5b346102c65760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657612970612d76565b60243561297c816135bf565b33151580612a9f575b80612a4e575b612a2057819073ffffffffffffffffffffffffffffffffffffffff80851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a4600052600f60205273ffffffffffffffffffffffffffffffffffffffff604060002091167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055600080f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b5073ffffffffffffffffffffffffffffffffffffffff81166000526010602052604060002073ffffffffffffffffffffffffffffffffffffffff331660005260205260ff604060002054161561298b565b503373ffffffffffffffffffffffffffffffffffffffff82161415612985565b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657600435612afa816135bf565b50600052600f602052602073ffffffffffffffffffffffffffffffffffffffff60406000205416604051908152f35b346102c65760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c6576040516000600b54612b6981612f44565b808452906001811690811561144f5750600114612b9057610d2a83610d1681850382612ec9565b919050600b6000527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9916000905b808210612bd657509091508101602001610d166113df565b919260018160209254838588010152019101909291612bbe565b346102c65760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102c657600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036102c657817f490649060000000000000000000000000000000000000000000000000000000060209314908115612c82575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115612ce6575b8115612cbc575b5083612c7b565b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612cb5565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612cae565b60005b838110612d235750506000910152565b8181015183820152602001612d13565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093612d6f81518092818752878088019101612d10565b0116010190565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036102c657565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036102c657565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60609101126102c65760043573ffffffffffffffffffffffffffffffffffffffff811681036102c6579060243573ffffffffffffffffffffffffffffffffffffffff811681036102c6579060443590565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60409101126102c6576004359060243590565b6080810190811067ffffffffffffffff821117612e7e57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6060810190811067ffffffffffffffff821117612e7e57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117612e7e57604052565b67ffffffffffffffff8111612e7e57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b90600182811c92168015612f8d575b6020831014612f5e57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691612f53565b908160209103126102c6575160ff811681036102c65790565b60ff16604d8111612fc157600a0a90565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810292918115918404141715612fc157565b91908203918211612fc157565b91908201809211612fc157565b919073ffffffffffffffffffffffffffffffffffffffff1691821561329357600090828252600d6020528273ffffffffffffffffffffffffffffffffffffffff6040842054169485331515806131a5575b507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef73ffffffffffffffffffffffffffffffffffffffff9582613135575b838152600e6020526040812060018154019055848152600d60205260408120847fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905580a41680830361310257505050565b7f64283d7b0000000000000000000000000000000000000000000000000000000060005260045260245260445260646000fd5b61316e85600052600f60205260406000207fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055565b828152600e602052604081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81540190556130ac565b91939492505080613222575b156131c15791908390853861306e565b8390856131f3576024917f7e273289000000000000000000000000000000000000000000000000000000008252600452fd5b6044917f177e802f00000000000000000000000000000000000000000000000000000000825233600452602452fd5b50338514801561325d575b806131b15750838152600f6020523373ffffffffffffffffffffffffffffffffffffffff604083205416146131b1565b5084815260106020526040812073ffffffffffffffffffffffffffffffffffffffff3316825260205260ff60408220541661322d565b7f64a0ae9200000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b60058210156106fa5752565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114612fc15760010190565b908160209103126102c6575180151581036102c65790565b9061331f83828461301d565b803b61332c575b50505050565b60209161339873ffffffffffffffffffffffffffffffffffffffff8093169560405195869485947f150b7a020000000000000000000000000000000000000000000000000000000086523360048701521660248501526044840152608060648401526084830190612d33565b03816000865af18091600091613473575b50906133f357506133b8613ad6565b805190816133ee57827f64a0ae920000000000000000000000000000000000000000000000000000000060005260045260246000fd5b602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000007f150b7a0200000000000000000000000000000000000000000000000000000000911603613446575038808080613326565b7f64a0ae920000000000000000000000000000000000000000000000000000000060005260045260246000fd5b6020813d6020116134cd575b8161348c60209383612ec9565b810103126134c95751907fffffffff00000000000000000000000000000000000000000000000000000000821682036134c65750386133a9565b80fd5b5080fd5b3d915061347f565b6134de816135bf565b5060005260116020526040600020604051908160008254926134ff84612f44565b808452936001811690811561357f5750600114613538575b5061352492500382612ec9565b6000604051613534602082612ec9565b5290565b90506000929192526020600020906000915b8183106135635750509060206135249282010138613517565b602091935080600191548385880101520191019091839261354a565b602093506135249592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091501682840152151560051b82010138613517565b80600052600d60205273ffffffffffffffffffffffffffffffffffffffff604060002054169081156135ef575090565b7f7e2732890000000000000000000000000000000000000000000000000000000060005260045260246000fd5b908160209103126102c6575161ffff811681036102c65790565b908160209103126102c6575173ffffffffffffffffffffffffffffffffffffffff811681036102c65790565b6136796103e89161ffff60045460a01c1690612ff0565b049073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016604051907f6b6f4a9d000000000000000000000000000000000000000000000000000000008252602082600481845afa91821561215c5760009261379d575b506020602491604051928380927f23f6f9680000000000000000000000000000000000000000000000000000000082523360048301525afa801561215c5773ffffffffffffffffffffffffffffffffffffffff9160009161376e575b5016156137685761376461ffff6064921684612ff0565b0490565b50600090565b613790915060203d602011613796575b6137888183612ec9565b810190613636565b3861374d565b503d61377e565b60249192506137c3602091823d84116137cb575b6137bb8183612ec9565b81019061361c565b9291506136f1565b503d6137b1565b6040517f23f6f968000000000000000000000000000000000000000000000000000000008152336004820152917f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1691602084602481865afa92831561215c576024946000946138ef575b50602090604051958680927f5d8162b000000000000000000000000000000000000000000000000000000000825273ffffffffffffffffffffffffffffffffffffffff881660048301525afa93841561215c576000946138c6575b506138c06103e89161ffff861690612ff0565b04929190565b6103e89194506138e76138c09160203d6020116137cb576137bb8183612ec9565b9491506138ad565b602091945061390a90823d8411613796576137888183612ec9565b9390613852565b73ffffffffffffffffffffffffffffffffffffffff60125416330361393257565b7f118cdaa7000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b61396981613662565b61397e61397882849594613003565b83613010565b340361398957505050565b61063e906040519384937f42d45f7800000000000000000000000000000000000000000000000000000000855234600486019094939260609260808301968352602083015260408201520152565b6000818152600d60205273ffffffffffffffffffffffffffffffffffffffff604082205416828115928315613a66575b818152600d602052604081207fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4506135ef5750565b613a9f82600052600f60205260406000207fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055565b828152600e602052604081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8154019055613a07565b3d15613b01573d90613ae782612f0a565b91613af56040519384612ec9565b82523d6000602084013e565b606090565b92919092613b8b600154600260405191613b1f83612ead565b8083526020830186815260408401916000835286600052600860205260406000209060005260205260406000209351845551600184015551151591019060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b6001546000526009602052604060002055600154600052600a602052604060002055600154918290836000907a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008610156141db575b806d04ee2d6d415b85acef8100000000600a9210156141c0575b662386f26fc100008110156141ac575b6305f5e10081101561419b575b61271081101561418c575b606481101561417e575b1015614176575b6001810194600a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6021613c7a613c648a612f0a565b99613c726040519b8c612ec9565b808b52612f0a565b947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe060208b0196013687378901015b01917f30313233343536373839616263646566000000000000000000000000000000008282061a8353048015613d03577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600a9192613ca9565b5050604051948591600091600554613d1a81612f44565b906001811690811561413557506001146140d4575b509282613dad93613d5c60059473ffffffffffffffffffffffffffffffffffffffff989751938491612d10565b017f2e6a736f6e0000000000000000000000000000000000000000000000000000008152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe5810188520186612ec9565b16801561329357600091808352600d60205273ffffffffffffffffffffffffffffffffffffffff60408420541691827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8115159586614064575b838152600e6020526040812060018154019055848152600d60205260408120847fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905580a450614035576001548060005260116020526040600020835167ffffffffffffffff8111612e7e57613e818254612f44565b601f8111613fed575b506020601f8211600114613f2557816020949392613efe927ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79798600092613f1a5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b90555b604051908152a1600154613f14816132ce565b60015590565b0151905038806122ec565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082169583600052816000209660005b818110613fd5575096600192849260209796957ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7999a10613f9e575b505050811b019055613f01565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c19169055388080613f91565b83830151895560019098019760209384019301613f55565b826000526020600020601f830160051c8101916020841061402b575b601f0160051c01905b81811061401f5750613e8a565b60008155600101614012565b9091508190614009565b7f73c6ac6e00000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b61409d85600052600f60205260406000207fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055565b828152600e602052604081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8154019055613e07565b9091925060056000527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db06000905b828210614119575050830160200191906005613d2f565b80546020838c018101919091528a965090910190600101614102565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166020808801919091528215159092028601909101935060059050613d2f565b600101613c2e565b606460029104920191613c27565b61271060049104920191613c1d565b6305f5e10060089104920191613c12565b662386f26fc1000060109104920191613c05565b6d04ee2d6d415b85acef810000000060209104920191613bf5565b50604090507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008504613bdb565b90614242575080511561421857805190602001fd5b7f1425ea420000000000000000000000000000000000000000000000000000000060005260046000fd5b81511580614297575b614253575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b50803b1561424b56fea2646970667358221220111cf0947d59636f65dfbc8bc0894c101c8d5d3ebbb44d9fe543e3ef97f6699a64736f6c634300081a0033a26469706673582212206f63e649585f826532accfb11c1f146c2e34c773a352fb9e6f78fd0add1cd1e464736f6c634300081a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c946cb236481c159f460b212b34ab246dac37fcd000000000000000000000000000000000000000000000000000000000000000a
-----Decoded View---------------
Arg [0] : initialOwner (address): 0xC946cB236481C159F460b212b34AB246daC37FcD
Arg [1] : _discount (uint16): 10
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000c946cb236481c159f460b212b34ab246dac37fcd
Arg [1] : 000000000000000000000000000000000000000000000000000000000000000a
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.