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.6.2; 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; event Launched(address token, address escrow); event LaunchedV2(address token, address escrow, string jobRequesterId); /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize(address _staking) external payable virtual initializer { __Ownable_init_unchained(); __EscrowFactory_init_unchained(_staking); } function __EscrowFactory_init_unchained( address _staking ) internal onlyInitializing { require(_staking != address(0), ERROR_ZERO_ADDRESS); staking = _staking; } function createEscrow( address token, address[] memory trustedHandlers, string memory jobRequesterId ) public returns (address) { bool hasAvailableStake = IStaking(staking).hasAvailableStake( msg.sender ); require( hasAvailableStake == true, 'Needs to stake HMT tokens 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) public view returns (bool) { return escrowCounters[_address] != 0; } // solhint-disable-next-line no-empty-blocks 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[46] 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 v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @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; 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 require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @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 v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../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 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.encodeWithSelector(token.transfer.selector, 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.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 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); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @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.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @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, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @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.isContract(address(token)); } }
// 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 Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * 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 pragma solidity >=0.6.2; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; import '@openzeppelin/contracts/security/ReentrancyGuard.sol'; import './interfaces/IEscrow.sol'; import './utils/SafeMath.sol'; contract Escrow is IEscrow, ReentrancyGuard { using SafeMath for uint256; 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 BulkTransfer( uint256 indexed _txId, address[] _recipients, uint256[] _amounts, bool _isPartial ); event Cancelled(); event Completed(); 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; 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.add(block.timestamp); // solhint-disable-line not-rely-on-time 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)) ); if (success) { return abi.decode(returnData, (uint256)); } return 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 = uint256(_reputationOracleFeePercentage) + uint256(_recordingOracleFeePercentage) + uint256(_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; emit Pending(manifestUrl, manifestHash); } function abort() external override trusted notComplete notPaid { if (getBalance() != 0) { cancel(); } selfdestruct(canceler); } function cancel() public override trusted notBroke notComplete notPaid nonReentrant returns (bool) { _safeTransfer(canceler, getBalance()); status = EscrowStatuses.Cancelled; emit Cancelled(); return true; } 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 complted / 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 */ function bulkPayOut( address[] memory _recipients, uint256[] memory _amounts, string memory _url, string memory _hash, uint256 _txId ) external override trustedOrReputationOracle notBroke notLaunched notPaid 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 balance = getBalance(); uint256 aggregatedBulkAmount = 0; for (uint256 i; i < _amounts.length; i++) { require(_amounts[i] > 0, 'Amount should be greater than zero'); aggregatedBulkAmount = aggregatedBulkAmount.add(_amounts[i]); } require(aggregatedBulkAmount < BULK_MAX_VALUE, 'Bulk value too high'); require(aggregatedBulkAmount <= balance, 'Not enough balance'); 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[] memory finalAmounts, uint256 reputationOracleFee, uint256 recordingOracleFee, uint256 exchangeOracleFee ) = finalizePayouts(_amounts); for (uint256 i = 0; i < _recipients.length; ++i) { if (finalAmounts[i] > 0) { _safeTransfer(_recipients[i], finalAmounts[i]); } } if (reputationOracleFee > 0) { _safeTransfer(reputationOracle, reputationOracleFee); } if (recordingOracleFee > 0) { _safeTransfer(recordingOracle, recordingOracleFee); } if (exchangeOracleFee > 0) { _safeTransfer(exchangeOracle, exchangeOracleFee); } balance = getBalance(); bool isPartial; if (balance == 0) { status = EscrowStatuses.Paid; isPartial = false; } else { status = EscrowStatuses.Partial; isPartial = true; } emit BulkTransfer(_txId, _recipients, finalAmounts, isPartial); } function finalizePayouts( uint256[] memory _amounts ) internal view returns (uint256[] memory, uint256, uint256, uint256) { uint256[] memory finalAmounts = new uint256[](_amounts.length); uint256 reputationOracleFee = 0; uint256 recordingOracleFee = 0; uint256 exchangeOracleFee = 0; for (uint256 j; j < _amounts.length; j++) { uint256 amount = _amounts[j]; uint256 amountFee = 0; { uint256 singleReputationOracleFee = uint256( reputationOracleFeePercentage ).mul(amount).div(100); reputationOracleFee = reputationOracleFee.add( singleReputationOracleFee ); amountFee = amountFee.add(singleReputationOracleFee); } { uint256 singleRecordingOracleFee = uint256( recordingOracleFeePercentage ).mul(_amounts[j]).div(100); recordingOracleFee = recordingOracleFee.add( singleRecordingOracleFee ); amountFee = amountFee.add(singleRecordingOracleFee); } { uint256 singleExchangeOracleFee = uint256( exchangeOracleFeePercentage ).mul(_amounts[j]).div(100); exchangeOracleFee = exchangeOracleFee.add( singleExchangeOracleFee ); amountFee = amountFee.add(singleExchangeOracleFee); } finalAmounts[j] = amount.sub(amountFee); } return ( finalAmounts, reputationOracleFee, recordingOracleFee, exchangeOracleFee ); } function _safeTransfer(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(getBalance() != 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'); // solhint-disable-line not-rely-on-time _; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2; 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 abort() external; function cancel() 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 ) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2; import '../libs/Stakes.sol'; interface IStaking { /** * @dev Possible states an allocation can be * States: * - Null = Staker == address(0) * - Pending = not Null && tokens > 0 && escrowAddress status == Pending * - Active = Pending && escrowAddress status == Launched * - Closed = Active && closedAt != 0 * - Completed = Closed && closedAt && escrowAddress status == Complete */ enum AllocationState { Null, Pending, Active, Closed, Completed } /** * @dev Possible sort fields * Fields: * - None = Do not sort * - Stake = Sort by stake amount */ enum SortField { None, Stake } /** * @dev Allocate HMT tokens for the purpose of serving queries of a subgraph deployment * An allocation is created in the allocate() function and consumed in claim() */ struct Allocation { address escrowAddress; address staker; uint256 tokens; // Tokens allocated to a escrowAddress uint256 createdAt; // Time when allocation was created uint256 closedAt; // Time when allocation was closed } function rewardPool() external view returns (address); function setMinimumStake(uint256 _minimumStake) external; function setLockPeriod(uint32 _lockPeriod) external; function setRewardPool(address _rewardPool) external; function isAllocation(address _escrowAddress) external view returns (bool); function hasStake(address _indexer) external view returns (bool); function hasAvailableStake(address _indexer) external view returns (bool); function getAllocation( address _escrowAddress ) external view returns (Allocation memory); function getAllocationState( address _escrowAddress ) external view returns (AllocationState); function getStakedTokens(address _staker) external view returns (uint256); function getStaker( address _staker ) external view returns (Stakes.Staker memory); 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 allocate(address escrowAddress, uint256 _tokens) external; function closeAllocation(address _escrowAddress) external; function getListOfStakers() external view returns (address[] memory, Stakes.Staker[] memory); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2; import '../utils/SafeMath.sol'; import '../utils/Math.sol'; /** * @title Structures, methods and data are available to manage the staker state. */ library Stakes { using SafeMath for uint256; using Stakes for Stakes.Staker; struct Staker { uint256 tokensStaked; // Tokens staked by the Staker uint256 tokensAllocated; // Tokens allocated for jobs 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 = stake.tokensStaked.add(_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 = stake.tokensStaked.sub(_tokens); } /** * @dev Add tokens from the main stack to tokensAllocated. * @param stake Staker struct * @param _tokens Amount of tokens to allocate */ function allocate(Stakes.Staker storage stake, uint256 _tokens) internal { stake.tokensAllocated = stake.tokensAllocated.add(_tokens); } /** * @dev Unallocate tokens from a escrowAddress back to the main stack. * @param stake Staker struct * @param _tokens Amount of tokens to unallocate */ function unallocate(Stakes.Staker storage stake, uint256 _tokens) internal { stake.tokensAllocated = stake.tokensAllocated.sub(_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 { uint256 lockingPeriod = _period; if (stake.tokensLocked > 0) { lockingPeriod = Math.weightedAverage( Math.diffOrZero(stake.tokensLockedUntil, block.number), // Remaining lock period stake.tokensLocked, _period, _tokens ); } stake.tokensLocked = stake.tokensLocked.add(_tokens); stake.tokensLockedUntil = block.number.add(lockingPeriod); } /** * @dev Unlock tokens. * @param stake Staker struct * @param _tokens Amount of tokens to unkock */ function unlockTokens( Stakes.Staker storage stake, uint256 _tokens ) internal { stake.tokensLocked = stake.tokensLocked.sub(_tokens); if (stake.tokensLocked == 0) { 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 = stake.tokensWithdrawable(); if (tokensToWithdraw > 0) { stake.unlockTokens(tokensToWithdraw); stake.release(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.sub(stake.tokensUsed()); } /** * @dev Return all tokens used in allocations and locked for withdrawal. * @param stake Staker struct * @return Token amount */ function tokensUsed( Stakes.Staker memory stake ) internal pure returns (uint256) { return stake.tokensAllocated.add(stake.tokensLocked); } /** * @dev Return the amount of tokens staked which are not locked. * @param stake Staker struct * @return Token amount */ function tokensSecureStake( Stakes.Staker memory stake ) internal pure returns (uint256) { return stake.tokensStaked.sub(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; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2; import './SafeMath.sol'; /** * @title Math Library * @notice A collection of functions to perform math operations */ library Math { using SafeMath for uint256; enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Calculates the weighted average of two values pondering each of these * values based on configured weights. The contribution of each value N is * weightN/(weightA + weightB). * @param valueA The amount for value A * @param weightA The weight to use for value A * @param valueB The amount for value B * @param weightB The weight to use for value B */ function weightedAverage( uint256 valueA, uint256 weightA, uint256 valueB, uint256 weightB ) internal pure returns (uint256) { return valueA.mul(weightA).add(valueB.mul(weightB)).div( weightA.add(weightB) ); } /** * @dev Returns the difference between two numbers or zero if negative. */ function diffOrZero(uint256 x, uint256 y) internal pure returns (uint256) { return (x > y) ? x.sub(y) : 0; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10( uint256 value, Rounding rounding ) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256( uint256 value, Rounding rounding ) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, 'SafeMath: addition overflow'); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, 'SafeMath: subtraction overflow'); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, 'SafeMath: multiplication overflow'); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, 'SafeMath: division by zero'); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, 'SafeMath: modulo by zero'); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
{ "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":"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"}],"name":"initialize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"lastEscrow","outputs":[{"internalType":"address","name":"","type":"address"}],"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":[],"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
60a080604052346100dc57306080526000549060ff8260081c1661008a575060ff8082160361004f575b604051613c0b90816100e282396080518181816107ac015281816108ac0152610b7a0152f35b60ff90811916176000557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160ff8152a138610029565b62461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b6064820152608490fd5b600080fdfe604060808152600490813610156200001657600080fd5b600091823560e01c80633659cfe61462000b4f5780633cc3e58d1462000b245780634cf088d91462000af95780634f1ef286146200085657806352d1902d146200079557806358d276f7146200075757806361bc221a1462000736578063715018a614620006e65780637e59879714620003c15780638da5cb5b1462000396578063979530e61462000356578063c4d66de8146200015b5763f2fde38b14620000be57600080fd5b34620001575760203660031901126200015757620000db62000dda565b91620000e662000f88565b6001600160a01b03831615620001055783620001028462000fe1565b80f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b8280fd5b50602036600319011262000157576200017362000dda565b9083549060ff8260081c16159182809362000348575b80156200032f575b15620002d55760ff198116600117865582620002c3575b50620001bb60ff865460081c1662001019565b620001c63362000fe1565b845492620001da60ff8560081c1662001019565b84516001600160a01b039190911691908086016001600160401b03811182821017620002b0578652601b81527a457363726f77466163746f72793a205a65726f204164647265737360281b602082015282156200028857505060cc80546001600160a01b03191691909117905562000250578280f35b61ff001916825551600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602090a138808280f35b90620002ac602092875193849362461bcd60e51b8552840152602483019062000f46565b0390fd5b634e487b7160e01b885260418352602488fd5b61ffff191661010117855538620001a8565b845162461bcd60e51b8152602081840152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b50303b158015620001915750600160ff82161462000191565b50600160ff82161062000189565b50503462000392576020366003190112620003925760209181906001600160a01b036200038262000dda565b16815260ca845220549051908152f35b5080fd5b505034620003925781600319360112620003925760335490516001600160a01b039091168152602090f35b508234620006e3576060366003190112620006e357620003e062000dda565b6001600160401b039360248035949192868611620006df5736602387011215620006df578583013592878411620006cd578360051b936020978651916200042a8a88018462000e28565b8252888201858197830101913683116200068e578601905b828210620006a857505050604435898111620006a45736602382011215620006a457620004789036908681860135910162000e68565b948460018060a01b03948a8660cc54168a5193848092630d7cb1d560e11b8252338a8301525afa9182156200069a578a9262000657575b5060018092151503620005fe5788519361292a808601809e878210911117620005ec578c9d8695949260c0929e9b9c9d9e620011ac88398960a0830195169b8c835233908301528d33908301526283d600606083015260a06080830152518094520192918d8d905b828210620005d2575050505050039088f0928315620005c85760c954916000198314620005b757505060010160c9819055911680865260ca8752948490205560cb80546001600160a01b03191685179055825190815280850184905260608184018190527fde4a6895269de599430e1230956361cbe11b52ad149311a97123c73666c52141928291620005ae919083019062000f46565b0390a151908152f35b634e487b7160e01b89526011905287fd5b86513d89823e3d90fd5b84518a168652879650948501949093019282018e62000517565b634e487b7160e01b8c5260418752888cfd5b885162461bcd60e51b81528086018c9052602e818901527f4e6565647320746f207374616b6520484d5420746f6b656e7320746f2063726560448201526d30ba329030b71032b9b1b937bb9760911b6064820152608490fd5b9091508a81813d831162000692575b62000672818362000e28565b810103126200068e575180151581036200068e57908c620004af565b8980fd5b503d62000666565b89513d8c823e3d90fd5b8780fd5b81356001600160a01b0381168103620006c9578152908a01908a0162000442565b8a80fd5b634e487b7160e01b8652604190528185fd5b8480fd5b80fd5b8334620006e35780600319360112620006e3576200070362000f88565b603380546001600160a01b0319811690915581906001600160a01b031660008051602062003b368339815191528280a380f35b505034620003925781600319360112620003925760209060c9549051908152f35b50503462000392576020366003190112620003925760209181906001600160a01b036200078362000dda565b16815260ca8452205415159051908152f35b508234620006e35780600319360112620006e357507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003620007f3576020825160008051602062003b168339815191528152f35b6020608492519162461bcd60e51b8352820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b6064820152fd5b50908060031936011262000157576200086e62000dda565b906024356001600160401b038111620006df5736602382011215620006df57620008a2903690602481870135910162000e68565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116929190620008de3085141562000ea4565b620008fe60008051602062003b1683398151915294828654161462000ef5565b6200090862000f88565b60008051602062003ad68339815191525460ff16156200093257505050506200010291506200107a565b82516352d1902d60e01b81526020959394918416919086818981865afa89918162000ac4575b50620009a757855162461bcd60e51b8152808901889052602e602482015260008051602062003bb683398151915260448201526d6f6e206973206e6f74205555505360901b6064820152608490fd5b969192959493960362000a805750620009c0856200107a565b60008051602062003b568339815191528680a282511580159062000a77575b620009ec575b5050505080f35b62000a6193858083519562000a018762000df6565b6027875260008051602062003b9683398151915286880152660819985a5b195960ca1b858801528581519101845af4913d1562000a6c573d62000a5262000a488262000e4c565b9251928362000e28565b81528681943d92013e6200110c565b5038808080620009e5565b50606092506200110c565b506001620009df565b825162461bcd60e51b81529081018490526029602482015260008051602062003b768339815191526044820152681a58589b195555525160ba1b6064820152608490fd5b9091508781813d831162000af1575b62000adf818362000e28565b810103126200068e5751903862000958565b503d62000ad3565b505034620003925781600319360112620003925760cc5490516001600160a01b039091168152602090f35b505034620003925781600319360112620003925760cb5490516001600160a01b039091168152602090f35b509034620001575760208060031936011262000dd65762000b6f62000dda565b916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811662000ba93082141562000ea4565b62000bc960008051602062003b1683398151915291838354161462000ef5565b62000bd362000f88565b8251848101929091906001600160401b0384118385101762000dc35783855288835260008051602062003ad68339815191525460ff161562000c21575050505050506200010291506200107a565b869293949596169085516352d1902d60e01b815287818a81865afa8a918162000d8e575b5062000c9457865162461bcd60e51b8152808a01899052602e602482015260008051602062003bb683398151915260448201526d6f6e206973206e6f74205555505360901b6064820152608490fd5b97919293969594970362000d4a575062000cae826200107a565b60008051602062003b568339815191528780a28584511580159062000d42575b62000cdd575b50505050505080f35b8062000d359684519662000cf18862000df6565b6027885260008051602062003b9683398151915287890152660819985a5b195960ca1b868901525190845af4913d1562000a6c573d62000a5262000a488262000e4c565b5038808080808562000cd4565b508062000cce565b835162461bcd60e51b81529081018590526029602482015260008051602062003b768339815191526044820152681a58589b195555525160ba1b6064820152608490fd5b9091508881813d831162000dbb575b62000da9818362000e28565b81010312620006c95751903862000c45565b503d62000d9d565b634e487b7160e01b895260418852602489fd5b8380fd5b600435906001600160a01b038216820362000df157565b600080fd5b606081019081106001600160401b0382111762000e1257604052565b634e487b7160e01b600052604160045260246000fd5b601f909101601f19168101906001600160401b0382119082101762000e1257604052565b6001600160401b03811162000e1257601f01601f191660200190565b92919262000e768262000e4c565b9162000e86604051938462000e28565b82948184528183011162000df1578281602093846000960137010152565b1562000eac57565b60405162461bcd60e51b815260206004820152602c602482015260008051602062003af683398151915260448201526b19195b1959d85d1958d85b1b60a21b6064820152608490fd5b1562000efd57565b60405162461bcd60e51b815260206004820152602c602482015260008051602062003af683398151915260448201526b6163746976652070726f787960a01b6064820152608490fd5b919082519283825260005b84811062000f73575050826000602080949584010152601f8019910116010190565b60208183018101518483018201520162000f51565b6033546001600160a01b0316330362000f9d57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b603380546001600160a01b039283166001600160a01b03198216811790925590911660008051602062003b36833981519152600080a3565b156200102157565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b803b15620010b15760008051602062003b1683398151915280546001600160a01b0319166001600160a01b03909216919091179055565b60405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b9192901562001171575081511562001122575090565b3b156200112c5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015620011855750805190602001fd5b60405162461bcd60e51b815260206004820152908190620002ac90602483019062000f4656fe60406080815234620002a4576200292a90813803806200001f81620002bf565b938439820160a083820312620002a4576200003a83620002e5565b9260206200004a818301620002e5565b94848301519260018060a01b0391828516809503620002a457606082015195608083015160018060401b0393848211620002a4570181601f82011215620002a4578051938411620002a9578360051b908680620000a9818501620002bf565b809781520192820101928311620002a45786809101915b8383106200028957505050506001948360009287845516620000ee620000e5620002fa565b82151562000344565b62000105620000fc620002fa565b83151562000344565b600780546001600160a01b03199081169092179055865460ff19908116885597428101908181116200027557811062000231578798999a8691600d5516908181600454161760045582816005541617600555339060065416176006558252600e90600e8652898320878a8254161790558252888220868982541617905581955b6200019a575b88516125509081620003da8239f35b82518610156200022b578686620001cd86620001b8849a88620003ae565b51161515620001c6620002fa565b9062000344565b85620001da8287620003ae565b511684528287528a8420828b8254161790557fad3769ac0c1a91ee9dcf369f6d2989f91572b6f876933bbc82ab85f6b969a07a87876200021b8489620003ae565b51168d51908152a1019562000185565b6200018b565b895162461bcd60e51b815260048101889052601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606490fd5b634e487b7160e01b85526011600452602485fd5b81906200029684620002e5565b8152019101908690620000c0565b600080fd5b634e487b7160e01b600052604160045260246000fd5b6040519190601f01601f191682016001600160401b03811183821017620002a957604052565b51906001600160a01b0382168203620002a457565b60408051919082016001600160401b03811183821017620002a957604052601482527f457363726f773a207a65726f20616464726573730000000000000000000000006020830152565b156200034d5750565b6040519062461bcd60e51b82528160208060048301528251908160248401526000935b82851062000394575050604492506000838284010152601f80199101168101030190fd5b848101820151868601604401529381019385935062000370565b8051821015620003c35760209160051b010190565b634e487b7160e01b600052603260045260246000fdfe608080604052600436101561001357600080fd5b60003560e01c9081630ae9dfad14611c5e575080630f46c9aa14611bcd5780630fb5a6b414611baf57806312065fe014611b8c57806316eebd1e14611b63578063200d2ed214611b39578063337f3f3214611aa857806335a063b414611a2b57806343aba9c21461199a578063522e1177146118b8578063697e4b871461163557806378c62420146116115780639753e432146115e8578063992d454d146115bf5780639c48b1021461152e5780639eb262f314611425578063a05220ad146113fc578063b63d1a00146109f6578063ba5fed341461092c578063bdd1daaa14610903578063c479bbf8146108df578063ea8a1af0146108ba578063f17171e91461087b578063f56679cf14610198578063fad844c11461016b5763fc0c546a1461013d57600080fd5b34610166576000366003190112610166576007546040516001600160a01b039091168152602090f35b600080fd5b346101665760003660031901126101665760015460405160089190911c6001600160a01b03168152602090f35b3461016657610100366003190112610166576101b2611db0565b602435906001600160a01b038216820361016657604435906001600160a01b03821682036101665760ff60643516606435036101665760ff60843516608435036101665760ff60a4351660a435036101665760c4356001600160401b03811161016657610223903690600401611d52565b906001600160401b0360e43511610166576102433660e435600401611d52565b9233600052600e60205261025e60ff60406000205416611edf565b61026b600d544210611fbf565b6001600160a01b0382161561082c576001600160a01b038516156107e8576001600160a01b038116156107a35760646102bb60ff60a435166102b660ff6084351660ff8535166121ab565b6121ab565b1161076357600194855460ff8116600681101561074d576106fc57610100600160a81b031916600893841b610100600160a81b0316178655600280546001600160a01b03199081166001600160a01b039384161790915560038054909116929091169190911781556006805460843560a81b60ff60a81b1662ffffff60a01b1990911660643560a01b60ff60a01b16171760a43560b01b60ff60b01b1617905582516001600160401b03811161062557806103768454611c7f565b94601f958681116106a9575b506020908683116001146106465760009261063b575b505060001982841b1c191690861b1782555b8351906001600160401b038211610625576009936103c88554611c7f565b958187116105dc575b839495965060209184116001146105755760009361056a575b505082861b92600019911b1c19161782555b60ff199083828154161784556040519360408552600091805461041e81611c7f565b9182604089015260609186858216918260001461054a575050600114610506575b5050508482036020860152600093805461045881611c7f565b808552948184169182156104d3575050600114610486575b6000805160206124fb83398151915286860387a1005b6000908152602081209094509192915b8285106104bb5750505001602001816000805160206124fb8339815191528480610470565b80546020868601810191909152909401938101610496565b90915087965060209493506000805160206124fb833981519152979592501683830152151560051b010191928480610470565b9091929350600052602060002090836000925b84841061053357505050606091508501019085808061043f565b90816020925484868c010152019201918490610519565b925092505060609394501682870152151560051b8501019085808061043f565b0151915086806103ea565b9190879450601f198416928760005260206000209360005b8181106105c4575085116105aa575b50505050811b0182556103fc565b01519060f884600019921b161c191690558580808061059c565b8284015186558a97909501946020938401930161058d565b85600052602060002082850160051c8101976020861061061b575b830160051c019688905b88811061060f5750506103d1565b60008155018890610601565b90975087906105f7565b634e487b7160e01b600052604160045260246000fd5b015190508780610398565b90889350601f198316918660005260206000209260005b81811061069157508411610679575b505050811b0182556103aa565b015160001983861b60f8161c1916905587808061066c565b8284015185558b96909401936020938401930161065d565b9091508460005260206000208680850160051c820192602086106106f3575b918a91869594930160051c01915b8281106106e4575050610382565b600081558594508a91016106d6565b925081926106c8565b60405162461bcd60e51b815260206004820152602360248201527f457363726f77206e6f7420696e204c61756e636865642073746174757320737460448201526261746560e81b6064820152608490fd5b634e487b7160e01b600052602160045260246000fd5b60405162461bcd60e51b815260206004820152601860248201527750657263656e74616765206f7574206f6620626f756e647360401b6044820152606490fd5b60405162461bcd60e51b815260206004820152601f60248201527f496e76616c69642065786368616e6765206f7261636c652061646472657373006044820152606490fd5b606460405162461bcd60e51b815260206004820152602060248201527f496e76616c6964207265636f7264696e67206f7261636c6520616464726573736044820152fd5b60405162461bcd60e51b815260206004820152602160248201527f496e76616c69642072657075746174696f6e206f7261636c65206164647265736044820152607360f81b6064820152608490fd5b34610166576020366003190112610166576001600160a01b0361089c611db0565b16600052600e602052602060ff604060002054166040519015158152f35b346101665760003660031901126101665760206108d56120f5565b6040519015158152f35b3461016657600036600319011261016657602060ff60065460a01c16604051908152f35b34610166576000366003190112610166576006546040516001600160a01b039091168152602090f35b3461016657600036600319011261016657604051600a5460008261094f83611c7f565b91828252602093600190856001821691826000146109d6575050600114610996575b5061097e92500383611cd4565b610992604051928284938452830190611cf7565b0390f35b849150600a60005281600020906000915b8583106109be57505061097e935082010185610971565b805483890185015287945086939092019181016109a7565b60ff19168582015261097e95151560051b85010192508791506109719050565b346101665760a0366003190112610166576004356001600160401b03811161016657610a26903690600401611dc6565b6024356001600160401b038111610166573660238201121561016657806004013590610a5182611d99565b91610a5f6040519384611cd4565b8083526024602084019160051b8301019136831161016657602401905b8282106113ec57505060443590506001600160401b03811161016657610aa6903690600401611d52565b906064356001600160401b03811161016657610ac6903690600401611d52565b9133600052600e60205260ff6040600020541680156113d2575b610ae990611edf565b610afb610af4611e66565b1515612081565b60ff60015416600681101561074d57801561138d576003610b1d911415611f75565b610b2a600d544210611fbf565b610b326121e8565b8351825103611334578151156112f1576064845110156112b65760ff60015416600681101561074d57600481141590816112aa575b501561127457610b75611e66565b926000946000955b8451871015610c0557610b9087866120cb565b5115610bb557610bad600191610ba689886120cb565b519061223e565b960195610b7d565b60405162461bcd60e51b815260206004820152602260248201527f416d6f756e742073686f756c642062652067726561746572207468616e207a65604482015261726f60f01b6064820152608490fd5b84908690676765c793fa10079d601b1b81101561123957116111ff57610c2d84511515611ffe565b610c398351151561203f565b83516001600160401b03811161062557610c54600b54611c7f565b601f811161119e575b506020601f8211600114611133578192939495600092611128575b50508160011b916000199060031b1c191617600b555b82516001600160401b03811161062557610ca9600c54611c7f565b601f81116110c3575b506020601f8211600114611058578192939460009261104d575b50508160011b916000199060031b1c191617600c55905b8151610d07610cf182611d99565b91610cff6040519384611cd4565b808352611d99565b601f190136602083013760065460009384919082805b8251811015610ea857610d3081846120cb565b5190610d438260ff60a088901c166123d3565b92604051610d5081611cb9565b601a81526020016000805160206124db833981519152905260648404610d759161223e565b92610d8082866120cb565b518660a81c60ff1690610d92916123d3565b99604051610d9f81611cb9565b601a81526020016000805160206124db833981519152905260648b04610dc49161223e565b9960649004906064900490610dd89161223e565b610de282866120cb565b518660b01c60ff1690610df4916123d3565b604051610e0081611cb9565b601a81526020016000805160206124db8339815191529052606490049687610e279161223e565b96610e319161223e565b604051610e3d81611cb9565b601e81527f536166654d6174683a207375627472616374696f6e206f766572666c6f7700006020820152610e7490848311156121b8565b8281810311610e925760019203610e8b82896120cb565b5201610d1d565b634e487b7160e01b600052601160045260246000fd5b858288878b60005b8351811015610efd5780610ec6600192886120cb565b51610ed2575b01610eb0565b610ef8828060a01b03610ee583886120cb565b5116610ef1838a6120cb565b5190612296565b610ecc565b5084938061102e575b5080611012575b5080610ff6575b50610f1d611e66565b610fe457600360ff19600154161760015560005b604051916060830160608452815180915260206080850192019060005b818110610fc55750505082810360208401526020808551928381520194019060005b818110610faf5783151560408601526084357f776950576f5bac7433f5095f1490841528a48d38607deca7d6f270988ec32b8a86880387a26001600055005b8251865260209586019590920191600101610f70565b82516001600160a01b0316845260209384019390920191600101610f4e565b6001805460ff19166002178155610f31565b60035461100c91906001600160a01b0316612296565b82610f14565b60025461102891906001600160a01b0316612296565b83610f0d565b600154611047919060081c6001600160a01b0316612296565b84610f06565b015190508480610ccc565b600c60005260206000209060005b601f19841681106110ab5750600193949583601f19811610611092575b505050811b01600c5590610ce3565b015160001960f88460031b161c19169055848080611083565b9091602060018192858a015181550193019101611066565b600c6000527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7601f830160051c8101916020841061111e575b601f0160051c01905b8181106111125750610cb2565b60008155600101611105565b90915081906110fc565b015190508580610c78565b600b60005260206000209060005b601f1984168110611186575060019394959683601f1981161061116d575b505050811b01600b55610c8e565b015160001960f88460031b161c1916905585808061115f565b9091602060018192858b015181550193019101611141565b600b6000527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9601f830160051c8101602084106111f8575b601f830160051c820181106111ec575050610c5d565b600081556001016111d6565b50806111d6565b60405162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f7567682062616c616e636560701b6044820152606490fd5b60405162461bcd60e51b8152602060048201526013602482015272084ead8d640ecc2d8eaca40e8dede40d0d2ced606b1b6044820152606490fd5b60405162461bcd60e51b815260206004820152600e60248201526d496e76616c69642073746174757360901b6044820152606490fd5b60059150141585610b67565b60405162461bcd60e51b8152602060048201526013602482015272546f6f206d616e7920726563697069656e747360681b6044820152606490fd5b60405162461bcd60e51b815260206004820152601b60248201527a416d6f756e74732073686f756c64206e6f7420626520656d70747960281b6044820152606490fd5b60405162461bcd60e51b815260206004820152602b60248201527f416d6f756e74206f6620726563697069656e747320616e642076616c7565732060448201526a0c8dedc4ee840dac2e8c6d60ab1b6064820152608490fd5b60405162461bcd60e51b815260206004820152601f60248201527f457363726f7720696e204c61756e6368656420737461747573207374617465006044820152606490fd5b506001543360089190911c6001600160a01b031614610ae0565b8135815260209182019101610a7c565b34610166576000366003190112610166576003546040516001600160a01b039091168152602090f35b3461016657602080600319360112610166576004356001600160401b03811161016657611456903690600401611dc6565b9033600052600e91600e60205261147460ff60406000205416611edf565b60005b815181101561152c576001907fad3769ac0c1a91ee9dcf369f6d2989f91572b6f876933bbc82ab85f6b969a07a846001600160a01b036114f1816114bb86896120cb565b51161515604051906114cc82611cb9565b6014825273457363726f773a207a65726f206164647265737360601b858301526121b8565b806114fc85886120cb565b511660005287825260406000208560ff1982541617905561151d84876120cb565b5116604051908152a101611477565b005b346101665760003660031901126101665760405160085460008261155183611c7f565b91828252602093600190856001821691826000146109d657505060011461157f575061097e92500383611cd4565b849150600860005281600020906000915b8583106115a757505061097e935082010185610971565b80548389018501528794508693909201918101611590565b34610166576000366003190112610166576005546040516001600160a01b039091168152602090f35b34610166576000366003190112610166576002546040516001600160a01b039091168152602090f35b3461016657600036600319011261016657602060ff60065460a81c16604051908152f35b34610166576040366003190112610166576001600160401b0360043581811161016657611666903690600401611d52565b6024358281116101665761167e903690600401611d52565b33600052602090600e825260ff6040600020541680156118a4575b6116a290611edf565b6116af600d544210611fbf565b600160ff815416600681101561074d57818114908115611899575b501561183e576116dc84511515611ffe565b6116e88251151561203f565b8351948511610625576116fc600a54611c7f565b601f81116117f4575b5082601f861160011461177a579185806000805160206124bb8339815191529761175d97969461176a9660009361176f575b501b916000199060031b1c191617600a555b604051948594604086526040860190611cf7565b9184830390850152611cf7565b0390a1005b88015192508a611737565b601f19861690600a600052846000209160005b8181106117df57509661176a949261175d97969492826000805160206124bb8339815191529a106117c6575b5050811b01600a55611749565b87015160001960f88460031b161c1916905588806117b9565b8783015184559284019291860191860161178d565b600a60005283600020601f870160051c810191858810611834575b601f0160051c019082905b828110611828575050611705565b6000815501829061181a565b909150819061180f565b60405162461bcd60e51b815260048101849052602d60248201527f457363726f77206e6f7420696e2050656e64696e67206f72205061727469616c60448201526c2073746174757320737461746560981b6064820152608490fd5b6002915014866116ca565b506002546001600160a01b03163314611699565b34610166576000366003190112610166576118d6600d544210611fbf565b33600052600e60205260ff604060002054168015611980575b6118f890611edf565b60015460ff8116600681101561074d576003036119405760ff19166004176001557fe06452d00b2b58f14a1fa6d499ea982ff93ea827ae700ea9ba03f4daddc94bc1600080a1005b60405162461bcd60e51b8152602060048201526018602482015277457363726f77206e6f7420696e205061696420737461746560401b6044820152606490fd5b506001543360089190911c6001600160a01b0316146118ef565b3461016657600036600319011261016657604051600b546000826119bd83611c7f565b91828252602093600190856001821691826000146109d65750506001146119eb575061097e92500383611cd4565b849150600b60005281600020906000915b858310611a1357505061097e935082010185610971565b805483890185015287945086939092019181016119fc565b346101665760003660031901126101665733600052600e602052611a5660ff60406000205416611edf565b60ff60015416600681101561074d57600381611a786004611a7f941415611f29565b1415611f75565b611a87611e66565b611a9a575b6005546001600160a01b0316ff5b611aa26120f5565b50611a8c565b3461016657600036600319011261016657604051600954600082611acb83611c7f565b91828252602093600190856001821691826000146109d6575050600114611af9575061097e92500383611cd4565b849150600960005281600020906000915b858310611b2157505061097e935082010185610971565b80548389018501528794508693909201918101611b0a565b346101665760003660031901126101665760ff60015416604051600682101561074d576020918152f35b34610166576000366003190112610166576004546040516001600160a01b039091168152602090f35b34610166576000366003190112610166576020611ba7611e66565b604051908152f35b34610166576000366003190112610166576020600d54604051908152f35b3461016657600036600319011261016657604051600c54600082611bf083611c7f565b91828252602093600190856001821691826000146109d6575050600114611c1e575061097e92500383611cd4565b849150600c60005281600020906000915b858310611c4657505061097e935082010185610971565b80548389018501528794508693909201918101611c2f565b346101665760003660031901126101665760209060ff60065460b01c168152f35b90600182811c92168015611caf575b6020831014611c9957565b634e487b7160e01b600052602260045260246000fd5b91607f1691611c8e565b604081019081106001600160401b0382111761062557604052565b601f909101601f19168101906001600160401b0382119082101761062557604052565b919082519283825260005b848110611d23575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201611d02565b6001600160401b03811161062557601f01601f191660200190565b81601f8201121561016657803590611d6982611d37565b92611d776040519485611cd4565b8284526020838301011161016657816000926020809301838601378301015290565b6001600160401b0381116106255760051b60200190565b600435906001600160a01b038216820361016657565b9080601f83011215610166576020908235611de081611d99565b93611dee6040519586611cd4565b81855260208086019260051b82010192831161016657602001905b828210611e17575050505090565b81356001600160a01b0381168103610166578152908301908301611e09565b3d15611e61573d90611e4782611d37565b91611e556040519384611cd4565b82523d6000602084013e565b606090565b6007546040516370a0823160e01b60208201908152306024808401919091528252909160608301916001600160a01b03909116908383106001600160401b0384111761062557600093849360405251915afa611ec0611e36565b90611ecb5750600090565b602081805181010312610166576020015190565b15611ee657565b60405162461bcd60e51b815260206004820152601b60248201527a1059191c995cdcc818d85b1b1a5b99c81b9bdd081d1c9d5cdd1959602a1b6044820152606490fd5b15611f3057565b60405162461bcd60e51b815260206004820152601f60248201527f457363726f7720696e20436f6d706c65746520737461747573207374617465006044820152606490fd5b15611f7c57565b60405162461bcd60e51b815260206004820152601b60248201527a457363726f7720696e20506169642073746174757320737461746560281b6044820152606490fd5b15611fc657565b60405162461bcd60e51b815260206004820152601060248201526f10dbdb9d1c9858dd08195e1c1a5c995960821b6044820152606490fd5b1561200557565b60405162461bcd60e51b815260206004820152601260248201527155524c2063616e277420626520656d70747960701b6044820152606490fd5b1561204657565b60405162461bcd60e51b8152602060048201526013602482015272486173682063616e277420626520656d70747960681b6044820152606490fd5b1561208857565b60405162461bcd60e51b815260206004820152601b60248201527a546f6b656e20636f6e7472616374206f7574206f662066756e647360281b6044820152606490fd5b80518210156120df5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b6000338152600e60205261210f60ff604083205416611edf565b61211a610af4611e66565b60ff600154166006811015612197579061213f600383611a7860046001961415611f29565b6121476121e8565b612162828060a01b036005541661215c611e66565b90612296565b815460ff191660051782557f63b958841f79ab97cb5456da181454b9932c0e15a3b17f1cbd27e2a8bc6104378180a155600190565b634e487b7160e01b82526021600452602482fd5b91908201809211610e9257565b156121c05750565b60405162461bcd60e51b8152602060048201529081906121e4906024830190611cf7565b0390fd5b6002600054146121f9576002600055565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b9061224990826121ab565b9081106122535790565b60405162461bcd60e51b815260206004820152601b60248201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b6044820152606490fd5b60075460405163a9059cbb60e01b602082019081526001600160a01b039384166024830152604480830195909552938152916080830191166001600160401b038211838310176106255761233592826040526122f183611cb9565b602083527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656460a0820152600080958192519082855af161232f611e36565b91612445565b9081519182159283156123a5575b5050501561234d57565b60405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608490fd5b8192935090602091810103126123cf57602001519081151582036123cc5750388080612343565b80fd5b5080fd5b90811561243e57808202918204808203610e9257036123ef5790565b60405162461bcd60e51b815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6044820152607760f81b6064820152608490fd5b5050600090565b919290156124a75750815115612459575090565b3b156124625790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156121c05750805190602001fdfeb20e0717219840fd5684a80bec782e8babb56ea224f677561b791a61192605c1536166654d6174683a206469766973696f6e206279207a65726f0000000000008ec464ac0c8e44e17130cd1ffb09967fa6f2c33339289678a59ea0112cfc2aa9a2646970667358221220fa77223a7263eb92392228757c8120010e1305dfdbc3df183ecb2d275fe8ac2f64736f6c634300081700334910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd914346756e6374696f6e206d7573742062652063616c6c6564207468726f75676820360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0bc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b45524331393637557067726164653a20756e737570706f727465642070726f78416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c45524331393637557067726164653a206e657720696d706c656d656e74617469a26469706673582212206748bc5d494150bceab8fee124334b8e2408bad9538ae35dd73bf0fa8325a49c64736f6c63430008170033
Deployed Bytecode
0x604060808152600490813610156200001657600080fd5b600091823560e01c80633659cfe61462000b4f5780633cc3e58d1462000b245780634cf088d91462000af95780634f1ef286146200085657806352d1902d146200079557806358d276f7146200075757806361bc221a1462000736578063715018a614620006e65780637e59879714620003c15780638da5cb5b1462000396578063979530e61462000356578063c4d66de8146200015b5763f2fde38b14620000be57600080fd5b34620001575760203660031901126200015757620000db62000dda565b91620000e662000f88565b6001600160a01b03831615620001055783620001028462000fe1565b80f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b8280fd5b50602036600319011262000157576200017362000dda565b9083549060ff8260081c16159182809362000348575b80156200032f575b15620002d55760ff198116600117865582620002c3575b50620001bb60ff865460081c1662001019565b620001c63362000fe1565b845492620001da60ff8560081c1662001019565b84516001600160a01b039190911691908086016001600160401b03811182821017620002b0578652601b81527a457363726f77466163746f72793a205a65726f204164647265737360281b602082015282156200028857505060cc80546001600160a01b03191691909117905562000250578280f35b61ff001916825551600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602090a138808280f35b90620002ac602092875193849362461bcd60e51b8552840152602483019062000f46565b0390fd5b634e487b7160e01b885260418352602488fd5b61ffff191661010117855538620001a8565b845162461bcd60e51b8152602081840152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b50303b158015620001915750600160ff82161462000191565b50600160ff82161062000189565b50503462000392576020366003190112620003925760209181906001600160a01b036200038262000dda565b16815260ca845220549051908152f35b5080fd5b505034620003925781600319360112620003925760335490516001600160a01b039091168152602090f35b508234620006e3576060366003190112620006e357620003e062000dda565b6001600160401b039360248035949192868611620006df5736602387011215620006df578583013592878411620006cd578360051b936020978651916200042a8a88018462000e28565b8252888201858197830101913683116200068e578601905b828210620006a857505050604435898111620006a45736602382011215620006a457620004789036908681860135910162000e68565b948460018060a01b03948a8660cc54168a5193848092630d7cb1d560e11b8252338a8301525afa9182156200069a578a9262000657575b5060018092151503620005fe5788519361292a808601809e878210911117620005ec578c9d8695949260c0929e9b9c9d9e620011ac88398960a0830195169b8c835233908301528d33908301526283d600606083015260a06080830152518094520192918d8d905b828210620005d2575050505050039088f0928315620005c85760c954916000198314620005b757505060010160c9819055911680865260ca8752948490205560cb80546001600160a01b03191685179055825190815280850184905260608184018190527fde4a6895269de599430e1230956361cbe11b52ad149311a97123c73666c52141928291620005ae919083019062000f46565b0390a151908152f35b634e487b7160e01b89526011905287fd5b86513d89823e3d90fd5b84518a168652879650948501949093019282018e62000517565b634e487b7160e01b8c5260418752888cfd5b885162461bcd60e51b81528086018c9052602e818901527f4e6565647320746f207374616b6520484d5420746f6b656e7320746f2063726560448201526d30ba329030b71032b9b1b937bb9760911b6064820152608490fd5b9091508a81813d831162000692575b62000672818362000e28565b810103126200068e575180151581036200068e57908c620004af565b8980fd5b503d62000666565b89513d8c823e3d90fd5b8780fd5b81356001600160a01b0381168103620006c9578152908a01908a0162000442565b8a80fd5b634e487b7160e01b8652604190528185fd5b8480fd5b80fd5b8334620006e35780600319360112620006e3576200070362000f88565b603380546001600160a01b0319811690915581906001600160a01b031660008051602062003b368339815191528280a380f35b505034620003925781600319360112620003925760209060c9549051908152f35b50503462000392576020366003190112620003925760209181906001600160a01b036200078362000dda565b16815260ca8452205415159051908152f35b508234620006e35780600319360112620006e357507f0000000000000000000000006d72734f28e807465aebc2e1302336129242c2e66001600160a01b03163003620007f3576020825160008051602062003b168339815191528152f35b6020608492519162461bcd60e51b8352820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b6064820152fd5b50908060031936011262000157576200086e62000dda565b906024356001600160401b038111620006df5736602382011215620006df57620008a2903690602481870135910162000e68565b6001600160a01b037f0000000000000000000000006d72734f28e807465aebc2e1302336129242c2e68116929190620008de3085141562000ea4565b620008fe60008051602062003b1683398151915294828654161462000ef5565b6200090862000f88565b60008051602062003ad68339815191525460ff16156200093257505050506200010291506200107a565b82516352d1902d60e01b81526020959394918416919086818981865afa89918162000ac4575b50620009a757855162461bcd60e51b8152808901889052602e602482015260008051602062003bb683398151915260448201526d6f6e206973206e6f74205555505360901b6064820152608490fd5b969192959493960362000a805750620009c0856200107a565b60008051602062003b568339815191528680a282511580159062000a77575b620009ec575b5050505080f35b62000a6193858083519562000a018762000df6565b6027875260008051602062003b9683398151915286880152660819985a5b195960ca1b858801528581519101845af4913d1562000a6c573d62000a5262000a488262000e4c565b9251928362000e28565b81528681943d92013e6200110c565b5038808080620009e5565b50606092506200110c565b506001620009df565b825162461bcd60e51b81529081018490526029602482015260008051602062003b768339815191526044820152681a58589b195555525160ba1b6064820152608490fd5b9091508781813d831162000af1575b62000adf818362000e28565b810103126200068e5751903862000958565b503d62000ad3565b505034620003925781600319360112620003925760cc5490516001600160a01b039091168152602090f35b505034620003925781600319360112620003925760cb5490516001600160a01b039091168152602090f35b509034620001575760208060031936011262000dd65762000b6f62000dda565b916001600160a01b037f0000000000000000000000006d72734f28e807465aebc2e1302336129242c2e6811662000ba93082141562000ea4565b62000bc960008051602062003b1683398151915291838354161462000ef5565b62000bd362000f88565b8251848101929091906001600160401b0384118385101762000dc35783855288835260008051602062003ad68339815191525460ff161562000c21575050505050506200010291506200107a565b869293949596169085516352d1902d60e01b815287818a81865afa8a918162000d8e575b5062000c9457865162461bcd60e51b8152808a01899052602e602482015260008051602062003bb683398151915260448201526d6f6e206973206e6f74205555505360901b6064820152608490fd5b97919293969594970362000d4a575062000cae826200107a565b60008051602062003b568339815191528780a28584511580159062000d42575b62000cdd575b50505050505080f35b8062000d359684519662000cf18862000df6565b6027885260008051602062003b9683398151915287890152660819985a5b195960ca1b868901525190845af4913d1562000a6c573d62000a5262000a488262000e4c565b5038808080808562000cd4565b508062000cce565b835162461bcd60e51b81529081018590526029602482015260008051602062003b768339815191526044820152681a58589b195555525160ba1b6064820152608490fd5b9091508881813d831162000dbb575b62000da9818362000e28565b81010312620006c95751903862000c45565b503d62000d9d565b634e487b7160e01b895260418852602489fd5b8380fd5b600435906001600160a01b038216820362000df157565b600080fd5b606081019081106001600160401b0382111762000e1257604052565b634e487b7160e01b600052604160045260246000fd5b601f909101601f19168101906001600160401b0382119082101762000e1257604052565b6001600160401b03811162000e1257601f01601f191660200190565b92919262000e768262000e4c565b9162000e86604051938462000e28565b82948184528183011162000df1578281602093846000960137010152565b1562000eac57565b60405162461bcd60e51b815260206004820152602c602482015260008051602062003af683398151915260448201526b19195b1959d85d1958d85b1b60a21b6064820152608490fd5b1562000efd57565b60405162461bcd60e51b815260206004820152602c602482015260008051602062003af683398151915260448201526b6163746976652070726f787960a01b6064820152608490fd5b919082519283825260005b84811062000f73575050826000602080949584010152601f8019910116010190565b60208183018101518483018201520162000f51565b6033546001600160a01b0316330362000f9d57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b603380546001600160a01b039283166001600160a01b03198216811790925590911660008051602062003b36833981519152600080a3565b156200102157565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b803b15620010b15760008051602062003b1683398151915280546001600160a01b0319166001600160a01b03909216919091179055565b60405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b9192901562001171575081511562001122575090565b3b156200112c5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015620011855750805190602001fd5b60405162461bcd60e51b815260206004820152908190620002ac90602483019062000f4656fe60406080815234620002a4576200292a90813803806200001f81620002bf565b938439820160a083820312620002a4576200003a83620002e5565b9260206200004a818301620002e5565b94848301519260018060a01b0391828516809503620002a457606082015195608083015160018060401b0393848211620002a4570181601f82011215620002a4578051938411620002a9578360051b908680620000a9818501620002bf565b809781520192820101928311620002a45786809101915b8383106200028957505050506001948360009287845516620000ee620000e5620002fa565b82151562000344565b62000105620000fc620002fa565b83151562000344565b600780546001600160a01b03199081169092179055865460ff19908116885597428101908181116200027557811062000231578798999a8691600d5516908181600454161760045582816005541617600555339060065416176006558252600e90600e8652898320878a8254161790558252888220868982541617905581955b6200019a575b88516125509081620003da8239f35b82518610156200022b578686620001cd86620001b8849a88620003ae565b51161515620001c6620002fa565b9062000344565b85620001da8287620003ae565b511684528287528a8420828b8254161790557fad3769ac0c1a91ee9dcf369f6d2989f91572b6f876933bbc82ab85f6b969a07a87876200021b8489620003ae565b51168d51908152a1019562000185565b6200018b565b895162461bcd60e51b815260048101889052601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606490fd5b634e487b7160e01b85526011600452602485fd5b81906200029684620002e5565b8152019101908690620000c0565b600080fd5b634e487b7160e01b600052604160045260246000fd5b6040519190601f01601f191682016001600160401b03811183821017620002a957604052565b51906001600160a01b0382168203620002a457565b60408051919082016001600160401b03811183821017620002a957604052601482527f457363726f773a207a65726f20616464726573730000000000000000000000006020830152565b156200034d5750565b6040519062461bcd60e51b82528160208060048301528251908160248401526000935b82851062000394575050604492506000838284010152601f80199101168101030190fd5b848101820151868601604401529381019385935062000370565b8051821015620003c35760209160051b010190565b634e487b7160e01b600052603260045260246000fdfe608080604052600436101561001357600080fd5b60003560e01c9081630ae9dfad14611c5e575080630f46c9aa14611bcd5780630fb5a6b414611baf57806312065fe014611b8c57806316eebd1e14611b63578063200d2ed214611b39578063337f3f3214611aa857806335a063b414611a2b57806343aba9c21461199a578063522e1177146118b8578063697e4b871461163557806378c62420146116115780639753e432146115e8578063992d454d146115bf5780639c48b1021461152e5780639eb262f314611425578063a05220ad146113fc578063b63d1a00146109f6578063ba5fed341461092c578063bdd1daaa14610903578063c479bbf8146108df578063ea8a1af0146108ba578063f17171e91461087b578063f56679cf14610198578063fad844c11461016b5763fc0c546a1461013d57600080fd5b34610166576000366003190112610166576007546040516001600160a01b039091168152602090f35b600080fd5b346101665760003660031901126101665760015460405160089190911c6001600160a01b03168152602090f35b3461016657610100366003190112610166576101b2611db0565b602435906001600160a01b038216820361016657604435906001600160a01b03821682036101665760ff60643516606435036101665760ff60843516608435036101665760ff60a4351660a435036101665760c4356001600160401b03811161016657610223903690600401611d52565b906001600160401b0360e43511610166576102433660e435600401611d52565b9233600052600e60205261025e60ff60406000205416611edf565b61026b600d544210611fbf565b6001600160a01b0382161561082c576001600160a01b038516156107e8576001600160a01b038116156107a35760646102bb60ff60a435166102b660ff6084351660ff8535166121ab565b6121ab565b1161076357600194855460ff8116600681101561074d576106fc57610100600160a81b031916600893841b610100600160a81b0316178655600280546001600160a01b03199081166001600160a01b039384161790915560038054909116929091169190911781556006805460843560a81b60ff60a81b1662ffffff60a01b1990911660643560a01b60ff60a01b16171760a43560b01b60ff60b01b1617905582516001600160401b03811161062557806103768454611c7f565b94601f958681116106a9575b506020908683116001146106465760009261063b575b505060001982841b1c191690861b1782555b8351906001600160401b038211610625576009936103c88554611c7f565b958187116105dc575b839495965060209184116001146105755760009361056a575b505082861b92600019911b1c19161782555b60ff199083828154161784556040519360408552600091805461041e81611c7f565b9182604089015260609186858216918260001461054a575050600114610506575b5050508482036020860152600093805461045881611c7f565b808552948184169182156104d3575050600114610486575b6000805160206124fb83398151915286860387a1005b6000908152602081209094509192915b8285106104bb5750505001602001816000805160206124fb8339815191528480610470565b80546020868601810191909152909401938101610496565b90915087965060209493506000805160206124fb833981519152979592501683830152151560051b010191928480610470565b9091929350600052602060002090836000925b84841061053357505050606091508501019085808061043f565b90816020925484868c010152019201918490610519565b925092505060609394501682870152151560051b8501019085808061043f565b0151915086806103ea565b9190879450601f198416928760005260206000209360005b8181106105c4575085116105aa575b50505050811b0182556103fc565b01519060f884600019921b161c191690558580808061059c565b8284015186558a97909501946020938401930161058d565b85600052602060002082850160051c8101976020861061061b575b830160051c019688905b88811061060f5750506103d1565b60008155018890610601565b90975087906105f7565b634e487b7160e01b600052604160045260246000fd5b015190508780610398565b90889350601f198316918660005260206000209260005b81811061069157508411610679575b505050811b0182556103aa565b015160001983861b60f8161c1916905587808061066c565b8284015185558b96909401936020938401930161065d565b9091508460005260206000208680850160051c820192602086106106f3575b918a91869594930160051c01915b8281106106e4575050610382565b600081558594508a91016106d6565b925081926106c8565b60405162461bcd60e51b815260206004820152602360248201527f457363726f77206e6f7420696e204c61756e636865642073746174757320737460448201526261746560e81b6064820152608490fd5b634e487b7160e01b600052602160045260246000fd5b60405162461bcd60e51b815260206004820152601860248201527750657263656e74616765206f7574206f6620626f756e647360401b6044820152606490fd5b60405162461bcd60e51b815260206004820152601f60248201527f496e76616c69642065786368616e6765206f7261636c652061646472657373006044820152606490fd5b606460405162461bcd60e51b815260206004820152602060248201527f496e76616c6964207265636f7264696e67206f7261636c6520616464726573736044820152fd5b60405162461bcd60e51b815260206004820152602160248201527f496e76616c69642072657075746174696f6e206f7261636c65206164647265736044820152607360f81b6064820152608490fd5b34610166576020366003190112610166576001600160a01b0361089c611db0565b16600052600e602052602060ff604060002054166040519015158152f35b346101665760003660031901126101665760206108d56120f5565b6040519015158152f35b3461016657600036600319011261016657602060ff60065460a01c16604051908152f35b34610166576000366003190112610166576006546040516001600160a01b039091168152602090f35b3461016657600036600319011261016657604051600a5460008261094f83611c7f565b91828252602093600190856001821691826000146109d6575050600114610996575b5061097e92500383611cd4565b610992604051928284938452830190611cf7565b0390f35b849150600a60005281600020906000915b8583106109be57505061097e935082010185610971565b805483890185015287945086939092019181016109a7565b60ff19168582015261097e95151560051b85010192508791506109719050565b346101665760a0366003190112610166576004356001600160401b03811161016657610a26903690600401611dc6565b6024356001600160401b038111610166573660238201121561016657806004013590610a5182611d99565b91610a5f6040519384611cd4565b8083526024602084019160051b8301019136831161016657602401905b8282106113ec57505060443590506001600160401b03811161016657610aa6903690600401611d52565b906064356001600160401b03811161016657610ac6903690600401611d52565b9133600052600e60205260ff6040600020541680156113d2575b610ae990611edf565b610afb610af4611e66565b1515612081565b60ff60015416600681101561074d57801561138d576003610b1d911415611f75565b610b2a600d544210611fbf565b610b326121e8565b8351825103611334578151156112f1576064845110156112b65760ff60015416600681101561074d57600481141590816112aa575b501561127457610b75611e66565b926000946000955b8451871015610c0557610b9087866120cb565b5115610bb557610bad600191610ba689886120cb565b519061223e565b960195610b7d565b60405162461bcd60e51b815260206004820152602260248201527f416d6f756e742073686f756c642062652067726561746572207468616e207a65604482015261726f60f01b6064820152608490fd5b84908690676765c793fa10079d601b1b81101561123957116111ff57610c2d84511515611ffe565b610c398351151561203f565b83516001600160401b03811161062557610c54600b54611c7f565b601f811161119e575b506020601f8211600114611133578192939495600092611128575b50508160011b916000199060031b1c191617600b555b82516001600160401b03811161062557610ca9600c54611c7f565b601f81116110c3575b506020601f8211600114611058578192939460009261104d575b50508160011b916000199060031b1c191617600c55905b8151610d07610cf182611d99565b91610cff6040519384611cd4565b808352611d99565b601f190136602083013760065460009384919082805b8251811015610ea857610d3081846120cb565b5190610d438260ff60a088901c166123d3565b92604051610d5081611cb9565b601a81526020016000805160206124db833981519152905260648404610d759161223e565b92610d8082866120cb565b518660a81c60ff1690610d92916123d3565b99604051610d9f81611cb9565b601a81526020016000805160206124db833981519152905260648b04610dc49161223e565b9960649004906064900490610dd89161223e565b610de282866120cb565b518660b01c60ff1690610df4916123d3565b604051610e0081611cb9565b601a81526020016000805160206124db8339815191529052606490049687610e279161223e565b96610e319161223e565b604051610e3d81611cb9565b601e81527f536166654d6174683a207375627472616374696f6e206f766572666c6f7700006020820152610e7490848311156121b8565b8281810311610e925760019203610e8b82896120cb565b5201610d1d565b634e487b7160e01b600052601160045260246000fd5b858288878b60005b8351811015610efd5780610ec6600192886120cb565b51610ed2575b01610eb0565b610ef8828060a01b03610ee583886120cb565b5116610ef1838a6120cb565b5190612296565b610ecc565b5084938061102e575b5080611012575b5080610ff6575b50610f1d611e66565b610fe457600360ff19600154161760015560005b604051916060830160608452815180915260206080850192019060005b818110610fc55750505082810360208401526020808551928381520194019060005b818110610faf5783151560408601526084357f776950576f5bac7433f5095f1490841528a48d38607deca7d6f270988ec32b8a86880387a26001600055005b8251865260209586019590920191600101610f70565b82516001600160a01b0316845260209384019390920191600101610f4e565b6001805460ff19166002178155610f31565b60035461100c91906001600160a01b0316612296565b82610f14565b60025461102891906001600160a01b0316612296565b83610f0d565b600154611047919060081c6001600160a01b0316612296565b84610f06565b015190508480610ccc565b600c60005260206000209060005b601f19841681106110ab5750600193949583601f19811610611092575b505050811b01600c5590610ce3565b015160001960f88460031b161c19169055848080611083565b9091602060018192858a015181550193019101611066565b600c6000527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7601f830160051c8101916020841061111e575b601f0160051c01905b8181106111125750610cb2565b60008155600101611105565b90915081906110fc565b015190508580610c78565b600b60005260206000209060005b601f1984168110611186575060019394959683601f1981161061116d575b505050811b01600b55610c8e565b015160001960f88460031b161c1916905585808061115f565b9091602060018192858b015181550193019101611141565b600b6000527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9601f830160051c8101602084106111f8575b601f830160051c820181106111ec575050610c5d565b600081556001016111d6565b50806111d6565b60405162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f7567682062616c616e636560701b6044820152606490fd5b60405162461bcd60e51b8152602060048201526013602482015272084ead8d640ecc2d8eaca40e8dede40d0d2ced606b1b6044820152606490fd5b60405162461bcd60e51b815260206004820152600e60248201526d496e76616c69642073746174757360901b6044820152606490fd5b60059150141585610b67565b60405162461bcd60e51b8152602060048201526013602482015272546f6f206d616e7920726563697069656e747360681b6044820152606490fd5b60405162461bcd60e51b815260206004820152601b60248201527a416d6f756e74732073686f756c64206e6f7420626520656d70747960281b6044820152606490fd5b60405162461bcd60e51b815260206004820152602b60248201527f416d6f756e74206f6620726563697069656e747320616e642076616c7565732060448201526a0c8dedc4ee840dac2e8c6d60ab1b6064820152608490fd5b60405162461bcd60e51b815260206004820152601f60248201527f457363726f7720696e204c61756e6368656420737461747573207374617465006044820152606490fd5b506001543360089190911c6001600160a01b031614610ae0565b8135815260209182019101610a7c565b34610166576000366003190112610166576003546040516001600160a01b039091168152602090f35b3461016657602080600319360112610166576004356001600160401b03811161016657611456903690600401611dc6565b9033600052600e91600e60205261147460ff60406000205416611edf565b60005b815181101561152c576001907fad3769ac0c1a91ee9dcf369f6d2989f91572b6f876933bbc82ab85f6b969a07a846001600160a01b036114f1816114bb86896120cb565b51161515604051906114cc82611cb9565b6014825273457363726f773a207a65726f206164647265737360601b858301526121b8565b806114fc85886120cb565b511660005287825260406000208560ff1982541617905561151d84876120cb565b5116604051908152a101611477565b005b346101665760003660031901126101665760405160085460008261155183611c7f565b91828252602093600190856001821691826000146109d657505060011461157f575061097e92500383611cd4565b849150600860005281600020906000915b8583106115a757505061097e935082010185610971565b80548389018501528794508693909201918101611590565b34610166576000366003190112610166576005546040516001600160a01b039091168152602090f35b34610166576000366003190112610166576002546040516001600160a01b039091168152602090f35b3461016657600036600319011261016657602060ff60065460a81c16604051908152f35b34610166576040366003190112610166576001600160401b0360043581811161016657611666903690600401611d52565b6024358281116101665761167e903690600401611d52565b33600052602090600e825260ff6040600020541680156118a4575b6116a290611edf565b6116af600d544210611fbf565b600160ff815416600681101561074d57818114908115611899575b501561183e576116dc84511515611ffe565b6116e88251151561203f565b8351948511610625576116fc600a54611c7f565b601f81116117f4575b5082601f861160011461177a579185806000805160206124bb8339815191529761175d97969461176a9660009361176f575b501b916000199060031b1c191617600a555b604051948594604086526040860190611cf7565b9184830390850152611cf7565b0390a1005b88015192508a611737565b601f19861690600a600052846000209160005b8181106117df57509661176a949261175d97969492826000805160206124bb8339815191529a106117c6575b5050811b01600a55611749565b87015160001960f88460031b161c1916905588806117b9565b8783015184559284019291860191860161178d565b600a60005283600020601f870160051c810191858810611834575b601f0160051c019082905b828110611828575050611705565b6000815501829061181a565b909150819061180f565b60405162461bcd60e51b815260048101849052602d60248201527f457363726f77206e6f7420696e2050656e64696e67206f72205061727469616c60448201526c2073746174757320737461746560981b6064820152608490fd5b6002915014866116ca565b506002546001600160a01b03163314611699565b34610166576000366003190112610166576118d6600d544210611fbf565b33600052600e60205260ff604060002054168015611980575b6118f890611edf565b60015460ff8116600681101561074d576003036119405760ff19166004176001557fe06452d00b2b58f14a1fa6d499ea982ff93ea827ae700ea9ba03f4daddc94bc1600080a1005b60405162461bcd60e51b8152602060048201526018602482015277457363726f77206e6f7420696e205061696420737461746560401b6044820152606490fd5b506001543360089190911c6001600160a01b0316146118ef565b3461016657600036600319011261016657604051600b546000826119bd83611c7f565b91828252602093600190856001821691826000146109d65750506001146119eb575061097e92500383611cd4565b849150600b60005281600020906000915b858310611a1357505061097e935082010185610971565b805483890185015287945086939092019181016119fc565b346101665760003660031901126101665733600052600e602052611a5660ff60406000205416611edf565b60ff60015416600681101561074d57600381611a786004611a7f941415611f29565b1415611f75565b611a87611e66565b611a9a575b6005546001600160a01b0316ff5b611aa26120f5565b50611a8c565b3461016657600036600319011261016657604051600954600082611acb83611c7f565b91828252602093600190856001821691826000146109d6575050600114611af9575061097e92500383611cd4565b849150600960005281600020906000915b858310611b2157505061097e935082010185610971565b80548389018501528794508693909201918101611b0a565b346101665760003660031901126101665760ff60015416604051600682101561074d576020918152f35b34610166576000366003190112610166576004546040516001600160a01b039091168152602090f35b34610166576000366003190112610166576020611ba7611e66565b604051908152f35b34610166576000366003190112610166576020600d54604051908152f35b3461016657600036600319011261016657604051600c54600082611bf083611c7f565b91828252602093600190856001821691826000146109d6575050600114611c1e575061097e92500383611cd4565b849150600c60005281600020906000915b858310611c4657505061097e935082010185610971565b80548389018501528794508693909201918101611c2f565b346101665760003660031901126101665760209060ff60065460b01c168152f35b90600182811c92168015611caf575b6020831014611c9957565b634e487b7160e01b600052602260045260246000fd5b91607f1691611c8e565b604081019081106001600160401b0382111761062557604052565b601f909101601f19168101906001600160401b0382119082101761062557604052565b919082519283825260005b848110611d23575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201611d02565b6001600160401b03811161062557601f01601f191660200190565b81601f8201121561016657803590611d6982611d37565b92611d776040519485611cd4565b8284526020838301011161016657816000926020809301838601378301015290565b6001600160401b0381116106255760051b60200190565b600435906001600160a01b038216820361016657565b9080601f83011215610166576020908235611de081611d99565b93611dee6040519586611cd4565b81855260208086019260051b82010192831161016657602001905b828210611e17575050505090565b81356001600160a01b0381168103610166578152908301908301611e09565b3d15611e61573d90611e4782611d37565b91611e556040519384611cd4565b82523d6000602084013e565b606090565b6007546040516370a0823160e01b60208201908152306024808401919091528252909160608301916001600160a01b03909116908383106001600160401b0384111761062557600093849360405251915afa611ec0611e36565b90611ecb5750600090565b602081805181010312610166576020015190565b15611ee657565b60405162461bcd60e51b815260206004820152601b60248201527a1059191c995cdcc818d85b1b1a5b99c81b9bdd081d1c9d5cdd1959602a1b6044820152606490fd5b15611f3057565b60405162461bcd60e51b815260206004820152601f60248201527f457363726f7720696e20436f6d706c65746520737461747573207374617465006044820152606490fd5b15611f7c57565b60405162461bcd60e51b815260206004820152601b60248201527a457363726f7720696e20506169642073746174757320737461746560281b6044820152606490fd5b15611fc657565b60405162461bcd60e51b815260206004820152601060248201526f10dbdb9d1c9858dd08195e1c1a5c995960821b6044820152606490fd5b1561200557565b60405162461bcd60e51b815260206004820152601260248201527155524c2063616e277420626520656d70747960701b6044820152606490fd5b1561204657565b60405162461bcd60e51b8152602060048201526013602482015272486173682063616e277420626520656d70747960681b6044820152606490fd5b1561208857565b60405162461bcd60e51b815260206004820152601b60248201527a546f6b656e20636f6e7472616374206f7574206f662066756e647360281b6044820152606490fd5b80518210156120df5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b6000338152600e60205261210f60ff604083205416611edf565b61211a610af4611e66565b60ff600154166006811015612197579061213f600383611a7860046001961415611f29565b6121476121e8565b612162828060a01b036005541661215c611e66565b90612296565b815460ff191660051782557f63b958841f79ab97cb5456da181454b9932c0e15a3b17f1cbd27e2a8bc6104378180a155600190565b634e487b7160e01b82526021600452602482fd5b91908201809211610e9257565b156121c05750565b60405162461bcd60e51b8152602060048201529081906121e4906024830190611cf7565b0390fd5b6002600054146121f9576002600055565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b9061224990826121ab565b9081106122535790565b60405162461bcd60e51b815260206004820152601b60248201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b6044820152606490fd5b60075460405163a9059cbb60e01b602082019081526001600160a01b039384166024830152604480830195909552938152916080830191166001600160401b038211838310176106255761233592826040526122f183611cb9565b602083527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656460a0820152600080958192519082855af161232f611e36565b91612445565b9081519182159283156123a5575b5050501561234d57565b60405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608490fd5b8192935090602091810103126123cf57602001519081151582036123cc5750388080612343565b80fd5b5080fd5b90811561243e57808202918204808203610e9257036123ef5790565b60405162461bcd60e51b815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6044820152607760f81b6064820152608490fd5b5050600090565b919290156124a75750815115612459575090565b3b156124625790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156121c05750805190602001fdfeb20e0717219840fd5684a80bec782e8babb56ea224f677561b791a61192605c1536166654d6174683a206469766973696f6e206279207a65726f0000000000008ec464ac0c8e44e17130cd1ffb09967fa6f2c33339289678a59ea0112cfc2aa9a2646970667358221220fa77223a7263eb92392228757c8120010e1305dfdbc3df183ecb2d275fe8ac2f64736f6c634300081700334910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd914346756e6374696f6e206d7573742062652063616c6c6564207468726f75676820360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0bc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b45524331393637557067726164653a20756e737570706f727465642070726f78416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c45524331393637557067726164653a206e657720696d706c656d656e74617469a26469706673582212206748bc5d494150bceab8fee124334b8e2408bad9538ae35dd73bf0fa8325a49c64736f6c63430008170033
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.