Source Code
Overview
POL Balance
0 POL
More Info
ContractCreator
Multichain Info
N/A
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 Source Code Verified (Exact Match)
Contract Name:
EscrowFactory
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 10 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import '@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol'; import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; import './interfaces/IStaking.sol'; import './Escrow.sol'; contract EscrowFactory is OwnableUpgradeable, UUPSUpgradeable { // all Escrows will have this duration. uint256 constant STANDARD_DURATION = 8640000; string constant ERROR_ZERO_ADDRESS = 'EscrowFactory: Zero Address'; uint256 public counter; mapping(address => uint256) public escrowCounters; address public lastEscrow; address public staking; uint256 public minimumStake; event Launched(address token, address escrow); event LaunchedV2( address token, address escrow, string jobRequesterId ); event SetStakingAddress(address indexed stakingAddress); event SetMinumumStake(uint256 indexed minimumStake); /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize( address _staking, uint256 _minimumStake ) external payable virtual initializer { __Ownable_init_unchained(); require(_staking != address(0), ERROR_ZERO_ADDRESS); _setStakingAddress(_staking); _setMinimumStake(_minimumStake); } /** * @dev Creates a new Escrow contract. * * @param token Token address to be associated with the Escrow contract. * @param trustedHandlers Array of addresses that will serve as the trusted handlers for the Escrow. * @param jobRequesterId String identifier for the job requester, used for tracking purposes. * * @return The address of the newly created Escrow contract. */ function createEscrow( address token, address[] memory trustedHandlers, string memory jobRequesterId ) external returns (address) { uint256 availableStake = IStaking(staking).getAvailableStake( msg.sender ); require( availableStake >= minimumStake, 'Insufficient stake to create an escrow.' ); Escrow escrow = new Escrow( token, msg.sender, payable(msg.sender), STANDARD_DURATION, trustedHandlers ); counter++; escrowCounters[address(escrow)] = counter; lastEscrow = address(escrow); emit LaunchedV2(token, lastEscrow, jobRequesterId); return lastEscrow; } function hasEscrow(address _address) external view returns (bool) { return escrowCounters[_address] != 0; } /** * @dev Set the Staking address. * @param _stakingAddress Staking address */ function setStakingAddress(address _stakingAddress) external onlyOwner { _setStakingAddress(_stakingAddress); } function _setStakingAddress(address _stakingAddress) private { require(_stakingAddress != address(0), ERROR_ZERO_ADDRESS); staking = _stakingAddress; emit SetStakingAddress(_stakingAddress); } /** * @dev Set the minimum stake amount. * @param _minimumStake Minimum stake */ function setMinimumStake(uint256 _minimumStake) external onlyOwner { _setMinimumStake(_minimumStake); } function _setMinimumStake(uint256 _minimumStake) private { require(_minimumStake > 0, 'Must be a positive number'); minimumStake = _minimumStake; emit SetMinumumStake(minimumStake); } function _authorizeUpgrade(address) internal override onlyOwner {} /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[45] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../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. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. 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 { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822ProxiableUpgradeable { /** * @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 v4.9.0) (interfaces/IERC1967.sol) pragma solidity ^0.8.0; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. * * _Available since v4.8.3._ */ interface IERC1967Upgradeable { /** * @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 v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeaconUpgradeable { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeaconUpgradeable.sol"; import "../../interfaces/IERC1967Upgradeable.sol"; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../../utils/AddressUpgradeable.sol"; import "../../utils/StorageSlotUpgradeable.sol"; import {Initializable} from "../utils/Initializable.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ */ abstract contract ERC1967UpgradeUpgradeable is Initializable, IERC1967Upgradeable { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; function __ERC1967Upgrade_init() internal onlyInitializing { } function __ERC1967Upgrade_init_unchained() internal onlyInitializing { } /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { AddressUpgradeable.functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { AddressUpgradeable.functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data); } } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @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 Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _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 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _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() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.0; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../ERC1967/ERC1967UpgradeUpgradeable.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. * * _Available since v4.1._ */ abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment address private immutable __self = address(this); /** * @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 ERC1967) 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 ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { require(address(this) != __self, "Function must be called through delegatecall"); require(_getImplementation() == __self, "Function must be called through active proxy"); _; } /** * @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() { require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall"); _; } function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /** * @dev Implementation of the ERC1822 {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 override notDelegated returns (bytes32) { return _IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeTo(address newImplementation) public virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); } /** * @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, true); } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeTo} and {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal override onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; 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; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.0; /** * @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 ERC1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ * _Available since v4.9 for `string`, `bytes`._ */ library StorageSlotUpgradeable { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 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) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { 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) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { 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) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC20Permit} from "../extensions/IERC20Permit.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev An operation with an ERC20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data); if (returndata.length != 0 && !abi.decode(returndata, (bool))) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert FailedInnerCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.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 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 pragma solidity ^0.8.0; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; import '@openzeppelin/contracts/utils/ReentrancyGuard.sol'; import './interfaces/IEscrow.sol'; contract Escrow is IEscrow, ReentrancyGuard { bytes4 private constant FUNC_SELECTOR_BALANCE_OF = bytes4(keccak256('balanceOf(address)')); string constant ERROR_ZERO_ADDRESS = 'Escrow: zero address'; uint256 private constant BULK_MAX_VALUE = 1e9 * (10 ** 18); uint32 private constant BULK_MAX_COUNT = 100; event TrustedHandlerAdded(address _handler); event IntermediateStorage(string _url, string _hash); event Pending(string manifest, string hash); event PendingV2( string manifest, string hash, address reputationOracle, address recordingOracle, address exchangeOracle ); event BulkTransfer( uint256 indexed _txId, address[] _recipients, uint256[] _amounts, bool _isPartial ); event BulkTransferV2( uint256 indexed _txId, address[] _recipients, uint256[] _amounts, bool _isPartial, string finalResultsUrl ); event Cancelled(); event Completed(); event Fund(uint256 _amount); event Withdraw(address _token, uint256 _amount); EscrowStatuses public override status; address public reputationOracle; address public recordingOracle; address public exchangeOracle; address public launcher; address payable public canceler; address public escrowFactory; uint8 public reputationOracleFeePercentage; uint8 public recordingOracleFeePercentage; uint8 public exchangeOracleFeePercentage; address public token; string public manifestUrl; string public manifestHash; string public intermediateResultsUrl; string public finalResultsUrl; string public finalResultsHash; uint256 public duration; mapping(address => bool) public areTrustedHandlers; uint256 public remainingFunds; constructor( address _token, address _launcher, address payable _canceler, uint256 _duration, address[] memory _handlers ) { require(_token != address(0), ERROR_ZERO_ADDRESS); require(_canceler != address(0), ERROR_ZERO_ADDRESS); token = _token; status = EscrowStatuses.Launched; duration = _duration + block.timestamp; launcher = _launcher; canceler = _canceler; escrowFactory = msg.sender; areTrustedHandlers[_launcher] = true; areTrustedHandlers[_canceler] = true; _addTrustedHandlers(_handlers); } function getBalance() public view returns (uint256) { (bool success, bytes memory returnData) = token.staticcall( abi.encodeWithSelector(FUNC_SELECTOR_BALANCE_OF, address(this)) ); return success ? abi.decode(returnData, (uint256)) : 0; } function getTokenBalance(address _token) public view returns (uint256) { (bool success, bytes memory returnData) = _token.staticcall( abi.encodeWithSelector(FUNC_SELECTOR_BALANCE_OF, address(this)) ); return success ? abi.decode(returnData, (uint256)) : 0; } function addTrustedHandlers( address[] memory _handlers ) public override trusted { _addTrustedHandlers(_handlers); } function _addTrustedHandlers(address[] memory _handlers) internal { for (uint256 i = 0; i < _handlers.length; i++) { require(_handlers[i] != address(0), ERROR_ZERO_ADDRESS); areTrustedHandlers[_handlers[i]] = true; emit TrustedHandlerAdded(_handlers[i]); } } // The escrower puts the Token in the contract without an agentless // and assigsn a reputation oracle to payout the bounty of size of the // amount specified function setup( address _reputationOracle, address _recordingOracle, address _exchangeOracle, uint8 _reputationOracleFeePercentage, uint8 _recordingOracleFeePercentage, uint8 _exchangeOracleFeePercentage, string memory _url, string memory _hash ) external override trusted notExpired { require( _reputationOracle != address(0), 'Invalid reputation oracle address' ); require( _recordingOracle != address(0), 'Invalid recording oracle address' ); require( _exchangeOracle != address(0), 'Invalid exchange oracle address' ); uint256 _totalFeePercentage = _reputationOracleFeePercentage + _recordingOracleFeePercentage + _exchangeOracleFeePercentage; require(_totalFeePercentage <= 100, 'Percentage out of bounds'); require( status == EscrowStatuses.Launched, 'Escrow not in Launched status state' ); reputationOracle = _reputationOracle; recordingOracle = _recordingOracle; exchangeOracle = _exchangeOracle; reputationOracleFeePercentage = _reputationOracleFeePercentage; recordingOracleFeePercentage = _recordingOracleFeePercentage; exchangeOracleFeePercentage = _exchangeOracleFeePercentage; manifestUrl = _url; manifestHash = _hash; status = EscrowStatuses.Pending; remainingFunds = getBalance(); require(remainingFunds > 0, 'Escrow balance is zero'); emit PendingV2( manifestUrl, manifestHash, reputationOracle, recordingOracle, exchangeOracle ); emit Fund(remainingFunds); } function cancel() public override trusted notBroke notComplete nonReentrant returns (bool) { _safeTransfer(token, canceler, remainingFunds); status = EscrowStatuses.Cancelled; remainingFunds = 0; emit Cancelled(); return true; } function withdraw( address _token ) public override trusted nonReentrant returns (bool) { uint256 _amount; if (_token == token) { uint256 _balance = getBalance(); require(_balance > remainingFunds, 'No funds to withdraw'); _amount = _balance - remainingFunds; } else { _amount = getTokenBalance(_token); } _safeTransfer(_token, canceler, _amount); emit Withdraw(_token, _amount); return true; } // For backward compatibility: this function can only be called on existing escrows, // as the "Paid" status is not set anywhere for new escrows. function complete() external override notExpired trustedOrReputationOracle { require(status == EscrowStatuses.Paid, 'Escrow not in Paid state'); status = EscrowStatuses.Complete; emit Completed(); } function storeResults( string memory _url, string memory _hash ) external override trustedOrRecordingOracle notExpired { require( status == EscrowStatuses.Pending || status == EscrowStatuses.Partial, 'Escrow not in Pending or Partial status state' ); require(bytes(_url).length != 0, "URL can't be empty"); require(bytes(_hash).length != 0, "Hash can't be empty"); intermediateResultsUrl = _url; emit IntermediateStorage(_url, _hash); } /** * @dev Performs bulk payout to multiple workers * Escrow needs to be completed / cancelled, so that it can be paid out. * Every recipient is paid with the amount after reputation and recording oracle fees taken out. * If the amount is less than the fee, the recipient is not paid. * If the fee is zero, reputation, and recording oracle are not paid. * Payout will fail if any of the transaction fails. * If the escrow is fully paid out, meaning that the balance of the escrow is 0, it'll set as Paid. * If the escrow is partially paid out, meaning that the escrow still has remaining balance, it'll set as Partial. * This contract is only callable if the contract is not broke, not launched, not paid, not expired, by trusted parties. * * @param _recipients Array of recipients * @param _amounts Array of amounts to be paid to each recipient. * @param _url URL storing results as transaction details * @param _hash Hash of the results * @param _txId Transaction ID * @param forceComplete Boolean parameter indicating if remaining balance should be transferred to the escrow creator */ function bulkPayOut( address[] memory _recipients, uint256[] memory _amounts, string memory _url, string memory _hash, uint256 _txId, bool forceComplete ) public override trustedOrReputationOracle notBroke notLaunched notExpired nonReentrant { require( _recipients.length == _amounts.length, "Amount of recipients and values don't match" ); require(_amounts.length > 0, 'Amounts should not be empty'); require(_recipients.length < BULK_MAX_COUNT, 'Too many recipients'); require( status != EscrowStatuses.Complete && status != EscrowStatuses.Cancelled, 'Invalid status' ); uint256 aggregatedBulkAmount = 0; uint256 cachedRemainingFunds = remainingFunds; for (uint256 i = 0; i < _amounts.length; i++) { uint256 amount = _amounts[i]; require(amount > 0, 'Amount should be greater than zero'); aggregatedBulkAmount += amount; } require(aggregatedBulkAmount < BULK_MAX_VALUE, 'Bulk value too high'); require( aggregatedBulkAmount <= cachedRemainingFunds, 'Not enough balance' ); cachedRemainingFunds -= aggregatedBulkAmount; require(bytes(_url).length != 0, "URL can't be empty"); require(bytes(_hash).length != 0, "Hash can't be empty"); finalResultsUrl = _url; finalResultsHash = _hash; uint256 totalFeePercentage = reputationOracleFeePercentage + recordingOracleFeePercentage + exchangeOracleFeePercentage; for (uint256 i = 0; i < _recipients.length; i++) { uint256 amount = _amounts[i]; uint256 amountFee = (totalFeePercentage * amount) / 100; _safeTransfer(token, _recipients[i], amount - amountFee); } // Transfer oracle fees if (reputationOracleFeePercentage > 0) { _safeTransfer( token, reputationOracle, (reputationOracleFeePercentage * aggregatedBulkAmount) / 100 ); } if (recordingOracleFeePercentage > 0) { _safeTransfer( token, recordingOracle, (recordingOracleFeePercentage * aggregatedBulkAmount) / 100 ); } if (exchangeOracleFeePercentage > 0) { _safeTransfer( token, exchangeOracle, (exchangeOracleFeePercentage * aggregatedBulkAmount) / 100 ); } remainingFunds = cachedRemainingFunds; // Check the forceComplete flag and transfer remaining funds if true if (forceComplete && cachedRemainingFunds > 0) { _safeTransfer(token, launcher, cachedRemainingFunds); cachedRemainingFunds = 0; } if (cachedRemainingFunds == 0) { status = EscrowStatuses.Complete; emit BulkTransferV2( _txId, _recipients, _amounts, false, finalResultsUrl ); emit Completed(); } else { status = EscrowStatuses.Partial; emit BulkTransferV2( _txId, _recipients, _amounts, true, finalResultsUrl ); } } /** * @dev Overloaded function to perform bulk payout with default forceComplete set to false. * Calls the main bulkPayout function with forceComplete as false. * * @param _recipients Array of recipients * @param _amounts Array of amounts to be paid to each recipient. * @param _url URL storing results as transaction details * @param _hash Hash of the results * @param _txId Transaction ID */ function bulkPayOut( address[] memory _recipients, uint256[] memory _amounts, string memory _url, string memory _hash, uint256 _txId ) external { bulkPayOut(_recipients, _amounts, _url, _hash, _txId, false); } function _safeTransfer(address _token, address to, uint256 value) internal { SafeERC20.safeTransfer(IERC20(_token), to, value); } modifier trusted() { require(areTrustedHandlers[msg.sender], 'Address calling not trusted'); _; } modifier trustedOrReputationOracle() { require( areTrustedHandlers[msg.sender] || msg.sender == reputationOracle, 'Address calling not trusted' ); _; } modifier trustedOrRecordingOracle() { require( areTrustedHandlers[msg.sender] || msg.sender == recordingOracle, 'Address calling not trusted' ); _; } modifier notBroke() { require(remainingFunds != 0, 'Token contract out of funds'); _; } modifier notComplete() { require( status != EscrowStatuses.Complete, 'Escrow in Complete status state' ); _; } modifier notPaid() { require(status != EscrowStatuses.Paid, 'Escrow in Paid status state'); _; } modifier notLaunched() { require( status != EscrowStatuses.Launched, 'Escrow in Launched status state' ); _; } modifier notExpired() { require(duration > block.timestamp, 'Contract expired'); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IEscrow { enum EscrowStatuses { Launched, Pending, Partial, Paid, Complete, Cancelled } function status() external view returns (EscrowStatuses); function addTrustedHandlers(address[] memory _handlers) external; function setup( address _reputationOracle, address _recordingOracle, address _exchangeOracle, uint8 _reputationOracleFeePercentage, uint8 _recordingOracleFeePercentage, uint8 _exchangeOracleFeePercentage, string memory _url, string memory _hash ) external; function cancel() external returns (bool); function withdraw(address _token) external returns (bool); function complete() external; function storeResults(string memory _url, string memory _hash) external; function bulkPayOut( address[] memory _recipients, uint256[] memory _amounts, string memory _url, string memory _hash, uint256 _txId, bool forceComplete ) external; function bulkPayOut( address[] memory _recipients, uint256[] memory _amounts, string memory _url, string memory _hash, uint256 _txId ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import '../libs/Stakes.sol'; interface IStaking { function setMinimumStake(uint256 _minimumStake) external; function setLockPeriod(uint32 _lockPeriod) external; function getAvailableStake(address _staker) external view returns (uint256); function getStakedTokens(address _staker) external view returns (uint256); function stake(uint256 _tokens) external; function unstake(uint256 _tokens) external; function withdraw() external; function slash( address _slasher, address _staker, address _escrowAddress, uint256 _tokens ) external; function getListOfStakers( uint256 _startIndex, uint256 _limit ) external view returns (address[] memory, Stakes.Staker[] memory); function withdrawFees() external; function addSlasher(address _slasher) external; function removeSlasher(address _slasher) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title Structures, methods and data are available to manage the staker state. */ library Stakes { struct Staker { uint256 tokensStaked; // Tokens staked by the Staker uint256 tokensLocked; // Tokens locked for withdrawal uint256 tokensLockedUntil; // Tokens locked until time } /** * @dev Deposit tokens to the staker stake. * @param stake Staker struct * @param _tokens Amount of tokens to deposit */ function deposit(Stakes.Staker storage stake, uint256 _tokens) internal { stake.tokensStaked += _tokens; } /** * @dev Release tokens from the staker stake. * @param stake Staker struct * @param _tokens Amount of tokens to release */ function release(Stakes.Staker storage stake, uint256 _tokens) internal { stake.tokensStaked -= _tokens; } /** * @dev Lock tokens until a lock period pass. * @param stake Staker struct * @param _tokens Amount of tokens to unstake * @param _period Period in blocks that need to pass before withdrawal */ function lockTokens( Stakes.Staker storage stake, uint256 _tokens, uint256 _period ) internal { stake.tokensLocked += _tokens; stake.tokensLockedUntil = block.number + _period; } /** * @dev Unlock tokens. * @param stake Staker struct * @param _tokens Amount of tokens to unlock */ function unlockTokens( Stakes.Staker storage stake, uint256 _tokens ) internal { stake.tokensLocked -= _tokens; stake.tokensLockedUntil = 0; } /** * @dev Return all tokens available for withdrawal. * @param stake Staker struct * @return Amount of tokens available for withdrawal */ function withdrawTokens( Stakes.Staker storage stake ) internal returns (uint256) { uint256 tokensToWithdraw = tokensWithdrawable(stake); if (tokensToWithdraw > 0) { unlockTokens(stake, tokensToWithdraw); release(stake, tokensToWithdraw); } return tokensToWithdraw; } /** * @dev Return all tokens available in stake. * @param stake Staker struct * @return Token amount */ function tokensAvailable( Stakes.Staker memory stake ) internal pure returns (uint256) { return stake.tokensStaked - stake.tokensLocked; } /** * @dev Tokens available for withdrawal after lock period. * @param stake Staker struct * @return Token amount */ function tokensWithdrawable( Stakes.Staker memory stake ) internal view returns (uint256) { if ( stake.tokensLockedUntil == 0 || block.number < stake.tokensLockedUntil ) { return 0; } return stake.tokensLocked; } }
{ "viaIR": true, "optimizer": { "enabled": true, "runs": 10 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"escrow","type":"address"}],"name":"Launched","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"escrow","type":"address"},{"indexed":false,"internalType":"string","name":"jobRequesterId","type":"string"}],"name":"LaunchedV2","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"minimumStake","type":"uint256"}],"name":"SetMinumumStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakingAddress","type":"address"}],"name":"SetStakingAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"counter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address[]","name":"trustedHandlers","type":"address[]"},{"internalType":"string","name":"jobRequesterId","type":"string"}],"name":"createEscrow","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"escrowCounters","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"hasEscrow","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staking","type":"address"},{"internalType":"uint256","name":"_minimumStake","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"lastEscrow","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minimumStake","type":"uint256"}],"name":"setMinimumStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stakingAddress","type":"address"}],"name":"setStakingAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"staking","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","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"}]
Contract Creation Code
60a080604052346100dc57306080526000549060ff8260081c1661008a575060ff8082160361004f575b60405161434d90816100e282396080518181816107d0015281816108d00152610ba60152f35b60ff90811916176000557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160ff8152a138610029565b62461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b6064820152608490fd5b600080fdfe6040608081526004803610156200001557600080fd5b600091823560e01c918263233e99031462000e065782633659cfe61462000b7b5782633cc3e58d1462000b505782634cf088d91462000b255782634f1ef286146200087a57826352d1902d14620007ba57826358d276f7146200077c57826361bc221a146200075b578263715018a6146200070b5782637e59879714620004075782638da5cb5b14620003dc578263979530e614620003a0578263cd6dc68714620001dd578263ec5ffac214620001b8578263f2fde38b146200011b57505063f4e0d9ac14620000e457600080fd5b34620001185760203660031901126200011857620001156200010562000e31565b6200010f6200105a565b6200115e565b80f35b80fd5b90915034620001b4576020366003190112620001b4576200013b62000e31565b91620001466200105a565b6001600160a01b03831615620001625783620001158462001126565b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b8280fd5b838234620001d95781600319360112620001d95760209060cd549051908152f35b5080fd5b90809250600319360112620001b457620001f662000e31565b83549160ff8360081c16159283809462000392575b801562000379575b156200031f5760ff1981166001178655836200030d575b5060ff855460081c1615620002b657506200026a906200024a3362001126565b6200010f6200025862000fdf565b6001600160a01b038316151562001027565b62000277602435620010b3565b62000280575080f35b60207f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989161ff001984541684555160018152a180f35b608490602085519162461bcd60e51b8352820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152fd5b61ffff1916610101178555386200022a565b845162461bcd60e51b8152602081840152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b50303b158015620002135750600160ff82161462000213565b50600160ff8216106200020b565b838234620001d9576020366003190112620001d95760209181906001600160a01b03620003cc62000e31565b16815260ca845220549051908152f35b838234620001d95781600319360112620001d95760335490516001600160a01b039091168152602090f35b838234620001d9576060366003190112620001d9576200042662000e31565b60248035946001600160401b039290919083871162000707573660238801121562000707578683013592848411620006f5578360051b94602098875195620004718b89018862000e7f565b865289860185819883010191368311620006b6578601905b828210620006d057505050604435818111620006cc5736602382011215620006cc57620004bf9036908681860135910162000ebf565b9560018060a01b0393858b8660cc54168b519283809263014f6b1960e41b8252338a8301525afa908115620006c2578b916200068b575b5060cd54116200063957885192612f55808501918211858310176200062757849392918d9960c092620012c387398860a0830194169a8b83523390830152338d8301526283d600606083015260a06080830152518093520191908b5b8d8282106200060d5750505050039088f0928315620006035760c954916000198314620005f257505060010160c9819055911680865260ca8752948490205560cb80546001600160a01b03191685179055825190815280850184905260608184018190527fde4a6895269de599430e1230956361cbe11b52ad149311a97123c73666c52141928291620005e9919083019062000f9d565b0390a151908152f35b634e487b7160e01b89526011905287fd5b86513d89823e3d90fd5b835189168552869550938401939092019160010162000552565b634e487b7160e01b8c5260418652878cfd5b885162461bcd60e51b81528085018c90526027818801527f496e73756666696369656e74207374616b6520746f2063726561746520616e2060448201526632b9b1b937bb9760c91b6064820152608490fd5b90508b81813d8311620006ba575b620006a5818362000e7f565b81010312620006b657518c620004f6565b8a80fd5b503d62000699565b8a513d8d823e3d90fd5b8880fd5b81356001600160a01b0381168103620006f1578152908b01908b0162000489565b8b80fd5b634e487b7160e01b8752604190528186fd5b8580fd5b83346200011857806003193601126200011857620007286200105a565b603380546001600160a01b0319811690915581906001600160a01b0316600080516020620042788339815191528280a380f35b838234620001d95781600319360112620001d95760209060c9549051908152f35b838234620001d9576020366003190112620001d95760209181906001600160a01b03620007a862000e31565b16815260ca8452205415159051908152f35b83346200011857806003193601126200011857507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003620008175760208251600080516020620042588339815191528152f35b6020608492519162461bcd60e51b8352820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b6064820152fd5b915080600319360112620001b4576200089262000e31565b906024356001600160401b03811162000b21573660238201121562000b2157620008c6903690602481870135910162000ebf565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116929190620009023085141562000efb565b620009226000805160206200425883398151915294828654161462000f4c565b6200092c6200105a565b600080516020620042188339815191525460ff1615620009565750505050620001159150620011b7565b82516352d1902d60e01b81526020959394918416919086818981865afa89918162000ae8575b50620009cb57855162461bcd60e51b8152808901889052602e6024820152600080516020620042f883398151915260448201526d6f6e206973206e6f74205555505360901b6064820152608490fd5b969192959493960362000aa45750620009e485620011b7565b600080516020620042988339815191528680a282511580159062000a9b575b62000a10575b5050505080f35b62000a8593858083519562000a258762000e4d565b60278752600080516020620042d883398151915286880152660819985a5b195960ca1b858801528581519101845af4913d1562000a90573d62000a7662000a6c8262000ea3565b9251928362000e7f565b81528681943d92013e62001249565b503880808062000a09565b506060925062001249565b50600162000a03565b825162461bcd60e51b815290810184905260296024820152600080516020620042b88339815191526044820152681a58589b195555525160ba1b6064820152608490fd5b9091508781813d831162000b19575b62000b03818362000e7f565b8101031262000b15575190386200097c565b8980fd5b503d62000af7565b8480fd5b838234620001d95781600319360112620001d95760cc5490516001600160a01b039091168152602090f35b838234620001d95781600319360112620001d95760cb5490516001600160a01b039091168152602090f35b915034620001b45760208060031936011262000e025762000b9b62000e31565b916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811662000bd53082141562000efb565b62000bf56000805160206200425883398151915291838354161462000f4c565b62000bff6200105a565b8251848101929091906001600160401b0384118385101762000def57838552888352600080516020620042188339815191525460ff161562000c4d57505050505050620001159150620011b7565b869293949596169085516352d1902d60e01b815287818a81865afa8a918162000dba575b5062000cc057865162461bcd60e51b8152808a01899052602e6024820152600080516020620042f883398151915260448201526d6f6e206973206e6f74205555505360901b6064820152608490fd5b97919293969594970362000d76575062000cda82620011b7565b600080516020620042988339815191528780a28584511580159062000d6e575b62000d09575b50505050505080f35b8062000d619684519662000d1d8862000e4d565b60278852600080516020620042d883398151915287890152660819985a5b195960ca1b868901525190845af4913d1562000a90573d62000a7662000a6c8262000ea3565b5038808080808562000d00565b508062000cfa565b835162461bcd60e51b815290810185905260296024820152600080516020620042b88339815191526044820152681a58589b195555525160ba1b6064820152608490fd5b9091508881813d831162000de7575b62000dd5818362000e7f565b81010312620006b65751903862000c71565b503d62000dc9565b634e487b7160e01b895260418852602489fd5b8380fd5b839034620001d9576020366003190112620001d957620001159062000e2a6200105a565b35620010b3565b600435906001600160a01b038216820362000e4857565b600080fd5b606081019081106001600160401b0382111762000e6957604052565b634e487b7160e01b600052604160045260246000fd5b601f909101601f19168101906001600160401b0382119082101762000e6957604052565b6001600160401b03811162000e6957601f01601f191660200190565b92919262000ecd8262000ea3565b9162000edd604051938462000e7f565b82948184528183011162000e48578281602093846000960137010152565b1562000f0357565b60405162461bcd60e51b815260206004820152602c60248201526000805160206200423883398151915260448201526b19195b1959d85d1958d85b1b60a21b6064820152608490fd5b1562000f5457565b60405162461bcd60e51b815260206004820152602c60248201526000805160206200423883398151915260448201526b6163746976652070726f787960a01b6064820152608490fd5b919082519283825260005b84811062000fca575050826000602080949584010152601f8019910116010190565b60208183018101518483018201520162000fa8565b60408051919082016001600160401b0381118382101762000e6957604052601b82527a457363726f77466163746f72793a205a65726f204164647265737360281b6020830152565b15620010305750565b60405162461bcd60e51b8152602060048201529081906200105690602483019062000f9d565b0390fd5b6033546001600160a01b031633036200106f57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b8015620010e5578060cd557f4ae07ff10245d5c3330b9a15e8c6b8644ea81b656ff7d5428edda75e77d061cd600080a2565b60405162461bcd60e51b815260206004820152601960248201527826bab9ba1031329030903837b9b4ba34bb3290373ab6b132b960391b6044820152606490fd5b603380546001600160a01b039283166001600160a01b03198216811790925590911660008051602062004278833981519152600080a3565b6001600160a01b03166200117e6200117562000fdf565b82151562001027565b60cc80546001600160a01b031916821790557fd6912e103d1553f15e77ffc98e99da32c9ce0d21d8be27cbb38437b1afe30928600080a2565b803b15620011ee576000805160206200425883398151915280546001600160a01b0319166001600160a01b03909216919091179055565b60405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b91929015620012ae57508151156200125f575090565b3b15620012695790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015620010305750805190602001fdfe60406080815234620002585762002f5590813803806200001f8162000273565b938439820160a08382031262000258576200003a8362000299565b9260206200004a81830162000299565b94848301519260018060a01b03918285168095036200025857606082015195608083015160018060401b039384821162000258570181601f82011215620002585780519384116200025d578360051b908680620000a981850162000273565b809781520192820101928311620002585786809101915b8383106200023d57505050506001948360009287845516620000ee620000e5620002ae565b821515620002f8565b62000105620000fc620002ae565b831515620002f8565b600780546001600160a01b03199081169092179055865460ff1990811688559742810190811062000229578798999a8691600d5516908181600454161760045582816005541617600555339060065416176006558252600e90600e8652898320878a8254161790558252888220868982541617905581955b62000192575b8851612bc790816200038e8239f35b825186101562000223578686620001c586620001b0849a8862000362565b51161515620001be620002ae565b90620002f8565b85620001d2828762000362565b511684528287528a8420828b8254161790557fad3769ac0c1a91ee9dcf369f6d2989f91572b6f876933bbc82ab85f6b969a07a878762000213848962000362565b51168d51908152a101956200017d565b62000183565b634e487b7160e01b84526011600452602484fd5b81906200024a8462000299565b8152019101908690620000c0565b600080fd5b634e487b7160e01b600052604160045260246000fd5b6040519190601f01601f191682016001600160401b038111838210176200025d57604052565b51906001600160a01b03821682036200025857565b60408051919082016001600160401b038111838210176200025d57604052601482527f457363726f773a207a65726f20616464726573730000000000000000000000006020830152565b15620003015750565b6040519062461bcd60e51b82528160208060048301528251908160248401526000935b82851062000348575050604492506000838284010152601f80199101168101030190fd5b848101820151868601604401529381019385935062000324565b8051821015620003775760209160051b010190565b634e487b7160e01b600052603260045260246000fdfe608080604052600436101561001357600080fd5b60003560e01c9081630ae9dfad146122d3575080630f46c9aa146122425780630fb5a6b41461222457806312065fe01461220957806316eebd1e146121e0578063200d2ed2146121b6578063337f3f32146121255780633aecd0e3146120fa57806343aba9c21461206957806351cff8d914611f59578063522e117714611e8957806355bf1d6a146118ec578063697e4b871461166957806378c62420146116455780639753e4321461161c578063992d454d146115f35780639c48b102146115625780639eb262f31461142c578063a05220ad14611403578063a5aa542e146113e5578063b63d1a0014610bd4578063ba5fed3414610b0a578063bdd1daaa14610ae1578063c479bbf814610abd578063ea8a1af0146109ba578063f17171e91461097b578063f56679cf146101b9578063fad844c11461018c5763fc0c546a1461015e57600080fd5b34610187576000366003190112610187576007546040516001600160a01b039091168152602090f35b600080fd5b346101875760003660031901126101875760015460405160089190911c6001600160a01b03168152602090f35b3461018757610100366003190112610187576101d36123ac565b6024356001600160a01b038116810361018757604435906001600160a01b03821682036101875760ff60643516606435036101875760ff60843516608435036101875760ff60a4351660a435036101875760c4356001600160401b038111610187576102439036906004016124c4565b9160e4356001600160401b038111610187576102639036906004016124c4565b9333600052600e60205261027e60ff604060002054166125c7565b61028b600d544210612639565b6001600160a01b0381161561092c576001600160a01b038316156108e8576001600160a01b038216156108a357606460ff6102d460a4356102cf608435853561276f565b61276f565b1611610863576001549060ff8216600681101561084d576107fc57610100600160a81b031990911660089190911b610100600160a81b031617600155600280546001600160a01b03199081166001600160a01b039485161790915560038054909116919092161790556006805460843560a81b60ff60a81b1662ffffff60a01b1990911660643560a01b60ff60a01b16171760a43560b01b60ff60b01b161790558051906001600160401b0382116107085781906103936008546122f4565b601f81116107a1575b50602090601f83116001146107295760009261071e575b50508160011b916000199060031b1c1916176008555b80516001600160401b038111610708576103e46009546122f4565b601f81116106b9575b506020601f8211600114610651578192600092610646575b50508160011b916000199060031b1c1916176009555b600160ff19815416178060015561043061253b565b80600f5580156106085760025460035460405160a0815260085490926000926001600160a01b0390811692911690610467816122f4565b908160a087015260c0906001811690816000146105e8575060011461059d575b505083830360208501526000926009546104a0816122f4565b808352906001811690811561057b575060011461052d575b50600887901c6001600160a01b0316604086015260608501829052608085018390527f27b2dc149fd3048bc27eadaaf660801a04305c72845da74066a17b72d6c5bb666020877ff3bcd83b3ad174382a0f0ee29dcba2eee468d36f13021623af7de1539e26807488880389a1604051908152a1005b6009600090815291979450600080516020612b528339815191525b81831061056157509396016020908101935086906104b8565b6001816020929493945483858d0101520191019190610548565b60ff191660208481019190915291151560051b909201810194508791506104b8565b60086000908152929450909190600080516020612b328339815191525b8383106105d257505060c09150840101918680610487565b6001816020925484868b010152019201916105ba565b91505060c092945060ff191682860152151560051b840101918680610487565b60405162461bcd60e51b8152602060048201526016602482015275457363726f772062616c616e6365206973207a65726f60501b6044820152606490fd5b015190508280610405565b600960005260206000209060005b601f19841681106106a1575060019383601f19811610610688575b505050811b0160095561041b565b015160001960f88460031b161c1916905582808061067a565b9091602060018192858801518155019301910161065f565b6009600052600080516020612b52833981519152601f830160051c810160208410610701575b601f830160051c820181106106f55750506103ed565b600081556001016106df565b50806106df565b634e487b7160e01b600052604160045260246000fd5b0151905083806103b3565b600860009081529350600080516020612b3283398151915291905b601f1984168510610786576001945083601f1981161061076d575b505050811b016008556103c9565b015160001960f88460031b161c1916905583808061075f565b81810151835560209485019460019093019290910190610744565b6008600052909150600080516020612b32833981519152601f840160051c8101602085106107f5575b90849392915b601f830160051c820181106107e657505061039c565b600081558594506001016107d0565b50806107ca565b60405162461bcd60e51b815260206004820152602360248201527f457363726f77206e6f7420696e204c61756e636865642073746174757320737460448201526261746560e81b6064820152608490fd5b634e487b7160e01b600052602160045260246000fd5b60405162461bcd60e51b815260206004820152601860248201527750657263656e74616765206f7574206f6620626f756e647360401b6044820152606490fd5b60405162461bcd60e51b815260206004820152601f60248201527f496e76616c69642065786368616e6765206f7261636c652061646472657373006044820152606490fd5b606460405162461bcd60e51b815260206004820152602060248201527f496e76616c6964207265636f7264696e67206f7261636c6520616464726573736044820152fd5b60405162461bcd60e51b815260206004820152602160248201527f496e76616c69642072657075746174696f6e206f7261636c65206164647265736044820152607360f81b6064820152608490fd5b34610187576020366003190112610187576001600160a01b0361099c6123ac565b16600052600e602052602060ff604060002054166040519015158152f35b346101875760003660031901126101875733600052600e6020526109e560ff604060002054166125c7565b6109f2600f541515612678565b60ff60015416600681101561084d57600414610a7857610a1061294f565b600754600554600f54610a319290916001600160a01b039081169116612972565b600560ff1960015416176001556000600f5560206040517f63b958841f79ab97cb5456da181454b9932c0e15a3b17f1cbd27e2a8bc610437600080a1600160005560018152f35b60405162461bcd60e51b815260206004820152601f60248201527f457363726f7720696e20436f6d706c65746520737461747573207374617465006044820152606490fd5b3461018757600036600319011261018757602060ff60065460a01c16604051908152f35b34610187576000366003190112610187576006546040516001600160a01b039091168152602090f35b3461018757600036600319011261018757604051600a54600082610b2d836122f4565b9182825260209360019085600182169182600014610bb4575050600114610b74575b50610b5c92500383612349565b610b7060405192828493845283019061236c565b0390f35b849150600a60005281600020906000915b858310610b9c575050610b5c935082010185610b4f565b80548389018501528794508693909201918101610b85565b60ff191685820152610b5c95151560051b8501019250879150610b4f9050565b346101875760a0366003190112610187576004356001600160401b03811161018757610c049036906004016123d9565b6024356001600160401b03811161018757610c23903690600401612449565b906044356001600160401b03811161018757610c439036906004016124c4565b916064356001600160401b03811161018757610c639036906004016124c4565b9133600052600e60205260ff6040600020541680156113cb575b610c86906125c7565b610c93600f541515612678565b60ff60015416600681101561084d571561138657610cb4600d544210612639565b610cbc61294f565b805182510361132d578151156112ea576064815110156112af5760ff60015416600681101561084d57600481141590816112a3575b501561126d57600093600f54936000955b8451871015610d9757610d1587866126c2565b518015610d47578082018211610d315760019101960195610d02565b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b815260206004820152602260248201527f416d6f756e742073686f756c642062652067726561746572207468616e207a65604482015261726f60f01b6064820152608490fd5b93919294676765c793fa10079d601b1b851015611232578085116111f85784610dbf91612611565b92610dcc815115156126ec565b610dd88251151561272d565b8051906001600160401b038211610708578190610df6600b546122f4565b601f811161119d575b50602090601f83116001146111255760009261111a575b50508160011b916000199060031b1c191617600b555b8051906001600160401b038211610708578190610e4a600c546122f4565b601f81116110bf575b50602090601f83116001146110475760009261103c575b50508160011b916000199060031b1c191617600c555b60ff610ea860065482610e9d818360a81c16828460a01c1661276f565b9160b01c169061276f565b169160005b8551811015610f015780610efb87610ec7600194876126c2565b51610ef56064610ed7838b612783565b04868060a01b03610eed878260075416966126c2565b511692612611565b91612972565b01610ead565b85600080516020612b1283398151915284848860ff60065460a01c1680611011575b5060ff60065460a81c1680610fe9575b5060ff60065460b01c169081610fba575b505080600f5515600014610f9157610f7390600460ff19600154161760015560405191829160843595836128bd565b0390a2600080516020612af2833981519152600080a15b6001600055005b610fb290600260ff1960015416176001556040519182916084359583612828565b0390a2610f8a565b610fe2916064610fdb60018060a01b03938460075416946003541693612783565b0491612972565b8480610f44565b61100b9060018060a01b03906064610fdb858460075416946002541693612783565b85610f33565b6110369060018060a01b03906064610fdb8584600754169460015460081c1693612783565b85610f23565b015190508680610e6a565b600c60009081529350600080516020612ab283398151915291905b601f19841685106110a4576001945083601f1981161061108b575b505050811b01600c55610e80565b015160001960f88460031b161c1916905586808061107d565b81810151835560209485019460019093019290910190611062565b600c600052909150600080516020612ab2833981519152601f840160051c810160208510611113575b90849392915b601f830160051c82018110611104575050610e53565b600081558594506001016110ee565b50806110e8565b015190508780610e16565b600b60009081529350600080516020612b7283398151915291905b601f1984168510611182576001945083601f19811610611169575b505050811b01600b55610e2c565b015160001960f88460031b161c1916905587808061115b565b81810151835560209485019460019093019290910190611140565b600b600052909150600080516020612b72833981519152601f840160051c8101602085106111f1575b90849392915b601f830160051c820181106111e2575050610dff565b600081558594506001016111cc565b50806111c6565b60405162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f7567682062616c616e636560701b6044820152606490fd5b60405162461bcd60e51b8152602060048201526013602482015272084ead8d640ecc2d8eaca40e8dede40d0d2ced606b1b6044820152606490fd5b60405162461bcd60e51b815260206004820152600e60248201526d496e76616c69642073746174757360901b6044820152606490fd5b60059150141585610cf1565b60405162461bcd60e51b8152602060048201526013602482015272546f6f206d616e7920726563697069656e747360681b6044820152606490fd5b60405162461bcd60e51b815260206004820152601b60248201527a416d6f756e74732073686f756c64206e6f7420626520656d70747960281b6044820152606490fd5b60405162461bcd60e51b815260206004820152602b60248201527f416d6f756e74206f6620726563697069656e747320616e642076616c7565732060448201526a0c8dedc4ee840dac2e8c6d60ab1b6064820152608490fd5b60405162461bcd60e51b815260206004820152601f60248201527f457363726f7720696e204c61756e6368656420737461747573207374617465006044820152606490fd5b506001543360089190911c6001600160a01b031614610c7d565b34610187576000366003190112610187576020600f54604051908152f35b34610187576000366003190112610187576003546040516001600160a01b039091168152602090f35b3461018757602080600319360112610187576001600160401b03906004358281116101875761145f9036906004016123d9565b9133600052600e92600e835261147c60ff604060002054166125c7565b60005b8151811015611560576001600160a01b038061149b83856126c2565b511615604051906040820182811087821117610708576040526014825273457363726f773a207a65726f206164647265737360601b8783015261153a5750907fad3769ac0c1a91ee9dcf369f6d2989f91572b6f876933bbc82ab85f6b969a07a858360019461150a85886126c2565b511660005288825260406000208560ff1982541617905561152b84876126c2565b5116604051908152a10161147f565b8561155c60405192839262461bcd60e51b84526004840152602483019061236c565b0390fd5b005b3461018757600036600319011261018757604051600854600082611585836122f4565b9182825260209360019085600182169182600014610bb45750506001146115b35750610b5c92500383612349565b849150600860005281600020906000915b8583106115db575050610b5c935082010185610b4f565b805483890185015287945086939092019181016115c4565b34610187576000366003190112610187576005546040516001600160a01b039091168152602090f35b34610187576000366003190112610187576002546040516001600160a01b039091168152602090f35b3461018757600036600319011261018757602060ff60065460a81c16604051908152f35b34610187576040366003190112610187576001600160401b036004358181116101875761169a9036906004016124c4565b602435828111610187576116b29036906004016124c4565b33600052602090600e825260ff6040600020541680156118d8575b6116d6906125c7565b6116e3600d544210612639565b600160ff815416600681101561084d578181149081156118cd575b501561187257611710845115156126ec565b61171c8251151561272d565b835194851161070857611730600a546122f4565b601f8111611828575b5082601f86116001146117ae57918580600080516020612a928339815191529761179197969461179e966000936117a3575b501b916000199060031b1c191617600a555b60405194859460408652604086019061236c565b918483039085015261236c565b0390a1005b88015192508a61176b565b601f19861690600a600052846000209160005b81811061181357509661179e94926117919796949282600080516020612a928339815191529a106117fa575b5050811b01600a5561177d565b87015160001960f88460031b161c1916905588806117ed565b878301518455928401929186019186016117c1565b600a60005283600020601f870160051c810191858810611868575b601f0160051c019082905b82811061185c575050611739565b6000815501829061184e565b9091508190611843565b60405162461bcd60e51b815260048101849052602d60248201527f457363726f77206e6f7420696e2050656e64696e67206f72205061727469616c60448201526c2073746174757320737461746560981b6064820152608490fd5b6002915014866116fe565b506002546001600160a01b031633146116cd565b346101875760c0366003190112610187576004356001600160401b0381116101875761191c9036906004016123d9565b6024356001600160401b0381116101875761193b903690600401612449565b906044356001600160401b0381116101875761195b9036906004016124c4565b916064356001600160401b0381116101875761197b9036906004016124c4565b9160a435151560a435036101875733600052600e60205260ff604060002054168015611e6f575b6119ab906125c7565b6119b8600f541515612678565b60ff60015416600681101561084d5715611386576119d9600d544210612639565b6119e161294f565b805182510361132d578151156112ea576064815110156112af5760ff60015416600681101561084d5760048114159081611e63575b501561126d57600093600f54936000955b8451871015611a5657611a3a87866126c2565b518015610d47578082018211610d315760019101960195611a27565b93919294676765c793fa10079d601b1b851015611232578085116111f85784611a7e91612611565b92611a8b815115156126ec565b611a978251151561272d565b8051906001600160401b038211610708578190611ab5600b546122f4565b601f8111611e08575b50602090601f8311600114611d9057600092611d85575b50508160011b916000199060031b1c191617600b555b8051906001600160401b038211610708578190611b09600c546122f4565b601f8111611d2a575b50602090601f8311600114611cb257600092611ca7575b50508160011b916000199060031b1c191617600c555b60ff611b5c60065482610e9d818360a81c16828460a01c1661276f565b169160005b8551811015611b815780611b7b87610ec7600194876126c2565b01611b61565b85600080516020612b1283398151915284848860ff60065460a01c1680611c7c575b5060ff60065460a81c1680611c54575b5060ff60065460b01c169081611c2c575b505080600f5560a43560a435611c23575b611bff575b610f9157610f7390600460ff19600154161760015560405191829160843595836128bd565b600754600454611c1c92916001600160a01b039182169116612972565b6000611bda565b50801515611bd5565b611c4d916064610fdb60018060a01b03938460075416946003541693612783565b8480611bc4565b611c769060018060a01b03906064610fdb858460075416946002541693612783565b85611bb3565b611ca19060018060a01b03906064610fdb8584600754169460015460081c1693612783565b85611ba3565b015190508680611b29565b600c60009081529350600080516020612ab283398151915291905b601f1984168510611d0f576001945083601f19811610611cf6575b505050811b01600c55611b3f565b015160001960f88460031b161c19169055868080611ce8565b81810151835560209485019460019093019290910190611ccd565b600c600052909150600080516020612ab2833981519152601f840160051c810160208510611d7e575b90849392915b601f830160051c82018110611d6f575050611b12565b60008155859450600101611d59565b5080611d53565b015190508780611ad5565b600b60009081529350600080516020612b7283398151915291905b601f1984168510611ded576001945083601f19811610611dd4575b505050811b01600b55611aeb565b015160001960f88460031b161c19169055878080611dc6565b81810151835560209485019460019093019290910190611dab565b600b600052909150600080516020612b72833981519152601f840160051c810160208510611e5c575b90849392915b601f830160051c82018110611e4d575050611abe565b60008155859450600101611e37565b5080611e31565b60059150141585611a16565b506001543360089190911c6001600160a01b0316146119a2565b3461018757600036600319011261018757611ea7600d544210612639565b33600052600e60205260ff604060002054168015611f3f575b611ec9906125c7565b60015460ff8116600681101561084d57600303611eff5760ff1916600417600155600080516020612af2833981519152600080a1005b60405162461bcd60e51b8152602060048201526018602482015277457363726f77206e6f7420696e205061696420737461746560401b6044820152606490fd5b506001543360089190911c6001600160a01b031614611ec0565b3461018757602036600319011261018757611f726123ac565b33600052600e602052611f8c60ff604060002054166125c7565b611f9461294f565b6007546001600160a01b03908282169082160361204657611fb361253b565b91600f548084111561200a57611fdb611fe891600080516020612ad283398151915295612611565b80935b6005541683612972565b611ff76040519283928361261e565b0390a16001600055602060405160018152f35b60405162461bcd60e51b81526020600482015260146024820152734e6f2066756e647320746f20776974686472617760601b6044820152606490fd5b81611fe8612062600080516020612ad2833981519152946125a2565b8093611fde565b3461018757600036600319011261018757604051600b5460008261208c836122f4565b9182825260209360019085600182169182600014610bb45750506001146120ba5750610b5c92500383612349565b849150600b60005281600020906000915b8583106120e2575050610b5c935082010185610b4f565b805483890185015287945086939092019181016120cb565b3461018757602036600319011261018757602061211d6121186123ac565b6125a2565b604051908152f35b3461018757600036600319011261018757604051600954600082612148836122f4565b9182825260209360019085600182169182600014610bb45750506001146121765750610b5c92500383612349565b849150600960005281600020906000915b85831061219e575050610b5c935082010185610b4f565b80548389018501528794508693909201918101612187565b346101875760003660031901126101875760ff60015416604051600682101561084d576020918152f35b34610187576000366003190112610187576004546040516001600160a01b039091168152602090f35b3461018757600036600319011261018757602061211d61253b565b34610187576000366003190112610187576020600d54604051908152f35b3461018757600036600319011261018757604051600c54600082612265836122f4565b9182825260209360019085600182169182600014610bb45750506001146122935750610b5c92500383612349565b849150600c60005281600020906000915b8583106122bb575050610b5c935082010185610b4f565b805483890185015287945086939092019181016122a4565b346101875760003660031901126101875760209060ff60065460b01c168152f35b90600182811c92168015612324575b602083101461230e57565b634e487b7160e01b600052602260045260246000fd5b91607f1691612303565b606081019081106001600160401b0382111761070857604052565b601f909101601f19168101906001600160401b0382119082101761070857604052565b919082519283825260005b848110612398575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201612377565b600435906001600160a01b038216820361018757565b6001600160401b0381116107085760051b60200190565b9080601f830112156101875760209082356123f3816123c2565b936124016040519586612349565b81855260208086019260051b82010192831161018757602001905b82821061242a575050505090565b81356001600160a01b038116810361018757815290830190830161241c565b9080601f83011215610187576020908235612463816123c2565b936124716040519586612349565b81855260208086019260051b82010192831161018757602001905b82821061249a575050505090565b8135815290830190830161248c565b6001600160401b03811161070857601f01601f191660200190565b81601f82011215610187578035906124db826124a9565b926124e96040519485612349565b8284526020838301011161018757816000926020809301838601378301015290565b3d15612536573d9061251c826124a9565b9161252a6040519384612349565b82523d6000602084013e565b606090565b60018060a01b036007541660405160208101906370a0823160e01b82523060248201526024815261256b8161232e565b6000928392839251915afa9061257f61250b565b911561259d5760208280518101031261259a57506020015190565b80fd5b905090565b60405160208101906370a0823160e01b82523060248201526024815261256b8161232e565b156125ce57565b60405162461bcd60e51b815260206004820152601b60248201527a1059191c995cdcc818d85b1b1a5b99c81b9bdd081d1c9d5cdd1959602a1b6044820152606490fd5b91908203918211610d3157565b6001600160a01b039091168152602081019190915260400190565b1561264057565b60405162461bcd60e51b815260206004820152601060248201526f10dbdb9d1c9858dd08195e1c1a5c995960821b6044820152606490fd5b1561267f57565b60405162461bcd60e51b815260206004820152601b60248201527a546f6b656e20636f6e7472616374206f7574206f662066756e647360281b6044820152606490fd5b80518210156126d65760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b156126f357565b60405162461bcd60e51b815260206004820152601260248201527155524c2063616e277420626520656d70747960701b6044820152606490fd5b1561273457565b60405162461bcd60e51b8152602060048201526013602482015272486173682063616e277420626520656d70747960681b6044820152606490fd5b9060ff8091169116019060ff8211610d3157565b81810292918115918404141715610d3157565b600b54600092916127a6826122f4565b9081815260209260019060018116908160001461280b57506001146127cc575b50505050565b9293945090600b6000528360002092846000945b8386106127f75750505050010190388080806127c6565b8054858701830152940193859082016127e0565b60ff191685840152505090151560051b01019150388080806127c6565b9190916080810160808252835180915260a082019060208095019060005b8181106128a0575050508181038483015283808451928381520193019360005b82811061288c575050506128899250600160408201526060818303910152612796565b90565b855185529481019493810193600101612866565b82516001600160a01b031684529286019291860191600101612846565b9190916080810160808252835180915260a082019060208095019060005b818110612932575050508181038483015283808451928381520193019360005b82811061291e575050506128899250600060408201526060818303910152612796565b8551855294810194938101936001016128fb565b82516001600160a01b0316845292860192918601916001016128db565b600260005414612960576002600055565b604051633ee5aeb560e01b8152600490fd5b60405163a9059cbb60e01b602082019081526001600160a01b039092169391926129d2926129b79183916129a9916024840161261e565b03601f198101835282612349565b600080938192519082875af16129cb61250b565b9084612a2e565b908151918215159283612a02575b5050506129ea5750565b60249060405190635274afe760e01b82526004820152fd5b819293509060209181010312612a2a57602001519081159182150361259a57503880806129e0565b5080fd5b90612a555750805115612a4357805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580612a88575b612a66575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15612a5e56feb20e0717219840fd5684a80bec782e8babb56ea224f677561b791a61192605c1df6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364e06452d00b2b58f14a1fa6d499ea982ff93ea827ae700ea9ba03f4daddc94bc145295fd5fffd2a8a91e1749ac8112d9807fa2c615cc8426558f23d1d71822708f3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee36e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9a26469706673582212208ca6660ae1066fdde17894c7f25d7d2fae6fabf834579e45e97eb7ef40786df964736f6c634300081700334910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd914346756e6374696f6e206d7573742062652063616c6c6564207468726f75676820360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0bc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b45524331393637557067726164653a20756e737570706f727465642070726f78416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c45524331393637557067726164653a206e657720696d706c656d656e74617469a2646970667358221220cf1a3fc6d69123504a9d0c7d69a790151da664196a2f25fd07d5d8dbd0e9f7ad64736f6c63430008170033
Deployed Bytecode
0x6040608081526004803610156200001557600080fd5b600091823560e01c918263233e99031462000e065782633659cfe61462000b7b5782633cc3e58d1462000b505782634cf088d91462000b255782634f1ef286146200087a57826352d1902d14620007ba57826358d276f7146200077c57826361bc221a146200075b578263715018a6146200070b5782637e59879714620004075782638da5cb5b14620003dc578263979530e614620003a0578263cd6dc68714620001dd578263ec5ffac214620001b8578263f2fde38b146200011b57505063f4e0d9ac14620000e457600080fd5b34620001185760203660031901126200011857620001156200010562000e31565b6200010f6200105a565b6200115e565b80f35b80fd5b90915034620001b4576020366003190112620001b4576200013b62000e31565b91620001466200105a565b6001600160a01b03831615620001625783620001158462001126565b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b8280fd5b838234620001d95781600319360112620001d95760209060cd549051908152f35b5080fd5b90809250600319360112620001b457620001f662000e31565b83549160ff8360081c16159283809462000392575b801562000379575b156200031f5760ff1981166001178655836200030d575b5060ff855460081c1615620002b657506200026a906200024a3362001126565b6200010f6200025862000fdf565b6001600160a01b038316151562001027565b62000277602435620010b3565b62000280575080f35b60207f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989161ff001984541684555160018152a180f35b608490602085519162461bcd60e51b8352820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152fd5b61ffff1916610101178555386200022a565b845162461bcd60e51b8152602081840152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b50303b158015620002135750600160ff82161462000213565b50600160ff8216106200020b565b838234620001d9576020366003190112620001d95760209181906001600160a01b03620003cc62000e31565b16815260ca845220549051908152f35b838234620001d95781600319360112620001d95760335490516001600160a01b039091168152602090f35b838234620001d9576060366003190112620001d9576200042662000e31565b60248035946001600160401b039290919083871162000707573660238801121562000707578683013592848411620006f5578360051b94602098875195620004718b89018862000e7f565b865289860185819883010191368311620006b6578601905b828210620006d057505050604435818111620006cc5736602382011215620006cc57620004bf9036908681860135910162000ebf565b9560018060a01b0393858b8660cc54168b519283809263014f6b1960e41b8252338a8301525afa908115620006c2578b916200068b575b5060cd54116200063957885192612f55808501918211858310176200062757849392918d9960c092620012c387398860a0830194169a8b83523390830152338d8301526283d600606083015260a06080830152518093520191908b5b8d8282106200060d5750505050039088f0928315620006035760c954916000198314620005f257505060010160c9819055911680865260ca8752948490205560cb80546001600160a01b03191685179055825190815280850184905260608184018190527fde4a6895269de599430e1230956361cbe11b52ad149311a97123c73666c52141928291620005e9919083019062000f9d565b0390a151908152f35b634e487b7160e01b89526011905287fd5b86513d89823e3d90fd5b835189168552869550938401939092019160010162000552565b634e487b7160e01b8c5260418652878cfd5b885162461bcd60e51b81528085018c90526027818801527f496e73756666696369656e74207374616b6520746f2063726561746520616e2060448201526632b9b1b937bb9760c91b6064820152608490fd5b90508b81813d8311620006ba575b620006a5818362000e7f565b81010312620006b657518c620004f6565b8a80fd5b503d62000699565b8a513d8d823e3d90fd5b8880fd5b81356001600160a01b0381168103620006f1578152908b01908b0162000489565b8b80fd5b634e487b7160e01b8752604190528186fd5b8580fd5b83346200011857806003193601126200011857620007286200105a565b603380546001600160a01b0319811690915581906001600160a01b0316600080516020620042788339815191528280a380f35b838234620001d95781600319360112620001d95760209060c9549051908152f35b838234620001d9576020366003190112620001d95760209181906001600160a01b03620007a862000e31565b16815260ca8452205415159051908152f35b83346200011857806003193601126200011857507f0000000000000000000000003c14f4900f5f59f29f8b684394a2748a71531dd76001600160a01b03163003620008175760208251600080516020620042588339815191528152f35b6020608492519162461bcd60e51b8352820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b6064820152fd5b915080600319360112620001b4576200089262000e31565b906024356001600160401b03811162000b21573660238201121562000b2157620008c6903690602481870135910162000ebf565b6001600160a01b037f0000000000000000000000003c14f4900f5f59f29f8b684394a2748a71531dd78116929190620009023085141562000efb565b620009226000805160206200425883398151915294828654161462000f4c565b6200092c6200105a565b600080516020620042188339815191525460ff1615620009565750505050620001159150620011b7565b82516352d1902d60e01b81526020959394918416919086818981865afa89918162000ae8575b50620009cb57855162461bcd60e51b8152808901889052602e6024820152600080516020620042f883398151915260448201526d6f6e206973206e6f74205555505360901b6064820152608490fd5b969192959493960362000aa45750620009e485620011b7565b600080516020620042988339815191528680a282511580159062000a9b575b62000a10575b5050505080f35b62000a8593858083519562000a258762000e4d565b60278752600080516020620042d883398151915286880152660819985a5b195960ca1b858801528581519101845af4913d1562000a90573d62000a7662000a6c8262000ea3565b9251928362000e7f565b81528681943d92013e62001249565b503880808062000a09565b506060925062001249565b50600162000a03565b825162461bcd60e51b815290810184905260296024820152600080516020620042b88339815191526044820152681a58589b195555525160ba1b6064820152608490fd5b9091508781813d831162000b19575b62000b03818362000e7f565b8101031262000b15575190386200097c565b8980fd5b503d62000af7565b8480fd5b838234620001d95781600319360112620001d95760cc5490516001600160a01b039091168152602090f35b838234620001d95781600319360112620001d95760cb5490516001600160a01b039091168152602090f35b915034620001b45760208060031936011262000e025762000b9b62000e31565b916001600160a01b037f0000000000000000000000003c14f4900f5f59f29f8b684394a2748a71531dd7811662000bd53082141562000efb565b62000bf56000805160206200425883398151915291838354161462000f4c565b62000bff6200105a565b8251848101929091906001600160401b0384118385101762000def57838552888352600080516020620042188339815191525460ff161562000c4d57505050505050620001159150620011b7565b869293949596169085516352d1902d60e01b815287818a81865afa8a918162000dba575b5062000cc057865162461bcd60e51b8152808a01899052602e6024820152600080516020620042f883398151915260448201526d6f6e206973206e6f74205555505360901b6064820152608490fd5b97919293969594970362000d76575062000cda82620011b7565b600080516020620042988339815191528780a28584511580159062000d6e575b62000d09575b50505050505080f35b8062000d619684519662000d1d8862000e4d565b60278852600080516020620042d883398151915287890152660819985a5b195960ca1b868901525190845af4913d1562000a90573d62000a7662000a6c8262000ea3565b5038808080808562000d00565b508062000cfa565b835162461bcd60e51b815290810185905260296024820152600080516020620042b88339815191526044820152681a58589b195555525160ba1b6064820152608490fd5b9091508881813d831162000de7575b62000dd5818362000e7f565b81010312620006b65751903862000c71565b503d62000dc9565b634e487b7160e01b895260418852602489fd5b8380fd5b839034620001d9576020366003190112620001d957620001159062000e2a6200105a565b35620010b3565b600435906001600160a01b038216820362000e4857565b600080fd5b606081019081106001600160401b0382111762000e6957604052565b634e487b7160e01b600052604160045260246000fd5b601f909101601f19168101906001600160401b0382119082101762000e6957604052565b6001600160401b03811162000e6957601f01601f191660200190565b92919262000ecd8262000ea3565b9162000edd604051938462000e7f565b82948184528183011162000e48578281602093846000960137010152565b1562000f0357565b60405162461bcd60e51b815260206004820152602c60248201526000805160206200423883398151915260448201526b19195b1959d85d1958d85b1b60a21b6064820152608490fd5b1562000f5457565b60405162461bcd60e51b815260206004820152602c60248201526000805160206200423883398151915260448201526b6163746976652070726f787960a01b6064820152608490fd5b919082519283825260005b84811062000fca575050826000602080949584010152601f8019910116010190565b60208183018101518483018201520162000fa8565b60408051919082016001600160401b0381118382101762000e6957604052601b82527a457363726f77466163746f72793a205a65726f204164647265737360281b6020830152565b15620010305750565b60405162461bcd60e51b8152602060048201529081906200105690602483019062000f9d565b0390fd5b6033546001600160a01b031633036200106f57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b8015620010e5578060cd557f4ae07ff10245d5c3330b9a15e8c6b8644ea81b656ff7d5428edda75e77d061cd600080a2565b60405162461bcd60e51b815260206004820152601960248201527826bab9ba1031329030903837b9b4ba34bb3290373ab6b132b960391b6044820152606490fd5b603380546001600160a01b039283166001600160a01b03198216811790925590911660008051602062004278833981519152600080a3565b6001600160a01b03166200117e6200117562000fdf565b82151562001027565b60cc80546001600160a01b031916821790557fd6912e103d1553f15e77ffc98e99da32c9ce0d21d8be27cbb38437b1afe30928600080a2565b803b15620011ee576000805160206200425883398151915280546001600160a01b0319166001600160a01b03909216919091179055565b60405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b91929015620012ae57508151156200125f575090565b3b15620012695790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015620010305750805190602001fdfe60406080815234620002585762002f5590813803806200001f8162000273565b938439820160a08382031262000258576200003a8362000299565b9260206200004a81830162000299565b94848301519260018060a01b03918285168095036200025857606082015195608083015160018060401b039384821162000258570181601f82011215620002585780519384116200025d578360051b908680620000a981850162000273565b809781520192820101928311620002585786809101915b8383106200023d57505050506001948360009287845516620000ee620000e5620002ae565b821515620002f8565b62000105620000fc620002ae565b831515620002f8565b600780546001600160a01b03199081169092179055865460ff1990811688559742810190811062000229578798999a8691600d5516908181600454161760045582816005541617600555339060065416176006558252600e90600e8652898320878a8254161790558252888220868982541617905581955b62000192575b8851612bc790816200038e8239f35b825186101562000223578686620001c586620001b0849a8862000362565b51161515620001be620002ae565b90620002f8565b85620001d2828762000362565b511684528287528a8420828b8254161790557fad3769ac0c1a91ee9dcf369f6d2989f91572b6f876933bbc82ab85f6b969a07a878762000213848962000362565b51168d51908152a101956200017d565b62000183565b634e487b7160e01b84526011600452602484fd5b81906200024a8462000299565b8152019101908690620000c0565b600080fd5b634e487b7160e01b600052604160045260246000fd5b6040519190601f01601f191682016001600160401b038111838210176200025d57604052565b51906001600160a01b03821682036200025857565b60408051919082016001600160401b038111838210176200025d57604052601482527f457363726f773a207a65726f20616464726573730000000000000000000000006020830152565b15620003015750565b6040519062461bcd60e51b82528160208060048301528251908160248401526000935b82851062000348575050604492506000838284010152601f80199101168101030190fd5b848101820151868601604401529381019385935062000324565b8051821015620003775760209160051b010190565b634e487b7160e01b600052603260045260246000fdfe608080604052600436101561001357600080fd5b60003560e01c9081630ae9dfad146122d3575080630f46c9aa146122425780630fb5a6b41461222457806312065fe01461220957806316eebd1e146121e0578063200d2ed2146121b6578063337f3f32146121255780633aecd0e3146120fa57806343aba9c21461206957806351cff8d914611f59578063522e117714611e8957806355bf1d6a146118ec578063697e4b871461166957806378c62420146116455780639753e4321461161c578063992d454d146115f35780639c48b102146115625780639eb262f31461142c578063a05220ad14611403578063a5aa542e146113e5578063b63d1a0014610bd4578063ba5fed3414610b0a578063bdd1daaa14610ae1578063c479bbf814610abd578063ea8a1af0146109ba578063f17171e91461097b578063f56679cf146101b9578063fad844c11461018c5763fc0c546a1461015e57600080fd5b34610187576000366003190112610187576007546040516001600160a01b039091168152602090f35b600080fd5b346101875760003660031901126101875760015460405160089190911c6001600160a01b03168152602090f35b3461018757610100366003190112610187576101d36123ac565b6024356001600160a01b038116810361018757604435906001600160a01b03821682036101875760ff60643516606435036101875760ff60843516608435036101875760ff60a4351660a435036101875760c4356001600160401b038111610187576102439036906004016124c4565b9160e4356001600160401b038111610187576102639036906004016124c4565b9333600052600e60205261027e60ff604060002054166125c7565b61028b600d544210612639565b6001600160a01b0381161561092c576001600160a01b038316156108e8576001600160a01b038216156108a357606460ff6102d460a4356102cf608435853561276f565b61276f565b1611610863576001549060ff8216600681101561084d576107fc57610100600160a81b031990911660089190911b610100600160a81b031617600155600280546001600160a01b03199081166001600160a01b039485161790915560038054909116919092161790556006805460843560a81b60ff60a81b1662ffffff60a01b1990911660643560a01b60ff60a01b16171760a43560b01b60ff60b01b161790558051906001600160401b0382116107085781906103936008546122f4565b601f81116107a1575b50602090601f83116001146107295760009261071e575b50508160011b916000199060031b1c1916176008555b80516001600160401b038111610708576103e46009546122f4565b601f81116106b9575b506020601f8211600114610651578192600092610646575b50508160011b916000199060031b1c1916176009555b600160ff19815416178060015561043061253b565b80600f5580156106085760025460035460405160a0815260085490926000926001600160a01b0390811692911690610467816122f4565b908160a087015260c0906001811690816000146105e8575060011461059d575b505083830360208501526000926009546104a0816122f4565b808352906001811690811561057b575060011461052d575b50600887901c6001600160a01b0316604086015260608501829052608085018390527f27b2dc149fd3048bc27eadaaf660801a04305c72845da74066a17b72d6c5bb666020877ff3bcd83b3ad174382a0f0ee29dcba2eee468d36f13021623af7de1539e26807488880389a1604051908152a1005b6009600090815291979450600080516020612b528339815191525b81831061056157509396016020908101935086906104b8565b6001816020929493945483858d0101520191019190610548565b60ff191660208481019190915291151560051b909201810194508791506104b8565b60086000908152929450909190600080516020612b328339815191525b8383106105d257505060c09150840101918680610487565b6001816020925484868b010152019201916105ba565b91505060c092945060ff191682860152151560051b840101918680610487565b60405162461bcd60e51b8152602060048201526016602482015275457363726f772062616c616e6365206973207a65726f60501b6044820152606490fd5b015190508280610405565b600960005260206000209060005b601f19841681106106a1575060019383601f19811610610688575b505050811b0160095561041b565b015160001960f88460031b161c1916905582808061067a565b9091602060018192858801518155019301910161065f565b6009600052600080516020612b52833981519152601f830160051c810160208410610701575b601f830160051c820181106106f55750506103ed565b600081556001016106df565b50806106df565b634e487b7160e01b600052604160045260246000fd5b0151905083806103b3565b600860009081529350600080516020612b3283398151915291905b601f1984168510610786576001945083601f1981161061076d575b505050811b016008556103c9565b015160001960f88460031b161c1916905583808061075f565b81810151835560209485019460019093019290910190610744565b6008600052909150600080516020612b32833981519152601f840160051c8101602085106107f5575b90849392915b601f830160051c820181106107e657505061039c565b600081558594506001016107d0565b50806107ca565b60405162461bcd60e51b815260206004820152602360248201527f457363726f77206e6f7420696e204c61756e636865642073746174757320737460448201526261746560e81b6064820152608490fd5b634e487b7160e01b600052602160045260246000fd5b60405162461bcd60e51b815260206004820152601860248201527750657263656e74616765206f7574206f6620626f756e647360401b6044820152606490fd5b60405162461bcd60e51b815260206004820152601f60248201527f496e76616c69642065786368616e6765206f7261636c652061646472657373006044820152606490fd5b606460405162461bcd60e51b815260206004820152602060248201527f496e76616c6964207265636f7264696e67206f7261636c6520616464726573736044820152fd5b60405162461bcd60e51b815260206004820152602160248201527f496e76616c69642072657075746174696f6e206f7261636c65206164647265736044820152607360f81b6064820152608490fd5b34610187576020366003190112610187576001600160a01b0361099c6123ac565b16600052600e602052602060ff604060002054166040519015158152f35b346101875760003660031901126101875733600052600e6020526109e560ff604060002054166125c7565b6109f2600f541515612678565b60ff60015416600681101561084d57600414610a7857610a1061294f565b600754600554600f54610a319290916001600160a01b039081169116612972565b600560ff1960015416176001556000600f5560206040517f63b958841f79ab97cb5456da181454b9932c0e15a3b17f1cbd27e2a8bc610437600080a1600160005560018152f35b60405162461bcd60e51b815260206004820152601f60248201527f457363726f7720696e20436f6d706c65746520737461747573207374617465006044820152606490fd5b3461018757600036600319011261018757602060ff60065460a01c16604051908152f35b34610187576000366003190112610187576006546040516001600160a01b039091168152602090f35b3461018757600036600319011261018757604051600a54600082610b2d836122f4565b9182825260209360019085600182169182600014610bb4575050600114610b74575b50610b5c92500383612349565b610b7060405192828493845283019061236c565b0390f35b849150600a60005281600020906000915b858310610b9c575050610b5c935082010185610b4f565b80548389018501528794508693909201918101610b85565b60ff191685820152610b5c95151560051b8501019250879150610b4f9050565b346101875760a0366003190112610187576004356001600160401b03811161018757610c049036906004016123d9565b6024356001600160401b03811161018757610c23903690600401612449565b906044356001600160401b03811161018757610c439036906004016124c4565b916064356001600160401b03811161018757610c639036906004016124c4565b9133600052600e60205260ff6040600020541680156113cb575b610c86906125c7565b610c93600f541515612678565b60ff60015416600681101561084d571561138657610cb4600d544210612639565b610cbc61294f565b805182510361132d578151156112ea576064815110156112af5760ff60015416600681101561084d57600481141590816112a3575b501561126d57600093600f54936000955b8451871015610d9757610d1587866126c2565b518015610d47578082018211610d315760019101960195610d02565b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b815260206004820152602260248201527f416d6f756e742073686f756c642062652067726561746572207468616e207a65604482015261726f60f01b6064820152608490fd5b93919294676765c793fa10079d601b1b851015611232578085116111f85784610dbf91612611565b92610dcc815115156126ec565b610dd88251151561272d565b8051906001600160401b038211610708578190610df6600b546122f4565b601f811161119d575b50602090601f83116001146111255760009261111a575b50508160011b916000199060031b1c191617600b555b8051906001600160401b038211610708578190610e4a600c546122f4565b601f81116110bf575b50602090601f83116001146110475760009261103c575b50508160011b916000199060031b1c191617600c555b60ff610ea860065482610e9d818360a81c16828460a01c1661276f565b9160b01c169061276f565b169160005b8551811015610f015780610efb87610ec7600194876126c2565b51610ef56064610ed7838b612783565b04868060a01b03610eed878260075416966126c2565b511692612611565b91612972565b01610ead565b85600080516020612b1283398151915284848860ff60065460a01c1680611011575b5060ff60065460a81c1680610fe9575b5060ff60065460b01c169081610fba575b505080600f5515600014610f9157610f7390600460ff19600154161760015560405191829160843595836128bd565b0390a2600080516020612af2833981519152600080a15b6001600055005b610fb290600260ff1960015416176001556040519182916084359583612828565b0390a2610f8a565b610fe2916064610fdb60018060a01b03938460075416946003541693612783565b0491612972565b8480610f44565b61100b9060018060a01b03906064610fdb858460075416946002541693612783565b85610f33565b6110369060018060a01b03906064610fdb8584600754169460015460081c1693612783565b85610f23565b015190508680610e6a565b600c60009081529350600080516020612ab283398151915291905b601f19841685106110a4576001945083601f1981161061108b575b505050811b01600c55610e80565b015160001960f88460031b161c1916905586808061107d565b81810151835560209485019460019093019290910190611062565b600c600052909150600080516020612ab2833981519152601f840160051c810160208510611113575b90849392915b601f830160051c82018110611104575050610e53565b600081558594506001016110ee565b50806110e8565b015190508780610e16565b600b60009081529350600080516020612b7283398151915291905b601f1984168510611182576001945083601f19811610611169575b505050811b01600b55610e2c565b015160001960f88460031b161c1916905587808061115b565b81810151835560209485019460019093019290910190611140565b600b600052909150600080516020612b72833981519152601f840160051c8101602085106111f1575b90849392915b601f830160051c820181106111e2575050610dff565b600081558594506001016111cc565b50806111c6565b60405162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f7567682062616c616e636560701b6044820152606490fd5b60405162461bcd60e51b8152602060048201526013602482015272084ead8d640ecc2d8eaca40e8dede40d0d2ced606b1b6044820152606490fd5b60405162461bcd60e51b815260206004820152600e60248201526d496e76616c69642073746174757360901b6044820152606490fd5b60059150141585610cf1565b60405162461bcd60e51b8152602060048201526013602482015272546f6f206d616e7920726563697069656e747360681b6044820152606490fd5b60405162461bcd60e51b815260206004820152601b60248201527a416d6f756e74732073686f756c64206e6f7420626520656d70747960281b6044820152606490fd5b60405162461bcd60e51b815260206004820152602b60248201527f416d6f756e74206f6620726563697069656e747320616e642076616c7565732060448201526a0c8dedc4ee840dac2e8c6d60ab1b6064820152608490fd5b60405162461bcd60e51b815260206004820152601f60248201527f457363726f7720696e204c61756e6368656420737461747573207374617465006044820152606490fd5b506001543360089190911c6001600160a01b031614610c7d565b34610187576000366003190112610187576020600f54604051908152f35b34610187576000366003190112610187576003546040516001600160a01b039091168152602090f35b3461018757602080600319360112610187576001600160401b03906004358281116101875761145f9036906004016123d9565b9133600052600e92600e835261147c60ff604060002054166125c7565b60005b8151811015611560576001600160a01b038061149b83856126c2565b511615604051906040820182811087821117610708576040526014825273457363726f773a207a65726f206164647265737360601b8783015261153a5750907fad3769ac0c1a91ee9dcf369f6d2989f91572b6f876933bbc82ab85f6b969a07a858360019461150a85886126c2565b511660005288825260406000208560ff1982541617905561152b84876126c2565b5116604051908152a10161147f565b8561155c60405192839262461bcd60e51b84526004840152602483019061236c565b0390fd5b005b3461018757600036600319011261018757604051600854600082611585836122f4565b9182825260209360019085600182169182600014610bb45750506001146115b35750610b5c92500383612349565b849150600860005281600020906000915b8583106115db575050610b5c935082010185610b4f565b805483890185015287945086939092019181016115c4565b34610187576000366003190112610187576005546040516001600160a01b039091168152602090f35b34610187576000366003190112610187576002546040516001600160a01b039091168152602090f35b3461018757600036600319011261018757602060ff60065460a81c16604051908152f35b34610187576040366003190112610187576001600160401b036004358181116101875761169a9036906004016124c4565b602435828111610187576116b29036906004016124c4565b33600052602090600e825260ff6040600020541680156118d8575b6116d6906125c7565b6116e3600d544210612639565b600160ff815416600681101561084d578181149081156118cd575b501561187257611710845115156126ec565b61171c8251151561272d565b835194851161070857611730600a546122f4565b601f8111611828575b5082601f86116001146117ae57918580600080516020612a928339815191529761179197969461179e966000936117a3575b501b916000199060031b1c191617600a555b60405194859460408652604086019061236c565b918483039085015261236c565b0390a1005b88015192508a61176b565b601f19861690600a600052846000209160005b81811061181357509661179e94926117919796949282600080516020612a928339815191529a106117fa575b5050811b01600a5561177d565b87015160001960f88460031b161c1916905588806117ed565b878301518455928401929186019186016117c1565b600a60005283600020601f870160051c810191858810611868575b601f0160051c019082905b82811061185c575050611739565b6000815501829061184e565b9091508190611843565b60405162461bcd60e51b815260048101849052602d60248201527f457363726f77206e6f7420696e2050656e64696e67206f72205061727469616c60448201526c2073746174757320737461746560981b6064820152608490fd5b6002915014866116fe565b506002546001600160a01b031633146116cd565b346101875760c0366003190112610187576004356001600160401b0381116101875761191c9036906004016123d9565b6024356001600160401b0381116101875761193b903690600401612449565b906044356001600160401b0381116101875761195b9036906004016124c4565b916064356001600160401b0381116101875761197b9036906004016124c4565b9160a435151560a435036101875733600052600e60205260ff604060002054168015611e6f575b6119ab906125c7565b6119b8600f541515612678565b60ff60015416600681101561084d5715611386576119d9600d544210612639565b6119e161294f565b805182510361132d578151156112ea576064815110156112af5760ff60015416600681101561084d5760048114159081611e63575b501561126d57600093600f54936000955b8451871015611a5657611a3a87866126c2565b518015610d47578082018211610d315760019101960195611a27565b93919294676765c793fa10079d601b1b851015611232578085116111f85784611a7e91612611565b92611a8b815115156126ec565b611a978251151561272d565b8051906001600160401b038211610708578190611ab5600b546122f4565b601f8111611e08575b50602090601f8311600114611d9057600092611d85575b50508160011b916000199060031b1c191617600b555b8051906001600160401b038211610708578190611b09600c546122f4565b601f8111611d2a575b50602090601f8311600114611cb257600092611ca7575b50508160011b916000199060031b1c191617600c555b60ff611b5c60065482610e9d818360a81c16828460a01c1661276f565b169160005b8551811015611b815780611b7b87610ec7600194876126c2565b01611b61565b85600080516020612b1283398151915284848860ff60065460a01c1680611c7c575b5060ff60065460a81c1680611c54575b5060ff60065460b01c169081611c2c575b505080600f5560a43560a435611c23575b611bff575b610f9157610f7390600460ff19600154161760015560405191829160843595836128bd565b600754600454611c1c92916001600160a01b039182169116612972565b6000611bda565b50801515611bd5565b611c4d916064610fdb60018060a01b03938460075416946003541693612783565b8480611bc4565b611c769060018060a01b03906064610fdb858460075416946002541693612783565b85611bb3565b611ca19060018060a01b03906064610fdb8584600754169460015460081c1693612783565b85611ba3565b015190508680611b29565b600c60009081529350600080516020612ab283398151915291905b601f1984168510611d0f576001945083601f19811610611cf6575b505050811b01600c55611b3f565b015160001960f88460031b161c19169055868080611ce8565b81810151835560209485019460019093019290910190611ccd565b600c600052909150600080516020612ab2833981519152601f840160051c810160208510611d7e575b90849392915b601f830160051c82018110611d6f575050611b12565b60008155859450600101611d59565b5080611d53565b015190508780611ad5565b600b60009081529350600080516020612b7283398151915291905b601f1984168510611ded576001945083601f19811610611dd4575b505050811b01600b55611aeb565b015160001960f88460031b161c19169055878080611dc6565b81810151835560209485019460019093019290910190611dab565b600b600052909150600080516020612b72833981519152601f840160051c810160208510611e5c575b90849392915b601f830160051c82018110611e4d575050611abe565b60008155859450600101611e37565b5080611e31565b60059150141585611a16565b506001543360089190911c6001600160a01b0316146119a2565b3461018757600036600319011261018757611ea7600d544210612639565b33600052600e60205260ff604060002054168015611f3f575b611ec9906125c7565b60015460ff8116600681101561084d57600303611eff5760ff1916600417600155600080516020612af2833981519152600080a1005b60405162461bcd60e51b8152602060048201526018602482015277457363726f77206e6f7420696e205061696420737461746560401b6044820152606490fd5b506001543360089190911c6001600160a01b031614611ec0565b3461018757602036600319011261018757611f726123ac565b33600052600e602052611f8c60ff604060002054166125c7565b611f9461294f565b6007546001600160a01b03908282169082160361204657611fb361253b565b91600f548084111561200a57611fdb611fe891600080516020612ad283398151915295612611565b80935b6005541683612972565b611ff76040519283928361261e565b0390a16001600055602060405160018152f35b60405162461bcd60e51b81526020600482015260146024820152734e6f2066756e647320746f20776974686472617760601b6044820152606490fd5b81611fe8612062600080516020612ad2833981519152946125a2565b8093611fde565b3461018757600036600319011261018757604051600b5460008261208c836122f4565b9182825260209360019085600182169182600014610bb45750506001146120ba5750610b5c92500383612349565b849150600b60005281600020906000915b8583106120e2575050610b5c935082010185610b4f565b805483890185015287945086939092019181016120cb565b3461018757602036600319011261018757602061211d6121186123ac565b6125a2565b604051908152f35b3461018757600036600319011261018757604051600954600082612148836122f4565b9182825260209360019085600182169182600014610bb45750506001146121765750610b5c92500383612349565b849150600960005281600020906000915b85831061219e575050610b5c935082010185610b4f565b80548389018501528794508693909201918101612187565b346101875760003660031901126101875760ff60015416604051600682101561084d576020918152f35b34610187576000366003190112610187576004546040516001600160a01b039091168152602090f35b3461018757600036600319011261018757602061211d61253b565b34610187576000366003190112610187576020600d54604051908152f35b3461018757600036600319011261018757604051600c54600082612265836122f4565b9182825260209360019085600182169182600014610bb45750506001146122935750610b5c92500383612349565b849150600c60005281600020906000915b8583106122bb575050610b5c935082010185610b4f565b805483890185015287945086939092019181016122a4565b346101875760003660031901126101875760209060ff60065460b01c168152f35b90600182811c92168015612324575b602083101461230e57565b634e487b7160e01b600052602260045260246000fd5b91607f1691612303565b606081019081106001600160401b0382111761070857604052565b601f909101601f19168101906001600160401b0382119082101761070857604052565b919082519283825260005b848110612398575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201612377565b600435906001600160a01b038216820361018757565b6001600160401b0381116107085760051b60200190565b9080601f830112156101875760209082356123f3816123c2565b936124016040519586612349565b81855260208086019260051b82010192831161018757602001905b82821061242a575050505090565b81356001600160a01b038116810361018757815290830190830161241c565b9080601f83011215610187576020908235612463816123c2565b936124716040519586612349565b81855260208086019260051b82010192831161018757602001905b82821061249a575050505090565b8135815290830190830161248c565b6001600160401b03811161070857601f01601f191660200190565b81601f82011215610187578035906124db826124a9565b926124e96040519485612349565b8284526020838301011161018757816000926020809301838601378301015290565b3d15612536573d9061251c826124a9565b9161252a6040519384612349565b82523d6000602084013e565b606090565b60018060a01b036007541660405160208101906370a0823160e01b82523060248201526024815261256b8161232e565b6000928392839251915afa9061257f61250b565b911561259d5760208280518101031261259a57506020015190565b80fd5b905090565b60405160208101906370a0823160e01b82523060248201526024815261256b8161232e565b156125ce57565b60405162461bcd60e51b815260206004820152601b60248201527a1059191c995cdcc818d85b1b1a5b99c81b9bdd081d1c9d5cdd1959602a1b6044820152606490fd5b91908203918211610d3157565b6001600160a01b039091168152602081019190915260400190565b1561264057565b60405162461bcd60e51b815260206004820152601060248201526f10dbdb9d1c9858dd08195e1c1a5c995960821b6044820152606490fd5b1561267f57565b60405162461bcd60e51b815260206004820152601b60248201527a546f6b656e20636f6e7472616374206f7574206f662066756e647360281b6044820152606490fd5b80518210156126d65760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b156126f357565b60405162461bcd60e51b815260206004820152601260248201527155524c2063616e277420626520656d70747960701b6044820152606490fd5b1561273457565b60405162461bcd60e51b8152602060048201526013602482015272486173682063616e277420626520656d70747960681b6044820152606490fd5b9060ff8091169116019060ff8211610d3157565b81810292918115918404141715610d3157565b600b54600092916127a6826122f4565b9081815260209260019060018116908160001461280b57506001146127cc575b50505050565b9293945090600b6000528360002092846000945b8386106127f75750505050010190388080806127c6565b8054858701830152940193859082016127e0565b60ff191685840152505090151560051b01019150388080806127c6565b9190916080810160808252835180915260a082019060208095019060005b8181106128a0575050508181038483015283808451928381520193019360005b82811061288c575050506128899250600160408201526060818303910152612796565b90565b855185529481019493810193600101612866565b82516001600160a01b031684529286019291860191600101612846565b9190916080810160808252835180915260a082019060208095019060005b818110612932575050508181038483015283808451928381520193019360005b82811061291e575050506128899250600060408201526060818303910152612796565b8551855294810194938101936001016128fb565b82516001600160a01b0316845292860192918601916001016128db565b600260005414612960576002600055565b604051633ee5aeb560e01b8152600490fd5b60405163a9059cbb60e01b602082019081526001600160a01b039092169391926129d2926129b79183916129a9916024840161261e565b03601f198101835282612349565b600080938192519082875af16129cb61250b565b9084612a2e565b908151918215159283612a02575b5050506129ea5750565b60249060405190635274afe760e01b82526004820152fd5b819293509060209181010312612a2a57602001519081159182150361259a57503880806129e0565b5080fd5b90612a555750805115612a4357805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580612a88575b612a66575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15612a5e56feb20e0717219840fd5684a80bec782e8babb56ea224f677561b791a61192605c1df6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364e06452d00b2b58f14a1fa6d499ea982ff93ea827ae700ea9ba03f4daddc94bc145295fd5fffd2a8a91e1749ac8112d9807fa2c615cc8426558f23d1d71822708f3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee36e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9a26469706673582212208ca6660ae1066fdde17894c7f25d7d2fae6fabf834579e45e97eb7ef40786df964736f6c634300081700334910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd914346756e6374696f6e206d7573742062652063616c6c6564207468726f75676820360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0bc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b45524331393637557067726164653a20756e737570706f727465642070726f78416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c45524331393637557067726164653a206e657720696d706c656d656e74617469a2646970667358221220cf1a3fc6d69123504a9d0c7d69a790151da664196a2f25fd07d5d8dbd0e9f7ad64736f6c63430008170033
Loading...
Loading
Loading...
Loading
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.