Source Code
Overview
APE Balance
More Info
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
DONApe
Compiler Version
v0.8.22+commit.4fc1097e
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {ProjectContract} from "./ProjectContract.sol"; import {CrowdfundingContract} from "./CrowdfundingContract.sol"; /** * @title DONApe * @dev An upgradeable donation platform for native APE tokens on ApeChain */ contract DONApe is Initializable, OwnableUpgradeable, ReentrancyGuardUpgradeable, UUPSUpgradeable { enum DonationType { PERSONAL, NFT_PROJECT, CROWDFUNDING } // Project structure struct Project { string name; // For personal and crowdfunding only, NFT projects use contract name string description; address payable owner; address contractAddress; // For NFT projects and crowdfunding, this is the donation contract address address nftContractAddress; // For NFT projects only uint256 totalDonations; uint256 fundingGoal; // For crowdfunding only uint256 deadline; // For crowdfunding only bool isActive; bool isVerified; DonationType donationType; } // Mapping from project ID to Project mapping(uint256 => Project) public projects; // Mapping to track project names mapping(bytes32 => bool) private projectNameExists; // Mapping to track NFT contract addresses mapping(address => bool) private nftContractExists; // Total number of projects uint256 public projectCount; // Platform fee percentage (in basis points, e.g., 100 = 1%) uint256 public platformFeeRate; // Events event ProjectCreated( uint256 indexed projectId, string name, address indexed owner, address contractAddress, DonationType donationType ); event DonationReceived( uint256 indexed projectId, address indexed donor, uint256 amount ); event ProjectStatusChanged(uint256 indexed projectId, bool isActive); event ProjectVerified(uint256 indexed projectId); event PlatformFeeChanged(uint256 newFeeRate); event FeesWithdrawn(uint256 amount); event CrowdfundingGoalReduced(uint256 indexed projectId, uint256 newGoal); event CrowdfundingClaimed(uint256 indexed projectId, uint256 amount); /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /** * @dev Initializer function (replaces constructor for upgradeable contracts) * @param _initialFeeRate Initial platform fee rate in basis points (100 = 1%) */ function initialize(uint256 _initialFeeRate) public initializer { require(_initialFeeRate <= 1000, "Fee rate cannot exceed 10%"); __Ownable_init(msg.sender); __ReentrancyGuard_init(); __UUPSUpgradeable_init(); platformFeeRate = _initialFeeRate; projectCount = 0; } /** * @dev Required by the UUPSUpgradeable module * @param newImplementation Address of the new implementation */ function _authorizeUpgrade( address newImplementation ) internal override onlyOwner {} /** * @dev Creates a new personal donation project * @param _name Name of the project * @param _description Description of the project * @param _owner Address of the project owner who will receive donations */ function createPersonalProject( string memory _name, string memory _description, address payable _owner ) external { require(bytes(_name).length > 0, "Project name cannot be empty"); require(_owner != address(0), "Invalid project owner address"); // Check if project name already exists bytes32 nameHash = keccak256(abi.encodePacked(_name)); require(!projectNameExists[nameHash], "Project name already exists"); // Mark project name as used projectNameExists[nameHash] = true; uint256 projectId = projectCount; projects[projectId] = Project({ name: _name, description: _description, owner: _owner, contractAddress: address(0), // No separate contract for personal donations nftContractAddress: address(0), // No NFT contract for personal donations totalDonations: 0, fundingGoal: 0, // Not applicable deadline: 0, // Not applicable isActive: true, isVerified: false, donationType: DonationType.PERSONAL }); projectCount++; emit ProjectCreated( projectId, _name, _owner, address(0), DonationType.PERSONAL ); } /** * @dev Creates a new NFT project donation * @param _description Description of the project * @param _owner Address of the project owner * @param _nftContractAddress Address of the NFT project's contract */ function createNFTProject( string memory _description, address payable _owner, address _nftContractAddress ) external { require(_owner != address(0), "Invalid project owner address"); require( _nftContractAddress != address(0), "Invalid NFT contract address" ); // Check if NFT contract already has a project require( !nftContractExists[_nftContractAddress], "NFT contract already has a project" ); // Mark NFT contract as used nftContractExists[_nftContractAddress] = true; // Deploy a new project contract for the NFT project ProjectContract projectContract = new ProjectContract( _description, _owner, _nftContractAddress, address(this) ); uint256 projectId = projectCount; projects[projectId] = Project({ name: "", // No custom name for NFT projects description: _description, owner: _owner, contractAddress: address(projectContract), nftContractAddress: _nftContractAddress, totalDonations: 0, fundingGoal: 0, // Not applicable deadline: 0, // Not applicable isActive: true, isVerified: false, donationType: DonationType.NFT_PROJECT }); projectCount++; emit ProjectCreated( projectId, "", _owner, address(projectContract), DonationType.NFT_PROJECT ); } /** * @dev Creates a new crowdfunding project * @param _name Name of the crowdfunding campaign * @param _description Description of the campaign * @param _fundingGoal Funding goal in native APE tokens */ function createCrowdfunding( string memory _name, string memory _description, uint256 _fundingGoal ) external { require(bytes(_name).length > 0, "Campaign name cannot be empty"); require(_fundingGoal > 0, "Funding goal must be greater than 0"); // Check if project name already exists bytes32 nameHash = keccak256(abi.encodePacked(_name)); require(!projectNameExists[nameHash], "Campaign name already exists"); // Mark project name as used projectNameExists[nameHash] = true; // Deploy a new crowdfunding contract CrowdfundingContract crowdfundingContract = new CrowdfundingContract( _name, _description, _fundingGoal, msg.sender, address(this) ); uint256 projectId = projectCount; projects[projectId] = Project({ name: _name, description: _description, owner: payable(msg.sender), contractAddress: address(crowdfundingContract), nftContractAddress: address(0), // Not applicable totalDonations: 0, fundingGoal: _fundingGoal, deadline: block.timestamp + 30 days, isActive: true, isVerified: false, donationType: DonationType.CROWDFUNDING }); projectCount++; emit ProjectCreated( projectId, _name, msg.sender, address(crowdfundingContract), DonationType.CROWDFUNDING ); } /** * @dev Donates native APE tokens to a project * @param _projectId ID of the project to donate to */ function donate(uint256 _projectId) external payable nonReentrant { require(_projectId < projectCount, "Project does not exist"); require(projects[_projectId].isActive, "Project is not active"); require(msg.value > 0, "Donation amount must be greater than 0"); Project storage project = projects[_projectId]; // For crowdfunding, check if deadline has passed if (project.donationType == DonationType.CROWDFUNDING) { require( block.timestamp < project.deadline, "Crowdfunding campaign has ended" ); } // Calculate platform fee uint256 platformFee = (msg.value * platformFeeRate) / 10000; uint256 projectDonation = msg.value - platformFee; // Handle donation based on project type if (project.donationType == DonationType.PERSONAL) { // For personal donations, send directly to the owner (bool success, ) = project.owner.call{value: projectDonation}(""); require(success, "Personal donation transfer failed"); } else { // For NFT projects and crowdfunding, send to the project contract bytes memory callData; if (project.donationType == DonationType.NFT_PROJECT) { callData = abi.encodeWithSignature("receiveDonation()"); } else { // CROWDFUNDING callData = abi.encodeWithSignature("receiveDonation()"); } (bool success, ) = project.contractAddress.call{ value: projectDonation }(callData); require(success, "Project donation transfer failed"); } // Update project total donations project.totalDonations += projectDonation; emit DonationReceived(_projectId, msg.sender, projectDonation); } /** * @dev Sets the active status of a project * @param _projectId ID of the project * @param _isActive New active status */ function setProjectStatus(uint256 _projectId, bool _isActive) external { require(_projectId < projectCount, "Project does not exist"); Project storage project = projects[_projectId]; // Only project owner or contract owner can change status require( msg.sender == project.owner || msg.sender == owner(), "Not authorized" ); project.isActive = _isActive; // Update status in project contract if it's not a personal donation if (project.donationType != DonationType.PERSONAL) { if (project.donationType == DonationType.NFT_PROJECT) { ProjectContract projectContract = ProjectContract( payable(project.contractAddress) ); projectContract.setActive(_isActive); } else { // CROWDFUNDING CrowdfundingContract crowdfundingContract = CrowdfundingContract( payable(project.contractAddress) ); crowdfundingContract.setActive(_isActive); } } emit ProjectStatusChanged(_projectId, _isActive); } /** * @dev Reduce funding goal for a crowdfunding project * @param _projectId ID of the crowdfunding project * @param _newGoal New funding goal */ function reduceCrowdfundingGoal( uint256 _projectId, uint256 _newGoal ) external { require(_projectId < projectCount, "Project does not exist"); Project storage project = projects[_projectId]; // Check if it's a crowdfunding project require( project.donationType == DonationType.CROWDFUNDING, "Not a crowdfunding project" ); // Only project owner can reduce goal require(msg.sender == project.owner, "Not authorized"); // Call the crowdfunding contract to reduce goal CrowdfundingContract crowdfundingContract = CrowdfundingContract( payable(project.contractAddress) ); crowdfundingContract.reduceFundingGoal(_newGoal); // Update project funding goal project.fundingGoal = _newGoal; emit CrowdfundingGoalReduced(_projectId, _newGoal); } /** * @dev Claim funds for a successful crowdfunding project * @param _projectId ID of the crowdfunding project */ function claimCrowdfunding(uint256 _projectId) external { require(_projectId < projectCount, "Project does not exist"); Project storage project = projects[_projectId]; // Check if it's a crowdfunding project require( project.donationType == DonationType.CROWDFUNDING, "Not a crowdfunding project" ); // Only project owner can claim require(msg.sender == project.owner, "Not authorized"); // Call the crowdfunding contract to claim funds CrowdfundingContract crowdfundingContract = CrowdfundingContract( payable(project.contractAddress) ); crowdfundingContract.claimFunds(); // Update project status project.isActive = false; emit CrowdfundingClaimed(_projectId, project.totalDonations); } /** * @dev Get refund for a failed crowdfunding project * @param _projectId ID of the crowdfunding project */ function getCrowdfundingRefund(uint256 _projectId) external { require(_projectId < projectCount, "Project does not exist"); Project storage project = projects[_projectId]; // Check if it's a crowdfunding project require( project.donationType == DonationType.CROWDFUNDING, "Not a crowdfunding project" ); // Call the crowdfunding contract to get refund CrowdfundingContract crowdfundingContract = CrowdfundingContract( payable(project.contractAddress) ); crowdfundingContract.getRefund(); } /** * @dev Verifies a project (only callable by platform owner) * @param _projectId ID of the project to verify */ function verifyProject(uint256 _projectId) external onlyOwner { require(_projectId < projectCount, "Project does not exist"); projects[_projectId].isVerified = true; emit ProjectVerified(_projectId); } /** * @dev Updates the platform fee rate * @param _newFeeRate New platform fee rate in basis points (100 = 1%) */ function setPlatformFeeRate(uint256 _newFeeRate) external onlyOwner { require(_newFeeRate <= 1000, "Fee rate cannot exceed 10%"); platformFeeRate = _newFeeRate; emit PlatformFeeChanged(_newFeeRate); } /** * @dev Withdraws platform fees to the contract owner */ function withdrawPlatformFees() external onlyOwner nonReentrant { uint256 balance = address(this).balance; require(balance > 0, "No fees to withdraw"); (bool success, ) = owner().call{value: balance}(""); require(success, "Fee withdrawal failed"); emit FeesWithdrawn(balance); } /** * @dev Gets project details * @param _projectId ID of the project */ function getProject( uint256 _projectId ) external view returns ( string memory name, string memory description, address owner, address contractAddress, address nftContractAddress, uint256 totalDonations, uint256 fundingGoal, uint256 deadline, bool isActive, bool isVerified, DonationType donationType ) { require(_projectId < projectCount, "Project does not exist"); Project storage project = projects[_projectId]; return ( project.name, project.description, project.owner, project.contractAddress, project.nftContractAddress, project.totalDonations, project.fundingGoal, project.deadline, project.isActive, project.isVerified, project.donationType ); } /** * @dev Gets crowdfunding project status * @param _projectId ID of the crowdfunding project */ function getCrowdfundingStatus( uint256 _projectId ) external view returns ( uint256 fundingGoal, uint256 totalRaised, uint256 deadline, bool isActive, bool isClaimed, bool isSuccessful, bool isExpired ) { require(_projectId < projectCount, "Project does not exist"); Project storage project = projects[_projectId]; require( project.donationType == DonationType.CROWDFUNDING, "Not a crowdfunding project" ); CrowdfundingContract crowdfundingContract = CrowdfundingContract( payable(project.contractAddress) ); return crowdfundingContract.getStatus(); } /** * @dev Gets donation amount for a specific donor in a crowdfunding project * @param _projectId ID of the crowdfunding project * @param _donor Address of the donor */ function getCrowdfundingDonation( uint256 _projectId, address _donor ) external view returns (uint256) { require(_projectId < projectCount, "Project does not exist"); Project storage project = projects[_projectId]; require( project.donationType == DonationType.CROWDFUNDING, "Not a crowdfunding project" ); CrowdfundingContract crowdfundingContract = CrowdfundingContract( payable(project.contractAddress) ); return crowdfundingContract.getDonationAmount(_donor); } /** * @dev Fallback function to accept native APE tokens */ receive() external payable {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.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 OwnableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable struct OwnableStorage { address _owner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; function _getOwnableStorage() private pure returns (OwnableStorage storage $) { assembly { $.slot := OwnableStorageLocation } } /** * @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. */ function __Ownable_init(address initialOwner) internal onlyInitializing { __Ownable_init_unchained(initialOwner); } function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { 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) { OwnableStorage storage $ = _getOwnableStorage(); 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 { OwnableStorage storage $ = _getOwnableStorage(); address oldOwner = $._owner; $._owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.22; import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol"; import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; import {Initializable} from "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. */ abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable __self = address(this); /** * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function * during an upgrade. */ string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; /** * @dev The call is from an unauthorized context. */ error UUPSUnauthorizedCallContext(); /** * @dev The storage `slot` is unsupported as a UUID. */ error UUPSUnsupportedProxiableUUID(bytes32 slot); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { _checkProxy(); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { _checkNotDelegated(); _; } function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /** * @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual notDelegated returns (bytes32) { return ERC1967Utils.IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data); } /** * @dev Reverts if the execution is not performed via delegatecall or the execution * context is not of a proxy with an ERC-1967 compliant implementation pointing to self. * See {_onlyProxy}. */ function _checkProxy() internal view virtual { if ( address(this) == __self || // Must be called through delegatecall ERC1967Utils.getImplementation() != __self // Must be called through an active proxy ) { revert UUPSUnauthorizedCallContext(); } } /** * @dev Reverts if the execution is performed via delegatecall. * See {notDelegated}. */ function _checkNotDelegated() internal view virtual { if (address(this) != __self) { // Must not be called through delegatecall revert UUPSUnauthorizedCallContext(); } } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call. * * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value * is expected to be the implementation slot in ERC-1967. * * Emits an {IERC1967-Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) { revert UUPSUnsupportedProxiableUUID(slot); } ERC1967Utils.upgradeToAndCall(newImplementation, data); } catch { // The implementation is not UUPS revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @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 ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } 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.1.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at, * consider using {ReentrancyGuardTransient} instead. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard struct ReentrancyGuardStorage { uint256 _status; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) { assembly { $.slot := ReentrancyGuardStorageLocation } } /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); $._status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // On the first call to nonReentrant, _status will be NOT_ENTERED if ($._status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail $._status = ENTERED; } function _nonReentrantAfter() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) $._status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); return $._status == ENTERED; } }
// 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.1.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.20; /** * @dev ERC-1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol) pragma solidity ^0.8.20; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. */ interface IERC1967 { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.20; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {UpgradeableBeacon} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (proxy/ERC1967/ERC1967Utils.sol) pragma solidity ^0.8.22; import {IBeacon} from "../beacon/IBeacon.sol"; import {IERC1967} from "../../interfaces/IERC1967.sol"; import {Address} from "../../utils/Address.sol"; import {StorageSlot} from "../../utils/StorageSlot.sol"; /** * @dev This library provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots. */ library ERC1967Utils { /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev The `implementation` of the proxy is invalid. */ error ERC1967InvalidImplementation(address implementation); /** * @dev The `admin` of the proxy is invalid. */ error ERC1967InvalidAdmin(address admin); /** * @dev The `beacon` of the proxy is invalid. */ error ERC1967InvalidBeacon(address beacon); /** * @dev An upgrade function sees `msg.value > 0` that may be lost. */ error ERC1967NonPayable(); /** * @dev Returns the current implementation address. */ function getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the ERC-1967 implementation slot. */ function _setImplementation(address newImplementation) private { if (newImplementation.code.length == 0) { revert ERC1967InvalidImplementation(newImplementation); } StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Performs implementation upgrade with additional setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) internal { _setImplementation(newImplementation); emit IERC1967.Upgraded(newImplementation); if (data.length > 0) { Address.functionDelegateCall(newImplementation, data); } else { _checkNonPayable(); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(ADMIN_SLOT).value; } /** * @dev Stores a new address in the ERC-1967 admin slot. */ function _setAdmin(address newAdmin) private { if (newAdmin == address(0)) { revert ERC1967InvalidAdmin(address(0)); } StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {IERC1967-AdminChanged} event. */ function changeAdmin(address newAdmin) internal { emit IERC1967.AdminChanged(getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(BEACON_SLOT).value; } /** * @dev Stores a new beacon in the ERC-1967 beacon slot. */ function _setBeacon(address newBeacon) private { if (newBeacon.code.length == 0) { revert ERC1967InvalidBeacon(newBeacon); } StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon; address beaconImplementation = IBeacon(newBeacon).implementation(); if (beaconImplementation.code.length == 0) { revert ERC1967InvalidImplementation(beaconImplementation); } } /** * @dev Change the beacon and trigger a setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-BeaconUpgraded} event. * * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for * efficiency. */ function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal { _setBeacon(newBeacon); emit IERC1967.BeaconUpgraded(newBeacon); if (data.length > 0) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } else { _checkNonPayable(); } } /** * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract * if an upgrade doesn't perform an initialization call. */ function _checkNonPayable() private { if (msg.value > 0) { revert ERC1967NonPayable(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (utils/Address.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @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 Errors.InsufficientBalance(address(this).balance, amount); } (bool success, bytes memory returndata) = recipient.call{value: amount}(""); if (!success) { _revert(returndata); } } /** * @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 * {Errors.FailedCall} 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 Errors.InsufficientBalance(address(this).balance, value); } (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 {Errors.FailedCall}) 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 {Errors.FailedCall} 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 {Errors.FailedCall}. */ 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 assembly ("memory-safe") { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert Errors.FailedCall(); } } }
// 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.1.0) (utils/Errors.sol) pragma solidity ^0.8.20; /** * @dev Collection of common custom errors used in multiple contracts * * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. * It is recommended to avoid relying on the error API for critical functionality. * * _Available since v5.1._ */ library Errors { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error InsufficientBalance(uint256 balance, uint256 needed); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedCall(); /** * @dev The deployment failed. */ error FailedDeployment(); /** * @dev A necessary precompile is missing. */ error MissingPrecompile(address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at, * consider using {ReentrancyGuardTransient} instead. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; uint256 private _status; /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); constructor() { _status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be NOT_ENTERED if (_status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail _status = ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.20; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC-1967 implementation slot: * ```solidity * contract ERC1967 { * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * TIP: Consider using this library along with {SlotDerivation}. */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct Int256Slot { int256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Int256Slot` with member `value` located at `slot`. */ function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } /** * @dev Returns a `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; /** * @title CrowdfundingContract * @dev Individual contract for crowdfunding campaigns */ contract CrowdfundingContract is Ownable, ReentrancyGuard { string public name; string public description; uint256 public fundingGoal; uint256 public initialFundingGoal; uint256 public deadline; uint256 public totalRaised; bool public isActive; bool public isClaimed; address public platformAddress; // Mapping of donor addresses to donation amounts mapping(address => uint256) public donations; // Array to keep track of all donors address[] public donors; event DonationReceived(address indexed donor, uint256 amount); event GoalReduced(uint256 oldGoal, uint256 newGoal); event FundsClaimed(address indexed owner, uint256 amount); event RefundIssued(address indexed donor, uint256 amount); event StatusChanged(bool isActive); constructor( string memory _name, string memory _description, uint256 _fundingGoal, address _owner, address _platformAddress ) Ownable(_owner) { name = _name; description = _description; fundingGoal = _fundingGoal; initialFundingGoal = _fundingGoal; deadline = block.timestamp + 30 days; isActive = true; isClaimed = false; platformAddress = _platformAddress; } /** * @dev Receive donation for crowdfunding */ function receiveDonation() external payable nonReentrant { require(isActive, "Campaign is not active"); require(block.timestamp < deadline, "Campaign has ended"); require(msg.value > 0, "Donation amount must be greater than 0"); // If this is the first donation from this address, add to donors array if (donations[tx.origin] == 0) { donors.push(tx.origin); } // Update donation record donations[tx.origin] += msg.value; totalRaised += msg.value; emit DonationReceived(tx.origin, msg.value); } /** * @dev Reduce funding goal (only by owner, max 25% reduction from initial) */ function reduceFundingGoal(uint256 _newGoal) external nonReentrant { require( msg.sender == owner() || msg.sender == platformAddress, "Not authorized" ); require(isActive, "Campaign is not active"); require(block.timestamp < deadline, "Campaign has ended"); require( _newGoal < fundingGoal, "New goal must be lower than current goal" ); // Calculate minimum allowed goal (75% of initial) uint256 minimumGoal = (initialFundingGoal * 75) / 100; require( _newGoal >= minimumGoal, "Cannot reduce by more than 25% of initial goal" ); uint256 oldGoal = fundingGoal; fundingGoal = _newGoal; emit GoalReduced(oldGoal, _newGoal); } /** * @dev Claim funds if goal is reached */ function claimFunds() external nonReentrant { require( msg.sender == owner() || msg.sender == platformAddress, "Not authorized" ); require(!isClaimed, "Funds already claimed"); require( totalRaised >= fundingGoal || block.timestamp >= deadline, "Cannot claim before deadline unless goal is reached" ); // Only allow claim if goal is reached require(totalRaised >= fundingGoal, "Funding goal not reached"); uint256 balance = address(this).balance; require(balance > 0, "No funds to claim"); isClaimed = true; isActive = false; (bool success, ) = owner().call{value: balance}(""); require(success, "Claim failed"); emit FundsClaimed(owner(), balance); } /** * @dev Get refund if goal not reached and deadline passed */ function getRefund() external nonReentrant { require(block.timestamp >= deadline, "Campaign still in progress"); require( totalRaised < fundingGoal, "Funding goal was reached, no refunds" ); require(!isClaimed, "Funds already claimed"); uint256 donationAmount = donations[msg.sender]; require(donationAmount > 0, "No donation to refund"); // Reset donation record donations[msg.sender] = 0; // Send refund (bool success, ) = msg.sender.call{value: donationAmount}(""); require(success, "Refund failed"); emit RefundIssued(msg.sender, donationAmount); } /** * @dev Issue refunds to all donors (emergency function) */ function issueAllRefunds() external nonReentrant { require( msg.sender == owner() || msg.sender == platformAddress, "Not authorized" ); require(isActive, "Campaign is not active"); require(!isClaimed, "Funds already claimed"); isActive = false; // Process refunds for all donors for (uint256 i = 0; i < donors.length; i++) { address donor = donors[i]; uint256 donationAmount = donations[donor]; if (donationAmount > 0) { donations[donor] = 0; (bool success, ) = donor.call{value: donationAmount}(""); if (success) { emit RefundIssued(donor, donationAmount); } } } } /** * @dev Set campaign active status */ function setActive(bool _isActive) external { require( msg.sender == owner() || msg.sender == platformAddress, "Not authorized" ); require(!isClaimed, "Funds already claimed"); isActive = _isActive; emit StatusChanged(_isActive); } /** * @dev Get campaign status */ function getStatus() external view returns ( uint256 _fundingGoal, uint256 _totalRaised, uint256 _deadline, bool _isActive, bool _isClaimed, bool _isSuccessful, bool _isExpired ) { return ( fundingGoal, totalRaised, deadline, isActive, isClaimed, totalRaised >= fundingGoal, block.timestamp >= deadline ); } /** * @dev Get donation amount for a specific donor */ function getDonationAmount(address donor) external view returns (uint256) { return donations[donor]; } /** * @dev Fallback function to accept native APE tokens */ receive() external payable { require(isActive, "Campaign is not active"); require(block.timestamp < deadline, "Campaign has ended"); // If this is the first donation from this address, add to donors array if (donations[tx.origin] == 0) { donors.push(tx.origin); } // Update donation record donations[tx.origin] += msg.value; totalRaised += msg.value; emit DonationReceived(tx.origin, msg.value); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; /** * @title ProjectContract * @dev Individual contract for NFT project donations that forwards donations directly to the NFT contract */ contract ProjectContract is Ownable { string public description; address public nftContractAddress; // The NFT project's own contract address uint256 public totalDonations; bool public isActive; address public platformAddress; event DonationReceived(address indexed donor, uint256 amount); event StatusChanged(bool isActive); constructor( string memory _description, address _owner, address _nftContractAddress, address _platformAddress ) Ownable(_owner) { description = _description; nftContractAddress = _nftContractAddress; isActive = true; platformAddress = _platformAddress; } /** * @dev Receive donation and forward it directly to the NFT contract */ function receiveDonation() external payable { require(isActive, "Project is not active"); require(msg.value > 0, "Donation amount must be greater than 0"); // Forward donation directly to the NFT contract (bool success, ) = nftContractAddress.call{value: msg.value}(""); require(success, "Forwarding to NFT contract failed"); // Update total donations (for tracking purposes only) totalDonations += msg.value; emit DonationReceived(tx.origin, msg.value); } /** * @dev Set project active status */ function setActive(bool _isActive) external { require( msg.sender == owner() || msg.sender == platformAddress, "Not authorized" ); isActive = _isActive; emit StatusChanged(_isActive); } /** * @dev Fallback function to accept and forward native APE tokens */ receive() external payable { require(isActive, "Project is not active"); require(msg.value > 0, "Donation amount must be greater than 0"); // Forward donation directly to the NFT contract (bool success, ) = nftContractAddress.call{value: msg.value}(""); require(success, "Forwarding to NFT contract failed"); // Update total donations (for tracking purposes only) totalDonations += msg.value; emit DonationReceived(tx.origin, msg.value); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CrowdfundingClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newGoal","type":"uint256"}],"name":"CrowdfundingGoalReduced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"address","name":"donor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DonationReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"PlatformFeeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"enum DONApe.DonationType","name":"donationType","type":"uint8"}],"name":"ProjectCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isActive","type":"bool"}],"name":"ProjectStatusChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"ProjectVerified","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"claimCrowdfunding","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_description","type":"string"},{"internalType":"uint256","name":"_fundingGoal","type":"uint256"}],"name":"createCrowdfunding","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_description","type":"string"},{"internalType":"address payable","name":"_owner","type":"address"},{"internalType":"address","name":"_nftContractAddress","type":"address"}],"name":"createNFTProject","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_description","type":"string"},{"internalType":"address payable","name":"_owner","type":"address"}],"name":"createPersonalProject","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"donate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"address","name":"_donor","type":"address"}],"name":"getCrowdfundingDonation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"getCrowdfundingRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"getCrowdfundingStatus","outputs":[{"internalType":"uint256","name":"fundingGoal","type":"uint256"},{"internalType":"uint256","name":"totalRaised","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"},{"internalType":"bool","name":"isSuccessful","type":"bool"},{"internalType":"bool","name":"isExpired","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"getProject","outputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"nftContractAddress","type":"address"},{"internalType":"uint256","name":"totalDonations","type":"uint256"},{"internalType":"uint256","name":"fundingGoal","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"bool","name":"isVerified","type":"bool"},{"internalType":"enum DONApe.DonationType","name":"donationType","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_initialFeeRate","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platformFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"projectCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"projects","outputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"address payable","name":"owner","type":"address"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"nftContractAddress","type":"address"},{"internalType":"uint256","name":"totalDonations","type":"uint256"},{"internalType":"uint256","name":"fundingGoal","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"bool","name":"isVerified","type":"bool"},{"internalType":"enum DONApe.DonationType","name":"donationType","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"uint256","name":"_newGoal","type":"uint256"}],"name":"reduceCrowdfundingGoal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newFeeRate","type":"uint256"}],"name":"setPlatformFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"},{"internalType":"bool","name":"_isActive","type":"bool"}],"name":"setProjectStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_projectId","type":"uint256"}],"name":"verifyProject","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawPlatformFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60a0604052306080523480156200001557600080fd5b506200002062000026565b620000da565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff1615620000775760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b0390811614620000d75780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b60805161559f62000104600039600081816123690152818161239301526124e8015261559f6000f3fe6080604052600436106200016b5760003560e01c8063ad3cb1cc11620000c5578063eeca08f01162000078578063eeca08f0146200042c578063f0c006371462000444578063f0f3f2c814620004a5578063f14faf6f14620004ca578063f2fde38b14620004e1578063fe4b84df146200050657600080fd5b8063ad3cb1cc146200033e578063bc4ac19b1462000380578063c55c518c14620003a5578063d0b7830b14620003ca578063dcd4720114620003e2578063ed1ca91a146200040757600080fd5b80635e15b14d116200011e5780635e15b14d1462000261578063715018a6146200028657806380e5be34146200029e5780638da5cb5b14620002c3578063909cfe6414620002f4578063927fef2e146200031957600080fd5b8063107046bd146200017857806326c2319c14620001bf57806336fbad2614620001e65780633af6cd1e146200020d5780634f1ef286146200023257806352d1902d146200024957600080fd5b366200017357005b600080fd5b3480156200018557600080fd5b506200019d62000197366004620028b2565b6200052b565b604051620001b69b9a9998979695949392919062002959565b60405180910390f35b348015620001cc57600080fd5b50620001e4620001de366004620028b2565b620006b8565b005b348015620001f357600080fd5b50620001fe60035481565b604051908152602001620001b6565b3480156200021a57600080fd5b50620001e46200022c366004620029fe565b6200079f565b620001e46200024336600462002ada565b6200099f565b3480156200025657600080fd5b50620001fe620009c4565b3480156200026e57600080fd5b50620001e462000280366004620028b2565b620009e4565b3480156200029357600080fd5b50620001e462000b30565b348015620002ab57600080fd5b50620001e4620002bd36600462002b68565b62000b48565b348015620002d057600080fd5b50620002db62000edc565b6040516001600160a01b039091168152602001620001b6565b3480156200030157600080fd5b50620001e46200031336600462002bd4565b62000f0a565b3480156200032657600080fd5b50620001e462000338366004620028b2565b6200121a565b3480156200034b57600080fd5b5062000371604051806040016040528060058152602001640352e302e360dc1b81525081565b604051620001b6919062002c4a565b3480156200038d57600080fd5b50620001e46200039f36600462002c5f565b620012b3565b348015620003b257600080fd5b50620001e4620003c436600462002cd3565b62001648565b348015620003d757600080fd5b50620001e462001793565b348015620003ef57600080fd5b50620001fe6200040136600462002cf6565b620018e3565b3480156200041457600080fd5b50620001e462000426366004620028b2565b620019db565b3480156200043957600080fd5b50620001fe60045481565b3480156200045157600080fd5b506200046962000463366004620028b2565b62001a51565b60408051978852602088019690965294860193909352901515606085015215156080840152151560a0830152151560c082015260e001620001b6565b348015620004b257600080fd5b506200019d620004c4366004620028b2565b62001b61565b620001e4620004db366004620028b2565b62001d4f565b348015620004ee57600080fd5b50620001e46200050036600462002d1e565b62002193565b3480156200051357600080fd5b50620001e462000525366004620028b2565b620021d4565b600060208190529081526040902080548190620005489062002d3e565b80601f0160208091040260200160405190810160405280929190818152602001828054620005769062002d3e565b8015620005c75780601f106200059b57610100808354040283529160200191620005c7565b820191906000526020600020905b815481529060010190602001808311620005a957829003601f168201915b505050505090806001018054620005de9062002d3e565b80601f01602080910402602001604051908101604052809291908181526020018280546200060c9062002d3e565b80156200065d5780601f1062000631576101008083540402835291602001916200065d565b820191906000526020600020905b8154815290600101906020018083116200063f57829003601f168201915b50505060028401546003850154600486015460058701546006880154600789015460089099015497986001600160a01b03958616989486169750929094169450929160ff80821691610100810482169162010000909104168b565b6003548110620006e55760405162461bcd60e51b8152600401620006dc9062002d7a565b60405180910390fd5b60008181526020819052604090206002600882015462010000900460ff16600281111562000717576200071762002920565b14620007375760405162461bcd60e51b8152600401620006dc9062002daa565b600381015460408051632cb56b9160e21b815290516001600160a01b0390921691829163b2d5ae4491600480830192600092919082900301818387803b1580156200078157600080fd5b505af115801562000796573d6000803e3d6000fd5b50505050505050565b6003548210620007c35760405162461bcd60e51b8152600401620006dc9062002d7a565b600082815260208190526040902060028101546001600160a01b0316331480620008075750620007f262000edc565b6001600160a01b0316336001600160a01b0316145b620008265760405162461bcd60e51b8152600401620006dc9062002de1565b60088101805460ff19168315151790556000600882015462010000900460ff1660028111156200085a576200085a62002920565b146200095d576001600882015462010000900460ff16600281111562000884576200088462002920565b03620008f657600381015460405163567619c560e11b815283151560048201526001600160a01b0390911690819063acec338a90602401600060405180830381600087803b158015620008d657600080fd5b505af1158015620008eb573d6000803e3d6000fd5b50505050506200095d565b600381015460405163567619c560e11b815283151560048201526001600160a01b0390911690819063acec338a90602401600060405180830381600087803b1580156200094257600080fd5b505af115801562000957573d6000803e3d6000fd5b50505050505b827f73c9860341fcf3a75820bf92ceafc9c352f5590f6693cd99123378b454372b7d8360405162000992911515815260200190565b60405180910390a2505050565b620009a96200235e565b620009b48262002407565b620009c0828262002411565b5050565b6000620009d0620024dd565b506000805160206200552a83398151915290565b600354811062000a085760405162461bcd60e51b8152600401620006dc9062002d7a565b60008181526020819052604090206002600882015462010000900460ff16600281111562000a3a5762000a3a62002920565b1462000a5a5760405162461bcd60e51b8152600401620006dc9062002daa565b60028101546001600160a01b0316331462000a895760405162461bcd60e51b8152600401620006dc9062002de1565b60038101546040805163ac30777360e01b815290516001600160a01b0390921691829163ac30777391600480830192600092919082900301818387803b15801562000ad357600080fd5b505af115801562000ae8573d6000803e3d6000fd5b5050505060088201805460ff19169055600582015460405190815283907f5ae12fb120f50967718dd9647cd2cf2c994c869ad44f4e3d05cc5e675b93c3569060200162000992565b62000b3a62002527565b62000b4660006200255d565b565b6001600160a01b03821662000ba05760405162461bcd60e51b815260206004820152601d60248201527f496e76616c69642070726f6a656374206f776e657220616464726573730000006044820152606401620006dc565b6001600160a01b03811662000bf85760405162461bcd60e51b815260206004820152601c60248201527f496e76616c6964204e465420636f6e74726163742061646472657373000000006044820152606401620006dc565b6001600160a01b03811660009081526002602052604090205460ff161562000c6e5760405162461bcd60e51b815260206004820152602260248201527f4e465420636f6e747261637420616c72656164792068617320612070726f6a6560448201526118dd60f21b6064820152608401620006dc565b6001600160a01b038116600090815260026020526040808220805460ff1916600117905551849084908490309062000ca69062002896565b62000cb5949392919062002e09565b604051809103906000f08015801562000cd2573d6000803e3d6000fd5b50905060006003549050604051806101600160405280604051806020016040528060008152508152602001868152602001856001600160a01b03168152602001836001600160a01b03168152602001846001600160a01b031681526020016000815260200160008152602001600081526020016001151581526020016000151581526020016001600281111562000d6d5762000d6d62002920565b905260008281526020819052604090208151819062000d8d908262002e93565b506020820151600182019062000da4908262002e93565b506040820151600282810180546001600160a01b03199081166001600160a01b039485161790915560608501516003850180548316918516919091179055608085015160048501805490921693169290921790915560a0830151600583015560c0830151600683015560e083015160078301556101008084015160088401805461012087015161ffff1990911692151561ff00191692909217911515909202178082556101408501519262ff000019909116906201000090849081111562000e705762000e7062002920565b021790555050600380549150600062000e898362002f76565b9190505550836001600160a01b0316817fad2affd458da4c47ec915e7c69a188631855c8c8863015c36e574a14ff23a59b84600160405162000ecd92919062002f92565b60405180910390a35050505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b600083511162000f5d5760405162461bcd60e51b815260206004820152601c60248201527f50726f6a656374206e616d652063616e6e6f7420626520656d707479000000006044820152606401620006dc565b6001600160a01b03811662000fb55760405162461bcd60e51b815260206004820152601d60248201527f496e76616c69642070726f6a656374206f776e657220616464726573730000006044820152606401620006dc565b60008360405160200162000fca919062002fbf565b60408051601f1981840301815291815281516020928301206000818152600190935291205490915060ff1615620010445760405162461bcd60e51b815260206004820152601b60248201527f50726f6a656374206e616d6520616c72656164792065786973747300000000006044820152606401620006dc565b6000818152600160208181526040808420805460ff1916841790556003548151610160810183528981528084018990526001600160a01b03881681840152606081018690526080810186905260a0810186905260c0810186905260e08101869052610100810194909452610120840185905261014084018590528085529184905290922081518190620010d8908262002e93565b5060208201516001820190620010ef908262002e93565b506040820151600282810180546001600160a01b03199081166001600160a01b039485161790915560608501516003850180548316918516919091179055608085015160048501805490921693169290921790915560a0830151600583015560c0830151600683015560e083015160078301556101008084015160088401805461012087015161ffff1990911692151561ff00191692909217911515909202178082556101408501519262ff0000199091169062010000908490811115620011bb57620011bb62002920565b0217905550506003805491506000620011d48362002f76565b9190505550826001600160a01b0316817fad2affd458da4c47ec915e7c69a188631855c8c8863015c36e574a14ff23a59b8760008060405162000ecd9392919062002fdd565b6200122462002527565b6103e8811115620012785760405162461bcd60e51b815260206004820152601a60248201527f46656520726174652063616e6e6f7420657863656564203130250000000000006044820152606401620006dc565b60048190556040518181527f72b05fd7e6e407beabebd17ae121166880efdc19a2a9b08063eafc0c001e470a9060200160405180910390a150565b6000835111620013065760405162461bcd60e51b815260206004820152601d60248201527f43616d706169676e206e616d652063616e6e6f7420626520656d7074790000006044820152606401620006dc565b60008111620013645760405162461bcd60e51b815260206004820152602360248201527f46756e64696e6720676f616c206d75737420626520677265617465722074686160448201526206e20360ec1b6064820152608401620006dc565b60008360405160200162001379919062002fbf565b60408051601f1981840301815291815281516020928301206000818152600190935291205490915060ff1615620013f35760405162461bcd60e51b815260206004820152601c60248201527f43616d706169676e206e616d6520616c726561647920657869737473000000006044820152606401620006dc565b6000818152600160208190526040808320805460ff191690921790915551859085908590339030906200142690620028a4565b620014369594939291906200301a565b604051809103906000f08015801562001453573d6000803e3d6000fd5b50905060006003549050604051806101600160405280878152602001868152602001336001600160a01b03168152602001836001600160a01b0316815260200160006001600160a01b03168152602001600081526020018581526020014262278d00620014c191906200306b565b8152600160208201526000604082015260600160029052600082815260208190526040902081518190620014f6908262002e93565b50602082015160018201906200150d908262002e93565b506040820151600282810180546001600160a01b03199081166001600160a01b039485161790915560608501516003850180548316918516919091179055608085015160048501805490921693169290921790915560a0830151600583015560c0830151600683015560e083015160078301556101008084015160088401805461012087015161ffff1990911692151561ff00191692909217911515909202178082556101408501519262ff0000199091169062010000908490811115620015d957620015d962002920565b0217905550506003805491506000620015f28362002f76565b9190505550336001600160a01b0316817fad2affd458da4c47ec915e7c69a188631855c8c8863015c36e574a14ff23a59b88856002604051620016389392919062002fdd565b60405180910390a3505050505050565b60035482106200166c5760405162461bcd60e51b8152600401620006dc9062002d7a565b60008281526020819052604090206002600882015462010000900460ff1660028111156200169e576200169e62002920565b14620016be5760405162461bcd60e51b8152600401620006dc9062002daa565b60028101546001600160a01b03163314620016ed5760405162461bcd60e51b8152600401620006dc9062002de1565b600381015460405163416a4a3b60e11b8152600481018490526001600160a01b039091169081906382d4947690602401600060405180830381600087803b1580156200173857600080fd5b505af11580156200174d573d6000803e3d6000fd5b505050506006820183905560405183815284907fe25725250b6d468fb62d50608eb0b36810bb3601dcd9e33e7c024041a13567c09060200160405180910390a250505050565b6200179d62002527565b620017a7620025ce565b4780620017ed5760405162461bcd60e51b81526020600482015260136024820152724e6f206665657320746f20776974686472617760681b6044820152606401620006dc565b6000620017f962000edc565b6001600160a01b03168260405160006040518083038185875af1925050503d806000811462001845576040519150601f19603f3d011682016040523d82523d6000602084013e6200184a565b606091505b5050905080620018955760405162461bcd60e51b8152602060048201526015602482015274119959481dda5d1a191c985dd85b0819985a5b1959605a1b6044820152606401620006dc565b6040518281527f9800e6f57aeb4360eaa72295a820a4293e1e66fbfcabcd8874ae141304a76deb9060200160405180910390a1505062000b4660016000805160206200554a83398151915255565b60006003548310620019095760405162461bcd60e51b8152600401620006dc9062002d7a565b60008381526020819052604090206002600882015462010000900460ff1660028111156200193b576200193b62002920565b146200195b5760405162461bcd60e51b8152600401620006dc9062002daa565b6003810154604051631479197f60e01b81526001600160a01b038581166004830152909116908190631479197f90602401602060405180830381865afa158015620019aa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620019d0919062003081565b925050505b92915050565b620019e562002527565b600354811062001a095760405162461bcd60e51b8152600401620006dc9062002d7a565b600081815260208190526040808220600801805461ff0019166101001790555182917f2fe72be8f4566f35545876185d6cc546d49e5b96e94813ba058f82a4d4b8162391a250565b6000806000806000806000600354881062001a805760405162461bcd60e51b8152600401620006dc9062002d7a565b60008881526020819052604090206002600882015462010000900460ff16600281111562001ab25762001ab262002920565b1462001ad25760405162461bcd60e51b8152600401620006dc9062002daa565b6003810154604080516302734eab60e51b815290516001600160a01b03909216918291634e69d5609160048083019260e09291908290030181865afa15801562001b20573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001b4691906200309b565b98509850985098509850985098505050919395979092949650565b60608060008060008060008060008060006003548c1062001b965760405162461bcd60e51b8152600401620006dc9062002d7a565b60008c815260208190526040902060028101546003820154600483015460058401546006850154600786015460088701548754889760018901976001600160a01b03918216979082169691169490939092909160ff80831692610100810482169262010000909104909116908b9062001c0f9062002d3e565b80601f016020809104026020016040519081016040528092919081815260200182805462001c3d9062002d3e565b801562001c8e5780601f1062001c625761010080835404028352916020019162001c8e565b820191906000526020600020905b81548152906001019060200180831162001c7057829003601f168201915b50505050509a5089805462001ca39062002d3e565b80601f016020809104026020016040519081016040528092919081815260200182805462001cd19062002d3e565b801562001d225780601f1062001cf65761010080835404028352916020019162001d22565b820191906000526020600020905b81548152906001019060200180831162001d0457829003601f168201915b505050505099509b509b509b509b509b509b509b509b509b509b509b505091939597999b90929496989a50565b62001d59620025ce565b600354811062001d7d5760405162461bcd60e51b8152600401620006dc9062002d7a565b60008181526020819052604090206008015460ff1662001dd85760405162461bcd60e51b815260206004820152601560248201527450726f6a656374206973206e6f742061637469766560581b6044820152606401620006dc565b6000341162001e395760405162461bcd60e51b815260206004820152602660248201527f446f6e6174696f6e20616d6f756e74206d75737420626520677265617465722060448201526507468616e20360d41b6064820152608401620006dc565b60008181526020819052604090206002600882015462010000900460ff16600281111562001e6b5762001e6b62002920565b0362001ec6578060070154421062001ec65760405162461bcd60e51b815260206004820152601f60248201527f43726f776466756e64696e672063616d706169676e2068617320656e646564006044820152606401620006dc565b60006127106004543462001edb919062003122565b62001ee791906200313c565b9050600062001ef782346200315f565b90506000600884015462010000900460ff16600281111562001f1d5762001f1d62002920565b0362001fdd5760028301546040516000916001600160a01b03169083908381818185875af1925050503d806000811462001f74576040519150601f19603f3d011682016040523d82523d6000602084013e62001f79565b606091505b505090508062001fd65760405162461bcd60e51b815260206004820152602160248201527f506572736f6e616c20646f6e6174696f6e207472616e73666572206661696c656044820152601960fa1b6064820152608401620006dc565b5062002122565b60606001600885015462010000900460ff16600281111562002003576200200362002920565b036200203957506040805160048152602481019091526020810180516001600160e01b03166345d3292b60e01b17905262002064565b506040805160048152602481019091526020810180516001600160e01b03166345d3292b60e01b1790525b60038401546040516000916001600160a01b03169084906200208890859062002fbf565b60006040518083038185875af1925050503d8060008114620020c7576040519150601f19603f3d011682016040523d82523d6000602084013e620020cc565b606091505b50509050806200211f5760405162461bcd60e51b815260206004820181905260248201527f50726f6a65637420646f6e6174696f6e207472616e73666572206661696c65646044820152606401620006dc565b50505b808360050160008282546200213891906200306b565b9091555050604051818152339085907f0b5b4c52969ff7329ecf7ee536409fda87812b15a8622bc6e8cdeab3aee14a269060200160405180910390a35050506200219060016000805160206200554a83398151915255565b50565b6200219d62002527565b6001600160a01b038116620021c957604051631e4fbdf760e01b815260006004820152602401620006dc565b62002190816200255d565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156200221b5750825b905060008267ffffffffffffffff166001148015620022395750303b155b90508115801562002248575080155b15620022675760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156200229257845460ff60401b1916600160401b1785555b6103e8861115620022e65760405162461bcd60e51b815260206004820152601a60248201527f46656520726174652063616e6e6f7420657863656564203130250000000000006044820152606401620006dc565b620022f1336200261d565b620022fb62002632565b6200230562002646565b6004869055600060035583156200235657845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480620023e857507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316620023dc6000805160206200552a833981519152546001600160a01b031690565b6001600160a01b031614155b1562000b465760405163703e46dd60e11b815260040160405180910390fd5b6200219062002527565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156200246e575060408051601f3d908101601f191682019092526200246b9181019062003081565b60015b6200249857604051634c9c8ce360e01b81526001600160a01b0383166004820152602401620006dc565b6000805160206200552a8339815191528114620024cc57604051632a87526960e21b815260048101829052602401620006dc565b620024d8838362002650565b505050565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161462000b465760405163703e46dd60e11b815260040160405180910390fd5b336200253262000edc565b6001600160a01b03161462000b465760405163118cdaa760e01b8152336004820152602401620006dc565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b6000805160206200554a8339815191528054600119016200260257604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b60016000805160206200554a83398151915255565b62002627620026ad565b6200219081620026f7565b6200263c620026ad565b62000b4662002701565b62000b46620026ad565b6200265b826200270b565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115620026a357620024d8828262002773565b620009c0620027e6565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1662000b4657604051631afcd79f60e31b815260040160405180910390fd5b6200219d620026ad565b62002608620026ad565b806001600160a01b03163b6000036200274357604051634c9c8ce360e01b81526001600160a01b0382166004820152602401620006dc565b6000805160206200552a83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b03168460405162002792919062002fbf565b600060405180830381855af49150503d8060008114620027cf576040519150601f19603f3d011682016040523d82523d6000602084013e620027d4565b606091505b5091509150620019d085838362002806565b341562000b465760405163b398979f60e01b815260040160405180910390fd5b6060826200281f5762002819826200286c565b62002865565b81511580156200283757506001600160a01b0384163b155b156200286257604051639996b31560e01b81526001600160a01b0385166004820152602401620006dc565b50805b9392505050565b8051156200287d5780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b610bcf806200317683390190565b6117e58062003d4583390190565b600060208284031215620028c557600080fd5b5035919050565b60005b83811015620028e9578181015183820152602001620028cf565b50506000910152565b600081518084526200290c816020860160208601620028cc565b601f01601f19169290920160200192915050565b634e487b7160e01b600052602160045260246000fd5b600381106200295557634e487b7160e01b600052602160045260246000fd5b9052565b60006101608083526200296f8184018f620028f2565b9050828103602084015262002985818e620028f2565b6001600160a01b038d811660408601528c811660608601528b16608085015260a084018a905260c0840189905260e084018890528615156101008501528515156101208501529150620029df905061014083018462002936565b9c9b505050505050505050505050565b80151581146200219057600080fd5b6000806040838503121562002a1257600080fd5b82359150602083013562002a2681620029ef565b809150509250929050565b6001600160a01b03811681146200219057600080fd5b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff8084111562002a7b5762002a7b62002a47565b604051601f8501601f19908116603f0116810190828211818310171562002aa65762002aa662002a47565b8160405280935085815286868601111562002ac057600080fd5b858560208301376000602087830101525050509392505050565b6000806040838503121562002aee57600080fd5b823562002afb8162002a31565b9150602083013567ffffffffffffffff81111562002b1857600080fd5b8301601f8101851362002b2a57600080fd5b62002b3b8582356020840162002a5d565b9150509250929050565b600082601f83011262002b5757600080fd5b620028658383356020850162002a5d565b60008060006060848603121562002b7e57600080fd5b833567ffffffffffffffff81111562002b9657600080fd5b62002ba48682870162002b45565b935050602084013562002bb78162002a31565b9150604084013562002bc98162002a31565b809150509250925092565b60008060006060848603121562002bea57600080fd5b833567ffffffffffffffff8082111562002c0357600080fd5b62002c118783880162002b45565b9450602086013591508082111562002c2857600080fd5b5062002c378682870162002b45565b925050604084013562002bc98162002a31565b602081526000620028656020830184620028f2565b60008060006060848603121562002c7557600080fd5b833567ffffffffffffffff8082111562002c8e57600080fd5b62002c9c8783880162002b45565b9450602086013591508082111562002cb357600080fd5b5062002cc28682870162002b45565b925050604084013590509250925092565b6000806040838503121562002ce757600080fd5b50508035926020909101359150565b6000806040838503121562002d0a57600080fd5b82359150602083013562002a268162002a31565b60006020828403121562002d3157600080fd5b8135620028658162002a31565b600181811c9082168062002d5357607f821691505b60208210810362002d7457634e487b7160e01b600052602260045260246000fd5b50919050565b602080825260169082015275141c9bda9958dd08191bd95cc81b9bdd08195e1a5cdd60521b604082015260600190565b6020808252601a908201527f4e6f7420612063726f776466756e64696e672070726f6a656374000000000000604082015260600190565b6020808252600e908201526d139bdd08185d5d1a1bdc9a5e995960921b604082015260600190565b60808152600062002e1e6080830187620028f2565b6001600160a01b0395861660208401529385166040830152509216606090920191909152919050565b601f821115620024d8576000816000526020600020601f850160051c8101602086101562002e725750805b601f850160051c820191505b81811015620023565782815560010162002e7e565b815167ffffffffffffffff81111562002eb05762002eb062002a47565b62002ec88162002ec1845462002d3e565b8462002e47565b602080601f83116001811462002f00576000841562002ee75750858301515b600019600386901b1c1916600185901b17855562002356565b600085815260208120601f198616915b8281101562002f315788860151825594840194600190910190840162002f10565b508582101562002f505787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601160045260246000fd5b60006001820162002f8b5762002f8b62002f60565b5060010190565b60608082526000908201526001600160a01b03831660208201526080810162002865604083018462002936565b6000825162002fd3818460208701620028cc565b9190910192915050565b60608152600062002ff26060830186620028f2565b6001600160a01b0385166020840152905062003012604083018462002936565b949350505050565b60a0815260006200302f60a0830188620028f2565b8281036020840152620030438188620028f2565b604084019690965250506001600160a01b039283166060820152911660809091015292915050565b80820180821115620019d557620019d562002f60565b6000602082840312156200309457600080fd5b5051919050565b600080600080600080600060e0888a031215620030b757600080fd5b8751965060208801519550604088015194506060880151620030d981620029ef565b6080890151909450620030ec81620029ef565b60a0890151909350620030ff81620029ef565b60c08901519092506200311281620029ef565b8091505092959891949750929550565b8082028115828204841417620019d557620019d562002f60565b6000826200315a57634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115620019d557620019d562002f6056fe60806040523480156200001157600080fd5b5060405162000bcf38038062000bcf833981016040819052620000349162000147565b826001600160a01b0381166200006457604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200006f81620000c4565b5060016200007e8582620002e5565b50600280546001600160a01b039384166001600160a01b03199091161790556004805491909216610100026001600160a81b031990911617600117905550620003b19050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b03811681146200014257600080fd5b919050565b600080600080608085870312156200015e57600080fd5b84516001600160401b03808211156200017657600080fd5b818701915087601f8301126200018b57600080fd5b815181811115620001a057620001a062000114565b604051601f8201601f19908116603f01168101908382118183101715620001cb57620001cb62000114565b81604052828152602093508a84848701011115620001e857600080fd5b600091505b828210156200020c5784820184015181830185015290830190620001ed565b6000848483010152809850505050620002278188016200012a565b9450505062000239604086016200012a565b915062000249606086016200012a565b905092959194509250565b600181811c908216806200026957607f821691505b6020821081036200028a57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620002e0576000816000526020600020601f850160051c81016020861015620002bb5750805b601f850160051c820191505b81811015620002dc57828155600101620002c7565b5050505b505050565b81516001600160401b0381111562000301576200030162000114565b620003198162000312845462000254565b8462000290565b602080601f831160018114620003515760008415620003385750858301515b600019600386901b1c1916600185901b178555620002dc565b600085815260208120601f198616915b82811015620003825788860151825594840194600190910190840162000361565b5085821015620003a15787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b61080e80620003c16000396000f3fe6080604052600436106100955760003560e01c8063aae282e111610059578063aae282e114610271578063acec338a14610291578063dbe55e56146102b1578063de2ed893146102d6578063f2fde38b146102fa57600080fd5b806322f3e2d4146101cf57806345d3292b146101fe578063715018a6146102085780637284e4161461021d5780638da5cb5b1461023f57600080fd5b366101ca5760045460ff166100e95760405162461bcd60e51b815260206004820152601560248201527450726f6a656374206973206e6f742061637469766560581b60448201526064015b60405180910390fd5b600034116101095760405162461bcd60e51b81526004016100e09061064f565b6002546040516000916001600160a01b03169034908381818185875af1925050503d8060008114610156576040519150601f19603f3d011682016040523d82523d6000602084013e61015b565b606091505b505090508061017c5760405162461bcd60e51b81526004016100e090610695565b346003600082825461018e91906106d6565b909155505060405134815232907f264f630d9efa0d07053a31163641d9fcc0adafc9d9e76f1c37c2ce3a558d2c529060200160405180910390a2005b600080fd5b3480156101db57600080fd5b506004546101e99060ff1681565b60405190151581526020015b60405180910390f35b61020661031a565b005b34801561021457600080fd5b50610206610446565b34801561022957600080fd5b5061023261045a565b6040516101f591906106fd565b34801561024b57600080fd5b506000546001600160a01b03165b6040516001600160a01b0390911681526020016101f5565b34801561027d57600080fd5b50600254610259906001600160a01b031681565b34801561029d57600080fd5b506102066102ac36600461074c565b6104e8565b3480156102bd57600080fd5b506004546102599061010090046001600160a01b031681565b3480156102e257600080fd5b506102ec60035481565b6040519081526020016101f5565b34801561030657600080fd5b50610206610315366004610775565b610594565b60045460ff166103645760405162461bcd60e51b815260206004820152601560248201527450726f6a656374206973206e6f742061637469766560581b60448201526064016100e0565b600034116103845760405162461bcd60e51b81526004016100e09061064f565b6002546040516000916001600160a01b03169034908381818185875af1925050503d80600081146103d1576040519150601f19603f3d011682016040523d82523d6000602084013e6103d6565b606091505b50509050806103f75760405162461bcd60e51b81526004016100e090610695565b346003600082825461040991906106d6565b909155505060405134815232907f264f630d9efa0d07053a31163641d9fcc0adafc9d9e76f1c37c2ce3a558d2c529060200160405180910390a250565b61044e6105d2565b61045860006105ff565b565b600180546104679061079e565b80601f01602080910402602001604051908101604052809291908181526020018280546104939061079e565b80156104e05780601f106104b5576101008083540402835291602001916104e0565b820191906000526020600020905b8154815290600101906020018083116104c357829003601f168201915b505050505081565b6000546001600160a01b0316331480610510575060045461010090046001600160a01b031633145b61054d5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b60448201526064016100e0565b6004805460ff19168215159081179091556040519081527f4dcbe1841ee9bd9c888e46c0b35574429b1c0f1071806180028dee2f9a1064309060200160405180910390a150565b61059c6105d2565b6001600160a01b0381166105c657604051631e4fbdf760e01b8152600060048201526024016100e0565b6105cf816105ff565b50565b6000546001600160a01b031633146104585760405163118cdaa760e01b81523360048201526024016100e0565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60208082526026908201527f446f6e6174696f6e20616d6f756e74206d75737420626520677265617465722060408201526507468616e20360d41b606082015260800190565b60208082526021908201527f466f7277617264696e6720746f204e465420636f6e7472616374206661696c656040820152601960fa1b606082015260800190565b808201808211156106f757634e487b7160e01b600052601160045260246000fd5b92915050565b60006020808352835180602085015260005b8181101561072b5785810183015185820160400152820161070f565b506000604082860101526040601f19601f8301168501019250505092915050565b60006020828403121561075e57600080fd5b8135801515811461076e57600080fd5b9392505050565b60006020828403121561078757600080fd5b81356001600160a01b038116811461076e57600080fd5b600181811c908216806107b257607f821691505b6020821081036107d257634e487b7160e01b600052602260045260246000fd5b5091905056fea2646970667358221220af1f36404a7641e33a0114723f662c150d75a4e182ec84acb75a4e04e64f04e464736f6c6343000816003360806040523480156200001157600080fd5b50604051620017e5380380620017e5833981016040819052620000349162000217565b816001600160a01b0381166200006457604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200006f81620000e2565b5060018055600262000082868262000341565b50600362000091858262000341565b5060048390556005839055620000ab4262278d006200040d565b600655600880546001600160a01b0390921662010000026001600160b01b0319909216919091176001179055506200043592505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200015a57600080fd5b81516001600160401b038082111562000177576200017762000132565b604051601f8301601f19908116603f01168101908282118183101715620001a257620001a262000132565b8160405283815260209250866020858801011115620001c057600080fd5b600091505b83821015620001e45785820183015181830184015290820190620001c5565b6000602085830101528094505050505092915050565b80516001600160a01b03811681146200021257600080fd5b919050565b600080600080600060a086880312156200023057600080fd5b85516001600160401b03808211156200024857600080fd5b6200025689838a0162000148565b965060208801519150808211156200026d57600080fd5b506200027c8882890162000148565b945050604086015192506200029460608701620001fa565b9150620002a460808701620001fa565b90509295509295909350565b600181811c90821680620002c557607f821691505b602082108103620002e657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200033c576000816000526020600020601f850160051c81016020861015620003175750805b601f850160051c820191505b81811015620003385782815560010162000323565b5050505b505050565b81516001600160401b038111156200035d576200035d62000132565b62000375816200036e8454620002b0565b84620002ec565b602080601f831160018114620003ad5760008415620003945750858301515b600019600386901b1c1916600185901b17855562000338565b600085815260208120601f198616915b82811015620003de57888601518255948401946001909101908401620003bd565b5085821015620003fd5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b808201808211156200042f57634e487b7160e01b600052601160045260246000fd5b92915050565b6113a080620004456000396000f3fe6080604052600436106101395760003560e01c806382d49476116100ab578063c5c4744c1161006f578063c5c4744c14610497578063c9250d91146104ad578063cc6cb19a146104c3578063dbe55e56146104f0578063df83307314610516578063f2fde38b1461052b57600080fd5b806382d494761461040f5780638da5cb5b1461042f578063ac3077731461044d578063acec338a14610462578063b2d5ae441461048257600080fd5b80634abfa163116100fd5780634abfa163146103155780634e69d5601461034d57806357c9ca14146103b0578063715018a6146103cf5780637284e416146103e45780637a3a0e84146103f957600080fd5b806306fdde031461025c5780631479197f1461028757806322f3e2d4146102cb57806329dcb0cf146102f557806345d3292b1461030b57600080fd5b366102575760085460ff166101695760405162461bcd60e51b815260040161016090611145565b60405180910390fd5b600654421061018a5760405162461bcd60e51b815260040161016090611175565b3260009081526009602052604081205490036101e357600a80546001810182556000919091527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a80180546001600160a01b031916321790555b32600090815260096020526040812080543492906102029084906111b7565b92505081905550346007600082825461021b91906111b7565b909155505060405134815232907f264f630d9efa0d07053a31163641d9fcc0adafc9d9e76f1c37c2ce3a558d2c529060200160405180910390a2005b600080fd5b34801561026857600080fd5b5061027161054b565b60405161027e91906111d0565b60405180910390f35b34801561029357600080fd5b506102bd6102a236600461121f565b6001600160a01b031660009081526009602052604090205490565b60405190815260200161027e565b3480156102d757600080fd5b506008546102e59060ff1681565b604051901515815260200161027e565b34801561030157600080fd5b506102bd60065481565b6103136105d9565b005b34801561032157600080fd5b5061033561033036600461124f565b610759565b6040516001600160a01b03909116815260200161027e565b34801561035957600080fd5b50600454600754600654600854604080518581526020810185905290810183905260ff8083161515606083015261010090920490911615156080820152929091101560a083015242101560c082015260e00161027e565b3480156103bc57600080fd5b506008546102e590610100900460ff1681565b3480156103db57600080fd5b50610313610783565b3480156103f057600080fd5b50610271610795565b34801561040557600080fd5b506102bd60045481565b34801561041b57600080fd5b5061031361042a36600461124f565b6107a2565b34801561043b57600080fd5b506000546001600160a01b0316610335565b34801561045957600080fd5b50610313610969565b34801561046e57600080fd5b5061031361047d366004611268565b610bfc565b34801561048e57600080fd5b50610313610cb0565b3480156104a357600080fd5b506102bd60075481565b3480156104b957600080fd5b506102bd60055481565b3480156104cf57600080fd5b506102bd6104de36600461121f565b60096020526000908152604090205481565b3480156104fc57600080fd5b50600854610335906201000090046001600160a01b031681565b34801561052257600080fd5b50610313610eaf565b34801561053757600080fd5b5061031361054636600461121f565b611063565b600280546105589061128a565b80601f01602080910402602001604051908101604052809291908181526020018280546105849061128a565b80156105d15780601f106105a6576101008083540402835291602001916105d1565b820191906000526020600020905b8154815290600101906020018083116105b457829003601f168201915b505050505081565b6105e161109e565b60085460ff166106035760405162461bcd60e51b815260040161016090611145565b60065442106106245760405162461bcd60e51b815260040161016090611175565b600034116106835760405162461bcd60e51b815260206004820152602660248201527f446f6e6174696f6e20616d6f756e74206d75737420626520677265617465722060448201526507468616e20360d41b6064820152608401610160565b3260009081526009602052604081205490036106dc57600a80546001810182556000919091527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a80180546001600160a01b031916321790555b32600090815260096020526040812080543492906106fb9084906111b7565b92505081905550346007600082825461071491906111b7565b909155505060405134815232907f264f630d9efa0d07053a31163641d9fcc0adafc9d9e76f1c37c2ce3a558d2c529060200160405180910390a261075760018055565b565b600a818154811061076957600080fd5b6000918252602090912001546001600160a01b0316905081565b61078b6110c8565b61075760006110f5565b600380546105589061128a565b6107aa61109e565b6000546001600160a01b03163314806107d357506008546201000090046001600160a01b031633145b6107ef5760405162461bcd60e51b8152600401610160906112c4565b60085460ff166108115760405162461bcd60e51b815260040161016090611145565b60065442106108325760405162461bcd60e51b815260040161016090611175565b60045481106108945760405162461bcd60e51b815260206004820152602860248201527f4e657720676f616c206d757374206265206c6f776572207468616e2063757272604482015267195b9d0819dbd85b60c21b6064820152608401610160565b60006064600554604b6108a791906112ec565b6108b19190611303565b90508082101561091a5760405162461bcd60e51b815260206004820152602e60248201527f43616e6e6f7420726564756365206279206d6f7265207468616e20323525206f60448201526d19881a5b9a5d1a585b0819dbd85b60921b6064820152608401610160565b600480549083905560408051828152602081018590527fb0849b0fc070e9c3b7b393322de992eebc64ffb9feaaf17e888555075d008f36910160405180910390a1505061096660018055565b50565b61097161109e565b6000546001600160a01b031633148061099a57506008546201000090046001600160a01b031633145b6109b65760405162461bcd60e51b8152600401610160906112c4565b600854610100900460ff16156109de5760405162461bcd60e51b815260040161016090611325565b6004546007541015806109f357506006544210155b610a5b5760405162461bcd60e51b815260206004820152603360248201527f43616e6e6f7420636c61696d206265666f726520646561646c696e6520756e6c604482015272195cdcc819dbd85b081a5cc81c995858da1959606a1b6064820152608401610160565b6004546007541015610aaf5760405162461bcd60e51b815260206004820152601860248201527f46756e64696e6720676f616c206e6f74207265616368656400000000000000006044820152606401610160565b4780610af15760405162461bcd60e51b81526020600482015260116024820152704e6f2066756e647320746f20636c61696d60781b6044820152606401610160565b6008805461ffff19166101001790556000610b146000546001600160a01b031690565b6001600160a01b03168260405160006040518083038185875af1925050503d8060008114610b5e576040519150601f19603f3d011682016040523d82523d6000602084013e610b63565b606091505b5050905080610ba35760405162461bcd60e51b815260206004820152600c60248201526b10db185a5b4819985a5b195960a21b6044820152606401610160565b6000546001600160a01b03166001600160a01b03167fa65a8b4f7f65a1063243d7f7e9e4da00ff767599acf21549ef2548a45d1695ae83604051610be991815260200190565b60405180910390a2505061075760018055565b6000546001600160a01b0316331480610c2557506008546201000090046001600160a01b031633145b610c415760405162461bcd60e51b8152600401610160906112c4565b600854610100900460ff1615610c695760405162461bcd60e51b815260040161016090611325565b6008805460ff19168215159081179091556040519081527f4dcbe1841ee9bd9c888e46c0b35574429b1c0f1071806180028dee2f9a1064309060200160405180910390a150565b610cb861109e565b600654421015610d0a5760405162461bcd60e51b815260206004820152601a60248201527f43616d706169676e207374696c6c20696e2070726f67726573730000000000006044820152606401610160565b60045460075410610d695760405162461bcd60e51b8152602060048201526024808201527f46756e64696e6720676f616c2077617320726561636865642c206e6f20726566604482015263756e647360e01b6064820152608401610160565b600854610100900460ff1615610d915760405162461bcd60e51b815260040161016090611325565b3360009081526009602052604090205480610de65760405162461bcd60e51b8152602060048201526015602482015274139bc8191bdb985d1a5bdb881d1bc81c99599d5b99605a1b6044820152606401610160565b336000818152600960205260408082208290555190919083908381818185875af1925050503d8060008114610e37576040519150601f19603f3d011682016040523d82523d6000602084013e610e3c565b606091505b5050905080610e7d5760405162461bcd60e51b815260206004820152600d60248201526c1499599d5b990819985a5b1959609a1b6044820152606401610160565b60405182815233907fa171b6942063c6f2800ce40a780edce37baa2b618571b11eedd1e69e626e7d7690602001610be9565b610eb761109e565b6000546001600160a01b0316331480610ee057506008546201000090046001600160a01b031633145b610efc5760405162461bcd60e51b8152600401610160906112c4565b60085460ff16610f1e5760405162461bcd60e51b815260040161016090611145565b600854610100900460ff1615610f465760405162461bcd60e51b815260040161016090611325565b6008805460ff1916905560005b600a54811015611059576000600a8281548110610f7257610f72611354565b60009182526020808320909101546001600160a01b03168083526009909152604090912054909150801561104f576001600160a01b0382166000818152600960205260408082208290555190919083908381818185875af1925050503d8060008114610ffa576040519150601f19603f3d011682016040523d82523d6000602084013e610fff565b606091505b50509050801561104d57826001600160a01b03167fa171b6942063c6f2800ce40a780edce37baa2b618571b11eedd1e69e626e7d768360405161104491815260200190565b60405180910390a25b505b5050600101610f53565b5061075760018055565b61106b6110c8565b6001600160a01b03811661109557604051631e4fbdf760e01b815260006004820152602401610160565b610966816110f5565b6002600154036110c157604051633ee5aeb560e01b815260040160405180910390fd5b6002600155565b6000546001600160a01b031633146107575760405163118cdaa760e01b8152336004820152602401610160565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60208082526016908201527543616d706169676e206973206e6f742061637469766560501b604082015260600190565b60208082526012908201527110d85b5c185a59db881a185cc8195b99195960721b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b808201808211156111ca576111ca6111a1565b92915050565b60006020808352835180602085015260005b818110156111fe578581018301518582016040015282016111e2565b506000604082860101526040601f19601f8301168501019250505092915050565b60006020828403121561123157600080fd5b81356001600160a01b038116811461124857600080fd5b9392505050565b60006020828403121561126157600080fd5b5035919050565b60006020828403121561127a57600080fd5b8135801515811461124857600080fd5b600181811c9082168061129e57607f821691505b6020821081036112be57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600e908201526d139bdd08185d5d1a1bdc9a5e995960921b604082015260600190565b80820281158282048414176111ca576111ca6111a1565b60008261132057634e487b7160e01b600052601260045260246000fd5b500490565b602080825260159082015274119d5b991cc8185b1c9958591e4818db185a5b5959605a1b604082015260600190565b634e487b7160e01b600052603260045260246000fdfea264697066735822122013c678477817949248c07bb4b85c522c358680328d105d4a9fae6cffd6bae7ca64736f6c63430008160033360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a26469706673582212207a0b01d41733e1795446df943e6084d74667a9406d2648398e1a7bcfd4a828da64736f6c63430008160033
Deployed Bytecode
0x6080604052600436106200016b5760003560e01c8063ad3cb1cc11620000c5578063eeca08f01162000078578063eeca08f0146200042c578063f0c006371462000444578063f0f3f2c814620004a5578063f14faf6f14620004ca578063f2fde38b14620004e1578063fe4b84df146200050657600080fd5b8063ad3cb1cc146200033e578063bc4ac19b1462000380578063c55c518c14620003a5578063d0b7830b14620003ca578063dcd4720114620003e2578063ed1ca91a146200040757600080fd5b80635e15b14d116200011e5780635e15b14d1462000261578063715018a6146200028657806380e5be34146200029e5780638da5cb5b14620002c3578063909cfe6414620002f4578063927fef2e146200031957600080fd5b8063107046bd146200017857806326c2319c14620001bf57806336fbad2614620001e65780633af6cd1e146200020d5780634f1ef286146200023257806352d1902d146200024957600080fd5b366200017357005b600080fd5b3480156200018557600080fd5b506200019d62000197366004620028b2565b6200052b565b604051620001b69b9a9998979695949392919062002959565b60405180910390f35b348015620001cc57600080fd5b50620001e4620001de366004620028b2565b620006b8565b005b348015620001f357600080fd5b50620001fe60035481565b604051908152602001620001b6565b3480156200021a57600080fd5b50620001e46200022c366004620029fe565b6200079f565b620001e46200024336600462002ada565b6200099f565b3480156200025657600080fd5b50620001fe620009c4565b3480156200026e57600080fd5b50620001e462000280366004620028b2565b620009e4565b3480156200029357600080fd5b50620001e462000b30565b348015620002ab57600080fd5b50620001e4620002bd36600462002b68565b62000b48565b348015620002d057600080fd5b50620002db62000edc565b6040516001600160a01b039091168152602001620001b6565b3480156200030157600080fd5b50620001e46200031336600462002bd4565b62000f0a565b3480156200032657600080fd5b50620001e462000338366004620028b2565b6200121a565b3480156200034b57600080fd5b5062000371604051806040016040528060058152602001640352e302e360dc1b81525081565b604051620001b6919062002c4a565b3480156200038d57600080fd5b50620001e46200039f36600462002c5f565b620012b3565b348015620003b257600080fd5b50620001e4620003c436600462002cd3565b62001648565b348015620003d757600080fd5b50620001e462001793565b348015620003ef57600080fd5b50620001fe6200040136600462002cf6565b620018e3565b3480156200041457600080fd5b50620001e462000426366004620028b2565b620019db565b3480156200043957600080fd5b50620001fe60045481565b3480156200045157600080fd5b506200046962000463366004620028b2565b62001a51565b60408051978852602088019690965294860193909352901515606085015215156080840152151560a0830152151560c082015260e001620001b6565b348015620004b257600080fd5b506200019d620004c4366004620028b2565b62001b61565b620001e4620004db366004620028b2565b62001d4f565b348015620004ee57600080fd5b50620001e46200050036600462002d1e565b62002193565b3480156200051357600080fd5b50620001e462000525366004620028b2565b620021d4565b600060208190529081526040902080548190620005489062002d3e565b80601f0160208091040260200160405190810160405280929190818152602001828054620005769062002d3e565b8015620005c75780601f106200059b57610100808354040283529160200191620005c7565b820191906000526020600020905b815481529060010190602001808311620005a957829003601f168201915b505050505090806001018054620005de9062002d3e565b80601f01602080910402602001604051908101604052809291908181526020018280546200060c9062002d3e565b80156200065d5780601f1062000631576101008083540402835291602001916200065d565b820191906000526020600020905b8154815290600101906020018083116200063f57829003601f168201915b50505060028401546003850154600486015460058701546006880154600789015460089099015497986001600160a01b03958616989486169750929094169450929160ff80821691610100810482169162010000909104168b565b6003548110620006e55760405162461bcd60e51b8152600401620006dc9062002d7a565b60405180910390fd5b60008181526020819052604090206002600882015462010000900460ff16600281111562000717576200071762002920565b14620007375760405162461bcd60e51b8152600401620006dc9062002daa565b600381015460408051632cb56b9160e21b815290516001600160a01b0390921691829163b2d5ae4491600480830192600092919082900301818387803b1580156200078157600080fd5b505af115801562000796573d6000803e3d6000fd5b50505050505050565b6003548210620007c35760405162461bcd60e51b8152600401620006dc9062002d7a565b600082815260208190526040902060028101546001600160a01b0316331480620008075750620007f262000edc565b6001600160a01b0316336001600160a01b0316145b620008265760405162461bcd60e51b8152600401620006dc9062002de1565b60088101805460ff19168315151790556000600882015462010000900460ff1660028111156200085a576200085a62002920565b146200095d576001600882015462010000900460ff16600281111562000884576200088462002920565b03620008f657600381015460405163567619c560e11b815283151560048201526001600160a01b0390911690819063acec338a90602401600060405180830381600087803b158015620008d657600080fd5b505af1158015620008eb573d6000803e3d6000fd5b50505050506200095d565b600381015460405163567619c560e11b815283151560048201526001600160a01b0390911690819063acec338a90602401600060405180830381600087803b1580156200094257600080fd5b505af115801562000957573d6000803e3d6000fd5b50505050505b827f73c9860341fcf3a75820bf92ceafc9c352f5590f6693cd99123378b454372b7d8360405162000992911515815260200190565b60405180910390a2505050565b620009a96200235e565b620009b48262002407565b620009c0828262002411565b5050565b6000620009d0620024dd565b506000805160206200552a83398151915290565b600354811062000a085760405162461bcd60e51b8152600401620006dc9062002d7a565b60008181526020819052604090206002600882015462010000900460ff16600281111562000a3a5762000a3a62002920565b1462000a5a5760405162461bcd60e51b8152600401620006dc9062002daa565b60028101546001600160a01b0316331462000a895760405162461bcd60e51b8152600401620006dc9062002de1565b60038101546040805163ac30777360e01b815290516001600160a01b0390921691829163ac30777391600480830192600092919082900301818387803b15801562000ad357600080fd5b505af115801562000ae8573d6000803e3d6000fd5b5050505060088201805460ff19169055600582015460405190815283907f5ae12fb120f50967718dd9647cd2cf2c994c869ad44f4e3d05cc5e675b93c3569060200162000992565b62000b3a62002527565b62000b4660006200255d565b565b6001600160a01b03821662000ba05760405162461bcd60e51b815260206004820152601d60248201527f496e76616c69642070726f6a656374206f776e657220616464726573730000006044820152606401620006dc565b6001600160a01b03811662000bf85760405162461bcd60e51b815260206004820152601c60248201527f496e76616c6964204e465420636f6e74726163742061646472657373000000006044820152606401620006dc565b6001600160a01b03811660009081526002602052604090205460ff161562000c6e5760405162461bcd60e51b815260206004820152602260248201527f4e465420636f6e747261637420616c72656164792068617320612070726f6a6560448201526118dd60f21b6064820152608401620006dc565b6001600160a01b038116600090815260026020526040808220805460ff1916600117905551849084908490309062000ca69062002896565b62000cb5949392919062002e09565b604051809103906000f08015801562000cd2573d6000803e3d6000fd5b50905060006003549050604051806101600160405280604051806020016040528060008152508152602001868152602001856001600160a01b03168152602001836001600160a01b03168152602001846001600160a01b031681526020016000815260200160008152602001600081526020016001151581526020016000151581526020016001600281111562000d6d5762000d6d62002920565b905260008281526020819052604090208151819062000d8d908262002e93565b506020820151600182019062000da4908262002e93565b506040820151600282810180546001600160a01b03199081166001600160a01b039485161790915560608501516003850180548316918516919091179055608085015160048501805490921693169290921790915560a0830151600583015560c0830151600683015560e083015160078301556101008084015160088401805461012087015161ffff1990911692151561ff00191692909217911515909202178082556101408501519262ff000019909116906201000090849081111562000e705762000e7062002920565b021790555050600380549150600062000e898362002f76565b9190505550836001600160a01b0316817fad2affd458da4c47ec915e7c69a188631855c8c8863015c36e574a14ff23a59b84600160405162000ecd92919062002f92565b60405180910390a35050505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b600083511162000f5d5760405162461bcd60e51b815260206004820152601c60248201527f50726f6a656374206e616d652063616e6e6f7420626520656d707479000000006044820152606401620006dc565b6001600160a01b03811662000fb55760405162461bcd60e51b815260206004820152601d60248201527f496e76616c69642070726f6a656374206f776e657220616464726573730000006044820152606401620006dc565b60008360405160200162000fca919062002fbf565b60408051601f1981840301815291815281516020928301206000818152600190935291205490915060ff1615620010445760405162461bcd60e51b815260206004820152601b60248201527f50726f6a656374206e616d6520616c72656164792065786973747300000000006044820152606401620006dc565b6000818152600160208181526040808420805460ff1916841790556003548151610160810183528981528084018990526001600160a01b03881681840152606081018690526080810186905260a0810186905260c0810186905260e08101869052610100810194909452610120840185905261014084018590528085529184905290922081518190620010d8908262002e93565b5060208201516001820190620010ef908262002e93565b506040820151600282810180546001600160a01b03199081166001600160a01b039485161790915560608501516003850180548316918516919091179055608085015160048501805490921693169290921790915560a0830151600583015560c0830151600683015560e083015160078301556101008084015160088401805461012087015161ffff1990911692151561ff00191692909217911515909202178082556101408501519262ff0000199091169062010000908490811115620011bb57620011bb62002920565b0217905550506003805491506000620011d48362002f76565b9190505550826001600160a01b0316817fad2affd458da4c47ec915e7c69a188631855c8c8863015c36e574a14ff23a59b8760008060405162000ecd9392919062002fdd565b6200122462002527565b6103e8811115620012785760405162461bcd60e51b815260206004820152601a60248201527f46656520726174652063616e6e6f7420657863656564203130250000000000006044820152606401620006dc565b60048190556040518181527f72b05fd7e6e407beabebd17ae121166880efdc19a2a9b08063eafc0c001e470a9060200160405180910390a150565b6000835111620013065760405162461bcd60e51b815260206004820152601d60248201527f43616d706169676e206e616d652063616e6e6f7420626520656d7074790000006044820152606401620006dc565b60008111620013645760405162461bcd60e51b815260206004820152602360248201527f46756e64696e6720676f616c206d75737420626520677265617465722074686160448201526206e20360ec1b6064820152608401620006dc565b60008360405160200162001379919062002fbf565b60408051601f1981840301815291815281516020928301206000818152600190935291205490915060ff1615620013f35760405162461bcd60e51b815260206004820152601c60248201527f43616d706169676e206e616d6520616c726561647920657869737473000000006044820152606401620006dc565b6000818152600160208190526040808320805460ff191690921790915551859085908590339030906200142690620028a4565b620014369594939291906200301a565b604051809103906000f08015801562001453573d6000803e3d6000fd5b50905060006003549050604051806101600160405280878152602001868152602001336001600160a01b03168152602001836001600160a01b0316815260200160006001600160a01b03168152602001600081526020018581526020014262278d00620014c191906200306b565b8152600160208201526000604082015260600160029052600082815260208190526040902081518190620014f6908262002e93565b50602082015160018201906200150d908262002e93565b506040820151600282810180546001600160a01b03199081166001600160a01b039485161790915560608501516003850180548316918516919091179055608085015160048501805490921693169290921790915560a0830151600583015560c0830151600683015560e083015160078301556101008084015160088401805461012087015161ffff1990911692151561ff00191692909217911515909202178082556101408501519262ff0000199091169062010000908490811115620015d957620015d962002920565b0217905550506003805491506000620015f28362002f76565b9190505550336001600160a01b0316817fad2affd458da4c47ec915e7c69a188631855c8c8863015c36e574a14ff23a59b88856002604051620016389392919062002fdd565b60405180910390a3505050505050565b60035482106200166c5760405162461bcd60e51b8152600401620006dc9062002d7a565b60008281526020819052604090206002600882015462010000900460ff1660028111156200169e576200169e62002920565b14620016be5760405162461bcd60e51b8152600401620006dc9062002daa565b60028101546001600160a01b03163314620016ed5760405162461bcd60e51b8152600401620006dc9062002de1565b600381015460405163416a4a3b60e11b8152600481018490526001600160a01b039091169081906382d4947690602401600060405180830381600087803b1580156200173857600080fd5b505af11580156200174d573d6000803e3d6000fd5b505050506006820183905560405183815284907fe25725250b6d468fb62d50608eb0b36810bb3601dcd9e33e7c024041a13567c09060200160405180910390a250505050565b6200179d62002527565b620017a7620025ce565b4780620017ed5760405162461bcd60e51b81526020600482015260136024820152724e6f206665657320746f20776974686472617760681b6044820152606401620006dc565b6000620017f962000edc565b6001600160a01b03168260405160006040518083038185875af1925050503d806000811462001845576040519150601f19603f3d011682016040523d82523d6000602084013e6200184a565b606091505b5050905080620018955760405162461bcd60e51b8152602060048201526015602482015274119959481dda5d1a191c985dd85b0819985a5b1959605a1b6044820152606401620006dc565b6040518281527f9800e6f57aeb4360eaa72295a820a4293e1e66fbfcabcd8874ae141304a76deb9060200160405180910390a1505062000b4660016000805160206200554a83398151915255565b60006003548310620019095760405162461bcd60e51b8152600401620006dc9062002d7a565b60008381526020819052604090206002600882015462010000900460ff1660028111156200193b576200193b62002920565b146200195b5760405162461bcd60e51b8152600401620006dc9062002daa565b6003810154604051631479197f60e01b81526001600160a01b038581166004830152909116908190631479197f90602401602060405180830381865afa158015620019aa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620019d0919062003081565b925050505b92915050565b620019e562002527565b600354811062001a095760405162461bcd60e51b8152600401620006dc9062002d7a565b600081815260208190526040808220600801805461ff0019166101001790555182917f2fe72be8f4566f35545876185d6cc546d49e5b96e94813ba058f82a4d4b8162391a250565b6000806000806000806000600354881062001a805760405162461bcd60e51b8152600401620006dc9062002d7a565b60008881526020819052604090206002600882015462010000900460ff16600281111562001ab25762001ab262002920565b1462001ad25760405162461bcd60e51b8152600401620006dc9062002daa565b6003810154604080516302734eab60e51b815290516001600160a01b03909216918291634e69d5609160048083019260e09291908290030181865afa15801562001b20573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001b4691906200309b565b98509850985098509850985098505050919395979092949650565b60608060008060008060008060008060006003548c1062001b965760405162461bcd60e51b8152600401620006dc9062002d7a565b60008c815260208190526040902060028101546003820154600483015460058401546006850154600786015460088701548754889760018901976001600160a01b03918216979082169691169490939092909160ff80831692610100810482169262010000909104909116908b9062001c0f9062002d3e565b80601f016020809104026020016040519081016040528092919081815260200182805462001c3d9062002d3e565b801562001c8e5780601f1062001c625761010080835404028352916020019162001c8e565b820191906000526020600020905b81548152906001019060200180831162001c7057829003601f168201915b50505050509a5089805462001ca39062002d3e565b80601f016020809104026020016040519081016040528092919081815260200182805462001cd19062002d3e565b801562001d225780601f1062001cf65761010080835404028352916020019162001d22565b820191906000526020600020905b81548152906001019060200180831162001d0457829003601f168201915b505050505099509b509b509b509b509b509b509b509b509b509b509b505091939597999b90929496989a50565b62001d59620025ce565b600354811062001d7d5760405162461bcd60e51b8152600401620006dc9062002d7a565b60008181526020819052604090206008015460ff1662001dd85760405162461bcd60e51b815260206004820152601560248201527450726f6a656374206973206e6f742061637469766560581b6044820152606401620006dc565b6000341162001e395760405162461bcd60e51b815260206004820152602660248201527f446f6e6174696f6e20616d6f756e74206d75737420626520677265617465722060448201526507468616e20360d41b6064820152608401620006dc565b60008181526020819052604090206002600882015462010000900460ff16600281111562001e6b5762001e6b62002920565b0362001ec6578060070154421062001ec65760405162461bcd60e51b815260206004820152601f60248201527f43726f776466756e64696e672063616d706169676e2068617320656e646564006044820152606401620006dc565b60006127106004543462001edb919062003122565b62001ee791906200313c565b9050600062001ef782346200315f565b90506000600884015462010000900460ff16600281111562001f1d5762001f1d62002920565b0362001fdd5760028301546040516000916001600160a01b03169083908381818185875af1925050503d806000811462001f74576040519150601f19603f3d011682016040523d82523d6000602084013e62001f79565b606091505b505090508062001fd65760405162461bcd60e51b815260206004820152602160248201527f506572736f6e616c20646f6e6174696f6e207472616e73666572206661696c656044820152601960fa1b6064820152608401620006dc565b5062002122565b60606001600885015462010000900460ff16600281111562002003576200200362002920565b036200203957506040805160048152602481019091526020810180516001600160e01b03166345d3292b60e01b17905262002064565b506040805160048152602481019091526020810180516001600160e01b03166345d3292b60e01b1790525b60038401546040516000916001600160a01b03169084906200208890859062002fbf565b60006040518083038185875af1925050503d8060008114620020c7576040519150601f19603f3d011682016040523d82523d6000602084013e620020cc565b606091505b50509050806200211f5760405162461bcd60e51b815260206004820181905260248201527f50726f6a65637420646f6e6174696f6e207472616e73666572206661696c65646044820152606401620006dc565b50505b808360050160008282546200213891906200306b565b9091555050604051818152339085907f0b5b4c52969ff7329ecf7ee536409fda87812b15a8622bc6e8cdeab3aee14a269060200160405180910390a35050506200219060016000805160206200554a83398151915255565b50565b6200219d62002527565b6001600160a01b038116620021c957604051631e4fbdf760e01b815260006004820152602401620006dc565b62002190816200255d565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156200221b5750825b905060008267ffffffffffffffff166001148015620022395750303b155b90508115801562002248575080155b15620022675760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156200229257845460ff60401b1916600160401b1785555b6103e8861115620022e65760405162461bcd60e51b815260206004820152601a60248201527f46656520726174652063616e6e6f7420657863656564203130250000000000006044820152606401620006dc565b620022f1336200261d565b620022fb62002632565b6200230562002646565b6004869055600060035583156200235657845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b306001600160a01b037f0000000000000000000000006cfcdd830ce5337b0913c28ee7235dc623be8eea161480620023e857507f0000000000000000000000006cfcdd830ce5337b0913c28ee7235dc623be8eea6001600160a01b0316620023dc6000805160206200552a833981519152546001600160a01b031690565b6001600160a01b031614155b1562000b465760405163703e46dd60e11b815260040160405180910390fd5b6200219062002527565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156200246e575060408051601f3d908101601f191682019092526200246b9181019062003081565b60015b6200249857604051634c9c8ce360e01b81526001600160a01b0383166004820152602401620006dc565b6000805160206200552a8339815191528114620024cc57604051632a87526960e21b815260048101829052602401620006dc565b620024d8838362002650565b505050565b306001600160a01b037f0000000000000000000000006cfcdd830ce5337b0913c28ee7235dc623be8eea161462000b465760405163703e46dd60e11b815260040160405180910390fd5b336200253262000edc565b6001600160a01b03161462000b465760405163118cdaa760e01b8152336004820152602401620006dc565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b6000805160206200554a8339815191528054600119016200260257604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b60016000805160206200554a83398151915255565b62002627620026ad565b6200219081620026f7565b6200263c620026ad565b62000b4662002701565b62000b46620026ad565b6200265b826200270b565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115620026a357620024d8828262002773565b620009c0620027e6565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1662000b4657604051631afcd79f60e31b815260040160405180910390fd5b6200219d620026ad565b62002608620026ad565b806001600160a01b03163b6000036200274357604051634c9c8ce360e01b81526001600160a01b0382166004820152602401620006dc565b6000805160206200552a83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b03168460405162002792919062002fbf565b600060405180830381855af49150503d8060008114620027cf576040519150601f19603f3d011682016040523d82523d6000602084013e620027d4565b606091505b5091509150620019d085838362002806565b341562000b465760405163b398979f60e01b815260040160405180910390fd5b6060826200281f5762002819826200286c565b62002865565b81511580156200283757506001600160a01b0384163b155b156200286257604051639996b31560e01b81526001600160a01b0385166004820152602401620006dc565b50805b9392505050565b8051156200287d5780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b610bcf806200317683390190565b6117e58062003d4583390190565b600060208284031215620028c557600080fd5b5035919050565b60005b83811015620028e9578181015183820152602001620028cf565b50506000910152565b600081518084526200290c816020860160208601620028cc565b601f01601f19169290920160200192915050565b634e487b7160e01b600052602160045260246000fd5b600381106200295557634e487b7160e01b600052602160045260246000fd5b9052565b60006101608083526200296f8184018f620028f2565b9050828103602084015262002985818e620028f2565b6001600160a01b038d811660408601528c811660608601528b16608085015260a084018a905260c0840189905260e084018890528615156101008501528515156101208501529150620029df905061014083018462002936565b9c9b505050505050505050505050565b80151581146200219057600080fd5b6000806040838503121562002a1257600080fd5b82359150602083013562002a2681620029ef565b809150509250929050565b6001600160a01b03811681146200219057600080fd5b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff8084111562002a7b5762002a7b62002a47565b604051601f8501601f19908116603f0116810190828211818310171562002aa65762002aa662002a47565b8160405280935085815286868601111562002ac057600080fd5b858560208301376000602087830101525050509392505050565b6000806040838503121562002aee57600080fd5b823562002afb8162002a31565b9150602083013567ffffffffffffffff81111562002b1857600080fd5b8301601f8101851362002b2a57600080fd5b62002b3b8582356020840162002a5d565b9150509250929050565b600082601f83011262002b5757600080fd5b620028658383356020850162002a5d565b60008060006060848603121562002b7e57600080fd5b833567ffffffffffffffff81111562002b9657600080fd5b62002ba48682870162002b45565b935050602084013562002bb78162002a31565b9150604084013562002bc98162002a31565b809150509250925092565b60008060006060848603121562002bea57600080fd5b833567ffffffffffffffff8082111562002c0357600080fd5b62002c118783880162002b45565b9450602086013591508082111562002c2857600080fd5b5062002c378682870162002b45565b925050604084013562002bc98162002a31565b602081526000620028656020830184620028f2565b60008060006060848603121562002c7557600080fd5b833567ffffffffffffffff8082111562002c8e57600080fd5b62002c9c8783880162002b45565b9450602086013591508082111562002cb357600080fd5b5062002cc28682870162002b45565b925050604084013590509250925092565b6000806040838503121562002ce757600080fd5b50508035926020909101359150565b6000806040838503121562002d0a57600080fd5b82359150602083013562002a268162002a31565b60006020828403121562002d3157600080fd5b8135620028658162002a31565b600181811c9082168062002d5357607f821691505b60208210810362002d7457634e487b7160e01b600052602260045260246000fd5b50919050565b602080825260169082015275141c9bda9958dd08191bd95cc81b9bdd08195e1a5cdd60521b604082015260600190565b6020808252601a908201527f4e6f7420612063726f776466756e64696e672070726f6a656374000000000000604082015260600190565b6020808252600e908201526d139bdd08185d5d1a1bdc9a5e995960921b604082015260600190565b60808152600062002e1e6080830187620028f2565b6001600160a01b0395861660208401529385166040830152509216606090920191909152919050565b601f821115620024d8576000816000526020600020601f850160051c8101602086101562002e725750805b601f850160051c820191505b81811015620023565782815560010162002e7e565b815167ffffffffffffffff81111562002eb05762002eb062002a47565b62002ec88162002ec1845462002d3e565b8462002e47565b602080601f83116001811462002f00576000841562002ee75750858301515b600019600386901b1c1916600185901b17855562002356565b600085815260208120601f198616915b8281101562002f315788860151825594840194600190910190840162002f10565b508582101562002f505787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601160045260246000fd5b60006001820162002f8b5762002f8b62002f60565b5060010190565b60608082526000908201526001600160a01b03831660208201526080810162002865604083018462002936565b6000825162002fd3818460208701620028cc565b9190910192915050565b60608152600062002ff26060830186620028f2565b6001600160a01b0385166020840152905062003012604083018462002936565b949350505050565b60a0815260006200302f60a0830188620028f2565b8281036020840152620030438188620028f2565b604084019690965250506001600160a01b039283166060820152911660809091015292915050565b80820180821115620019d557620019d562002f60565b6000602082840312156200309457600080fd5b5051919050565b600080600080600080600060e0888a031215620030b757600080fd5b8751965060208801519550604088015194506060880151620030d981620029ef565b6080890151909450620030ec81620029ef565b60a0890151909350620030ff81620029ef565b60c08901519092506200311281620029ef565b8091505092959891949750929550565b8082028115828204841417620019d557620019d562002f60565b6000826200315a57634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115620019d557620019d562002f6056fe60806040523480156200001157600080fd5b5060405162000bcf38038062000bcf833981016040819052620000349162000147565b826001600160a01b0381166200006457604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200006f81620000c4565b5060016200007e8582620002e5565b50600280546001600160a01b039384166001600160a01b03199091161790556004805491909216610100026001600160a81b031990911617600117905550620003b19050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b03811681146200014257600080fd5b919050565b600080600080608085870312156200015e57600080fd5b84516001600160401b03808211156200017657600080fd5b818701915087601f8301126200018b57600080fd5b815181811115620001a057620001a062000114565b604051601f8201601f19908116603f01168101908382118183101715620001cb57620001cb62000114565b81604052828152602093508a84848701011115620001e857600080fd5b600091505b828210156200020c5784820184015181830185015290830190620001ed565b6000848483010152809850505050620002278188016200012a565b9450505062000239604086016200012a565b915062000249606086016200012a565b905092959194509250565b600181811c908216806200026957607f821691505b6020821081036200028a57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620002e0576000816000526020600020601f850160051c81016020861015620002bb5750805b601f850160051c820191505b81811015620002dc57828155600101620002c7565b5050505b505050565b81516001600160401b0381111562000301576200030162000114565b620003198162000312845462000254565b8462000290565b602080601f831160018114620003515760008415620003385750858301515b600019600386901b1c1916600185901b178555620002dc565b600085815260208120601f198616915b82811015620003825788860151825594840194600190910190840162000361565b5085821015620003a15787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b61080e80620003c16000396000f3fe6080604052600436106100955760003560e01c8063aae282e111610059578063aae282e114610271578063acec338a14610291578063dbe55e56146102b1578063de2ed893146102d6578063f2fde38b146102fa57600080fd5b806322f3e2d4146101cf57806345d3292b146101fe578063715018a6146102085780637284e4161461021d5780638da5cb5b1461023f57600080fd5b366101ca5760045460ff166100e95760405162461bcd60e51b815260206004820152601560248201527450726f6a656374206973206e6f742061637469766560581b60448201526064015b60405180910390fd5b600034116101095760405162461bcd60e51b81526004016100e09061064f565b6002546040516000916001600160a01b03169034908381818185875af1925050503d8060008114610156576040519150601f19603f3d011682016040523d82523d6000602084013e61015b565b606091505b505090508061017c5760405162461bcd60e51b81526004016100e090610695565b346003600082825461018e91906106d6565b909155505060405134815232907f264f630d9efa0d07053a31163641d9fcc0adafc9d9e76f1c37c2ce3a558d2c529060200160405180910390a2005b600080fd5b3480156101db57600080fd5b506004546101e99060ff1681565b60405190151581526020015b60405180910390f35b61020661031a565b005b34801561021457600080fd5b50610206610446565b34801561022957600080fd5b5061023261045a565b6040516101f591906106fd565b34801561024b57600080fd5b506000546001600160a01b03165b6040516001600160a01b0390911681526020016101f5565b34801561027d57600080fd5b50600254610259906001600160a01b031681565b34801561029d57600080fd5b506102066102ac36600461074c565b6104e8565b3480156102bd57600080fd5b506004546102599061010090046001600160a01b031681565b3480156102e257600080fd5b506102ec60035481565b6040519081526020016101f5565b34801561030657600080fd5b50610206610315366004610775565b610594565b60045460ff166103645760405162461bcd60e51b815260206004820152601560248201527450726f6a656374206973206e6f742061637469766560581b60448201526064016100e0565b600034116103845760405162461bcd60e51b81526004016100e09061064f565b6002546040516000916001600160a01b03169034908381818185875af1925050503d80600081146103d1576040519150601f19603f3d011682016040523d82523d6000602084013e6103d6565b606091505b50509050806103f75760405162461bcd60e51b81526004016100e090610695565b346003600082825461040991906106d6565b909155505060405134815232907f264f630d9efa0d07053a31163641d9fcc0adafc9d9e76f1c37c2ce3a558d2c529060200160405180910390a250565b61044e6105d2565b61045860006105ff565b565b600180546104679061079e565b80601f01602080910402602001604051908101604052809291908181526020018280546104939061079e565b80156104e05780601f106104b5576101008083540402835291602001916104e0565b820191906000526020600020905b8154815290600101906020018083116104c357829003601f168201915b505050505081565b6000546001600160a01b0316331480610510575060045461010090046001600160a01b031633145b61054d5760405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b60448201526064016100e0565b6004805460ff19168215159081179091556040519081527f4dcbe1841ee9bd9c888e46c0b35574429b1c0f1071806180028dee2f9a1064309060200160405180910390a150565b61059c6105d2565b6001600160a01b0381166105c657604051631e4fbdf760e01b8152600060048201526024016100e0565b6105cf816105ff565b50565b6000546001600160a01b031633146104585760405163118cdaa760e01b81523360048201526024016100e0565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60208082526026908201527f446f6e6174696f6e20616d6f756e74206d75737420626520677265617465722060408201526507468616e20360d41b606082015260800190565b60208082526021908201527f466f7277617264696e6720746f204e465420636f6e7472616374206661696c656040820152601960fa1b606082015260800190565b808201808211156106f757634e487b7160e01b600052601160045260246000fd5b92915050565b60006020808352835180602085015260005b8181101561072b5785810183015185820160400152820161070f565b506000604082860101526040601f19601f8301168501019250505092915050565b60006020828403121561075e57600080fd5b8135801515811461076e57600080fd5b9392505050565b60006020828403121561078757600080fd5b81356001600160a01b038116811461076e57600080fd5b600181811c908216806107b257607f821691505b6020821081036107d257634e487b7160e01b600052602260045260246000fd5b5091905056fea2646970667358221220af1f36404a7641e33a0114723f662c150d75a4e182ec84acb75a4e04e64f04e464736f6c6343000816003360806040523480156200001157600080fd5b50604051620017e5380380620017e5833981016040819052620000349162000217565b816001600160a01b0381166200006457604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200006f81620000e2565b5060018055600262000082868262000341565b50600362000091858262000341565b5060048390556005839055620000ab4262278d006200040d565b600655600880546001600160a01b0390921662010000026001600160b01b0319909216919091176001179055506200043592505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200015a57600080fd5b81516001600160401b038082111562000177576200017762000132565b604051601f8301601f19908116603f01168101908282118183101715620001a257620001a262000132565b8160405283815260209250866020858801011115620001c057600080fd5b600091505b83821015620001e45785820183015181830184015290820190620001c5565b6000602085830101528094505050505092915050565b80516001600160a01b03811681146200021257600080fd5b919050565b600080600080600060a086880312156200023057600080fd5b85516001600160401b03808211156200024857600080fd5b6200025689838a0162000148565b965060208801519150808211156200026d57600080fd5b506200027c8882890162000148565b945050604086015192506200029460608701620001fa565b9150620002a460808701620001fa565b90509295509295909350565b600181811c90821680620002c557607f821691505b602082108103620002e657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200033c576000816000526020600020601f850160051c81016020861015620003175750805b601f850160051c820191505b81811015620003385782815560010162000323565b5050505b505050565b81516001600160401b038111156200035d576200035d62000132565b62000375816200036e8454620002b0565b84620002ec565b602080601f831160018114620003ad5760008415620003945750858301515b600019600386901b1c1916600185901b17855562000338565b600085815260208120601f198616915b82811015620003de57888601518255948401946001909101908401620003bd565b5085821015620003fd5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b808201808211156200042f57634e487b7160e01b600052601160045260246000fd5b92915050565b6113a080620004456000396000f3fe6080604052600436106101395760003560e01c806382d49476116100ab578063c5c4744c1161006f578063c5c4744c14610497578063c9250d91146104ad578063cc6cb19a146104c3578063dbe55e56146104f0578063df83307314610516578063f2fde38b1461052b57600080fd5b806382d494761461040f5780638da5cb5b1461042f578063ac3077731461044d578063acec338a14610462578063b2d5ae441461048257600080fd5b80634abfa163116100fd5780634abfa163146103155780634e69d5601461034d57806357c9ca14146103b0578063715018a6146103cf5780637284e416146103e45780637a3a0e84146103f957600080fd5b806306fdde031461025c5780631479197f1461028757806322f3e2d4146102cb57806329dcb0cf146102f557806345d3292b1461030b57600080fd5b366102575760085460ff166101695760405162461bcd60e51b815260040161016090611145565b60405180910390fd5b600654421061018a5760405162461bcd60e51b815260040161016090611175565b3260009081526009602052604081205490036101e357600a80546001810182556000919091527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a80180546001600160a01b031916321790555b32600090815260096020526040812080543492906102029084906111b7565b92505081905550346007600082825461021b91906111b7565b909155505060405134815232907f264f630d9efa0d07053a31163641d9fcc0adafc9d9e76f1c37c2ce3a558d2c529060200160405180910390a2005b600080fd5b34801561026857600080fd5b5061027161054b565b60405161027e91906111d0565b60405180910390f35b34801561029357600080fd5b506102bd6102a236600461121f565b6001600160a01b031660009081526009602052604090205490565b60405190815260200161027e565b3480156102d757600080fd5b506008546102e59060ff1681565b604051901515815260200161027e565b34801561030157600080fd5b506102bd60065481565b6103136105d9565b005b34801561032157600080fd5b5061033561033036600461124f565b610759565b6040516001600160a01b03909116815260200161027e565b34801561035957600080fd5b50600454600754600654600854604080518581526020810185905290810183905260ff8083161515606083015261010090920490911615156080820152929091101560a083015242101560c082015260e00161027e565b3480156103bc57600080fd5b506008546102e590610100900460ff1681565b3480156103db57600080fd5b50610313610783565b3480156103f057600080fd5b50610271610795565b34801561040557600080fd5b506102bd60045481565b34801561041b57600080fd5b5061031361042a36600461124f565b6107a2565b34801561043b57600080fd5b506000546001600160a01b0316610335565b34801561045957600080fd5b50610313610969565b34801561046e57600080fd5b5061031361047d366004611268565b610bfc565b34801561048e57600080fd5b50610313610cb0565b3480156104a357600080fd5b506102bd60075481565b3480156104b957600080fd5b506102bd60055481565b3480156104cf57600080fd5b506102bd6104de36600461121f565b60096020526000908152604090205481565b3480156104fc57600080fd5b50600854610335906201000090046001600160a01b031681565b34801561052257600080fd5b50610313610eaf565b34801561053757600080fd5b5061031361054636600461121f565b611063565b600280546105589061128a565b80601f01602080910402602001604051908101604052809291908181526020018280546105849061128a565b80156105d15780601f106105a6576101008083540402835291602001916105d1565b820191906000526020600020905b8154815290600101906020018083116105b457829003601f168201915b505050505081565b6105e161109e565b60085460ff166106035760405162461bcd60e51b815260040161016090611145565b60065442106106245760405162461bcd60e51b815260040161016090611175565b600034116106835760405162461bcd60e51b815260206004820152602660248201527f446f6e6174696f6e20616d6f756e74206d75737420626520677265617465722060448201526507468616e20360d41b6064820152608401610160565b3260009081526009602052604081205490036106dc57600a80546001810182556000919091527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a80180546001600160a01b031916321790555b32600090815260096020526040812080543492906106fb9084906111b7565b92505081905550346007600082825461071491906111b7565b909155505060405134815232907f264f630d9efa0d07053a31163641d9fcc0adafc9d9e76f1c37c2ce3a558d2c529060200160405180910390a261075760018055565b565b600a818154811061076957600080fd5b6000918252602090912001546001600160a01b0316905081565b61078b6110c8565b61075760006110f5565b600380546105589061128a565b6107aa61109e565b6000546001600160a01b03163314806107d357506008546201000090046001600160a01b031633145b6107ef5760405162461bcd60e51b8152600401610160906112c4565b60085460ff166108115760405162461bcd60e51b815260040161016090611145565b60065442106108325760405162461bcd60e51b815260040161016090611175565b60045481106108945760405162461bcd60e51b815260206004820152602860248201527f4e657720676f616c206d757374206265206c6f776572207468616e2063757272604482015267195b9d0819dbd85b60c21b6064820152608401610160565b60006064600554604b6108a791906112ec565b6108b19190611303565b90508082101561091a5760405162461bcd60e51b815260206004820152602e60248201527f43616e6e6f7420726564756365206279206d6f7265207468616e20323525206f60448201526d19881a5b9a5d1a585b0819dbd85b60921b6064820152608401610160565b600480549083905560408051828152602081018590527fb0849b0fc070e9c3b7b393322de992eebc64ffb9feaaf17e888555075d008f36910160405180910390a1505061096660018055565b50565b61097161109e565b6000546001600160a01b031633148061099a57506008546201000090046001600160a01b031633145b6109b65760405162461bcd60e51b8152600401610160906112c4565b600854610100900460ff16156109de5760405162461bcd60e51b815260040161016090611325565b6004546007541015806109f357506006544210155b610a5b5760405162461bcd60e51b815260206004820152603360248201527f43616e6e6f7420636c61696d206265666f726520646561646c696e6520756e6c604482015272195cdcc819dbd85b081a5cc81c995858da1959606a1b6064820152608401610160565b6004546007541015610aaf5760405162461bcd60e51b815260206004820152601860248201527f46756e64696e6720676f616c206e6f74207265616368656400000000000000006044820152606401610160565b4780610af15760405162461bcd60e51b81526020600482015260116024820152704e6f2066756e647320746f20636c61696d60781b6044820152606401610160565b6008805461ffff19166101001790556000610b146000546001600160a01b031690565b6001600160a01b03168260405160006040518083038185875af1925050503d8060008114610b5e576040519150601f19603f3d011682016040523d82523d6000602084013e610b63565b606091505b5050905080610ba35760405162461bcd60e51b815260206004820152600c60248201526b10db185a5b4819985a5b195960a21b6044820152606401610160565b6000546001600160a01b03166001600160a01b03167fa65a8b4f7f65a1063243d7f7e9e4da00ff767599acf21549ef2548a45d1695ae83604051610be991815260200190565b60405180910390a2505061075760018055565b6000546001600160a01b0316331480610c2557506008546201000090046001600160a01b031633145b610c415760405162461bcd60e51b8152600401610160906112c4565b600854610100900460ff1615610c695760405162461bcd60e51b815260040161016090611325565b6008805460ff19168215159081179091556040519081527f4dcbe1841ee9bd9c888e46c0b35574429b1c0f1071806180028dee2f9a1064309060200160405180910390a150565b610cb861109e565b600654421015610d0a5760405162461bcd60e51b815260206004820152601a60248201527f43616d706169676e207374696c6c20696e2070726f67726573730000000000006044820152606401610160565b60045460075410610d695760405162461bcd60e51b8152602060048201526024808201527f46756e64696e6720676f616c2077617320726561636865642c206e6f20726566604482015263756e647360e01b6064820152608401610160565b600854610100900460ff1615610d915760405162461bcd60e51b815260040161016090611325565b3360009081526009602052604090205480610de65760405162461bcd60e51b8152602060048201526015602482015274139bc8191bdb985d1a5bdb881d1bc81c99599d5b99605a1b6044820152606401610160565b336000818152600960205260408082208290555190919083908381818185875af1925050503d8060008114610e37576040519150601f19603f3d011682016040523d82523d6000602084013e610e3c565b606091505b5050905080610e7d5760405162461bcd60e51b815260206004820152600d60248201526c1499599d5b990819985a5b1959609a1b6044820152606401610160565b60405182815233907fa171b6942063c6f2800ce40a780edce37baa2b618571b11eedd1e69e626e7d7690602001610be9565b610eb761109e565b6000546001600160a01b0316331480610ee057506008546201000090046001600160a01b031633145b610efc5760405162461bcd60e51b8152600401610160906112c4565b60085460ff16610f1e5760405162461bcd60e51b815260040161016090611145565b600854610100900460ff1615610f465760405162461bcd60e51b815260040161016090611325565b6008805460ff1916905560005b600a54811015611059576000600a8281548110610f7257610f72611354565b60009182526020808320909101546001600160a01b03168083526009909152604090912054909150801561104f576001600160a01b0382166000818152600960205260408082208290555190919083908381818185875af1925050503d8060008114610ffa576040519150601f19603f3d011682016040523d82523d6000602084013e610fff565b606091505b50509050801561104d57826001600160a01b03167fa171b6942063c6f2800ce40a780edce37baa2b618571b11eedd1e69e626e7d768360405161104491815260200190565b60405180910390a25b505b5050600101610f53565b5061075760018055565b61106b6110c8565b6001600160a01b03811661109557604051631e4fbdf760e01b815260006004820152602401610160565b610966816110f5565b6002600154036110c157604051633ee5aeb560e01b815260040160405180910390fd5b6002600155565b6000546001600160a01b031633146107575760405163118cdaa760e01b8152336004820152602401610160565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60208082526016908201527543616d706169676e206973206e6f742061637469766560501b604082015260600190565b60208082526012908201527110d85b5c185a59db881a185cc8195b99195960721b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b808201808211156111ca576111ca6111a1565b92915050565b60006020808352835180602085015260005b818110156111fe578581018301518582016040015282016111e2565b506000604082860101526040601f19601f8301168501019250505092915050565b60006020828403121561123157600080fd5b81356001600160a01b038116811461124857600080fd5b9392505050565b60006020828403121561126157600080fd5b5035919050565b60006020828403121561127a57600080fd5b8135801515811461124857600080fd5b600181811c9082168061129e57607f821691505b6020821081036112be57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600e908201526d139bdd08185d5d1a1bdc9a5e995960921b604082015260600190565b80820281158282048414176111ca576111ca6111a1565b60008261132057634e487b7160e01b600052601260045260246000fd5b500490565b602080825260159082015274119d5b991cc8185b1c9958591e4818db185a5b5959605a1b604082015260600190565b634e487b7160e01b600052603260045260246000fdfea264697066735822122013c678477817949248c07bb4b85c522c358680328d105d4a9fae6cffd6bae7ca64736f6c63430008160033360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a26469706673582212207a0b01d41733e1795446df943e6084d74667a9406d2648398e1a7bcfd4a828da64736f6c63430008160033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ 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.