Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Factory
Compiler Version
v0.8.22+commit.4fc1097e
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/proxy/Clones.sol"; import "./Market.sol"; contract Factory is Initializable, OwnableUpgradeable, UUPSUpgradeable, ReentrancyGuardUpgradeable { // State variables address public feeRecipient; address public governor; uint256 public marketCreationFee; uint256 public tradingFee; uint256 public lpShare; uint256 public protocolShare; address public susdToken; mapping(uint256 => address) public markets; mapping(address => bool) public verifiedMarkets; uint256 public marketId; mapping(address => bool) public whitelistedAddresses; address public router; // Router state variables mapping(address => uint256) public marketBalances; mapping(address => bool) public validMarkets; // Events event MarketCreated( address indexed market, uint256 indexed id, string[] outcomes, address reporter, uint256 b, uint256 disputeBondAmount ); event MarketVerified(address indexed market); event MarketUnverified(address indexed market); event FeeRecipientSet(address newFeeRecipient); event MarketCreationFeeSet(uint256 newFee); event FeeSharesSet(uint256 newLpShare, uint256 newProtocolShare); event MarketImplementationUpgraded(address newImplementation); event TokensDeposited(address indexed user, address indexed market, uint256 amount); event TokensWithdrawn(address indexed user, address indexed market, uint256 amount); event WhitelistedAddressAdded(address indexed account); event WhitelistedAddressRemoved(address indexed account); event GovernorSet(address newGovernor); event TradingFeeSet(uint256 newTradingFee); /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize( address _governor, address _feeRecipient, uint256 _marketCreationFee, address _susdToken, uint256 _tradingFee ) external initializer { // Initialize parent contracts in linearized order __Ownable_init(_governor); __ReentrancyGuard_init(); __UUPSUpgradeable_init(); require(_governor != address(0), "Invalid governor"); require(_feeRecipient != address(0), "Invalid fee recipient"); require(_susdToken != address(0), "Invalid SUSD token"); // Initialize original state variables marketId = 0; feeRecipient = _feeRecipient; governor = _governor; marketCreationFee = _marketCreationFee; susdToken = _susdToken; tradingFee = _tradingFee; lpShare = 900; // 9% to LPs protocolShare = 100; // 1% to protocol } function _authorizeUpgrade(address newImplementation) internal override onlyOwner {} function createMarket( string[] memory outcomes, uint256 resolutionDelay, address reporter, uint256 b, uint256 disputeBondAmount ) external nonReentrant returns (address) { require( IERC20(susdToken).transferFrom(msg.sender, address(this), marketCreationFee), "Market creation fee transfer failed" ); // Deploy new Market instance using the implementation contract Market market = new Market( outcomes, feeRecipient, resolutionDelay, reporter, governor, b, tradingFee, susdToken, disputeBondAmount ); // Store market data address marketAddr = address(market); markets[marketId] = marketAddr; validMarkets[marketAddr] = true; emit MarketCreated( marketAddr, marketId, outcomes, reporter, b, disputeBondAmount ); marketId++; return marketAddr; } function setTradingFee(uint256 _tradingFee) external onlyOwner { require(_tradingFee <= 2000, "Fee too high"); // Max 20% tradingFee = _tradingFee; emit FeeSharesSet(lpShare, protocolShare); } function setFeeShares(uint256 _lpShare, uint256 _protocolShare) external onlyOwner { require(_lpShare + _protocolShare == tradingFee, "Shares must sum to trading fee"); lpShare = _lpShare; protocolShare = _protocolShare; emit FeeSharesSet(_lpShare, _protocolShare); } function addValidMarket(address account) external onlyOwner { validMarkets[account] = true; } function removeValidMarket(address account) external onlyOwner { validMarkets[account] = false; } function setMarketCreationFee(uint256 _fee) external onlyOwner { marketCreationFee = _fee; emit MarketCreationFeeSet(_fee); } function setGovernor(address _governor) external onlyOwner { require(_governor != address(0), "Invalid governor"); governor = _governor; emit GovernorSet(_governor); } function getMarketAddress(uint256 _marketId) external view returns (address) { return markets[_marketId]; } // Router functions function trade( address market, int256[] calldata shareDeltas, uint256 maxCost ) external nonReentrant { require(verifiedMarkets[market], "Invalid market"); Market marketContract = Market(market); // Calculate cost uint256 tradeCost = marketContract.getNetCost(shareDeltas); require(tradeCost <= maxCost, "Cost exceeds maximum"); // Transfer tokens from user to factory require( IERC20(susdToken).transferFrom(msg.sender, address(this), tradeCost), "Token transfer failed" ); // Update market balance marketBalances[market] += tradeCost; // Execute trade on market marketContract.tradeViaFactory(msg.sender, shareDeltas); emit TokensDeposited(msg.sender, market, tradeCost); } function sell( address market, int256[] calldata shareDeltas ) external nonReentrant { require(verifiedMarkets[market], "Invalid market"); Market marketContract = Market(market); // Execute sell on market and get return amount uint256 returnAmount = marketContract.sellViaFactory(msg.sender, shareDeltas); // Transfer tokens from factory to user require( IERC20(susdToken).transfer(msg.sender, returnAmount), "Token transfer failed" ); // Update market balance marketBalances[market] -= returnAmount; emit TokensWithdrawn(msg.sender, market, returnAmount); } function payout( address market ) external nonReentrant { require(verifiedMarkets[market], "Invalid market"); Market marketContract = Market(market); // Get payout amount from market uint256 payoutAmount = marketContract.payoutViaFactory(msg.sender); require(payoutAmount > 0, "No payout available"); // Transfer tokens from factory to user require( IERC20(susdToken).transfer(msg.sender, payoutAmount), "Token transfer failed" ); // Update market balance marketBalances[market] -= payoutAmount; emit TokensWithdrawn(msg.sender, market, payoutAmount); } // View functions function getMarketBalance(address market) external view returns (uint256) { return marketBalances[market]; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable struct OwnableStorage { address _owner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; function _getOwnableStorage() private pure returns (OwnableStorage storage $) { assembly { $.slot := OwnableStorageLocation } } /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ function __Ownable_init(address initialOwner) internal onlyInitializing { __Ownable_init_unchained(initialOwner); } function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { OwnableStorage storage $ = _getOwnableStorage(); return $._owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { OwnableStorage storage $ = _getOwnableStorage(); address oldOwner = $._owner; $._owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.22; import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol"; import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; import {Initializable} from "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. */ abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable __self = address(this); /** * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function * during an upgrade. */ string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; /** * @dev The call is from an unauthorized context. */ error UUPSUnauthorizedCallContext(); /** * @dev The storage `slot` is unsupported as a UUID. */ error UUPSUnsupportedProxiableUUID(bytes32 slot); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { _checkProxy(); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { _checkNotDelegated(); _; } function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /** * @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual notDelegated returns (bytes32) { return ERC1967Utils.IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data); } /** * @dev Reverts if the execution is not performed via delegatecall or the execution * context is not of a proxy with an ERC-1967 compliant implementation pointing to self. * See {_onlyProxy}. */ function _checkProxy() internal view virtual { if ( address(this) == __self || // Must be called through delegatecall ERC1967Utils.getImplementation() != __self // Must be called through an active proxy ) { revert UUPSUnauthorizedCallContext(); } } /** * @dev Reverts if the execution is performed via delegatecall. * See {notDelegated}. */ function _checkNotDelegated() internal view virtual { if (address(this) != __self) { // Must not be called through delegatecall revert UUPSUnauthorizedCallContext(); } } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call. * * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value * is expected to be the implementation slot in ERC-1967. * * Emits an {IERC1967-Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) { revert UUPSUnsupportedProxiableUUID(slot); } ERC1967Utils.upgradeToAndCall(newImplementation, data); } catch { // The implementation is not UUPS revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at, * consider using {ReentrancyGuardTransient} instead. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard struct ReentrancyGuardStorage { uint256 _status; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) { assembly { $.slot := ReentrancyGuardStorageLocation } } /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); $._status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // On the first call to nonReentrant, _status will be NOT_ENTERED if ($._status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail $._status = ENTERED; } function _nonReentrantAfter() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) $._status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); return $._status == ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.20; /** * @dev ERC-1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol) pragma solidity ^0.8.20; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. */ interface IERC1967 { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.20; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {UpgradeableBeacon} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (proxy/Clones.sol) pragma solidity ^0.8.20; import {Create2} from "../utils/Create2.sol"; import {Errors} from "../utils/Errors.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-1167[ERC-1167] is a standard for * deploying minimal proxy contracts, also known as "clones". * * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies * > a minimal bytecode implementation that delegates all calls to a known, fixed address. * * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the * deterministic method. */ library Clones { error CloneArgumentsTooLong(); /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create opcode, which should never revert. */ function clone(address implementation) internal returns (address instance) { return clone(implementation, 0); } /** * @dev Same as {xref-Clones-clone-address-}[clone], but with a `value` parameter to send native currency * to the new contract. * * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory) * to always have enough balance for new deployments. Consider exposing this function under a payable method. */ function clone(address implementation, uint256 value) internal returns (address instance) { if (address(this).balance < value) { revert Errors.InsufficientBalance(address(this).balance, value); } assembly ("memory-safe") { // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes // of the `implementation` address with the bytecode before the address. mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) instance := create(value, 0x09, 0x37) } if (instance == address(0)) { revert Errors.FailedDeployment(); } } /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create2 opcode and a `salt` to deterministically deploy * the clone. Using the same `implementation` and `salt` multiple times will revert, since * the clones cannot be deployed twice at the same address. */ function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { return cloneDeterministic(implementation, salt, 0); } /** * @dev Same as {xref-Clones-cloneDeterministic-address-bytes32-}[cloneDeterministic], but with * a `value` parameter to send native currency to the new contract. * * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory) * to always have enough balance for new deployments. Consider exposing this function under a payable method. */ function cloneDeterministic( address implementation, bytes32 salt, uint256 value ) internal returns (address instance) { if (address(this).balance < value) { revert Errors.InsufficientBalance(address(this).balance, value); } assembly ("memory-safe") { // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes // of the `implementation` address with the bytecode before the address. mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) instance := create2(value, 0x09, 0x37, salt) } if (instance == address(0)) { revert Errors.FailedDeployment(); } } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { assembly ("memory-safe") { let ptr := mload(0x40) mstore(add(ptr, 0x38), deployer) mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff) mstore(add(ptr, 0x14), implementation) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73) mstore(add(ptr, 0x58), salt) mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37)) predicted := and(keccak256(add(ptr, 0x43), 0x55), 0xffffffffffffffffffffffffffffffffffffffff) } } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress( address implementation, bytes32 salt ) internal view returns (address predicted) { return predictDeterministicAddress(implementation, salt, address(this)); } /** * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom * immutable arguments. These are provided through `args` and cannot be changed after deployment. To * access the arguments within the implementation, use {fetchCloneArgs}. * * This function uses the create opcode, which should never revert. */ function cloneWithImmutableArgs(address implementation, bytes memory args) internal returns (address instance) { return cloneWithImmutableArgs(implementation, args, 0); } /** * @dev Same as {xref-Clones-cloneWithImmutableArgs-address-bytes-}[cloneWithImmutableArgs], but with a `value` * parameter to send native currency to the new contract. * * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory) * to always have enough balance for new deployments. Consider exposing this function under a payable method. */ function cloneWithImmutableArgs( address implementation, bytes memory args, uint256 value ) internal returns (address instance) { if (address(this).balance < value) { revert Errors.InsufficientBalance(address(this).balance, value); } bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args); assembly ("memory-safe") { instance := create(value, add(bytecode, 0x20), mload(bytecode)) } if (instance == address(0)) { revert Errors.FailedDeployment(); } } /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation` with custom * immutable arguments. These are provided through `args` and cannot be changed after deployment. To * access the arguments within the implementation, use {fetchCloneArgs}. * * This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same * `implementation`, `args` and `salt` multiple times will revert, since the clones cannot be deployed twice * at the same address. */ function cloneDeterministicWithImmutableArgs( address implementation, bytes memory args, bytes32 salt ) internal returns (address instance) { return cloneDeterministicWithImmutableArgs(implementation, args, salt, 0); } /** * @dev Same as {xref-Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-}[cloneDeterministicWithImmutableArgs], * but with a `value` parameter to send native currency to the new contract. * * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory) * to always have enough balance for new deployments. Consider exposing this function under a payable method. */ function cloneDeterministicWithImmutableArgs( address implementation, bytes memory args, bytes32 salt, uint256 value ) internal returns (address instance) { bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args); return Create2.deploy(value, salt, bytecode); } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}. */ function predictDeterministicAddressWithImmutableArgs( address implementation, bytes memory args, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args); return Create2.computeAddress(salt, keccak256(bytecode), deployer); } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}. */ function predictDeterministicAddressWithImmutableArgs( address implementation, bytes memory args, bytes32 salt ) internal view returns (address predicted) { return predictDeterministicAddressWithImmutableArgs(implementation, args, salt, address(this)); } /** * @dev Get the immutable args attached to a clone. * * - If `instance` is a clone that was deployed using `clone` or `cloneDeterministic`, this * function will return an empty array. * - If `instance` is a clone that was deployed using `cloneWithImmutableArgs` or * `cloneDeterministicWithImmutableArgs`, this function will return the args array used at * creation. * - If `instance` is NOT a clone deployed using this library, the behavior is undefined. This * function should only be used to check addresses that are known to be clones. */ function fetchCloneArgs(address instance) internal view returns (bytes memory) { bytes memory result = new bytes(instance.code.length - 45); // revert if length is too short assembly ("memory-safe") { extcodecopy(instance, add(result, 32), 45, mload(result)) } return result; } /** * @dev Helper that prepares the initcode of the proxy with immutable args. * * An assembly variant of this function requires copying the `args` array, which can be efficiently done using * `mcopy`. Unfortunately, that opcode is not available before cancun. A pure solidity implementation using * abi.encodePacked is more expensive but also more portable and easier to review. * * NOTE: https://eips.ethereum.org/EIPS/eip-170[EIP-170] limits the length of the contract code to 24576 bytes. * With the proxy code taking 45 bytes, that limits the length of the immutable args to 24531 bytes. */ function _cloneCodeWithImmutableArgs( address implementation, bytes memory args ) private pure returns (bytes memory) { if (args.length > 24531) revert CloneArgumentsTooLong(); return abi.encodePacked( hex"61", uint16(args.length + 45), hex"3d81600a3d39f3363d3d373d3d3d363d73", implementation, hex"5af43d82803e903d91602b57fd5bf3", args ); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (proxy/ERC1967/ERC1967Utils.sol) pragma solidity ^0.8.22; import {IBeacon} from "../beacon/IBeacon.sol"; import {IERC1967} from "../../interfaces/IERC1967.sol"; import {Address} from "../../utils/Address.sol"; import {StorageSlot} from "../../utils/StorageSlot.sol"; /** * @dev This library provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots. */ library ERC1967Utils { /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev The `implementation` of the proxy is invalid. */ error ERC1967InvalidImplementation(address implementation); /** * @dev The `admin` of the proxy is invalid. */ error ERC1967InvalidAdmin(address admin); /** * @dev The `beacon` of the proxy is invalid. */ error ERC1967InvalidBeacon(address beacon); /** * @dev An upgrade function sees `msg.value > 0` that may be lost. */ error ERC1967NonPayable(); /** * @dev Returns the current implementation address. */ function getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the ERC-1967 implementation slot. */ function _setImplementation(address newImplementation) private { if (newImplementation.code.length == 0) { revert ERC1967InvalidImplementation(newImplementation); } StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Performs implementation upgrade with additional setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) internal { _setImplementation(newImplementation); emit IERC1967.Upgraded(newImplementation); if (data.length > 0) { Address.functionDelegateCall(newImplementation, data); } else { _checkNonPayable(); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(ADMIN_SLOT).value; } /** * @dev Stores a new address in the ERC-1967 admin slot. */ function _setAdmin(address newAdmin) private { if (newAdmin == address(0)) { revert ERC1967InvalidAdmin(address(0)); } StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {IERC1967-AdminChanged} event. */ function changeAdmin(address newAdmin) internal { emit IERC1967.AdminChanged(getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(BEACON_SLOT).value; } /** * @dev Stores a new beacon in the ERC-1967 beacon slot. */ function _setBeacon(address newBeacon) private { if (newBeacon.code.length == 0) { revert ERC1967InvalidBeacon(newBeacon); } StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon; address beaconImplementation = IBeacon(newBeacon).implementation(); if (beaconImplementation.code.length == 0) { revert ERC1967InvalidImplementation(beaconImplementation); } } /** * @dev Change the beacon and trigger a setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-BeaconUpgraded} event. * * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for * efficiency. */ function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal { _setBeacon(newBeacon); emit IERC1967.BeaconUpgraded(newBeacon); if (data.length > 0) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } else { _checkNonPayable(); } } /** * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract * if an upgrade doesn't perform an initialization call. */ function _checkNonPayable() private { if (msg.value > 0) { revert ERC1967NonPayable(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 standard as defined in the ERC. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (utils/Address.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert Errors.InsufficientBalance(address(this).balance, amount); } (bool success, bytes memory returndata) = recipient.call{value: amount}(""); if (!success) { _revert(returndata); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {Errors.FailedCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert Errors.InsufficientBalance(address(this).balance, value); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case * of an unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {Errors.FailedCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly ("memory-safe") { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert Errors.FailedCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Create2.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; /** * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer. * `CREATE2` can be used to compute in advance the address where a smart * contract will be deployed, which allows for interesting new mechanisms known * as 'counterfactual interactions'. * * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more * information. */ library Create2 { /** * @dev There's no code to deploy. */ error Create2EmptyBytecode(); /** * @dev Deploys a contract using `CREATE2`. The address where the contract * will be deployed can be known in advance via {computeAddress}. * * The bytecode for a contract can be obtained from Solidity with * `type(contractName).creationCode`. * * Requirements: * * - `bytecode` must not be empty. * - `salt` must have not been used for `bytecode` already. * - the factory must have a balance of at least `amount`. * - if `amount` is non-zero, `bytecode` must have a `payable` constructor. */ function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) { if (address(this).balance < amount) { revert Errors.InsufficientBalance(address(this).balance, amount); } if (bytecode.length == 0) { revert Create2EmptyBytecode(); } assembly ("memory-safe") { addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt) // if no address was created, and returndata is not empty, bubble revert if and(iszero(addr), not(iszero(returndatasize()))) { let p := mload(0x40) returndatacopy(p, 0, returndatasize()) revert(p, returndatasize()) } } if (addr == address(0)) { revert Errors.FailedDeployment(); } } /** * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the * `bytecodeHash` or `salt` will result in a new destination address. */ function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) { return computeAddress(salt, bytecodeHash, address(this)); } /** * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}. */ function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) { assembly ("memory-safe") { let ptr := mload(0x40) // Get free memory pointer // | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... | // |-------------------|---------------------------------------------------------------------------| // | bytecodeHash | CCCCCCCCCCCCC...CC | // | salt | BBBBBBBBBBBBB...BB | // | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA | // | 0xFF | FF | // |-------------------|---------------------------------------------------------------------------| // | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC | // | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ | mstore(add(ptr, 0x40), bytecodeHash) mstore(add(ptr, 0x20), salt) mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff mstore8(start, 0xff) addr := and(keccak256(start, 85), 0xffffffffffffffffffffffffffffffffffffffff) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol) pragma solidity ^0.8.20; /** * @dev Collection of common custom errors used in multiple contracts * * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. * It is recommended to avoid relying on the error API for critical functionality. * * _Available since v5.1._ */ library Errors { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error InsufficientBalance(uint256 balance, uint256 needed); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedCall(); /** * @dev The deployment failed. */ error FailedDeployment(); /** * @dev A necessary precompile is missing. */ error MissingPrecompile(address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { bool private _paused; /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); /** * @dev The operation failed because the contract is paused. */ error EnforcedPause(); /** * @dev The operation failed because the contract is not paused. */ error ExpectedPause(); /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { if (paused()) { revert EnforcedPause(); } } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { if (!paused()) { revert ExpectedPause(); } } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at, * consider using {ReentrancyGuardTransient} instead. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; uint256 private _status; /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); constructor() { _status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be NOT_ENTERED if (_status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail _status = ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.20; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC-1967 implementation slot: * ```solidity * contract ERC1967 { * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * TIP: Consider using this library along with {SlotDerivation}. */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct Int256Slot { int256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Int256Slot` with member `value` located at `slot`. */ function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } /** * @dev Returns a `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; library LMSRMath { // Fixed point precision uint256 constant FIXED_ONE = 1e18; // Maximum value for exponentiation to avoid overflow uint256 constant MAX_EXPONENT = 100e18; function calcCost( uint256[] memory outcomeShares, int256[] memory shareDeltas, uint256 b ) internal pure returns (int256) { require(outcomeShares.length == shareDeltas.length, "Array length mismatch"); require(outcomeShares.length > 0, "Empty arrays"); require(b > 0, "Invalid liquidity parameter"); // Calculate cost before trade uint256 costBefore = calcCostFromShares(outcomeShares, b); // Calculate new outcome shares after trade uint256[] memory newShares = new uint256[](outcomeShares.length); for (uint256 i = 0; i < outcomeShares.length; i++) { if (shareDeltas[i] >= 0) { newShares[i] = outcomeShares[i] + uint256(shareDeltas[i]); } else { require(outcomeShares[i] >= uint256(-shareDeltas[i]), "Insufficient shares"); newShares[i] = outcomeShares[i] - uint256(-shareDeltas[i]); } } // Calculate cost after trade uint256 costAfter = calcCostFromShares(newShares, b); // Return difference in costs if (costAfter >= costBefore) { return int256(costAfter - costBefore); } else { return -int256(costBefore - costAfter); } } function calcCostFromShares( uint256[] memory shares, uint256 b ) internal pure returns (uint256) { uint256 sum = 0; // Calculate sum of exp(q_i/b) for all outcomes for (uint256 i = 0; i < shares.length; i++) { // Normalize shares by dividing by b uint256 normalizedShares = (shares[i] * FIXED_ONE) / b; // Prevent overflow by capping the exponent if (normalizedShares > MAX_EXPONENT) { normalizedShares = MAX_EXPONENT; } // Calculate exp(q_i/b) and add to sum sum += exp(normalizedShares); } // Calculate b * ln(sum) return (b * ln(sum)) / FIXED_ONE; } function calcMarginalPrice( uint256 outcomeIndex, uint256[] memory shares, uint256 b ) internal pure returns (uint256) { require(outcomeIndex < shares.length, "Invalid outcome index"); // Calculate sum of exp(q_i/b) for all outcomes uint256 sum = 0; for (uint256 i = 0; i < shares.length; i++) { uint256 normalizedShares = (shares[i] * FIXED_ONE) / b; if (normalizedShares > MAX_EXPONENT) { normalizedShares = MAX_EXPONENT; } sum += exp(normalizedShares); } // Calculate exp(q_i/b) for the specific outcome uint256 normalizedOutcomeShares = (shares[outcomeIndex] * FIXED_ONE) / b; if (normalizedOutcomeShares > MAX_EXPONENT) { normalizedOutcomeShares = MAX_EXPONENT; } uint256 outcomeExp = exp(normalizedOutcomeShares); // Calculate price = exp(q_i/b) / sum(exp(q_j/b)) return (outcomeExp * FIXED_ONE) / sum; } function exp(uint256 x) internal pure returns (uint256) { // If x is 0, e^0 = 1 if (x == 0) return FIXED_ONE; // If x is very large, return maximum value to avoid overflow if (x > MAX_EXPONENT) return type(uint256).max; // Taylor series approximation for e^x // e^x = 1 + x + x^2/2! + x^3/3! + ... + x^n/n! uint256 result = FIXED_ONE; // 1 uint256 term = FIXED_ONE; // Start with 1 // Add x term = (term * x) / FIXED_ONE; result += term; // Add x^2/2! term = (term * x) / (2 * FIXED_ONE); result += term; // Add x^3/3! term = (term * x) / (3 * FIXED_ONE); result += term; // Add x^4/4! term = (term * x) / (4 * FIXED_ONE); result += term; // Add x^5/5! term = (term * x) / (5 * FIXED_ONE); result += term; // Add x^6/6! term = (term * x) / (6 * FIXED_ONE); result += term; // Add x^7/7! term = (term * x) / (7 * FIXED_ONE); result += term; // Add x^8/8! term = (term * x) / (8 * FIXED_ONE); result += term; return result; } function ln(uint256 x) internal pure returns (uint256) { // If x is 0 or very small, return a very negative number // In practice, this should never happen in LMSR if (x < FIXED_ONE / 1000) { return 0; // Should revert in practice } // If x is 1, ln(1) = 0 if (x == FIXED_ONE) return 0; // If x < 1, use ln(x) = -ln(1/x) if (x < FIXED_ONE) { return type(uint256).max - ln((FIXED_ONE * FIXED_ONE) / x) + 1; } // For x > 1, use binary search to find y such that e^y = x uint256 low = 0; uint256 high = MAX_EXPONENT; uint256 mid; uint256 midExp; // Binary search for 32 iterations (sufficient precision) for (uint256 i = 0; i < 32; i++) { mid = (low + high) / 2; midExp = exp(mid); if (midExp < x) { low = mid; } else if (midExp > x) { high = mid; } else { return mid; // Exact match found } } // Return the closest approximation return (low + high) / 2; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "@openzeppelin/contracts/utils/Pausable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./LMSRMath.sol"; contract Market is Ownable, Pausable, ReentrancyGuard { // State variables address public factory; address public feeRecipient; address public reporter; address public governor; address public susdToken; uint256 public b; uint256 public resolutionDelay; uint256 public tradingFee; uint256 public disputeBondAmount; uint256 public reporterResolutionDeadline; uint256 public resolutionTimestamp; uint256 public totalVotes; uint256 public mostVotedOutcome; uint256 public winningOutcome; bool public resolved; string[] public outcomes; mapping(uint256 => uint256) public outcomeShares; mapping(address => mapping(uint256 => uint256)) public userShares; mapping(address => uint256) public disputeBonds; mapping(uint256 => uint256) public disputeVotes; mapping(address => bool) public hasVoted; uint256 public constant DISPUTE_PERIOD = 7 days; uint256 public constant MAX_TRADE_PERCENTAGE = 10; // Events event Trade( address indexed user, int256[] shareDeltas, uint256[] shareBalances, uint256 feesPaid ); event MarketResolved(uint256 indexed outcome); event ResolutionProposed(uint256 indexed outcome, uint256 resolutionTimestamp); event DisputeSubmitted( address indexed disputer, uint256 indexed proposedOutcome, uint256 bondAmount ); event VoteCast(address indexed voter, uint256 indexed outcome); event Payout(address indexed user, uint256 amount); event ReporterDeadlineSet(uint256 deadline); event EmergencyResolution(uint256 indexed outcome, address resolver); // Modifiers modifier onlyFactory() { require(msg.sender == factory, "Only factory can call this function"); _; } constructor( string[] memory _outcomes, address _feeRecipient, uint256 _resolutionDelay, address _reporter, address _governor, uint256 _b, uint256 _tradingFee, address _susdToken, uint256 _disputeBondAmount ) Ownable(_governor) Pausable() ReentrancyGuard() { require(_outcomes.length >= 2, "Must have at least 2 outcomes"); require(_feeRecipient != address(0), "Invalid fee recipient"); require(_reporter != address(0), "Invalid reporter"); require(_governor != address(0), "Invalid governor"); require(_susdToken != address(0), "Invalid SUSD token"); require(_b > 0, "Invalid liquidity parameter"); factory = msg.sender; feeRecipient = _feeRecipient; reporter = _reporter; governor = _governor; susdToken = _susdToken; b = _b; resolutionDelay = _resolutionDelay; tradingFee = _tradingFee; disputeBondAmount = _disputeBondAmount; for (uint256 i = 0; i < _outcomes.length; i++) { outcomes.push(_outcomes[i]); outcomeShares[i] = 1e18; } reporterResolutionDeadline = block.timestamp + 30 days; emit ReporterDeadlineSet(reporterResolutionDeadline); _transferOwnership(governor); } // Existing Market contract functions function getCurrentShares() public view returns (uint256[] memory) { uint256[] memory shares = new uint256[](outcomes.length); for (uint256 i = 0; i < outcomes.length; i++) { shares[i] = outcomeShares[i]; } return shares; } function getCost(int256[] memory shareDeltas) public view returns (int256) { require(shareDeltas.length == outcomes.length, "Invalid array length"); // Get current shares uint256[] memory shares = getCurrentShares(); // Calculate cost using LMSR math return LMSRMath.calcCost(shares, shareDeltas, b); } function getNetCost(int256[] memory shareDeltas) public view returns (uint256) { int256 cost = getCost(shareDeltas); // If cost is negative (selling), return 0 as net cost if (cost <= 0) return 0; // Apply trading fee uint256 fee = (uint256(cost) * tradingFee) / 10000; return uint256(cost) + fee; } function getMarginalPrice(uint256 outcomeIndex) public view returns (uint256) { require(outcomeIndex < outcomes.length, "Invalid outcome index"); uint256[] memory shares = getCurrentShares(); return LMSRMath.calcMarginalPrice(outcomeIndex, shares, b); } function resolveMarket(uint256 outcome) external { require(!resolved, "Market already resolved"); require(block.timestamp >= reporterResolutionDeadline, "Too early"); require(outcome < outcomes.length, "Invalid outcome"); winningOutcome = outcome; resolutionTimestamp = block.timestamp; resolved = true; emit ResolutionProposed(outcome, resolutionTimestamp); emit MarketResolved(outcome); } function overrideResolution(uint256 outcome) external onlyFactory { require(!resolved, "Market already resolved"); require(block.timestamp < resolutionTimestamp, "Dispute period ended"); require(outcome < outcomes.length, "Invalid outcome"); resolved = true; winningOutcome = outcome; resolutionTimestamp = 0; emit MarketResolved(outcome); } // Dispute mechanism for users function submitDispute(uint256 proposedOutcome) external nonReentrant { require(!resolved, "Market already resolved"); require(proposedOutcome < outcomes.length, "Invalid outcome"); require(!hasVoted[msg.sender], "Already voted"); require(block.timestamp <= resolutionTimestamp + DISPUTE_PERIOD, "Dispute period ended"); require(IERC20(susdToken).transferFrom(msg.sender, address(this), disputeBondAmount), "Bond transfer failed"); disputeBonds[msg.sender] = disputeBondAmount; disputeVotes[proposedOutcome] += disputeBondAmount; totalVotes += disputeBondAmount; hasVoted[msg.sender] = true; if (disputeVotes[proposedOutcome] > disputeVotes[mostVotedOutcome]) { mostVotedOutcome = proposedOutcome; } emit DisputeSubmitted(msg.sender, proposedOutcome, disputeBondAmount); emit VoteCast(msg.sender, proposedOutcome); } function finalizeDispute() external nonReentrant { require(!resolved, "Market already resolved"); require(block.timestamp > resolutionTimestamp + DISPUTE_PERIOD, "Dispute period not ended"); require(totalVotes > 0, "No disputes submitted"); winningOutcome = mostVotedOutcome; resolved = true; emit MarketResolved(mostVotedOutcome); } function claimDisputeBond() external nonReentrant { require(resolved, "Market not resolved"); require(disputeBonds[msg.sender] > 0, "No bond to claim"); require(block.timestamp > resolutionTimestamp + DISPUTE_PERIOD, "Dispute period not ended"); uint256 bondAmount = disputeBonds[msg.sender]; disputeBonds[msg.sender] = 0; // If voted for winning outcome, get reward from losing votes if (hasVoted[msg.sender]) { uint256 shareOfWinningVotes = (bondAmount * 1e18) / disputeVotes[winningOutcome]; bondAmount += (totalVotes - disputeVotes[winningOutcome]) * shareOfWinningVotes / 1e18; } require(IERC20(susdToken).transfer(msg.sender, bondAmount), "Bond return failed"); } // Emergency resolution if reporter never resolves function emergencyResolve() external { require(!resolved, "Market already resolved"); require(block.timestamp > reporterResolutionDeadline, "Reporter deadline not passed"); // If disputes exist, use most voted outcome uint256 finalOutcome = totalVotes > 0 ? mostVotedOutcome : 0; resolved = true; winningOutcome = finalOutcome; emit EmergencyResolution(finalOutcome, msg.sender); emit MarketResolved(finalOutcome); } // Allow factory to set a new reporter deadline function setReporterDeadline(uint256 newDeadline) external onlyFactory { require(newDeadline > block.timestamp, "Deadline must be in future"); reporterResolutionDeadline = newDeadline; emit ReporterDeadlineSet(newDeadline); } function verifyInitialization( string[] calldata _outcomes, uint256 _resolutionDelay, address _reporter, address _governor ) external view returns (bool) { // Verify that initialization parameters match if (_outcomes.length != outcomes.length) return false; if (_reporter != reporter) return false; if (_governor != governor) return false; if (_resolutionDelay != resolutionDelay) return false; // Verify outcomes match for (uint256 i = 0; i < _outcomes.length; i++) { if (keccak256(bytes(_outcomes[i])) != keccak256(bytes(outcomes[i]))) { return false; } } return true; } // View functions function getMarketInfo() external view returns ( string[] memory, uint256[] memory, uint256, bool, uint256 ) { uint256[] memory shares = getCurrentShares(); return (outcomes, shares, b, resolved, winningOutcome); } function getResolutionDelay() external view returns (uint256) { return resolutionDelay; } function getProposedOutcome() external view returns (uint256) { return winningOutcome; } function getResolutionTimestamp() external view returns (uint256) { return resolutionTimestamp; } function getReporter() external view returns (address) { return reporter; } function getGovernor() external view returns (address) { return governor; } function getAIAddress() external view returns (address) { return address(this); } function getTradingFee() external view returns (uint256) { return tradingFee; } // Pause/unpause functions function pause() external onlyOwner { _pause(); } function unpause() external onlyOwner { _unpause(); } // Router functions renamed to factory functions function tradeViaFactory( address user, int256[] calldata shareDeltas ) external onlyFactory whenNotPaused { require(!resolved, "Market already resolved"); require(shareDeltas.length == outcomes.length, "Invalid array length"); // Validate trade size to prevent manipulation uint256[] memory shares = getCurrentShares(); for (uint256 i = 0; i < shareDeltas.length; i++) { if (shareDeltas[i] > 0) { require( uint256(shareDeltas[i]) <= (shares[i] * MAX_TRADE_PERCENTAGE) / 100, "Trade size too large" ); } else if (shareDeltas[i] < 0) { require( uint256(-shareDeltas[i]) <= userShares[user][i], "Insufficient shares" ); } } // Update shares for (uint256 i = 0; i < shareDeltas.length; i++) { if (shareDeltas[i] != 0) { outcomeShares[i] = uint256(int256(outcomeShares[i]) + shareDeltas[i]); userShares[user][i] = uint256(int256(userShares[user][i]) + shareDeltas[i]); } } // Get updated share balances for the event uint256[] memory newBalances = getCurrentShares(); emit Trade(user, shareDeltas, newBalances, 0); } function sellViaFactory( address user, int256[] calldata shareDeltas ) external onlyFactory whenNotPaused returns (uint256) { require(!resolved, "Market already resolved"); require(shareDeltas.length == outcomes.length, "Invalid array length"); // Calculate return amount int256 cost = getCost(shareDeltas); uint256 returnAmount = uint256(-cost); // Cost will be negative for sells // Update shares for (uint256 i = 0; i < shareDeltas.length; i++) { if (shareDeltas[i] != 0) { require( uint256(-shareDeltas[i]) <= userShares[user][i], "Insufficient shares" ); outcomeShares[i] = uint256(int256(outcomeShares[i]) + shareDeltas[i]); userShares[user][i] = uint256(int256(userShares[user][i]) + shareDeltas[i]); } } // Get updated share balances for the event uint256[] memory newBalances = getCurrentShares(); emit Trade(user, shareDeltas, newBalances, 0); return returnAmount; } function payoutViaFactory( address user ) external onlyFactory returns (uint256) { require(resolved, "Market not resolved"); uint256 shares = userShares[user][winningOutcome]; require(shares > 0, "No winning shares"); uint256 payoutAmount = shares; userShares[user][winningOutcome] = 0; emit Payout(user, payoutAmount); return payoutAmount; } }
{ "optimizer": { "enabled": true, "runs": 200 }, "viaIR": true, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newFeeRecipient","type":"address"}],"name":"FeeRecipientSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newLpShare","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newProtocolShare","type":"uint256"}],"name":"FeeSharesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newGovernor","type":"address"}],"name":"GovernorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"market","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"string[]","name":"outcomes","type":"string[]"},{"indexed":false,"internalType":"address","name":"reporter","type":"address"},{"indexed":false,"internalType":"uint256","name":"b","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"disputeBondAmount","type":"uint256"}],"name":"MarketCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"MarketCreationFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newImplementation","type":"address"}],"name":"MarketImplementationUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"market","type":"address"}],"name":"MarketUnverified","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"market","type":"address"}],"name":"MarketVerified","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":"user","type":"address"},{"indexed":true,"internalType":"address","name":"market","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"market","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newTradingFee","type":"uint256"}],"name":"TradingFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"WhitelistedAddressAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"WhitelistedAddressRemoved","type":"event"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addValidMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string[]","name":"outcomes","type":"string[]"},{"internalType":"uint256","name":"resolutionDelay","type":"uint256"},{"internalType":"address","name":"reporter","type":"address"},{"internalType":"uint256","name":"b","type":"uint256"},{"internalType":"uint256","name":"disputeBondAmount","type":"uint256"}],"name":"createMarket","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_marketId","type":"uint256"}],"name":"getMarketAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"getMarketBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_governor","type":"address"},{"internalType":"address","name":"_feeRecipient","type":"address"},{"internalType":"uint256","name":"_marketCreationFee","type":"uint256"},{"internalType":"address","name":"_susdToken","type":"address"},{"internalType":"uint256","name":"_tradingFee","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lpShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"marketBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketCreationFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"markets","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"payout","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"protocolShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"removeValidMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"int256[]","name":"shareDeltas","type":"int256[]"}],"name":"sell","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lpShare","type":"uint256"},{"internalType":"uint256","name":"_protocolShare","type":"uint256"}],"name":"setFeeShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_governor","type":"address"}],"name":"setGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setMarketCreationFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tradingFee","type":"uint256"}],"name":"setTradingFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"susdToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"internalType":"int256[]","name":"shareDeltas","type":"int256[]"},{"internalType":"uint256","name":"maxCost","type":"uint256"}],"name":"trade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tradingFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"validMarkets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"verifiedMarkets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelistedAddresses","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60a080604052346100cc57306080527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff8260401c166100bd57506001600160401b036002600160401b031982821601610078575b6040516147bb90816100d2823960805181818161119c015261125e0152f35b6001600160401b031990911681179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1388080610059565b63f92ee8a960e01b8152600490fd5b600080fdfe60808060405260043610156200001457600080fd5b600090813560e01c90816306c933d81462001662575080630b7e9c44146200153b5780630c340a2414620015105780631103f31514620014f05780632ef1bdfa14620014d05780632f1ac04a14620008595780634690484014620014a7578063484a87a2146200145d5780634f1ef286146200120757806352d1902d146200118757806356f433521462001167578063647096ea1462000fb057806366f13ae41462000ef75780636a9caa5314620004da5780636ed71ede1462000ed757806370ee6b121462000e90578063715018a61462000e215780637c94674f1462000aae5780638da5cb5b1462000a755780639cb120c41462000a325780639f37022a14620009e0578063ad3cb1cc146200096a578063adaf1c431462000927578063b0d54bcf146200088e578063b1283e771462000859578063c42cf53514620007dc578063d02ab9531462000517578063e80b5b5f14620004da578063ebc38ab014620004ba578063f2fde38b1462000485578063f39690e4146200045a578063f7c00e6314620001db5763f887ea4014620001ae57600080fd5b34620001d85780600319360112620001d857600b546040516001600160a01b039091168152602090f35b80fd5b5034620001d85760a0366003190112620001d857620001f9620016a2565b6001600160a01b03906024358281169190829003620004555760643583811680910362000455577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009283549460ff8660401c16159367ffffffffffffffff8716968715806200044d575b6001809914908162000442575b15908162000438575b50620004265767ffffffffffffffff198116881787558562000406575b50620002a162001a6e565b620002ab62001a6e565b620002b6816200198b565b620002c062001a6e565b620002ca62001a6e565b866000805160206200476683398151915255620002e662001a6e565b16620002f48115156200194b565b8115620003c95782156200038f57866009556bffffffffffffffffffffffff60a01b918288541617875581865416178555604435600255600654161760065560843560035561038460045560646005556200034d578280f35b805468ff0000000000000000191690556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a138808280f35b60405162461bcd60e51b815260206004820152601260248201527124b73b30b634b21029aaa9a2103a37b5b2b760711b6044820152606490fd5b60405162461bcd60e51b8152602060048201526015602482015274125b9d985b1a5908199959481c9958da5c1a595b9d605a1b6044820152606490fd5b68ffffffffffffffffff1916680100000000000000011786553862000296565b60405163f92ee8a960e01b8152600490fd5b9050153862000279565b303b15915062000270565b508562000263565b600080fd5b5034620001d85780600319360112620001d8576006546040516001600160a01b039091168152602090f35b5034620001d8576020366003190112620001d857620004b7620004a7620016a2565b620004b162001a33565b6200198b565b80f35b5034620001d85780600319360112620001d8576020600454604051908152f35b5034620001d8576020366003190112620001d8576020906040906001600160a01b0362000506620016a2565b168152600c83522054604051908152f35b5034620001d8576060366003190112620001d85762000535620016a2565b67ffffffffffffffff90602435828111620007d8576200055a9036906004016200174b565b906200056562001a01565b60018060a01b0380931693848652602092600884526200058c60ff604089205416620017c1565b604051635fae637160e01b81526004810185905294848680620005b460248201868962001882565b03818a5afa958615620007cd57889662000794575b50604435861162000758576006546040516323b872dd60e01b81523360048201523060248201526044810188905289939290918791839160649183918891165af180156200074d576200062591849162000719575b5062001819565b868252600c8552604082206200063d878254620018dc565b9055863b1562000715576040516304b047c760e41b815293849182916200066a91903360048501620018b5565b038183895af180156200070a57620006c0575b50507fcbc4a4091b012bb1329c38bbbb15455f5cac5aa3673da0a7f38cd61a4f495517906040519283523392a36001600080516020620047668339815191525580f35b8195929511620006f657604052927fcbc4a4091b012bb1329c38bbbb15455f5cac5aa3673da0a7f38cd61a4f495517386200067d565b634e487b7160e01b82526041600452602482fd5b6040513d88823e3d90fd5b5080fd5b6200073e9150873d891162000745575b620007358183620016b9565b810190620017ff565b386200061e565b503d62000729565b6040513d85823e3d90fd5b60405162461bcd60e51b8152600481018690526014602482015273436f73742065786365656473206d6178696d756d60601b6044820152606490fd5b9095508481813d8311620007c5575b620007af8183620016b9565b81010312620007c157519438620005c9565b8780fd5b503d620007a3565b6040513d8a823e3d90fd5b8380fd5b5034620001d8576020366003190112620001d8577f1cbb37f5a02c38ab13773cb770fae505cce417a4d81560117389e3a9f7e001f260206200081d620016a2565b6200082762001a33565b6001600160a01b03166200083d8115156200194b565b600180546001600160a01b03191682179055604051908152a180f35b5034620001d8576020366003190112620001d857602090600435815260078252604060018060a01b0391205416604051908152f35b5034620001d8576020366003190112620001d857600435620008af62001a33565b6107d08111620008f3576003557ffabf709ddcab6908663bc153944d0c2f54570ba46d078aecb046e384610874d4604060045460055482519182526020820152a180f35b60405162461bcd60e51b815260206004820152600c60248201526b08ccaca40e8dede40d0d2ced60a31b6044820152606490fd5b5034620001d8576020366003190112620001d85760209060ff906040906001600160a01b0362000956620016a2565b168152600d84522054166040519015158152f35b5034620001d85780600319360112620001d8576040516040810181811067ffffffffffffffff821117620009cc57620009c8925060405260058152640352e302e360dc1b60208201526040519182916020835260208301906200177f565b0390f35b634e487b7160e01b83526041600452602483fd5b5034620001d8576020366003190112620001d8577f583934e5b9be5235b40454ddbb9f61b157293eafefaa7b988cff6fd79f2ca43e602060043562000a2462001a33565b80600255604051908152a180f35b5034620001d8576020366003190112620001d85760209060ff906040906001600160a01b0362000a61620016a2565b168152600884522054166040519015158152f35b5034620001d85780600319360112620001d85760008051602062004746833981519152546040516001600160a01b039091168152602090f35b5034620001d85760a0366003190112620001d8576004359067ffffffffffffffff90818311620001d85736602384011215620001d857826004013592828411620006f6578360051b906040519462000b0a6020840187620016b9565b85526024602086019282010190368211620007d85760248101925b82841062000ddf575050604435939150506001600160a01b0383168303620007155762000b5162001a01565b6006546002546040516323b872dd60e01b81523360048201523060248201526044810191909152906020908290606490829087906001600160a01b03165af19081156200074d57839162000dbb575b501562000d6a578154600154600354600654604051946001600160a01b03948516949182169390911690612c2d86019081119086111762000d56579084939291612c2d62001b198639610120612c2d860181815262000c0191018a620018ea565b612c2d8601602081019590955260243560408601526001600160a01b0389166060860152608085019190915260643560a085015260c084019190915260e083019190915260843561010090920191909152039082f0801562000d495760018060a01b0316916009548252600760205260408220836bffffffffffffffffffffffff60a01b825416179055828252600d60205260408220600160ff19825416179055827f4b85df0c16f0c5066543554eec76a5782a8fe0bd2d18987467be7cd704d1e93862000ce3600954968794604051928392608084526080840190620018ea565b6001600160a01b039091166020830152606435604083015260843560608301520390a3600019831462000d35575060016020920160095560016000805160206200476683398151915255604051908152f35b634e487b7160e01b81526011600452602490fd5b50604051903d90823e3d90fd5b634e487b7160e01b86526041600452602486fd5b60405162461bcd60e51b815260206004820152602360248201527f4d61726b6574206372656174696f6e20666565207472616e73666572206661696044820152621b195960ea1b6064820152608490fd5b62000dd8915060203d6020116200074557620007358183620016b9565b3862000ba0565b833586811162000e1d5782013660438201121562000e1d5760209162000e11839236906044602482013591016200170f565b81520193019262000b25565b8580fd5b5034620001d85780600319360112620001d85762000e3e62001a33565b6000805160206200474683398151915280546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b5034620001d8576020366003190112620001d85762000eae620016a2565b62000eb862001a33565b6001600160a01b03168152600d60205260408120805460ff1916905580f35b5034620001d85780600319360112620001d8576020600954604051908152f35b5034620001d8576040366003190112620001d85760043560243562000f1b62001a33565b62000f278183620018dc565b6003540362000f6b57816040917ffabf709ddcab6908663bc153944d0c2f54570ba46d078aecb046e384610874d4936004558060055582519182526020820152a180f35b60405162461bcd60e51b815260206004820152601e60248201527f536861726573206d7573742073756d20746f2074726164696e672066656500006044820152606490fd5b5034620001d8576040366003190112620001d85762000fce620016a2565b60243567ffffffffffffffff8111620011635762000ff5620010479136906004016200174b565b90926200100162001a01565b60018060a01b03809116938486526020928391600883526200102a60ff60408a205416620017c1565b60405163c91de47360e01b815295869283923360048501620018b5565b038188885af19283156200111f5785936200112a575b5060065460405163a9059cbb60e01b81523360048201526024810185905292918291849116818881604481015b03925af19182156200111f577f6337ed398c0e8467698c581374fdce4db14922df487b5a39483079f5f59b60a492620010cb91879162001104575062001819565b838552600c815260408520620010e38482546200185e565b90556040519283523392a36001600080516020620047668339815191525580f35b6200073e9150833d85116200074557620007358183620016b9565b6040513d87823e3d90fd5b9092508181813d83116200115b575b620011458183620016b9565b8101031262001157575191386200105d565b8480fd5b503d62001139565b8280fd5b5034620001d85780600319360112620001d8576020600354604051908152f35b5034620001d85780600319360112620001d8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003620011f55760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b60405163703e46dd60e11b8152600490fd5b506040366003190112620001d8576200121f620016a2565b60243567ffffffffffffffff81116200116357366023820112156200116357620012549036906024816004013591016200170f565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081163081149081156200142e575b50620011f5576200129b62001a33565b6040516352d1902d60e01b8152908316926020918281600481885afa869181620013f5575b50620012df57604051634c9c8ce360e01b815260048101869052602490fd5b9385947f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90818103620013dd5750823b15620013c45780546001600160a01b0319168217905560405185917fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8380a2845115620013a657508084846200139896519101845af4903d156200139c573d6200137981620016f2565b90620013896040519283620016b9565b81528581943d92013e62001ab0565b5080f35b6060925062001ab0565b935050505034620013b5575080f35b63b398979f60e01b8152600490fd5b604051634c9c8ce360e01b815260048101839052602490fd5b60249060405190632a87526960e21b82526004820152fd5b9091508381813d831162001426575b620014108183620016b9565b810103126200142257519038620012c0565b8680fd5b503d62001404565b9050817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54161415386200128b565b5034620001d8576020366003190112620001d8576200147b620016a2565b6200148562001a33565b6001600160a01b03168152600d60205260408120805460ff1916600117905580f35b5034620001d85780600319360112620001d857546040516001600160a01b039091168152602090f35b5034620001d85780600319360112620001d8576020600254604051908152f35b5034620001d85780600319360112620001d8576020600554604051908152f35b5034620001d85780600319360112620001d8576001546040516001600160a01b039091168152602090f35b5034620001d85760208060031936011262000715576200155a620016a2565b6200156462001a01565b6001600160a01b039081168084526008835260408420549092906200158c9060ff16620017c1565b60405163bb23e5d160e01b815233600482015291818360248188885af19283156200111f5785936200162d575b508215620015f25760065460405163a9059cbb60e01b81523360048201526024810185905292918291849116818881604481016200108a565b60405162461bcd60e51b81526004810183905260136024820152724e6f207061796f757420617661696c61626c6560681b6044820152606490fd5b9092508181813d83116200165a575b620016488183620016b9565b810103126200115757519138620015b9565b503d6200163c565b90503462000715576020366003190112620007155760209160ff906040906001600160a01b0362001692620016a2565b168152600a855220541615158152f35b600435906001600160a01b03821682036200045557565b90601f8019910116810190811067ffffffffffffffff821117620016dc57604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff8111620016dc57601f01601f191660200190565b9291926200171d82620016f2565b916200172d6040519384620016b9565b82948184528183011162000455578281602093846000960137010152565b9181601f84011215620004555782359167ffffffffffffffff831162000455576020808501948460051b0101116200045557565b919082519283825260005b848110620017ac575050826000602080949584010152601f8019910116010190565b6020818301810151848301820152016200178a565b15620017c957565b60405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a59081b585c9ad95d60921b6044820152606490fd5b908160209103126200045557518015158103620004555790565b156200182157565b60405162461bcd60e51b8152602060048201526015602482015274151bdad95b881d1c985b9cd9995c8819985a5b1959605a1b6044820152606490fd5b919082039182116200186c57565b634e487b7160e01b600052601160045260246000fd5b91908082526020809201929160005b828110620018a0575050505090565b83358552938101939281019260010162001891565b6001600160a01b039091168152604060208201819052620018d99391019162001882565b90565b919082018092116200186c57565b90808251908181526020809101926020808460051b8301019501936000915b8483106200191a5750505050505090565b90919293949584806200193a600193601f198682030187528a516200177f565b980193019301919493929062001909565b156200195357565b60405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b21033b7bb32b93737b960811b6044820152606490fd5b6001600160a01b03908116908115620019e8576000805160206200474683398151915280546001600160a01b031981168417909155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b604051631e4fbdf760e01b815260006004820152602490fd5b60008051602062004766833981519152600281541462001a215760029055565b604051633ee5aeb560e01b8152600490fd5b60008051602062004746833981519152546001600160a01b0316330362001a5657565b60405163118cdaa760e01b8152336004820152602490fd5b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161562001a9e57565b604051631afcd79f60e31b8152600490fd5b9062001ad9575080511562001ac757805190602001fd5b60405163d6bda27560e01b8152600490fd5b8151158062001b0e575b62001aec575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1562001ae356fe608060405234620006105762002c2d803803806200001d816200062a565b92833981019061012081830312620006105780516001600160401b0381116200061057810182601f8201121562000610578051926001600160401b0384116200037a578360051b91602080620000758186016200062a565b80978152019382010190828211620006105760208101935b8285106200057a578686620000a56020820162000650565b906040810151620000b96060830162000650565b91620000c86080820162000650565b9060a08101519160c082015194610100620000e660e0850162000650565b930151966001600160a01b038316156200056157620001058362000665565b6000805460ff60a01b191690556001805588516002116200051c576001600160a01b03811615620004d7576001600160a01b038216156200049f576001600160a01b03841615620004655784156200042057600280546001600160a01b031990811633179091556003805482166001600160a01b0393841617905560048054821693831693909317909255600580548316938216939093179092556006805490911692909116919091179055600755600855600955600a5560005b8151811015620003a65760208160051b830101516011805490680100000000000000008210156200037a5760018201808255821015620003905760009081526020902082519101916001600160401b0382116200037a578254600181811c911680156200036f575b60208210146200035957601f81116200030c575b50602090601f83116001146200029b57600194939291600091836200028f575b5050600019600383901b1c191690841b1790555b806000526012602052670de0b6b3a764000060406000205501620001c0565b0151905086806200025c565b90601f198316918460005260206000209260005b818110620002f3575091600196959492918388959310620002d9575b505050811b01905562000270565b015160001960f88460031b161c19169055868080620002cb565b92936020600181928786015181550195019301620002af565b836000526020600020601f840160051c810191602085106200034e575b601f0160051c01905b8181106200034157506200023c565b6000815560010162000332565b909150819062000329565b634e487b7160e01b600052602260045260246000fd5b90607f169062000228565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b62278d0042018042116200040a576020817fb78308b2eb98fa00faea36698f56c2389c9bd7c8e76f7c0f7725e33135d4809292600b55604051908152a1600554620003fa906001600160a01b031662000665565b6040516125809081620006ad8239f35b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c697175696469747920706172616d6574657200000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601260248201527124b73b30b634b21029aaa9a2103a37b5b2b760711b6044820152606490fd5b60405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b2103932b837b93a32b960811b6044820152606490fd5b60405162461bcd60e51b815260206004820152601560248201527f496e76616c69642066656520726563697069656e7400000000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601d60248201527f4d7573742068617665206174206c656173742032206f7574636f6d65730000006044820152606490fd5b604051631e4fbdf760e01b815260006004820152602490fd5b84516001600160401b0381116200061057820184603f82011215620006105760208101516001600160401b0381116200061557620005c2601f8201601f19166020016200062a565b918183528660408383010111620006105760005b828110620005f9575050918160006020809581950101528152019401936200008d565b8060406020928401015182828701015201620005d6565b600080fd5b60246000634e487b7160e01b81526041600452fd5b6040519190601f01601f191682016001600160401b038111838210176200037a57604052565b51906001600160a01b03821682036200061057565b600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a356fe608060408181526004918236101561001657600080fd5b600092833560e01c918263010ec441146117df5750816304f09b4a14610d7057816309eef43e146117a15781630c340a241461104e5781630d15fd77146117825781630ff352f5146116a75781631bd8db031461102f57816323341a05146115735781632d844c49146114145781633f4ba83a146113a65781633f6fa655146113825781634020dffc146112da57816346904840146112b15781634b047c70146110965781634df7e3d0146110775781634fc07d751461104e57816356f433521461102f5781635a0e829014610ff75781635c975abb14610fd25781635fae637114610fb75781636399d03d14610ef857816370aa268714610d29578163715018a614610e9e5781638456cb5914610e3f57816385af5d351461064a578163882636cb14610e225781638948261d14610df15781638da5cb5b14610dc95781639236260b14610dae57816397f03f1c14610d8f5781639b34ae0314610d705781639da0ae3e14610d48578163a0cd655214610d29578163a5bbe22b14610d0b578163ad9914f814610ce3578163bb23e5d114610c04578163bee4f74614610be8578163c13ebbe614610bc9578163c45a015514610ba0578163c91de47314610a01578163d3967a6b146107e0578163d8ca24c11461076b578163d92f0810146106f1578163deb8d278146106d2578163e2ae5524146106aa578163e53dc68014610669578163e62ff3eb1461064a578163ead1df1714610457578163ec77537b1461038e578163eed2a14714610317578163f2fde38b1461028c575063f39690e41461026157600080fd5b3461028857816003193601126102885760065490516001600160a01b039091168152602090f35b5080fd5b905034610313576020366003190112610313576102a7611803565b906102b0612078565b6001600160a01b039182169283156102fd57505082546001600160a01b0319811683178455167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b51631e4fbdf760e01b8152908101849052602490fd5b8280fd5b9050823461038b57602036600319011261038b57813560115481101561028857610340906119e4565b92909261037957835161037590856103638261035c8189611a31565b0383611907565b5191829160208352602083019061181e565b0390f35b634e487b7160e01b8252819052602490fd5b80fd5b9050346103135782600319360112610313576103a8612283565b601054916103b960ff841615611aee565b600c5462093a808101809111610444576103d490421161201f565b600d54156104095750506001600e549182600f5560ff19161760105560008051602061252b8339815191528280a26001805580f35b906020606492519162461bcd60e51b83528201526015602482015274139bc8191a5cdc1d5d195cc81cdd589b5a5d1d1959605a1b6044820152fd5b634e487b7160e01b855260118352602485fd5b91905034610313578260031936011261031357610472612283565b61048060ff60105416611e7d565b33835260209060148252808420541561061657600c5462093a808101809111610603576104ae90421161201f565b33845260148252838282822082815491556016825260ff8484205416610588575b600654845163a9059cbb60e01b8152338882015260248101929092529092839160449183916001600160a01b03165af190811561057e578591610551575b501561051b57836001805580f35b5162461bcd60e51b8152918201526012602482015271109bdb99081c995d1d5c9b8819985a5b195960721b604482015260649150fd5b6105719150833d8511610577575b6105698183611907565b810190611f02565b3861050d565b503d61055f565b82513d87823e3d90fd5b915050670de0b6b3a76400008082028281048214831517156105f057869285926105e46105eb936105df6105ca600f5492838a52601589528a8a205490611ce9565b91600d5490895260158852898920549061206b565b611ca6565b0490611d6f565b6104cf565b634e487b7160e01b875260118652602487fd5b634e487b7160e01b855260118452602485fd5b5162461bcd60e51b815291820152601060248201526f4e6f20626f6e6420746f20636c61696d60801b604482015260649150fd5b505034610288578160031936011261028857602090600c549051908152f35b50503461028857806003193601126102885760209181906001600160a01b03610690611803565b168152601384528181206024358252845220549051908152f35b9050346103135760203660031901126103135760209282913581526012845220549051908152f35b505034610288578160031936011261028857602090600e549051908152f35b839034610288576020366003190112610288573561071a60018060a01b03600254163314611b7e565b600160105461072c60ff821615611aee565b610739600c544210611ebf565b6107466011548410611da7565b60ff19161760105580600f5581600c5560008051602061252b8339815191528280a280f35b9050346103135760803660031901126103135780359067ffffffffffffffff82116107dc5761079c91369101611892565b6001600160a01b0393604435929190858416840361038b57606435958616860361038b575091602094916107d39360243591611f1a565b90519015158152f35b8380fd5b91905034610313576020806003193601126107dc57823592610800612283565b61080f60ff6010541615611aee565b61081c6011548510611da7565b3385526016825260ff83862054166109d057600c5462093a8081018091116109bd5761084a90421115611ebf565b848260018060a01b03600654166064600a54875194859384926323b872dd60e01b8452338985015230602485015260448401525af19081156109b3578691610996575b501561095e5750907fde5c01453f40d10a9cdeaaa7f2b644609198dabb4cf1d17a1496d1d506e2346d8392600a54338752601482528084882055848752601582526108dc848820918254611d6f565b90556108ec600a54600d54611d6f565b600d5533865260168152828620805460ff191660011790558386526015815282862054600e5487528387205410610955575b600a5492519283523392a3337fa36cc2bebb74db33e9f88110a07ef56e1b31b24b4c4f51b54b1664266e29f45b8380a36001805580f35b83600e5561091e565b915162461bcd60e51b8152918201526014602482015273109bdb99081d1c985b9cd9995c8819985a5b195960621b6044820152606490fd5b6109ad9150833d8511610577576105698183611907565b3861088d565b84513d88823e3d90fd5b634e487b7160e01b865260118252602486fd5b915162461bcd60e51b815291820152600d60248201526c105b1c9958591e481d9bdd1959609a1b6044820152606490fd5b82843461038b57610a11366118c3565b6002549294926001600160a01b039190610a2e9083163314611b7e565b610a366120a4565b610a4560ff6010541615611aee565b610a526011548214611bd6565b610a6d610a68610a63368487611957565b611de5565b611c29565b94805b828110610ac157505090602095610ab87f3b55ce5afbfa91d536b2a2394b85b42d8abc5fb48daa07088154bb0bc5fa6c0093610aaa611e3b565b908751948594169684611d0f565b0390a251908152f35b80610acf6001928588611c19565b35610adb575b01610a70565b610aef610ae9828689611c19565b35611c29565b6001600160a01b038a166000908152601360205260409020610b1f90918386526020928352898620541015611c50565b8184526012808252610b4089862054610b3985898c611c19565b3590611cf3565b838652908252888520556001600160a01b038a1660009081526013602052604090208285528152610b7988852054610b3984888b611c19565b6001600160a01b038b16600090815260136020526040902090918386525287842055610ad5565b50503461028857816003193601126102885760025490516001600160a01b039091168152602090f35b505034610288578160031936011261028857602090600b549051908152f35b50503461028857816003193601126102885760209051600a8152f35b91905034610313576020928360031936011261038b57610c22611803565b6002546001600160a01b039190610c3c9083163314611b7e565b610c4a60ff60105416611e7d565b169081815260138552828120600f5490818352865283822054948515610cac5750828252601386528382209082528552828120557f5afeca38b2064c23a692c4cf353015d80ab3ecc417b4f893f372690c11fbd9a6848351858152a251908152f35b845162461bcd60e51b815290810187905260116024820152704e6f2077696e6e696e672073686172657360781b6044820152606490fd5b9050346103135782600319360112610313575490516001600160a01b03909116815260209150f35b5050346102885781600319360112610288576020905162093a808152f35b5050346102885781600319360112610288576020906008549051908152f35b9050346103135760203660031901126103135760209282913581526015845220549051908152f35b505034610288578160031936011261028857602090600f549051908152f35b505034610288578160031936011261028857602090600a549051908152f35b50503461028857816003193601126102885760209051308152f35b505034610288578160031936011261028857905490516001600160a01b039091168152602090f35b50503461028857816003193601126102885761037590610e0f611e3b565b905191829160208352602083019061185e565b50503461028857602090610e38610a63366119a5565b9051908152f35b50503461028857816003193601126102885760207f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25891610e7d612078565b610e856120a4565b835460ff60a01b1916600160a01b17845551338152a180f35b833461038b578060031936011261038b57610eb7612078565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b9190503461031357602036600319011261031357601054823592610f1f60ff831615611aee565b600b544210610f8857506020839260017fffac1500e5679b3ff6518aa340b377b1b544ffde8e2e1f3a786f8b1fe9f140de93610f5e6011548710611da7565b85600f5542600c5560ff19161760105551428152a260008051602061252b8339815191528280a280f35b606490602084519162461bcd60e51b83528201526009602482015268546f6f206561726c7960b81b6044820152fd5b50503461028857602090610e38610fcd366119a5565b611d7c565b50503461028857816003193601126102885760ff6020925460a01c1690519015158152f35b5050346102885760203660031901126102885760209181906001600160a01b0361101f611803565b1681526014845220549051908152f35b5050346102885781600319360112610288576020906009549051908152f35b50503461028857816003193601126102885760055490516001600160a01b039091168152602090f35b5050346102885781600319360112610288576020906007549051908152f35b83915034610288576110a7366118c3565b60025491936001600160a01b0393926110c39085163314611b7e565b6110cb6120a4565b6110da60ff6010541615611aee565b6011906110ea6011548414611bd6565b6110f2611e3b565b90875b8481106111ca5750505050845b81811061114d57507f3b55ce5afbfa91d536b2a2394b85b42d8abc5fb48daa07088154bb0bc5fa6c009394956111479161113a611e3b565b9151948594169684611d0f565b0390a280f35b8061115b6001928488611c19565b35611167575b01611102565b80875260126020908082526111848a8a2054610b3985888c611c19565b90838a528252898920558585169081895260138082528a8a20848b5282526111b48b8b2054610b3986898d611c19565b928a52815289892090838a525288882055611161565b886111d682878b611c19565b351315611266576111e881868a611c19565b356111f38285611c92565b5190600a918281029281840414901517156112545760648092041061121d57506001905b016110f5565b8a5162461bcd60e51b8152602081850152601460248201527354726164652073697a6520746f6f206c6172676560601b6044820152fd5b634e487b7160e01b8b5285845260248bfd5b8089611275600193888c611c19565b351215611217576112ac61128d610ae983898d611c19565b8989168c528b8d846020916013835283209252528c8c20541015611c50565b611217565b50503461028857816003193601126102885760035490516001600160a01b039091168152602090f35b919050346103135760203660031901126103135781359161130660018060a01b03600254163314611b7e565b428311156113405750816020917fb78308b2eb98fa00faea36698f56c2389c9bd7c8e76f7c0f7725e33135d4809293600b5551908152a180f35b6020606492519162461bcd60e51b8352820152601a60248201527f446561646c696e65206d75737420626520696e206675747572650000000000006044820152fd5b50503461028857816003193601126102885760209060ff6010541690519015158152f35b9050346103135782600319360112610313576113c0612078565b82549060ff8260a01c1615611406575060ff60a01b19168255513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa90602090a180f35b8251638dfc202b60e01b8152fd5b9050823461038b57602036600319011261038b5781359160119161143b6011548510611b3a565b611443611e3b565b926007549361145481518710611b3a565b829683975b82518910156114da5761146c8984611c92565b51670de0b6b3a7640000908181029181830414901517156114c8576001916114b261149a8a6114b894611ce9565b68056bc75e2d631000008082116114c0575b506122a6565b90611d6f565b980197611459565b90508d6114ac565b634e487b7160e01b8652848752602486fd5b86856114e78a8996611c92565b5191670de0b6b3a76400009283810290808204851490151715611560576115289161151191611ce9565b68056bc75e2d6310000080821161155857506122a6565b82810292818404149015171561154557602084610e388585611ce9565b634e487b7160e01b815260118552602490fd5b9050876114ac565b634e487b7160e01b835260118752602483fd5b82843461038b578060031936011261038b5761158d611e3b565b9160075460ff60105416600f5491601154956115a88761193f565b956115b586519788611907565b878752602096602081019889601184527f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6884915b838310611675575050505086519760a089019160a08a525180925260c0890160c08360051b8b01019a93905b838210611648575050505050866116349187809903602089015261185e565b938501521515606084015260808301520390f35b909192939a83806116666001938f8f60bf199083030187525161181e565b9d019201920190939291611615565b60018c81928d9e97989e516116958161168e8189611a31565b0382611907565b8152019201920191909a94939a6115e9565b83915034610288578160031936011261028857601054906116cb60ff831615611aee565b600b5442111561173f57507fe4d6efcb12aa89dc35692182a18a22bcfd2c5d86dd221420209b7287daab0888602060019394600d54151560001461173657600e549485945b60ff19161760105583600f5551338152a260008051602061252b8339815191528280a280f35b85948594611710565b606490602085519162461bcd60e51b8352820152601c60248201527f5265706f7274657220646561646c696e65206e6f7420706173736564000000006044820152fd5b505034610288578160031936011261028857602090600d549051908152f35b5050346102885760203660031901126102885760209160ff9082906001600160a01b036117cc611803565b1681526016855220541690519015158152f35b849134610313578260031936011261031357546001600160a01b0316815260209150f35b600435906001600160a01b038216820361181957565b600080fd5b919082519283825260005b84811061184a575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201611829565b90815180825260208080930193019160005b82811061187e575050505090565b835185529381019392810192600101611870565b9181601f840112156118195782359167ffffffffffffffff8311611819576020808501948460051b01011161181957565b906040600319830112611819576004356001600160a01b038116810361181957916024359067ffffffffffffffff82116118195761190391600401611892565b9091565b90601f8019910116810190811067ffffffffffffffff82111761192957604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff81116119295760051b60200190565b92916119628261193f565b916119706040519384611907565b829481845260208094019160051b810192831161181957905b8282106119965750505050565b81358152908301908301611989565b6020600319820112611819576004359067ffffffffffffffff82116118195780602383011215611819578160246119e193600401359101611957565b90565b601154811015611a1b5760116000527f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c680190600090565b634e487b7160e01b600052603260045260246000fd5b80546000939260018083169383821c938515611ae4575b6020958686108114611ace57858552908115611aaf5750600114611a6e575b5050505050565b90939495506000929192528360002092846000945b838610611a9b57505050500101903880808080611a67565b805485870183015294019385908201611a83565b60ff19168685015250505090151560051b010191503880808080611a67565b634e487b7160e01b600052602260045260246000fd5b93607f1693611a48565b15611af557565b60405162461bcd60e51b815260206004820152601760248201527f4d61726b657420616c7265616479207265736f6c7665640000000000000000006044820152606490fd5b15611b4157565b60405162461bcd60e51b8152602060048201526015602482015274092dcecc2d8d2c840deeae8c6dedaca40d2dcc8caf605b1b6044820152606490fd5b15611b8557565b60405162461bcd60e51b815260206004820152602360248201527f4f6e6c7920666163746f72792063616e2063616c6c20746869732066756e637460448201526234b7b760e91b6064820152608490fd5b15611bdd57565b60405162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c840c2e4e4c2f240d8cadccee8d60631b6044820152606490fd5b9190811015611a1b5760051b0190565b600160ff1b8114611c3a5760000390565b634e487b7160e01b600052601160045260246000fd5b15611c5757565b60405162461bcd60e51b8152602060048201526013602482015272496e73756666696369656e742073686172657360681b6044820152606490fd5b8051821015611a1b5760209160051b010190565b81810292918115918404141715611c3a57565b8015611cd3576ec097ce7bc90715b34b9f10000000000490565b634e487b7160e01b600052601260045260246000fd5b8115611cd3570490565b91909160008382019384129112908015821691151617611c3a57565b939290918060608601606087525260808501929060005b818110611d4b57505050611d46826040928660009503602088015261185e565b930152565b8235855260209485019490920191600101611d26565b9060018201809211611c3a57565b91908201809211611c3a57565b611d8590611de5565b6000811315611da1576119e1906127106105e460095483611ca6565b50600090565b15611dae57565b60405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206f7574636f6d6560881b6044820152606490fd5b6119e190611df7815160115414611bd6565b611dff611e3b565b90600754916120c5565b90611e138261193f565b611e206040519182611907565b8281528092611e31601f199161193f565b0190602036910137565b60115490611e4882611e09565b60009260005b818110611e5c575090925050565b80600191865260126020526040862054611e768286611c92565b5201611e4e565b15611e8457565b60405162461bcd60e51b815260206004820152601360248201527213585c9ad95d081b9bdd081c995cdbdb1d9959606a1b6044820152606490fd5b15611ec657565b60405162461bcd60e51b8152602060048201526014602482015273111a5cdc1d5d19481c195c9a5bd908195b99195960621b6044820152606490fd5b90816020910312611819575180151581036118195790565b929190936011548503612015576004546001600160a01b039390841690841603612015576005928060055416911603612004576008540361200d5760005b838110611f685750505050600190565b80821b830135601e1984360301811215611819578301803567ffffffffffffffff81116118195760208083018236038113611819576040938451611fb584601f19601f8801160182611907565b8481528381019184863692010111611819576000848661035c97611ff29686378301015251902093611fe6866119e4565b50905193848092611a31565b81519101200361200457600101611f58565b50505050600090565b505050600090565b5050505050600090565b1561202657565b60405162461bcd60e51b815260206004820152601860248201527f4469737075746520706572696f64206e6f7420656e64656400000000000000006044820152606490fd5b91908203918211611c3a57565b6000546001600160a01b0316330361208c57565b60405163118cdaa760e01b8152336004820152602490fd5b60ff60005460a01c166120b357565b60405163d93c066560e01b8152600490fd5b92908351815103612246578351156122125782156121cd576120e783856123d5565b6120f18551611e09565b9260009160005b875181101561219f57808461210f60019388611c92565b511261214657612134612122828b611c92565b5161212d8389611c92565b5190611d6f565b61213e8289611c92565b525b016120f8565b61216e612153828b611c92565b51612167612161848a611c92565b51611c29565b1115611c50565b61218f61217b828b611c92565b51612189612161848a611c92565b9061206b565b6121998289611c92565b52612140565b509492509450506121af916123d5565b908082106121c0576119e19161206b565b6119e191610a689161206b565b60405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c697175696469747920706172616d6574657200000000006044820152606490fd5b60405162461bcd60e51b815260206004820152600c60248201526b456d7074792061727261797360a01b6044820152606490fd5b60405162461bcd60e51b8152602060048201526015602482015274082e4e4c2f240d8cadccee8d040dad2e6dac2e8c6d605b1b6044820152606490fd5b600260015414612294576002600155565b604051633ee5aeb560e01b8152600490fd5b80156123c85768056bc75e2d6310000081116123c157670de0b6b3a7640000808281020490818303611c3a57818101809111611c3a578280808094936122ed828096611ca6565b671bc16d674ec800009004908161230391611d6f565b9161230d91611ca6565b6729a2241af62c00009004908161232391611d6f565b9161232d91611ca6565b673782dace9d9000009004908161234391611d6f565b9161234d91611ca6565b674563918244f400009004908161236391611d6f565b9161236d91611ca6565b6753444835ec5800009004908161238391611d6f565b9161238d91611ca6565b676124fee993bc0000900490816123a391611d6f565b916123ad91611ca6565b676f05b59d3b20000090046119e191611d6f565b5060001990565b50670de0b6b3a764000090565b909190600090815b8151831015612445576123f08383611c92565b51670de0b6b3a764000090818102918183041490151715611c3a576001916114b261241e8861243594611ce9565b68056bc75e2d6310000080821161243d57506122a6565b9201916123dd565b9050386114ac565b6124669250670de0b6b3a7640000939491506124609061246a565b90611ca6565b0490565b66038d7ea4c680008110611da157670de0b6b3a764000080821461252357811061250857600068056bc75e2d63100000916000905b602082106124bc5750506119e1916124b691611d6f565b60011c90565b90916124cb6124b68583611d6f565b906124d5826122a6565b838110156124eb575050600190925b019061249f565b83919495501160001461250157600190936124e4565b9250505090565b61251461251991611cb9565b61246a565b6119e19019611d61565b505060009056fe93608ecbcf057462da63f5aef413ce7f78c5e1b3bb51859d77a40845ece2bfc3a2646970667358221220c746eb8654f9a031a39b1cdb68e7d9e0ab6bb2f5d5f5ab74b4850b5a555f6a7b64736f6c634300081600339016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993009b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a2646970667358221220217839749afe34a0d3c4dd1fbaa2b9f18c23e5049f50433ed2bf8f0e65940e4b64736f6c63430008160033
Deployed Bytecode
0x60808060405260043610156200001457600080fd5b600090813560e01c90816306c933d81462001662575080630b7e9c44146200153b5780630c340a2414620015105780631103f31514620014f05780632ef1bdfa14620014d05780632f1ac04a14620008595780634690484014620014a7578063484a87a2146200145d5780634f1ef286146200120757806352d1902d146200118757806356f433521462001167578063647096ea1462000fb057806366f13ae41462000ef75780636a9caa5314620004da5780636ed71ede1462000ed757806370ee6b121462000e90578063715018a61462000e215780637c94674f1462000aae5780638da5cb5b1462000a755780639cb120c41462000a325780639f37022a14620009e0578063ad3cb1cc146200096a578063adaf1c431462000927578063b0d54bcf146200088e578063b1283e771462000859578063c42cf53514620007dc578063d02ab9531462000517578063e80b5b5f14620004da578063ebc38ab014620004ba578063f2fde38b1462000485578063f39690e4146200045a578063f7c00e6314620001db5763f887ea4014620001ae57600080fd5b34620001d85780600319360112620001d857600b546040516001600160a01b039091168152602090f35b80fd5b5034620001d85760a0366003190112620001d857620001f9620016a2565b6001600160a01b03906024358281169190829003620004555760643583811680910362000455577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009283549460ff8660401c16159367ffffffffffffffff8716968715806200044d575b6001809914908162000442575b15908162000438575b50620004265767ffffffffffffffff198116881787558562000406575b50620002a162001a6e565b620002ab62001a6e565b620002b6816200198b565b620002c062001a6e565b620002ca62001a6e565b866000805160206200476683398151915255620002e662001a6e565b16620002f48115156200194b565b8115620003c95782156200038f57866009556bffffffffffffffffffffffff60a01b918288541617875581865416178555604435600255600654161760065560843560035561038460045560646005556200034d578280f35b805468ff0000000000000000191690556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a138808280f35b60405162461bcd60e51b815260206004820152601260248201527124b73b30b634b21029aaa9a2103a37b5b2b760711b6044820152606490fd5b60405162461bcd60e51b8152602060048201526015602482015274125b9d985b1a5908199959481c9958da5c1a595b9d605a1b6044820152606490fd5b68ffffffffffffffffff1916680100000000000000011786553862000296565b60405163f92ee8a960e01b8152600490fd5b9050153862000279565b303b15915062000270565b508562000263565b600080fd5b5034620001d85780600319360112620001d8576006546040516001600160a01b039091168152602090f35b5034620001d8576020366003190112620001d857620004b7620004a7620016a2565b620004b162001a33565b6200198b565b80f35b5034620001d85780600319360112620001d8576020600454604051908152f35b5034620001d8576020366003190112620001d8576020906040906001600160a01b0362000506620016a2565b168152600c83522054604051908152f35b5034620001d8576060366003190112620001d85762000535620016a2565b67ffffffffffffffff90602435828111620007d8576200055a9036906004016200174b565b906200056562001a01565b60018060a01b0380931693848652602092600884526200058c60ff604089205416620017c1565b604051635fae637160e01b81526004810185905294848680620005b460248201868962001882565b03818a5afa958615620007cd57889662000794575b50604435861162000758576006546040516323b872dd60e01b81523360048201523060248201526044810188905289939290918791839160649183918891165af180156200074d576200062591849162000719575b5062001819565b868252600c8552604082206200063d878254620018dc565b9055863b1562000715576040516304b047c760e41b815293849182916200066a91903360048501620018b5565b038183895af180156200070a57620006c0575b50507fcbc4a4091b012bb1329c38bbbb15455f5cac5aa3673da0a7f38cd61a4f495517906040519283523392a36001600080516020620047668339815191525580f35b8195929511620006f657604052927fcbc4a4091b012bb1329c38bbbb15455f5cac5aa3673da0a7f38cd61a4f495517386200067d565b634e487b7160e01b82526041600452602482fd5b6040513d88823e3d90fd5b5080fd5b6200073e9150873d891162000745575b620007358183620016b9565b810190620017ff565b386200061e565b503d62000729565b6040513d85823e3d90fd5b60405162461bcd60e51b8152600481018690526014602482015273436f73742065786365656473206d6178696d756d60601b6044820152606490fd5b9095508481813d8311620007c5575b620007af8183620016b9565b81010312620007c157519438620005c9565b8780fd5b503d620007a3565b6040513d8a823e3d90fd5b8380fd5b5034620001d8576020366003190112620001d8577f1cbb37f5a02c38ab13773cb770fae505cce417a4d81560117389e3a9f7e001f260206200081d620016a2565b6200082762001a33565b6001600160a01b03166200083d8115156200194b565b600180546001600160a01b03191682179055604051908152a180f35b5034620001d8576020366003190112620001d857602090600435815260078252604060018060a01b0391205416604051908152f35b5034620001d8576020366003190112620001d857600435620008af62001a33565b6107d08111620008f3576003557ffabf709ddcab6908663bc153944d0c2f54570ba46d078aecb046e384610874d4604060045460055482519182526020820152a180f35b60405162461bcd60e51b815260206004820152600c60248201526b08ccaca40e8dede40d0d2ced60a31b6044820152606490fd5b5034620001d8576020366003190112620001d85760209060ff906040906001600160a01b0362000956620016a2565b168152600d84522054166040519015158152f35b5034620001d85780600319360112620001d8576040516040810181811067ffffffffffffffff821117620009cc57620009c8925060405260058152640352e302e360dc1b60208201526040519182916020835260208301906200177f565b0390f35b634e487b7160e01b83526041600452602483fd5b5034620001d8576020366003190112620001d8577f583934e5b9be5235b40454ddbb9f61b157293eafefaa7b988cff6fd79f2ca43e602060043562000a2462001a33565b80600255604051908152a180f35b5034620001d8576020366003190112620001d85760209060ff906040906001600160a01b0362000a61620016a2565b168152600884522054166040519015158152f35b5034620001d85780600319360112620001d85760008051602062004746833981519152546040516001600160a01b039091168152602090f35b5034620001d85760a0366003190112620001d8576004359067ffffffffffffffff90818311620001d85736602384011215620001d857826004013592828411620006f6578360051b906040519462000b0a6020840187620016b9565b85526024602086019282010190368211620007d85760248101925b82841062000ddf575050604435939150506001600160a01b0383168303620007155762000b5162001a01565b6006546002546040516323b872dd60e01b81523360048201523060248201526044810191909152906020908290606490829087906001600160a01b03165af19081156200074d57839162000dbb575b501562000d6a578154600154600354600654604051946001600160a01b03948516949182169390911690612c2d86019081119086111762000d56579084939291612c2d62001b198639610120612c2d860181815262000c0191018a620018ea565b612c2d8601602081019590955260243560408601526001600160a01b0389166060860152608085019190915260643560a085015260c084019190915260e083019190915260843561010090920191909152039082f0801562000d495760018060a01b0316916009548252600760205260408220836bffffffffffffffffffffffff60a01b825416179055828252600d60205260408220600160ff19825416179055827f4b85df0c16f0c5066543554eec76a5782a8fe0bd2d18987467be7cd704d1e93862000ce3600954968794604051928392608084526080840190620018ea565b6001600160a01b039091166020830152606435604083015260843560608301520390a3600019831462000d35575060016020920160095560016000805160206200476683398151915255604051908152f35b634e487b7160e01b81526011600452602490fd5b50604051903d90823e3d90fd5b634e487b7160e01b86526041600452602486fd5b60405162461bcd60e51b815260206004820152602360248201527f4d61726b6574206372656174696f6e20666565207472616e73666572206661696044820152621b195960ea1b6064820152608490fd5b62000dd8915060203d6020116200074557620007358183620016b9565b3862000ba0565b833586811162000e1d5782013660438201121562000e1d5760209162000e11839236906044602482013591016200170f565b81520193019262000b25565b8580fd5b5034620001d85780600319360112620001d85762000e3e62001a33565b6000805160206200474683398151915280546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b5034620001d8576020366003190112620001d85762000eae620016a2565b62000eb862001a33565b6001600160a01b03168152600d60205260408120805460ff1916905580f35b5034620001d85780600319360112620001d8576020600954604051908152f35b5034620001d8576040366003190112620001d85760043560243562000f1b62001a33565b62000f278183620018dc565b6003540362000f6b57816040917ffabf709ddcab6908663bc153944d0c2f54570ba46d078aecb046e384610874d4936004558060055582519182526020820152a180f35b60405162461bcd60e51b815260206004820152601e60248201527f536861726573206d7573742073756d20746f2074726164696e672066656500006044820152606490fd5b5034620001d8576040366003190112620001d85762000fce620016a2565b60243567ffffffffffffffff8111620011635762000ff5620010479136906004016200174b565b90926200100162001a01565b60018060a01b03809116938486526020928391600883526200102a60ff60408a205416620017c1565b60405163c91de47360e01b815295869283923360048501620018b5565b038188885af19283156200111f5785936200112a575b5060065460405163a9059cbb60e01b81523360048201526024810185905292918291849116818881604481015b03925af19182156200111f577f6337ed398c0e8467698c581374fdce4db14922df487b5a39483079f5f59b60a492620010cb91879162001104575062001819565b838552600c815260408520620010e38482546200185e565b90556040519283523392a36001600080516020620047668339815191525580f35b6200073e9150833d85116200074557620007358183620016b9565b6040513d87823e3d90fd5b9092508181813d83116200115b575b620011458183620016b9565b8101031262001157575191386200105d565b8480fd5b503d62001139565b8280fd5b5034620001d85780600319360112620001d8576020600354604051908152f35b5034620001d85780600319360112620001d8577f000000000000000000000000a3cbae4b3e43a14d0db7df9bae8331647ea840986001600160a01b03163003620011f55760206040517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b60405163703e46dd60e11b8152600490fd5b506040366003190112620001d8576200121f620016a2565b60243567ffffffffffffffff81116200116357366023820112156200116357620012549036906024816004013591016200170f565b6001600160a01b037f000000000000000000000000a3cbae4b3e43a14d0db7df9bae8331647ea8409881163081149081156200142e575b50620011f5576200129b62001a33565b6040516352d1902d60e01b8152908316926020918281600481885afa869181620013f5575b50620012df57604051634c9c8ce360e01b815260048101869052602490fd5b9385947f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90818103620013dd5750823b15620013c45780546001600160a01b0319168217905560405185917fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8380a2845115620013a657508084846200139896519101845af4903d156200139c573d6200137981620016f2565b90620013896040519283620016b9565b81528581943d92013e62001ab0565b5080f35b6060925062001ab0565b935050505034620013b5575080f35b63b398979f60e01b8152600490fd5b604051634c9c8ce360e01b815260048101839052602490fd5b60249060405190632a87526960e21b82526004820152fd5b9091508381813d831162001426575b620014108183620016b9565b810103126200142257519038620012c0565b8680fd5b503d62001404565b9050817f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54161415386200128b565b5034620001d8576020366003190112620001d8576200147b620016a2565b6200148562001a33565b6001600160a01b03168152600d60205260408120805460ff1916600117905580f35b5034620001d85780600319360112620001d857546040516001600160a01b039091168152602090f35b5034620001d85780600319360112620001d8576020600254604051908152f35b5034620001d85780600319360112620001d8576020600554604051908152f35b5034620001d85780600319360112620001d8576001546040516001600160a01b039091168152602090f35b5034620001d85760208060031936011262000715576200155a620016a2565b6200156462001a01565b6001600160a01b039081168084526008835260408420549092906200158c9060ff16620017c1565b60405163bb23e5d160e01b815233600482015291818360248188885af19283156200111f5785936200162d575b508215620015f25760065460405163a9059cbb60e01b81523360048201526024810185905292918291849116818881604481016200108a565b60405162461bcd60e51b81526004810183905260136024820152724e6f207061796f757420617661696c61626c6560681b6044820152606490fd5b9092508181813d83116200165a575b620016488183620016b9565b810103126200115757519138620015b9565b503d6200163c565b90503462000715576020366003190112620007155760209160ff906040906001600160a01b0362001692620016a2565b168152600a855220541615158152f35b600435906001600160a01b03821682036200045557565b90601f8019910116810190811067ffffffffffffffff821117620016dc57604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff8111620016dc57601f01601f191660200190565b9291926200171d82620016f2565b916200172d6040519384620016b9565b82948184528183011162000455578281602093846000960137010152565b9181601f84011215620004555782359167ffffffffffffffff831162000455576020808501948460051b0101116200045557565b919082519283825260005b848110620017ac575050826000602080949584010152601f8019910116010190565b6020818301810151848301820152016200178a565b15620017c957565b60405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a59081b585c9ad95d60921b6044820152606490fd5b908160209103126200045557518015158103620004555790565b156200182157565b60405162461bcd60e51b8152602060048201526015602482015274151bdad95b881d1c985b9cd9995c8819985a5b1959605a1b6044820152606490fd5b919082039182116200186c57565b634e487b7160e01b600052601160045260246000fd5b91908082526020809201929160005b828110620018a0575050505090565b83358552938101939281019260010162001891565b6001600160a01b039091168152604060208201819052620018d99391019162001882565b90565b919082018092116200186c57565b90808251908181526020809101926020808460051b8301019501936000915b8483106200191a5750505050505090565b90919293949584806200193a600193601f198682030187528a516200177f565b980193019301919493929062001909565b156200195357565b60405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b21033b7bb32b93737b960811b6044820152606490fd5b6001600160a01b03908116908115620019e8576000805160206200474683398151915280546001600160a01b031981168417909155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b604051631e4fbdf760e01b815260006004820152602490fd5b60008051602062004766833981519152600281541462001a215760029055565b604051633ee5aeb560e01b8152600490fd5b60008051602062004746833981519152546001600160a01b0316330362001a5657565b60405163118cdaa760e01b8152336004820152602490fd5b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161562001a9e57565b604051631afcd79f60e31b8152600490fd5b9062001ad9575080511562001ac757805190602001fd5b60405163d6bda27560e01b8152600490fd5b8151158062001b0e575b62001aec575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b1562001ae356fe608060405234620006105762002c2d803803806200001d816200062a565b92833981019061012081830312620006105780516001600160401b0381116200061057810182601f8201121562000610578051926001600160401b0384116200037a578360051b91602080620000758186016200062a565b80978152019382010190828211620006105760208101935b8285106200057a578686620000a56020820162000650565b906040810151620000b96060830162000650565b91620000c86080820162000650565b9060a08101519160c082015194610100620000e660e0850162000650565b930151966001600160a01b038316156200056157620001058362000665565b6000805460ff60a01b191690556001805588516002116200051c576001600160a01b03811615620004d7576001600160a01b038216156200049f576001600160a01b03841615620004655784156200042057600280546001600160a01b031990811633179091556003805482166001600160a01b0393841617905560048054821693831693909317909255600580548316938216939093179092556006805490911692909116919091179055600755600855600955600a5560005b8151811015620003a65760208160051b830101516011805490680100000000000000008210156200037a5760018201808255821015620003905760009081526020902082519101916001600160401b0382116200037a578254600181811c911680156200036f575b60208210146200035957601f81116200030c575b50602090601f83116001146200029b57600194939291600091836200028f575b5050600019600383901b1c191690841b1790555b806000526012602052670de0b6b3a764000060406000205501620001c0565b0151905086806200025c565b90601f198316918460005260206000209260005b818110620002f3575091600196959492918388959310620002d9575b505050811b01905562000270565b015160001960f88460031b161c19169055868080620002cb565b92936020600181928786015181550195019301620002af565b836000526020600020601f840160051c810191602085106200034e575b601f0160051c01905b8181106200034157506200023c565b6000815560010162000332565b909150819062000329565b634e487b7160e01b600052602260045260246000fd5b90607f169062000228565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b62278d0042018042116200040a576020817fb78308b2eb98fa00faea36698f56c2389c9bd7c8e76f7c0f7725e33135d4809292600b55604051908152a1600554620003fa906001600160a01b031662000665565b6040516125809081620006ad8239f35b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c697175696469747920706172616d6574657200000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601260248201527124b73b30b634b21029aaa9a2103a37b5b2b760711b6044820152606490fd5b60405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b2103932b837b93a32b960811b6044820152606490fd5b60405162461bcd60e51b815260206004820152601560248201527f496e76616c69642066656520726563697069656e7400000000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601d60248201527f4d7573742068617665206174206c656173742032206f7574636f6d65730000006044820152606490fd5b604051631e4fbdf760e01b815260006004820152602490fd5b84516001600160401b0381116200061057820184603f82011215620006105760208101516001600160401b0381116200061557620005c2601f8201601f19166020016200062a565b918183528660408383010111620006105760005b828110620005f9575050918160006020809581950101528152019401936200008d565b8060406020928401015182828701015201620005d6565b600080fd5b60246000634e487b7160e01b81526041600452fd5b6040519190601f01601f191682016001600160401b038111838210176200037a57604052565b51906001600160a01b03821682036200061057565b600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a356fe608060408181526004918236101561001657600080fd5b600092833560e01c918263010ec441146117df5750816304f09b4a14610d7057816309eef43e146117a15781630c340a241461104e5781630d15fd77146117825781630ff352f5146116a75781631bd8db031461102f57816323341a05146115735781632d844c49146114145781633f4ba83a146113a65781633f6fa655146113825781634020dffc146112da57816346904840146112b15781634b047c70146110965781634df7e3d0146110775781634fc07d751461104e57816356f433521461102f5781635a0e829014610ff75781635c975abb14610fd25781635fae637114610fb75781636399d03d14610ef857816370aa268714610d29578163715018a614610e9e5781638456cb5914610e3f57816385af5d351461064a578163882636cb14610e225781638948261d14610df15781638da5cb5b14610dc95781639236260b14610dae57816397f03f1c14610d8f5781639b34ae0314610d705781639da0ae3e14610d48578163a0cd655214610d29578163a5bbe22b14610d0b578163ad9914f814610ce3578163bb23e5d114610c04578163bee4f74614610be8578163c13ebbe614610bc9578163c45a015514610ba0578163c91de47314610a01578163d3967a6b146107e0578163d8ca24c11461076b578163d92f0810146106f1578163deb8d278146106d2578163e2ae5524146106aa578163e53dc68014610669578163e62ff3eb1461064a578163ead1df1714610457578163ec77537b1461038e578163eed2a14714610317578163f2fde38b1461028c575063f39690e41461026157600080fd5b3461028857816003193601126102885760065490516001600160a01b039091168152602090f35b5080fd5b905034610313576020366003190112610313576102a7611803565b906102b0612078565b6001600160a01b039182169283156102fd57505082546001600160a01b0319811683178455167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b51631e4fbdf760e01b8152908101849052602490fd5b8280fd5b9050823461038b57602036600319011261038b57813560115481101561028857610340906119e4565b92909261037957835161037590856103638261035c8189611a31565b0383611907565b5191829160208352602083019061181e565b0390f35b634e487b7160e01b8252819052602490fd5b80fd5b9050346103135782600319360112610313576103a8612283565b601054916103b960ff841615611aee565b600c5462093a808101809111610444576103d490421161201f565b600d54156104095750506001600e549182600f5560ff19161760105560008051602061252b8339815191528280a26001805580f35b906020606492519162461bcd60e51b83528201526015602482015274139bc8191a5cdc1d5d195cc81cdd589b5a5d1d1959605a1b6044820152fd5b634e487b7160e01b855260118352602485fd5b91905034610313578260031936011261031357610472612283565b61048060ff60105416611e7d565b33835260209060148252808420541561061657600c5462093a808101809111610603576104ae90421161201f565b33845260148252838282822082815491556016825260ff8484205416610588575b600654845163a9059cbb60e01b8152338882015260248101929092529092839160449183916001600160a01b03165af190811561057e578591610551575b501561051b57836001805580f35b5162461bcd60e51b8152918201526012602482015271109bdb99081c995d1d5c9b8819985a5b195960721b604482015260649150fd5b6105719150833d8511610577575b6105698183611907565b810190611f02565b3861050d565b503d61055f565b82513d87823e3d90fd5b915050670de0b6b3a76400008082028281048214831517156105f057869285926105e46105eb936105df6105ca600f5492838a52601589528a8a205490611ce9565b91600d5490895260158852898920549061206b565b611ca6565b0490611d6f565b6104cf565b634e487b7160e01b875260118652602487fd5b634e487b7160e01b855260118452602485fd5b5162461bcd60e51b815291820152601060248201526f4e6f20626f6e6420746f20636c61696d60801b604482015260649150fd5b505034610288578160031936011261028857602090600c549051908152f35b50503461028857806003193601126102885760209181906001600160a01b03610690611803565b168152601384528181206024358252845220549051908152f35b9050346103135760203660031901126103135760209282913581526012845220549051908152f35b505034610288578160031936011261028857602090600e549051908152f35b839034610288576020366003190112610288573561071a60018060a01b03600254163314611b7e565b600160105461072c60ff821615611aee565b610739600c544210611ebf565b6107466011548410611da7565b60ff19161760105580600f5581600c5560008051602061252b8339815191528280a280f35b9050346103135760803660031901126103135780359067ffffffffffffffff82116107dc5761079c91369101611892565b6001600160a01b0393604435929190858416840361038b57606435958616860361038b575091602094916107d39360243591611f1a565b90519015158152f35b8380fd5b91905034610313576020806003193601126107dc57823592610800612283565b61080f60ff6010541615611aee565b61081c6011548510611da7565b3385526016825260ff83862054166109d057600c5462093a8081018091116109bd5761084a90421115611ebf565b848260018060a01b03600654166064600a54875194859384926323b872dd60e01b8452338985015230602485015260448401525af19081156109b3578691610996575b501561095e5750907fde5c01453f40d10a9cdeaaa7f2b644609198dabb4cf1d17a1496d1d506e2346d8392600a54338752601482528084882055848752601582526108dc848820918254611d6f565b90556108ec600a54600d54611d6f565b600d5533865260168152828620805460ff191660011790558386526015815282862054600e5487528387205410610955575b600a5492519283523392a3337fa36cc2bebb74db33e9f88110a07ef56e1b31b24b4c4f51b54b1664266e29f45b8380a36001805580f35b83600e5561091e565b915162461bcd60e51b8152918201526014602482015273109bdb99081d1c985b9cd9995c8819985a5b195960621b6044820152606490fd5b6109ad9150833d8511610577576105698183611907565b3861088d565b84513d88823e3d90fd5b634e487b7160e01b865260118252602486fd5b915162461bcd60e51b815291820152600d60248201526c105b1c9958591e481d9bdd1959609a1b6044820152606490fd5b82843461038b57610a11366118c3565b6002549294926001600160a01b039190610a2e9083163314611b7e565b610a366120a4565b610a4560ff6010541615611aee565b610a526011548214611bd6565b610a6d610a68610a63368487611957565b611de5565b611c29565b94805b828110610ac157505090602095610ab87f3b55ce5afbfa91d536b2a2394b85b42d8abc5fb48daa07088154bb0bc5fa6c0093610aaa611e3b565b908751948594169684611d0f565b0390a251908152f35b80610acf6001928588611c19565b35610adb575b01610a70565b610aef610ae9828689611c19565b35611c29565b6001600160a01b038a166000908152601360205260409020610b1f90918386526020928352898620541015611c50565b8184526012808252610b4089862054610b3985898c611c19565b3590611cf3565b838652908252888520556001600160a01b038a1660009081526013602052604090208285528152610b7988852054610b3984888b611c19565b6001600160a01b038b16600090815260136020526040902090918386525287842055610ad5565b50503461028857816003193601126102885760025490516001600160a01b039091168152602090f35b505034610288578160031936011261028857602090600b549051908152f35b50503461028857816003193601126102885760209051600a8152f35b91905034610313576020928360031936011261038b57610c22611803565b6002546001600160a01b039190610c3c9083163314611b7e565b610c4a60ff60105416611e7d565b169081815260138552828120600f5490818352865283822054948515610cac5750828252601386528382209082528552828120557f5afeca38b2064c23a692c4cf353015d80ab3ecc417b4f893f372690c11fbd9a6848351858152a251908152f35b845162461bcd60e51b815290810187905260116024820152704e6f2077696e6e696e672073686172657360781b6044820152606490fd5b9050346103135782600319360112610313575490516001600160a01b03909116815260209150f35b5050346102885781600319360112610288576020905162093a808152f35b5050346102885781600319360112610288576020906008549051908152f35b9050346103135760203660031901126103135760209282913581526015845220549051908152f35b505034610288578160031936011261028857602090600f549051908152f35b505034610288578160031936011261028857602090600a549051908152f35b50503461028857816003193601126102885760209051308152f35b505034610288578160031936011261028857905490516001600160a01b039091168152602090f35b50503461028857816003193601126102885761037590610e0f611e3b565b905191829160208352602083019061185e565b50503461028857602090610e38610a63366119a5565b9051908152f35b50503461028857816003193601126102885760207f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25891610e7d612078565b610e856120a4565b835460ff60a01b1916600160a01b17845551338152a180f35b833461038b578060031936011261038b57610eb7612078565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b9190503461031357602036600319011261031357601054823592610f1f60ff831615611aee565b600b544210610f8857506020839260017fffac1500e5679b3ff6518aa340b377b1b544ffde8e2e1f3a786f8b1fe9f140de93610f5e6011548710611da7565b85600f5542600c5560ff19161760105551428152a260008051602061252b8339815191528280a280f35b606490602084519162461bcd60e51b83528201526009602482015268546f6f206561726c7960b81b6044820152fd5b50503461028857602090610e38610fcd366119a5565b611d7c565b50503461028857816003193601126102885760ff6020925460a01c1690519015158152f35b5050346102885760203660031901126102885760209181906001600160a01b0361101f611803565b1681526014845220549051908152f35b5050346102885781600319360112610288576020906009549051908152f35b50503461028857816003193601126102885760055490516001600160a01b039091168152602090f35b5050346102885781600319360112610288576020906007549051908152f35b83915034610288576110a7366118c3565b60025491936001600160a01b0393926110c39085163314611b7e565b6110cb6120a4565b6110da60ff6010541615611aee565b6011906110ea6011548414611bd6565b6110f2611e3b565b90875b8481106111ca5750505050845b81811061114d57507f3b55ce5afbfa91d536b2a2394b85b42d8abc5fb48daa07088154bb0bc5fa6c009394956111479161113a611e3b565b9151948594169684611d0f565b0390a280f35b8061115b6001928488611c19565b35611167575b01611102565b80875260126020908082526111848a8a2054610b3985888c611c19565b90838a528252898920558585169081895260138082528a8a20848b5282526111b48b8b2054610b3986898d611c19565b928a52815289892090838a525288882055611161565b886111d682878b611c19565b351315611266576111e881868a611c19565b356111f38285611c92565b5190600a918281029281840414901517156112545760648092041061121d57506001905b016110f5565b8a5162461bcd60e51b8152602081850152601460248201527354726164652073697a6520746f6f206c6172676560601b6044820152fd5b634e487b7160e01b8b5285845260248bfd5b8089611275600193888c611c19565b351215611217576112ac61128d610ae983898d611c19565b8989168c528b8d846020916013835283209252528c8c20541015611c50565b611217565b50503461028857816003193601126102885760035490516001600160a01b039091168152602090f35b919050346103135760203660031901126103135781359161130660018060a01b03600254163314611b7e565b428311156113405750816020917fb78308b2eb98fa00faea36698f56c2389c9bd7c8e76f7c0f7725e33135d4809293600b5551908152a180f35b6020606492519162461bcd60e51b8352820152601a60248201527f446561646c696e65206d75737420626520696e206675747572650000000000006044820152fd5b50503461028857816003193601126102885760209060ff6010541690519015158152f35b9050346103135782600319360112610313576113c0612078565b82549060ff8260a01c1615611406575060ff60a01b19168255513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa90602090a180f35b8251638dfc202b60e01b8152fd5b9050823461038b57602036600319011261038b5781359160119161143b6011548510611b3a565b611443611e3b565b926007549361145481518710611b3a565b829683975b82518910156114da5761146c8984611c92565b51670de0b6b3a7640000908181029181830414901517156114c8576001916114b261149a8a6114b894611ce9565b68056bc75e2d631000008082116114c0575b506122a6565b90611d6f565b980197611459565b90508d6114ac565b634e487b7160e01b8652848752602486fd5b86856114e78a8996611c92565b5191670de0b6b3a76400009283810290808204851490151715611560576115289161151191611ce9565b68056bc75e2d6310000080821161155857506122a6565b82810292818404149015171561154557602084610e388585611ce9565b634e487b7160e01b815260118552602490fd5b9050876114ac565b634e487b7160e01b835260118752602483fd5b82843461038b578060031936011261038b5761158d611e3b565b9160075460ff60105416600f5491601154956115a88761193f565b956115b586519788611907565b878752602096602081019889601184527f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6884915b838310611675575050505086519760a089019160a08a525180925260c0890160c08360051b8b01019a93905b838210611648575050505050866116349187809903602089015261185e565b938501521515606084015260808301520390f35b909192939a83806116666001938f8f60bf199083030187525161181e565b9d019201920190939291611615565b60018c81928d9e97989e516116958161168e8189611a31565b0382611907565b8152019201920191909a94939a6115e9565b83915034610288578160031936011261028857601054906116cb60ff831615611aee565b600b5442111561173f57507fe4d6efcb12aa89dc35692182a18a22bcfd2c5d86dd221420209b7287daab0888602060019394600d54151560001461173657600e549485945b60ff19161760105583600f5551338152a260008051602061252b8339815191528280a280f35b85948594611710565b606490602085519162461bcd60e51b8352820152601c60248201527f5265706f7274657220646561646c696e65206e6f7420706173736564000000006044820152fd5b505034610288578160031936011261028857602090600d549051908152f35b5050346102885760203660031901126102885760209160ff9082906001600160a01b036117cc611803565b1681526016855220541690519015158152f35b849134610313578260031936011261031357546001600160a01b0316815260209150f35b600435906001600160a01b038216820361181957565b600080fd5b919082519283825260005b84811061184a575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201611829565b90815180825260208080930193019160005b82811061187e575050505090565b835185529381019392810192600101611870565b9181601f840112156118195782359167ffffffffffffffff8311611819576020808501948460051b01011161181957565b906040600319830112611819576004356001600160a01b038116810361181957916024359067ffffffffffffffff82116118195761190391600401611892565b9091565b90601f8019910116810190811067ffffffffffffffff82111761192957604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff81116119295760051b60200190565b92916119628261193f565b916119706040519384611907565b829481845260208094019160051b810192831161181957905b8282106119965750505050565b81358152908301908301611989565b6020600319820112611819576004359067ffffffffffffffff82116118195780602383011215611819578160246119e193600401359101611957565b90565b601154811015611a1b5760116000527f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c680190600090565b634e487b7160e01b600052603260045260246000fd5b80546000939260018083169383821c938515611ae4575b6020958686108114611ace57858552908115611aaf5750600114611a6e575b5050505050565b90939495506000929192528360002092846000945b838610611a9b57505050500101903880808080611a67565b805485870183015294019385908201611a83565b60ff19168685015250505090151560051b010191503880808080611a67565b634e487b7160e01b600052602260045260246000fd5b93607f1693611a48565b15611af557565b60405162461bcd60e51b815260206004820152601760248201527f4d61726b657420616c7265616479207265736f6c7665640000000000000000006044820152606490fd5b15611b4157565b60405162461bcd60e51b8152602060048201526015602482015274092dcecc2d8d2c840deeae8c6dedaca40d2dcc8caf605b1b6044820152606490fd5b15611b8557565b60405162461bcd60e51b815260206004820152602360248201527f4f6e6c7920666163746f72792063616e2063616c6c20746869732066756e637460448201526234b7b760e91b6064820152608490fd5b15611bdd57565b60405162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c840c2e4e4c2f240d8cadccee8d60631b6044820152606490fd5b9190811015611a1b5760051b0190565b600160ff1b8114611c3a5760000390565b634e487b7160e01b600052601160045260246000fd5b15611c5757565b60405162461bcd60e51b8152602060048201526013602482015272496e73756666696369656e742073686172657360681b6044820152606490fd5b8051821015611a1b5760209160051b010190565b81810292918115918404141715611c3a57565b8015611cd3576ec097ce7bc90715b34b9f10000000000490565b634e487b7160e01b600052601260045260246000fd5b8115611cd3570490565b91909160008382019384129112908015821691151617611c3a57565b939290918060608601606087525260808501929060005b818110611d4b57505050611d46826040928660009503602088015261185e565b930152565b8235855260209485019490920191600101611d26565b9060018201809211611c3a57565b91908201809211611c3a57565b611d8590611de5565b6000811315611da1576119e1906127106105e460095483611ca6565b50600090565b15611dae57565b60405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206f7574636f6d6560881b6044820152606490fd5b6119e190611df7815160115414611bd6565b611dff611e3b565b90600754916120c5565b90611e138261193f565b611e206040519182611907565b8281528092611e31601f199161193f565b0190602036910137565b60115490611e4882611e09565b60009260005b818110611e5c575090925050565b80600191865260126020526040862054611e768286611c92565b5201611e4e565b15611e8457565b60405162461bcd60e51b815260206004820152601360248201527213585c9ad95d081b9bdd081c995cdbdb1d9959606a1b6044820152606490fd5b15611ec657565b60405162461bcd60e51b8152602060048201526014602482015273111a5cdc1d5d19481c195c9a5bd908195b99195960621b6044820152606490fd5b90816020910312611819575180151581036118195790565b929190936011548503612015576004546001600160a01b039390841690841603612015576005928060055416911603612004576008540361200d5760005b838110611f685750505050600190565b80821b830135601e1984360301811215611819578301803567ffffffffffffffff81116118195760208083018236038113611819576040938451611fb584601f19601f8801160182611907565b8481528381019184863692010111611819576000848661035c97611ff29686378301015251902093611fe6866119e4565b50905193848092611a31565b81519101200361200457600101611f58565b50505050600090565b505050600090565b5050505050600090565b1561202657565b60405162461bcd60e51b815260206004820152601860248201527f4469737075746520706572696f64206e6f7420656e64656400000000000000006044820152606490fd5b91908203918211611c3a57565b6000546001600160a01b0316330361208c57565b60405163118cdaa760e01b8152336004820152602490fd5b60ff60005460a01c166120b357565b60405163d93c066560e01b8152600490fd5b92908351815103612246578351156122125782156121cd576120e783856123d5565b6120f18551611e09565b9260009160005b875181101561219f57808461210f60019388611c92565b511261214657612134612122828b611c92565b5161212d8389611c92565b5190611d6f565b61213e8289611c92565b525b016120f8565b61216e612153828b611c92565b51612167612161848a611c92565b51611c29565b1115611c50565b61218f61217b828b611c92565b51612189612161848a611c92565b9061206b565b6121998289611c92565b52612140565b509492509450506121af916123d5565b908082106121c0576119e19161206b565b6119e191610a689161206b565b60405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c697175696469747920706172616d6574657200000000006044820152606490fd5b60405162461bcd60e51b815260206004820152600c60248201526b456d7074792061727261797360a01b6044820152606490fd5b60405162461bcd60e51b8152602060048201526015602482015274082e4e4c2f240d8cadccee8d040dad2e6dac2e8c6d605b1b6044820152606490fd5b600260015414612294576002600155565b604051633ee5aeb560e01b8152600490fd5b80156123c85768056bc75e2d6310000081116123c157670de0b6b3a7640000808281020490818303611c3a57818101809111611c3a578280808094936122ed828096611ca6565b671bc16d674ec800009004908161230391611d6f565b9161230d91611ca6565b6729a2241af62c00009004908161232391611d6f565b9161232d91611ca6565b673782dace9d9000009004908161234391611d6f565b9161234d91611ca6565b674563918244f400009004908161236391611d6f565b9161236d91611ca6565b6753444835ec5800009004908161238391611d6f565b9161238d91611ca6565b676124fee993bc0000900490816123a391611d6f565b916123ad91611ca6565b676f05b59d3b20000090046119e191611d6f565b5060001990565b50670de0b6b3a764000090565b909190600090815b8151831015612445576123f08383611c92565b51670de0b6b3a764000090818102918183041490151715611c3a576001916114b261241e8861243594611ce9565b68056bc75e2d6310000080821161243d57506122a6565b9201916123dd565b9050386114ac565b6124669250670de0b6b3a7640000939491506124609061246a565b90611ca6565b0490565b66038d7ea4c680008110611da157670de0b6b3a764000080821461252357811061250857600068056bc75e2d63100000916000905b602082106124bc5750506119e1916124b691611d6f565b60011c90565b90916124cb6124b68583611d6f565b906124d5826122a6565b838110156124eb575050600190925b019061249f565b83919495501160001461250157600190936124e4565b9250505090565b61251461251991611cb9565b61246a565b6119e19019611d61565b505060009056fe93608ecbcf057462da63f5aef413ce7f78c5e1b3bb51859d77a40845ece2bfc3a2646970667358221220c746eb8654f9a031a39b1cdb68e7d9e0ab6bb2f5d5f5ab74b4850b5a555f6a7b64736f6c634300081600339016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993009b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a2646970667358221220217839749afe34a0d3c4dd1fbaa2b9f18c23e5049f50433ed2bf8f0e65940e4b64736f6c63430008160033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.