Address Details
contract
0x4dd49B462aB127045263413b8D10Bef892e2F7A4
- Contract Name
- OrderManager
- Creator
- 0xd3c2ab–ffc681 at 0x18d692–4d8804
- Balance
- 0.023 CELO ( )
- Locked CELO Balance
- 0.00 CELO
- Voting CELO Balance
- 0.00 CELO
- Pending Unlocked Gold
- 0.00 CELO
- Tokens
-
Fetching tokens...
- Transactions
- 280 Transactions
- Transfers
- 123 Transfers
- Gas Used
- 27,439,086
- Last Balance Update
- 17951363
Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
This contract has been verified via Sourcify.
View contract in Sourcify repository
- Contract name:
- OrderManager
- Optimization enabled
- true
- Compiler version
- v0.8.16+commit.07a7930e
- Optimization runs
- 800
- EVM Version
- london
- Verified at
- 2023-02-24T23:47:57.338086Z
contracts/core/OrderManager.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "../access/Governable.sol"; import "../interfaces/IOracle.sol"; import "../interfaces/IDex.sol"; contract OrderManager is ReentrancyGuard, Governable { using SafeERC20 for IERC20; struct OpenOrder { address account; bool isLong; bool isTriggerAbove; uint256 productId; uint256 margin; uint256 leverage; uint256 tradeFee; uint256 triggerPrice; uint256 tpPrice; uint256 slPrice; uint256 timestamp; } struct CloseOrder { address account; bool isLong; bool isTriggerAbove; uint256 productId; uint256 size; uint256 triggerPrice; uint256 timestamp; } bool public isInitialized; address public positionManager; address public immutable dex; address public immutable oracle; address public immutable collateralToken; uint256 public maxOpenOrders = 8; uint256 public maxCloseOrders = 8; uint256 public executionFee = 1e15; uint256 private immutable tokenBase; uint256 private constant BASE = 10**8; mapping(bytes32 => OpenOrder) public openOrders; mapping(bytes32 => CloseOrder) public closeOrders; mapping(address => bool) public isKeeper; event CreateOpenOrder( bytes32 indexed orderKey, address indexed account, bool isLong, bool isTriggerAbove, uint256 productId, uint256 margin, uint256 leverage, uint256 tradeFee, uint256 triggerPrice, uint256 tpPrice, uint256 slPrice, uint256 timestamp ); event EditOpenOrder( bytes32 indexed orderKey, address indexed account, bool isLong, bool isTriggerAbove, uint256 productId, uint256 margin, uint256 leverage, uint256 tradeFee, uint256 triggerPrice, uint256 tpPrice, uint256 slPrice, uint256 timestamp ); event CancelOpenOrder( bytes32 indexed orderKey, address indexed account, bool isLong, bool isTriggerAbove, uint256 productId, uint256 margin, uint256 leverage, uint256 tradeFee, uint256 triggerPrice, uint256 tpPrice, uint256 slPrice, uint256 timestamp ); event ExecuteOpenOrder( bytes32 indexed orderKey, address indexed account, bool isLong, bool isTriggerAbove, uint256 productId, uint256 margin, uint256 leverage, uint256 tradeFee, uint256 triggerPrice, uint256 tpPrice, uint256 slPrice, uint256 timestamp, uint256 executionPrice ); event CreateCloseOrder( bytes32 indexed orderKey, address indexed account, bool isLong, bool isTriggerAbove, uint256 productId, uint256 size, uint256 triggerPrice, uint256 timestamp ); event EditCloseOrder( bytes32 indexed orderKey, address indexed account, bool isLong, bool isTriggerAbove, uint256 productId, uint256 size, uint256 triggerPrice, uint256 timestamp ); event CancelCloseOrder( bytes32 indexed orderKey, address indexed account, bool isLong, bool isTriggerAbove, uint256 productId, uint256 size, uint256 triggerPrice, uint256 timestamp ); event ExecuteCloseOrder( bytes32 indexed orderKey, address indexed account, bool isLong, bool isTriggerAbove, uint256 productId, uint256 size, uint256 triggerPrice, uint256 timestamp, uint256 executionPrice ); event ExecuteOpenOrderError(bytes32 indexed orderKey, address indexed account, string executionError); event ExecuteCloseOrderError(bytes32 indexed orderKey, address indexed account, string executionError); event ExecutionFeeRefundError(address indexed account, uint256 totalExecutionFee); event SetKeeper(address keeper, bool isActive); modifier onlyKeeper() { require(isKeeper[msg.sender], "OrderManager: !keeper"); _; } constructor( address _dex, address _oracle, address _collateralToken, uint256 _tokenBase ) { dex = _dex; oracle = _oracle; collateralToken = _collateralToken; tokenBase = _tokenBase; isKeeper[address(this)] = true; } function initialize(address _positionManager) external onlyGov { require(!isInitialized, "OrderManager: already initialized"); isInitialized = true; positionManager = _positionManager; } function createOpenOrder( uint256 productId, bool isLong, bool isTriggerAbove, uint256 margin, uint256 leverage, uint256 triggerPrice, uint256 tpPrice, // no tp set if tpPrice == 0 uint256 slPrice // no sl set if slPrice == 0 ) external payable nonReentrant { uint256 numOfExecutions = 1; if (tpPrice > 0) numOfExecutions += 2; if (slPrice > 0) numOfExecutions += 2; require(msg.value == executionFee * numOfExecutions, "OrderManager: invalid executionFee"); _createOpenOrder( msg.sender, isLong, isTriggerAbove, productId, margin, leverage, triggerPrice, tpPrice, slPrice ); } function _createOpenOrder( address account, bool isLong, bool isTriggerAbove, uint256 productId, uint256 margin, uint256 leverage, uint256 triggerPrice, uint256 tpPrice, uint256 slPrice ) private { IDex(dex).validateOpenPositionRequirements(margin, leverage, productId); uint256 _maxOpenOrders = maxOpenOrders; for (uint256 i = 0; i < _maxOpenOrders; ++i) { bytes32 orderKey = getOrderKey(account, productId, isLong, i); if (openOrders[orderKey].account == address(0)) { uint256 tradeFee = IDex(dex).getTradeFee(margin, leverage, productId); IERC20(collateralToken).safeTransferFrom( account, address(this), ((margin + tradeFee) * tokenBase) / BASE ); openOrders[orderKey] = OpenOrder( account, isLong, isTriggerAbove, productId, margin, leverage, tradeFee, triggerPrice, tpPrice, slPrice, block.timestamp ); emit CreateOpenOrder( orderKey, account, isLong, isTriggerAbove, productId, margin, leverage, tradeFee, triggerPrice, tpPrice, slPrice, block.timestamp ); return; } } revert("OrderManager: maxOpenOrders exceeded"); } function editOpenOrder( bytes32 orderKey, bool isAdjustingTriggerPrice, uint256 triggerPrice, bool isAdjustingTpPrice, uint256 tpPrice, bool isAdjustingSlPrice, uint256 slPrice ) external payable nonReentrant { OpenOrder storage order = openOrders[orderKey]; require(order.account == msg.sender, "OrderManager: !order.account"); if (isAdjustingTriggerPrice) order.triggerPrice = triggerPrice; uint256 numOfExecutions = 0; if (isAdjustingTpPrice) { if (order.tpPrice == 0) { if (tpPrice != 0) { order.tpPrice = tpPrice; numOfExecutions += 1; } } else { if (tpPrice == 0) { order.tpPrice = tpPrice; (bool success, ) = payable(msg.sender).call{value: executionFee}(""); require(success, "OrderManager: failed to send execution fee"); } else { order.tpPrice = tpPrice; } } } if (isAdjustingSlPrice) { if (order.slPrice == 0) { if (slPrice != 0) { order.slPrice = slPrice; numOfExecutions += 1; } } else { if (slPrice == 0) { order.slPrice = slPrice; (bool success, ) = payable(msg.sender).call{value: executionFee}(""); require(success, "OrderManager: failed to send execution fee"); } else { order.slPrice = slPrice; } } } require(msg.value == executionFee * numOfExecutions, "OrderManager: invalid executionFee"); order.timestamp = block.timestamp; emit EditOpenOrder( orderKey, order.account, order.isLong, order.isTriggerAbove, order.productId, order.margin, order.leverage, order.tradeFee, order.triggerPrice, order.tpPrice, order.slPrice, order.timestamp ); } function cancelOpenOrder(bytes32 orderKey) public nonReentrant { OpenOrder memory order = openOrders[orderKey]; require(order.account == msg.sender, "OrderManager: !order.account"); IERC20(collateralToken).safeTransfer(msg.sender, ((order.margin + order.tradeFee) * tokenBase) / BASE); delete openOrders[orderKey]; uint256 numOfExecutions = 1; if (order.tpPrice > 0) numOfExecutions += 2; if (order.slPrice > 0) numOfExecutions += 2; (bool success, ) = payable(msg.sender).call{value: executionFee * numOfExecutions}(""); require(success, "OrderManager: failed to send execution fee"); emit CancelOpenOrder( orderKey, order.account, order.isLong, order.isTriggerAbove, order.productId, order.margin, order.leverage, order.tradeFee, order.triggerPrice, order.tpPrice, order.slPrice, order.timestamp ); } function executeOpenOrder(bytes32 orderKey) external { require(msg.sender == address(this) || isKeeper[msg.sender], "OrderManager: !keeper"); OpenOrder memory order = openOrders[orderKey]; if (order.account == address(0)) return; (uint256 currentPrice, ) = validateExecutionPrice( order.isLong, order.isTriggerAbove, order.triggerPrice, order.productId ); IERC20(collateralToken).safeIncreaseAllowance(dex, ((order.margin + order.tradeFee) * tokenBase) / BASE); IDex(dex).openPosition(order.account, order.productId, order.isLong, order.margin, order.leverage); uint256 numOfExecutions = 1; if (order.tpPrice != 0) { _createCloseOrder( order.account, order.isLong, order.isLong, order.productId, (order.margin * order.leverage) / BASE, order.tpPrice ); numOfExecutions += 1; } if (order.slPrice != 0) { _createCloseOrder( order.account, order.isLong, !order.isLong, order.productId, (order.margin * order.leverage) / BASE, order.slPrice ); numOfExecutions += 1; } delete openOrders[orderKey]; (bool success, ) = payable(tx.origin).call{value: executionFee * numOfExecutions}(""); require(success, "OrderManager: failed to send execution fee"); emit ExecuteOpenOrder( orderKey, order.account, order.isLong, order.isTriggerAbove, order.productId, order.margin, order.leverage, order.tradeFee, order.triggerPrice, order.tpPrice, order.slPrice, order.timestamp, currentPrice ); } function createCloseOrder( bool isLong, bool isTriggerAbove, uint256 productId, uint256 size, uint256 triggerPrice ) external payable nonReentrant { require(msg.value == executionFee, "OrderManager: invalid executionFee"); _createCloseOrder(msg.sender, isLong, isTriggerAbove, productId, size, triggerPrice); } function createCloseOrderForTPSL( address account, bool isLong, bool isTriggerAbove, uint256 productId, uint256 size, uint256 triggerPrice ) external payable { require(msg.sender == positionManager, "OrderManager: !positionManager"); require(msg.value == executionFee, "OrderManager: invalid executionFee"); _createCloseOrder(account, isLong, isTriggerAbove, productId, size, triggerPrice); } function _createCloseOrder( address account, bool isLong, bool isTriggerAbove, uint256 productId, uint256 size, uint256 triggerPrice ) private { require(triggerPrice > 0, "OrderManager: triggerPrice cannot be 0"); uint256 _maxCloseOrders = maxCloseOrders; for (uint256 i = 0; i < _maxCloseOrders; ++i) { bytes32 orderKey = getOrderKey(account, productId, isLong, i); if (closeOrders[orderKey].account == address(0)) { closeOrders[orderKey] = CloseOrder( account, isLong, isTriggerAbove, productId, size, triggerPrice, block.timestamp ); emit CreateCloseOrder( orderKey, account, isLong, isTriggerAbove, productId, size, triggerPrice, block.timestamp ); return; } } revert("OrderManager: maxCloseOrders exceeded"); } function editCloseOrder(bytes32 orderKey, uint256 triggerPrice) external nonReentrant { CloseOrder storage order = closeOrders[orderKey]; require(order.account == msg.sender, "OrderManager: !order.account"); order.triggerPrice = triggerPrice; order.timestamp = block.timestamp; emit EditCloseOrder( orderKey, order.account, order.isLong, order.isTriggerAbove, order.productId, order.size, order.triggerPrice, order.timestamp ); } function cancelCloseOrder(bytes32 orderKey) public nonReentrant { require(closeOrders[orderKey].account == msg.sender, "OrderManager: !order.account"); _cancelCloseOrder(orderKey); (bool success, ) = payable(msg.sender).call{value: executionFee}(""); require(success, "OrderManager: failed to send execution fee"); } function cancelActiveCloseOrders( address account, uint256 productId, bool isLong ) external { require(msg.sender == dex, "OrderManager: !dex"); uint256 numOfExecutions = 0; uint256 _maxCloseOrders = maxCloseOrders; for (uint256 i = 0; i < _maxCloseOrders; ++i) { bytes32 orderKey = getOrderKey(account, productId, isLong, i); if (closeOrders[orderKey].account != address(0)) { _cancelCloseOrder(orderKey); numOfExecutions += 1; } } if (numOfExecutions != 0) { uint256 _executionFee = executionFee; (bool success, ) = payable(account).call{value: _executionFee * numOfExecutions}(""); if (!success) { emit ExecutionFeeRefundError(account, _executionFee * numOfExecutions); (bool success2, ) = payable(tx.origin).call{value: _executionFee * numOfExecutions}(""); require(success2, "OrderManager: failed to send execution fee"); } } } function _cancelCloseOrder(bytes32 orderKey) private { CloseOrder memory order = closeOrders[orderKey]; delete closeOrders[orderKey]; emit CancelCloseOrder( orderKey, order.account, order.isLong, order.isTriggerAbove, order.productId, order.size, order.triggerPrice, order.timestamp ); } function executeCloseOrder(bytes32 orderKey) external { require(msg.sender == address(this) || isKeeper[msg.sender], "OrderManager: !keeper"); CloseOrder memory order = closeOrders[orderKey]; if (order.account == address(0)) return; (uint256 currentPrice, ) = validateExecutionPrice( !order.isLong, order.isTriggerAbove, order.triggerPrice, order.productId ); IDex(dex).closePosition( order.account, order.productId, order.isLong, (order.size * BASE) / IDex(dex).getPositionLeverage(order.account, order.productId, order.isLong) ); delete closeOrders[orderKey]; (bool success, ) = payable(tx.origin).call{value: executionFee}(""); require(success, "OrderManager: failed to send execution fee"); emit ExecuteCloseOrder( orderKey, order.account, order.isLong, order.isTriggerAbove, order.productId, order.size, order.triggerPrice, order.timestamp, currentPrice ); } function executeOrdersWithPrices( uint256[] memory productIds, uint256[] memory prices, bytes32[] memory openOrderKeys, bytes32[] memory closeOrderKeys ) external onlyKeeper { IOracle(oracle).setPrices(productIds, prices); for (uint256 i = 0; i < openOrderKeys.length; ++i) { try this.executeOpenOrder(openOrderKeys[i]) {} catch Error(string memory executionError) { emit ExecuteOpenOrderError(openOrderKeys[i], openOrders[openOrderKeys[i]].account, executionError); } catch (bytes memory) {} } for (uint256 i = 0; i < closeOrderKeys.length; ++i) { try this.executeCloseOrder(closeOrderKeys[i]) {} catch Error(string memory executionError) { emit ExecuteCloseOrderError(closeOrderKeys[i], closeOrders[closeOrderKeys[i]].account, executionError); } catch (bytes memory) {} } } function cancelMultipleOrders(bytes32[] memory openOrderKeys, bytes32[] memory closeOrderKeys) external { for (uint256 i = 0; i < openOrderKeys.length; ++i) { cancelOpenOrder(openOrderKeys[i]); } for (uint256 i = 0; i < closeOrderKeys.length; ++i) { cancelCloseOrder(closeOrderKeys[i]); } } function validateExecutionPrice( bool isLong, bool isTriggerAbove, uint256 triggerPrice, uint256 productId ) public view returns (uint256, bool) { uint256 currentPrice = IOracle(oracle).getPrice(productId, isLong); bool isPriceValid = isTriggerAbove ? currentPrice >= triggerPrice : currentPrice <= triggerPrice; require(isPriceValid, "OrderManager: invalid price for execution"); return (currentPrice, isPriceValid); } function getOrderKey( address account, uint256 productId, bool isLong, uint256 orderIndex ) public pure returns (bytes32) { return keccak256(abi.encodePacked(account, productId, isLong, orderIndex)); } function getOpenOrder( address account, uint256 productId, bool isLong, uint256 orderIndex ) external view returns ( uint256, uint256, uint256, uint256, bool, uint256, uint256, uint256 ) { OpenOrder memory order = openOrders[getOrderKey(account, productId, isLong, orderIndex)]; return ( order.margin, order.leverage, order.tradeFee, order.triggerPrice, order.isTriggerAbove, order.tpPrice, order.slPrice, order.timestamp ); } function getCloseOrder( address account, uint256 productId, bool isLong, uint256 orderIndex ) external view returns ( uint256, uint256, bool, uint256 ) { CloseOrder memory order = closeOrders[getOrderKey(account, productId, isLong, orderIndex)]; return (order.size, order.triggerPrice, order.isTriggerAbove, order.timestamp); } function getUserOpenOrders( address user, uint256 startId, uint256 endId ) public view returns (bytes32[] memory userOpenOrderKeys, OpenOrder[] memory userOpenOrders) { require(startId > 0, "OrderManager: !startId"); uint256 totalProducts = IDex(dex).totalProducts(); if (endId > totalProducts) endId = totalProducts; uint256 _maxOpenOrders = maxOpenOrders; userOpenOrderKeys = new bytes32[]((endId - startId + 1) * _maxOpenOrders * 2); userOpenOrders = new OpenOrder[]((endId - startId + 1) * _maxOpenOrders * 2); bytes32 orderKey; uint256 count; for (uint256 i = startId; i <= endId; ++i) { for (uint256 j = 0; j < _maxOpenOrders; ++j) { orderKey = getOrderKey(user, i, true, j); if (openOrders[orderKey].account != address(0)) { userOpenOrderKeys[count] = orderKey; userOpenOrders[count++] = openOrders[orderKey]; } orderKey = getOrderKey(user, i, false, j); if (openOrders[orderKey].account != address(0)) { userOpenOrderKeys[count] = orderKey; userOpenOrders[count++] = openOrders[orderKey]; } } } } function getUserCloseOrders( address user, uint256 startId, uint256 endId ) external view returns (bytes32[] memory userCloseOrderKeys, CloseOrder[] memory userCloseOrders) { require(startId > 0, "OrderManager: !startId"); uint256 totalProducts = IDex(dex).totalProducts(); if (endId > totalProducts) endId = totalProducts; uint256 _maxCloseOrders = maxCloseOrders; userCloseOrderKeys = new bytes32[]((endId - startId + 1) * _maxCloseOrders * 2); userCloseOrders = new CloseOrder[]((endId - startId + 1) * _maxCloseOrders * 2); bytes32 orderKey; uint256 count; for (uint256 i = startId; i <= endId; ++i) { for (uint256 j = 0; j < _maxCloseOrders; ++j) { orderKey = getOrderKey(user, i, true, j); if (closeOrders[orderKey].account != address(0)) { userCloseOrderKeys[count] = orderKey; userCloseOrders[count++] = closeOrders[orderKey]; } orderKey = getOrderKey(user, i, false, j); if (closeOrders[orderKey].account != address(0)) { userCloseOrderKeys[count] = orderKey; userCloseOrders[count++] = closeOrders[orderKey]; } } } } function isUserOpenOrderAvailable( address user, uint256 productId, bool isLong ) external view returns (bool) { uint256 _maxOpenOrders = maxOpenOrders; for (uint256 i = 0; i < _maxOpenOrders; ++i) { if (openOrders[getOrderKey(user, productId, isLong, i)].account == address(0)) { return true; } } return false; } function isUserCloseOrderAvailable( address user, uint256 productId, bool isLong ) external view returns (bool) { uint256 _maxCloseOrders = maxCloseOrders; for (uint256 i = 0; i < _maxCloseOrders; ++i) { if (closeOrders[getOrderKey(user, productId, isLong, i)].account == address(0)) { return true; } } return false; } function getUserAvailableOpenOrderSlots( address user, uint256 productId, bool isLong ) external view returns (uint256 availableOpenOrderSlots) { availableOpenOrderSlots = 0; uint256 _maxOpenOrders = maxOpenOrders; for (uint256 i = 0; i < _maxOpenOrders; ++i) { if (openOrders[getOrderKey(user, productId, isLong, i)].account == address(0)) { availableOpenOrderSlots += 1; } } } function getUserAvailableCloseOrderSlots( address user, uint256 productId, bool isLong ) external view returns (uint256 availableCloseOrderSlots) { availableCloseOrderSlots = 0; uint256 _maxCloseOrders = maxCloseOrders; for (uint256 i = 0; i < _maxCloseOrders; ++i) { if (closeOrders[getOrderKey(user, productId, isLong, i)].account == address(0)) { availableCloseOrderSlots += 1; } } } function setMaxOrders(uint256 _maxOpenOrders, uint256 _maxCloseOrders) external onlyGov { require(maxOpenOrders >= 5 && maxCloseOrders >= 5, "OrderManager: !maxNumOfOrders"); maxOpenOrders = _maxOpenOrders; maxCloseOrders = _maxCloseOrders; } function setExecutionFee(uint256 _executionFee) external onlyGov { require(_executionFee <= 1e18); executionFee = _executionFee; } function setKeeper(address _account, bool _isActive) external onlyGov { isKeeper[_account] = _isActive; emit SetKeeper(_account, _isActive); } }
/_openzeppelin/contracts/security/ReentrancyGuard.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
/_openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
/_openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
/_openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
/_openzeppelin/contracts/utils/Address.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
/contracts/access/Governable.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Governable { address public gov; event SetGov(address indexed newGov); constructor() { gov = msg.sender; } modifier onlyGov() { require(msg.sender == gov, "Governable: forbidden"); _; } function setGov(address _gov) external onlyGov { gov = _gov; emit SetGov(_gov); } }
/contracts/interfaces/IDex.sol
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IDex { function stakeVaultToCompound(address user, uint256 amount) external; function openPosition( address user, uint256 productId, bool isLong, uint256 margin, uint256 leverage ) external; function validateOpenPositionRequirements( uint256 margin, uint256 leverage, uint256 productId ) external view; function closePosition( address user, uint256 productId, bool isLong, uint256 margin ) external; function liquidatePositions(bytes32[] calldata positionKeys) external; function distributeVaultReward() external returns (uint256); function distributeStakingReward() external returns (uint256); function getVaultShares() external view returns (uint256); function getStakeShares(address user) external view returns (uint256); function getPositionLeverage( address account, uint256 productId, bool isLong ) external view returns (uint256); function minMargin() external view returns (uint256); function totalProducts() external view returns (uint256); function getTradeFee( uint256 margin, uint256 leverage, uint256 productId ) external view returns (uint256); function getPendingVaultReward() external view returns (uint256); function getPendingStakingReward() external view returns (uint256); }
/contracts/interfaces/IOracle.sol
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IOracle { function getPrice(uint256 productId) external view returns (uint256); function getPrice(uint256 productId, bool isLong) external view returns (uint256); function setPrices(uint256[] memory productIds, uint256[] memory prices) external; }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_dex","internalType":"address"},{"type":"address","name":"_oracle","internalType":"address"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"uint256","name":"_tokenBase","internalType":"uint256"}]},{"type":"event","name":"CancelCloseOrder","inputs":[{"type":"bytes32","name":"orderKey","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"bool","name":"isTriggerAbove","internalType":"bool","indexed":false},{"type":"uint256","name":"productId","internalType":"uint256","indexed":false},{"type":"uint256","name":"size","internalType":"uint256","indexed":false},{"type":"uint256","name":"triggerPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"CancelOpenOrder","inputs":[{"type":"bytes32","name":"orderKey","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"bool","name":"isTriggerAbove","internalType":"bool","indexed":false},{"type":"uint256","name":"productId","internalType":"uint256","indexed":false},{"type":"uint256","name":"margin","internalType":"uint256","indexed":false},{"type":"uint256","name":"leverage","internalType":"uint256","indexed":false},{"type":"uint256","name":"tradeFee","internalType":"uint256","indexed":false},{"type":"uint256","name":"triggerPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"tpPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"slPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"CreateCloseOrder","inputs":[{"type":"bytes32","name":"orderKey","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"bool","name":"isTriggerAbove","internalType":"bool","indexed":false},{"type":"uint256","name":"productId","internalType":"uint256","indexed":false},{"type":"uint256","name":"size","internalType":"uint256","indexed":false},{"type":"uint256","name":"triggerPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"CreateOpenOrder","inputs":[{"type":"bytes32","name":"orderKey","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"bool","name":"isTriggerAbove","internalType":"bool","indexed":false},{"type":"uint256","name":"productId","internalType":"uint256","indexed":false},{"type":"uint256","name":"margin","internalType":"uint256","indexed":false},{"type":"uint256","name":"leverage","internalType":"uint256","indexed":false},{"type":"uint256","name":"tradeFee","internalType":"uint256","indexed":false},{"type":"uint256","name":"triggerPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"tpPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"slPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"EditCloseOrder","inputs":[{"type":"bytes32","name":"orderKey","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"bool","name":"isTriggerAbove","internalType":"bool","indexed":false},{"type":"uint256","name":"productId","internalType":"uint256","indexed":false},{"type":"uint256","name":"size","internalType":"uint256","indexed":false},{"type":"uint256","name":"triggerPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"EditOpenOrder","inputs":[{"type":"bytes32","name":"orderKey","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"bool","name":"isTriggerAbove","internalType":"bool","indexed":false},{"type":"uint256","name":"productId","internalType":"uint256","indexed":false},{"type":"uint256","name":"margin","internalType":"uint256","indexed":false},{"type":"uint256","name":"leverage","internalType":"uint256","indexed":false},{"type":"uint256","name":"tradeFee","internalType":"uint256","indexed":false},{"type":"uint256","name":"triggerPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"tpPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"slPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExecuteCloseOrder","inputs":[{"type":"bytes32","name":"orderKey","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"bool","name":"isTriggerAbove","internalType":"bool","indexed":false},{"type":"uint256","name":"productId","internalType":"uint256","indexed":false},{"type":"uint256","name":"size","internalType":"uint256","indexed":false},{"type":"uint256","name":"triggerPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false},{"type":"uint256","name":"executionPrice","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExecuteCloseOrderError","inputs":[{"type":"bytes32","name":"orderKey","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"string","name":"executionError","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"ExecuteOpenOrder","inputs":[{"type":"bytes32","name":"orderKey","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"bool","name":"isTriggerAbove","internalType":"bool","indexed":false},{"type":"uint256","name":"productId","internalType":"uint256","indexed":false},{"type":"uint256","name":"margin","internalType":"uint256","indexed":false},{"type":"uint256","name":"leverage","internalType":"uint256","indexed":false},{"type":"uint256","name":"tradeFee","internalType":"uint256","indexed":false},{"type":"uint256","name":"triggerPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"tpPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"slPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false},{"type":"uint256","name":"executionPrice","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExecuteOpenOrderError","inputs":[{"type":"bytes32","name":"orderKey","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"string","name":"executionError","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"ExecutionFeeRefundError","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"uint256","name":"totalExecutionFee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetGov","inputs":[{"type":"address","name":"newGov","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"SetKeeper","inputs":[{"type":"address","name":"keeper","internalType":"address","indexed":false},{"type":"bool","name":"isActive","internalType":"bool","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelActiveCloseOrders","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"bool","name":"isLong","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelCloseOrder","inputs":[{"type":"bytes32","name":"orderKey","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelMultipleOrders","inputs":[{"type":"bytes32[]","name":"openOrderKeys","internalType":"bytes32[]"},{"type":"bytes32[]","name":"closeOrderKeys","internalType":"bytes32[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelOpenOrder","inputs":[{"type":"bytes32","name":"orderKey","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"account","internalType":"address"},{"type":"bool","name":"isLong","internalType":"bool"},{"type":"bool","name":"isTriggerAbove","internalType":"bool"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"uint256","name":"size","internalType":"uint256"},{"type":"uint256","name":"triggerPrice","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}],"name":"closeOrders","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"collateralToken","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"createCloseOrder","inputs":[{"type":"bool","name":"isLong","internalType":"bool"},{"type":"bool","name":"isTriggerAbove","internalType":"bool"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"uint256","name":"size","internalType":"uint256"},{"type":"uint256","name":"triggerPrice","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"createCloseOrderForTPSL","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"bool","name":"isLong","internalType":"bool"},{"type":"bool","name":"isTriggerAbove","internalType":"bool"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"uint256","name":"size","internalType":"uint256"},{"type":"uint256","name":"triggerPrice","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"createOpenOrder","inputs":[{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"bool","name":"isLong","internalType":"bool"},{"type":"bool","name":"isTriggerAbove","internalType":"bool"},{"type":"uint256","name":"margin","internalType":"uint256"},{"type":"uint256","name":"leverage","internalType":"uint256"},{"type":"uint256","name":"triggerPrice","internalType":"uint256"},{"type":"uint256","name":"tpPrice","internalType":"uint256"},{"type":"uint256","name":"slPrice","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"dex","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"editCloseOrder","inputs":[{"type":"bytes32","name":"orderKey","internalType":"bytes32"},{"type":"uint256","name":"triggerPrice","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"editOpenOrder","inputs":[{"type":"bytes32","name":"orderKey","internalType":"bytes32"},{"type":"bool","name":"isAdjustingTriggerPrice","internalType":"bool"},{"type":"uint256","name":"triggerPrice","internalType":"uint256"},{"type":"bool","name":"isAdjustingTpPrice","internalType":"bool"},{"type":"uint256","name":"tpPrice","internalType":"uint256"},{"type":"bool","name":"isAdjustingSlPrice","internalType":"bool"},{"type":"uint256","name":"slPrice","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeCloseOrder","inputs":[{"type":"bytes32","name":"orderKey","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeOpenOrder","inputs":[{"type":"bytes32","name":"orderKey","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeOrdersWithPrices","inputs":[{"type":"uint256[]","name":"productIds","internalType":"uint256[]"},{"type":"uint256[]","name":"prices","internalType":"uint256[]"},{"type":"bytes32[]","name":"openOrderKeys","internalType":"bytes32[]"},{"type":"bytes32[]","name":"closeOrderKeys","internalType":"bytes32[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"executionFee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"bool","name":"","internalType":"bool"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"getCloseOrder","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"bool","name":"isLong","internalType":"bool"},{"type":"uint256","name":"orderIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"bool","name":"","internalType":"bool"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"getOpenOrder","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"bool","name":"isLong","internalType":"bool"},{"type":"uint256","name":"orderIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getOrderKey","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"bool","name":"isLong","internalType":"bool"},{"type":"uint256","name":"orderIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"availableCloseOrderSlots","internalType":"uint256"}],"name":"getUserAvailableCloseOrderSlots","inputs":[{"type":"address","name":"user","internalType":"address"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"bool","name":"isLong","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"availableOpenOrderSlots","internalType":"uint256"}],"name":"getUserAvailableOpenOrderSlots","inputs":[{"type":"address","name":"user","internalType":"address"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"bool","name":"isLong","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32[]","name":"userCloseOrderKeys","internalType":"bytes32[]"},{"type":"tuple[]","name":"userCloseOrders","internalType":"struct OrderManager.CloseOrder[]","components":[{"type":"address","name":"account","internalType":"address"},{"type":"bool","name":"isLong","internalType":"bool"},{"type":"bool","name":"isTriggerAbove","internalType":"bool"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"uint256","name":"size","internalType":"uint256"},{"type":"uint256","name":"triggerPrice","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}]}],"name":"getUserCloseOrders","inputs":[{"type":"address","name":"user","internalType":"address"},{"type":"uint256","name":"startId","internalType":"uint256"},{"type":"uint256","name":"endId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32[]","name":"userOpenOrderKeys","internalType":"bytes32[]"},{"type":"tuple[]","name":"userOpenOrders","internalType":"struct OrderManager.OpenOrder[]","components":[{"type":"address","name":"account","internalType":"address"},{"type":"bool","name":"isLong","internalType":"bool"},{"type":"bool","name":"isTriggerAbove","internalType":"bool"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"uint256","name":"margin","internalType":"uint256"},{"type":"uint256","name":"leverage","internalType":"uint256"},{"type":"uint256","name":"tradeFee","internalType":"uint256"},{"type":"uint256","name":"triggerPrice","internalType":"uint256"},{"type":"uint256","name":"tpPrice","internalType":"uint256"},{"type":"uint256","name":"slPrice","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}]}],"name":"getUserOpenOrders","inputs":[{"type":"address","name":"user","internalType":"address"},{"type":"uint256","name":"startId","internalType":"uint256"},{"type":"uint256","name":"endId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"gov","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_positionManager","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isInitialized","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isKeeper","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isUserCloseOrderAvailable","inputs":[{"type":"address","name":"user","internalType":"address"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"bool","name":"isLong","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isUserOpenOrderAvailable","inputs":[{"type":"address","name":"user","internalType":"address"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"bool","name":"isLong","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxCloseOrders","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxOpenOrders","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"account","internalType":"address"},{"type":"bool","name":"isLong","internalType":"bool"},{"type":"bool","name":"isTriggerAbove","internalType":"bool"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"uint256","name":"margin","internalType":"uint256"},{"type":"uint256","name":"leverage","internalType":"uint256"},{"type":"uint256","name":"tradeFee","internalType":"uint256"},{"type":"uint256","name":"triggerPrice","internalType":"uint256"},{"type":"uint256","name":"tpPrice","internalType":"uint256"},{"type":"uint256","name":"slPrice","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}],"name":"openOrders","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"oracle","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"positionManager","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setExecutionFee","inputs":[{"type":"uint256","name":"_executionFee","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setGov","inputs":[{"type":"address","name":"_gov","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setKeeper","inputs":[{"type":"address","name":"_account","internalType":"address"},{"type":"bool","name":"_isActive","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxOrders","inputs":[{"type":"uint256","name":"_maxOpenOrders","internalType":"uint256"},{"type":"uint256","name":"_maxCloseOrders","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"bool","name":"","internalType":"bool"}],"name":"validateExecutionPrice","inputs":[{"type":"bool","name":"isLong","internalType":"bool"},{"type":"bool","name":"isTriggerAbove","internalType":"bool"},{"type":"uint256","name":"triggerPrice","internalType":"uint256"},{"type":"uint256","name":"productId","internalType":"uint256"}]}]
Contract Creation Code
0x6101006040526008600355600860045566038d7ea4c680006005553480156200002757600080fd5b506040516200528b3803806200528b8339810160408190526200004a91620000bc565b6001600081815581546001600160a01b031916331782556001600160a01b0395861660805293851660a0529190931660c05260e092909252308152600860205260409020805460ff191690911790556200010e565b80516001600160a01b0381168114620000b757600080fd5b919050565b60008060008060808587031215620000d357600080fd5b620000de856200009f565b9350620000ee602086016200009f565b9250620000fe604086016200009f565b6060959095015193969295505050565b60805160a05160c05160e0516150da620001b1600039600081816111e501528181612803015261421101526000818161079b015281816112360152818161285401526142580152600081816106300152818161231d015261321c01526000818161053801528181610a48015281816111bf015281816112ac01528181611cb101528181612d650152818161332b0152818161408c015261419001526150da6000f3fe6080604052600436106102a05760003560e01c8063791b98bc1161016e578063c4d66de8116100cb578063e084f3581161007f578063ee0d84e211610064578063ee0d84e21461094f578063f3fadffb1461096f578063fa6165181461098f57600080fd5b8063e084f35814610885578063e57593131461092f57600080fd5b8063cb33d0be116100b0578063cb33d0be14610825578063cfad57a214610845578063d1b9e8531461086557600080fd5b8063c4d66de8146107d0578063c817b238146107f057600080fd5b80639af9255c11610122578063aae4b73411610107578063aae4b73414610769578063b2016bd414610789578063c0848ebe146107bd57600080fd5b80639af9255c146106d8578063a1f20fbf1461074957600080fd5b80637e7e3159116101535780637e7e3159146106525780638c4dc9d91461067257806390bb9e6a1461069257600080fd5b8063791b98bc146105fe5780637dc0d1d01461061e57600080fd5b806341e276e91161021c5780636962fe56116101d05780636f314266116101b55780636f3142661461059d57806373e15834146105cb57806375b77945146105eb57600080fd5b80636962fe561461055a5780636ba42aaa1461056d57600080fd5b806352a1c2a71161020157806352a1c2a71461042657806366cb458114610446578063692058c21461052657600080fd5b806341e276e9146103f05780634aa38c6d1461040657600080fd5b8063237aae9c1161027357806337a063d21161025857806337a063d214610399578063392e53cd146103b957806340e9903b146103da57600080fd5b8063237aae9c1461035557806336e5e4e21461037557600080fd5b806312d43a51146102a55780631683d218146102e25780631844f44f1461031057806320cd610414610325575b600080fd5b3480156102b157600080fd5b506001546102c5906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102ee57600080fd5b506103026102fd3660046147c0565b6109ec565b6040516102d992919061482e565b61032361031e36600461490c565b610f15565b005b34801561033157600080fd5b5061034561034036600461496f565b610fe1565b60405190151581526020016102d9565b34801561036157600080fd5b506103236103703660046149af565b611083565b34801561038157600080fd5b5061038b60045481565b6040519081526020016102d9565b3480156103a557600080fd5b506103236103b43660046149af565b6115b8565b3480156103c557600080fd5b5060015461034590600160a01b900460ff1681565b3480156103e657600080fd5b5061038b60055481565b3480156103fc57600080fd5b5061038b60035481565b34801561041257600080fd5b506103236104213660046149af565b611624565b34801561043257600080fd5b506103236104413660046149c8565b61179f565b34801561045257600080fd5b506104c36104613660046149af565b60066020819052600091825260409091208054600182015460028301546003840154600485015460058601549686015460078701546008909701546001600160a01b0387169860ff600160a01b8904811699600160a81b90990416979092918b565b604080516001600160a01b03909c168c5299151560208c0152971515988a01989098526060890195909552608088019390935260a087019190915260c086015260e0850152610100840152610120830191909152610140820152610160016102d9565b34801561053257600080fd5b506102c57f000000000000000000000000000000000000000000000000000000000000000081565b6103236105683660046149ea565b61185e565b34801561057957600080fd5b50610345610588366004614a5c565b60086020526000908152604090205460ff1681565b3480156105a957600080fd5b506105bd6105b83660046147c0565b611c5a565b6040516102d9929190614a77565b3480156105d757600080fd5b5061038b6105e636600461496f565b6120fe565b6103236105f9366004614b0a565b61219e565b34801561060a57600080fd5b506002546102c5906001600160a01b031681565b34801561062a57600080fd5b506102c57f000000000000000000000000000000000000000000000000000000000000000081565b34801561065e57600080fd5b5061032361066d366004614c50565b6122a7565b34801561067e57600080fd5b5061032361068d3660046149af565b6126ae565b34801561069e57600080fd5b506106b26106ad366004614cfd565b612aa1565b6040805194855260208501939093529015159183019190915260608201526080016102d9565b3480156106e457600080fd5b5061038b6106f3366004614cfd565b6040516001600160601b0319606086901b1660208201526034810184905282151560f81b605482015260558101829052600090607501604051602081830303815290604052805190602001209050949350505050565b34801561075557600080fd5b50610323610764366004614d43565b612b9d565b34801561077557600080fd5b506103236107843660046149af565b612c1f565b34801561079557600080fd5b506102c57f000000000000000000000000000000000000000000000000000000000000000081565b6103236107cb366004614da7565b61300e565b3480156107dc57600080fd5b506103236107eb366004614a5c565b6130db565b3480156107fc57600080fd5b5061081061080b366004614df8565b6131ef565b604080519283529015156020830152016102d9565b34801561083157600080fd5b5061032361084036600461496f565b613320565b34801561085157600080fd5b50610323610860366004614a5c565b6135a9565b34801561087157600080fd5b50610323610880366004614e3e565b613652565b34801561089157600080fd5b506108ea6108a03660046149af565b600760205260009081526040902080546001820154600283015460038401546004909401546001600160a01b0384169460ff600160a01b8604811695600160a81b90041693929187565b604080516001600160a01b0390981688529515156020880152931515948601949094526060850191909152608084015260a083019190915260c082015260e0016102d9565b34801561093b57600080fd5b5061034561094a36600461496f565b613707565b34801561095b57600080fd5b5061038b61096a36600461496f565b61379b565b34801561097b57600080fd5b5061032361098a3660046149c8565b613832565b34801561099b57600080fd5b506109af6109aa366004614cfd565b61398b565b6040805198895260208901979097529587019490945260608601929092521515608085015260a084015260c083015260e0820152610100016102d9565b60608060008411610a445760405162461bcd60e51b815260206004820152601660248201527f4f726465724d616e616765723a2021737461727449640000000000000000000060448201526064015b60405180910390fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639b9d326d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610aa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac89190614e75565b905080841115610ad6578093505b60035480610ae48787614ea4565b610aef906001614ebd565b610af99190614ed0565b610b04906002614ed0565b67ffffffffffffffff811115610b1c57610b1c614b78565b604051908082528060200260200182016040528015610b45578160200160208202803683370190505b50935080610b538787614ea4565b610b5e906001614ebd565b610b689190614ed0565b610b73906002614ed0565b67ffffffffffffffff811115610b8b57610b8b614b78565b604051908082528060200260200182016040528015610c2657816020015b610c1360405180610160016040528060006001600160a01b0316815260200160001515815260200160001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b815260200190600190039081610ba95790505b509250600080875b878111610f085760005b84811015610ef7576040805160608d901b6001600160601b03191660208083019190915260348201859052600160f81b6054830152605580830185905283518084039091018152607590920190925280519101206000818152600660205260409020549094506001600160a01b031615610d955783888481518110610cbf57610cbf614eef565b6020908102919091018101919091526000858152600680835260409182902082516101608101845281546001600160a01b038116825260ff600160a01b82048116151596830196909652600160a81b90049094161515928401929092526001820154606084015260028201546080840152600382015460a0840152600482015460c0840152600582015460e08401528101546101008301526007810154610120830152600801546101408201528784610d7781614f05565b955081518110610d8957610d89614eef565b60200260200101819052505b6040805160608d901b6001600160601b0319166020808301919091526034820185905260006054830152605580830185905283518084039091018152607590920190925280519101206000818152600660205260409020549094506001600160a01b031615610ee75783888481518110610e1157610e11614eef565b6020908102919091018101919091526000858152600680835260409182902082516101608101845281546001600160a01b038116825260ff600160a01b82048116151596830196909652600160a81b90049094161515928401929092526001820154606084015260028201546080840152600382015460a0840152600482015460c0840152600582015460e08401528101546101008301526007810154610120830152600801546101408201528784610ec981614f05565b955081518110610edb57610edb614eef565b60200260200101819052505b610ef081614f05565b9050610c38565b50610f0181614f05565b9050610c2e565b5050505050935093915050565b6002546001600160a01b03163314610f6f5760405162461bcd60e51b815260206004820152601e60248201527f4f726465724d616e616765723a2021706f736974696f6e4d616e6167657200006044820152606401610a3b565b6005543414610fcb5760405162461bcd60e51b815260206004820152602260248201527f4f726465724d616e616765723a20696e76616c696420657865637574696f6e46604482015261656560f01b6064820152608401610a3b565b610fd9868686868686613ad1565b505050505050565b600454600090815b8181101561107557604080516001600160601b0319606089901b166020808301919091526034820188905286151560f81b6054830152605580830185905283518084039091018152607590920183528151918101919091206000908152600790915220546001600160a01b03166110655760019250505061107c565b61106e81614f05565b9050610fe9565b5060009150505b9392505050565b333014806110a057503360009081526008602052604090205460ff165b6110ec5760405162461bcd60e51b815260206004820152601560248201527f4f726465724d616e616765723a20216b656570657200000000000000000000006044820152606401610a3b565b60008181526006602081815260409283902083516101608101855281546001600160a01b03811680835260ff600160a01b83048116151595840195909552600160a81b9091049093161515948101949094526001810154606085015260028101546080850152600381015460a0850152600481015460c0850152600581015460e0850152918201546101008401526007820154610120840152600890910154610140830152611199575050565b60006111b7826020015183604001518460e0015185606001516131ef565b50905061125d7f00000000000000000000000000000000000000000000000000000000000000006305f5e1007f00000000000000000000000000000000000000000000000000000000000000008560c0015186608001516112189190614ebd565b6112229190614ed0565b61122c9190614f1e565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169190613d98565b815160608301516020840151608085015160a0860151604051639267fbbd60e01b81526001600160a01b03958616600482015260248101949094529115156044840152606483015260848201527f000000000000000000000000000000000000000000000000000000000000000090911690639267fbbd9060a401600060405180830381600087803b1580156112f257600080fd5b505af1158015611306573d6000803e3d6000fd5b505050610100830151600191501561136b5761135d83600001518460200151856020015186606001516305f5e1008860a0015189608001516113489190614ed0565b6113529190614f1e565b886101000151613ad1565b611368600182614ebd565b90505b610120830151156113ca576113bc8360000151846020015185602001511586606001516305f5e1008860a0015189608001516113a79190614ed0565b6113b19190614f1e565b886101200151613ad1565b6113c7600182614ebd565b90505b60008481526006602081905260408220805475ffffffffffffffffffffffffffffffffffffffffffff191681556001810183905560028101839055600381018390556004810183905560058082018490559181018390556007810183905560080182905554329061143c908490614ed0565b604051600081818185875af1925050503d8060008114611478576040519150601f19603f3d011682016040523d82523d6000602084013e61147d565b606091505b50509050806114e15760405162461bcd60e51b815260206004820152602a60248201527f4f726465724d616e616765723a206661696c656420746f2073656e6420657865604482015269637574696f6e2066656560b01b6064820152608401610a3b565b83600001516001600160a01b0316857f07cc7aa86de748bd1ef6a42d07028c18d69cb3cf9556ff2d219aae37aa94350d86602001518760400151886060015189608001518a60a001518b60c001518c60e001518d61010001518e61012001518f61014001518f6040516115a99b9a999897969594939291909a15158b5298151560208b015260408a01979097526060890195909552608088019390935260a087019190915260c086015260e08501526101008401526101208301526101408201526101600190565b60405180910390a35050505050565b6001546001600160a01b0316331461160a5760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a3b565b670de0b6b3a764000081111561161f57600080fd5b600555565b6002600054036116765760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a3b565b60026000908155818152600760205260409020546001600160a01b031633146116e15760405162461bcd60e51b815260206004820152601c60248201527f4f726465724d616e616765723a20216f726465722e6163636f756e74000000006044820152606401610a3b565b6116ea81613eb0565b60055460405160009133918381818185875af1925050503d806000811461172d576040519150601f19603f3d011682016040523d82523d6000602084013e611732565b606091505b50509050806117965760405162461bcd60e51b815260206004820152602a60248201527f4f726465724d616e616765723a206661696c656420746f2073656e6420657865604482015269637574696f6e2066656560b01b6064820152608401610a3b565b50506001600055565b6001546001600160a01b031633146117f15760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a3b565b6005600354101580156118075750600560045410155b6118535760405162461bcd60e51b815260206004820152601d60248201527f4f726465724d616e616765723a20216d61784e756d4f664f72646572730000006044820152606401610a3b565b600391909155600455565b6002600054036118b05760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a3b565b6002600090815587815260066020526040902080546001600160a01b0316331461191c5760405162461bcd60e51b815260206004820152601c60248201527f4f726465724d616e616765723a20216f726465722e6163636f756e74000000006044820152606401610a3b565b861561192a57600581018690555b60008515611a2757816006015460000361195e5784156119595760068201859055611956600182614ebd565b90505b611a27565b84600003611a1f576006820185905560055460405160009133918381818185875af1925050503d80600081146119b0576040519150601f19603f3d011682016040523d82523d6000602084013e6119b5565b606091505b5050905080611a195760405162461bcd60e51b815260206004820152602a60248201527f4f726465724d616e616765723a206661696c656420746f2073656e6420657865604482015269637574696f6e2066656560b01b6064820152608401610a3b565b50611a27565b600682018590555b8315611b22578160070154600003611a59578215611a545760078201839055611a51600182614ebd565b90505b611b22565b82600003611b1a576007820183905560055460405160009133918381818185875af1925050503d8060008114611aab576040519150601f19603f3d011682016040523d82523d6000602084013e611ab0565b606091505b5050905080611b145760405162461bcd60e51b815260206004820152602a60248201527f4f726465724d616e616765723a206661696c656420746f2073656e6420657865604482015269637574696f6e2066656560b01b6064820152608401610a3b565b50611b22565b600782018390555b80600554611b309190614ed0565b3414611b895760405162461bcd60e51b815260206004820152602260248201527f4f726465724d616e616765723a20696e76616c696420657865637574696f6e46604482015261656560f01b6064820152608401610a3b565b4260088301819055825460018401546002850154600386015460048701546005880154600689015460078a01546040805160ff600160a01b8b04811615158252600160a81b8b041615156020820152908101979097526060870195909552608086019390935260a085019190915260c084015260e08301526101008201526101208101929092526001600160a01b0316908a907f0a5e00c5dd98a039848cc82972d5b769df4d9e8889c0d7dda308a38f7cdb18a9906101400160405180910390a35050600160005550505050505050565b60608060008411611cad5760405162461bcd60e51b815260206004820152601660248201527f4f726465724d616e616765723a202173746172744964000000000000000000006044820152606401610a3b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639b9d326d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d319190614e75565b905080841115611d3f578093505b60045480611d4d8787614ea4565b611d58906001614ebd565b611d629190614ed0565b611d6d906002614ed0565b67ffffffffffffffff811115611d8557611d85614b78565b604051908082528060200260200182016040528015611dae578160200160208202803683370190505b50935080611dbc8787614ea4565b611dc7906001614ebd565b611dd19190614ed0565b611ddc906002614ed0565b67ffffffffffffffff811115611df457611df4614b78565b604051908082528060200260200182016040528015611e7257816020015b611e5f6040518060e0016040528060006001600160a01b03168152602001600015158152602001600015158152602001600081526020016000815260200160008152602001600081525090565b815260200190600190039081611e125790505b509250600080875b878111610f085760005b848110156120ed576040805160608d901b6001600160601b03191660208083019190915260348201859052600160f81b6054830152605580830185905283518084039091018152607590920190925280519101206000818152600760205260409020549094506001600160a01b031615611fb65783888481518110611f0b57611f0b614eef565b602090810291909101810191909152600085815260078252604090819020815160e08101835281546001600160a01b038116825260ff600160a01b82048116151595830195909552600160a81b90049093161515918301919091526001810154606083015260028101546080830152600381015460a08301526004015460c08201528784611f9881614f05565b955081518110611faa57611faa614eef565b60200260200101819052505b6040805160608d901b6001600160601b0319166020808301919091526034820185905260006054830152605580830185905283518084039091018152607590920190925280519101206000818152600760205260409020549094506001600160a01b0316156120dd578388848151811061203257612032614eef565b602090810291909101810191909152600085815260078252604090819020815160e08101835281546001600160a01b038116825260ff600160a01b82048116151595830195909552600160a81b90049093161515918301919091526001810154606083015260028101546080830152600381015460a08301526004015460c082015287846120bf81614f05565b9550815181106120d1576120d1614eef565b60200260200101819052505b6120e681614f05565b9050611e84565b506120f781614f05565b9050611e7a565b600354600090815b8181101561219557604080516001600160601b0319606089901b166020808301919091526034820188905286151560f81b6054830152605580830185905283518084039091018152607590920183528151918101919091206000908152600690915220546001600160a01b031661218557612182600184614ebd565b92505b61218e81614f05565b9050612106565b50509392505050565b6002600054036121f05760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a3b565b60026000556001821561220b57612208600282614ebd565b90505b811561221f5761221c600282614ebd565b90505b8060055461222d9190614ed0565b34146122865760405162461bcd60e51b815260206004820152602260248201527f4f726465724d616e616765723a20696e76616c696420657865637574696f6e46604482015261656560f01b6064820152608401610a3b565b6122973389898c8a8a8a8a8a614068565b5050600160005550505050505050565b3360009081526008602052604090205460ff166123065760405162461bcd60e51b815260206004820152601560248201527f4f726465724d616e616765723a20216b656570657200000000000000000000006044820152606401610a3b565b604051630682f55760e51b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d05eaae0906123549087908790600401614f40565b600060405180830381600087803b15801561236e57600080fd5b505af1158015612382573d6000803e3d6000fd5b5050505060005b825181101561251657306001600160a01b031663237aae9c8483815181106123b3576123b3614eef565b60200260200101516040518263ffffffff1660e01b81526004016123d991815260200190565b600060405180830381600087803b1580156123f357600080fd5b505af1925050508015612404575060015b61250657612410614f6e565b806308c379a0036124d25750612424614f8a565b8061242f57506124d4565b6006600085848151811061244557612445614eef565b6020026020010151815260200190815260200160002060000160009054906101000a90046001600160a01b03166001600160a01b031684838151811061248d5761248d614eef565b60200260200101517f81302fc3204662085acace33c36464c982ee6cd7aa54f729176650cc51a4b861836040516124c49190615038565b60405180910390a350612506565b505b3d8080156124fe576040519150601f19603f3d011682016040523d82523d6000602084013e612503565b606091505b50505b61250f81614f05565b9050612389565b5060005b81518110156126a757306001600160a01b031663aae4b73483838151811061254457612544614eef565b60200260200101516040518263ffffffff1660e01b815260040161256a91815260200190565b600060405180830381600087803b15801561258457600080fd5b505af1925050508015612595575060015b612697576125a1614f6e565b806308c379a00361266357506125b5614f8a565b806125c05750612665565b600760008484815181106125d6576125d6614eef565b6020026020010151815260200190815260200160002060000160009054906101000a90046001600160a01b03166001600160a01b031683838151811061261e5761261e614eef565b60200260200101517f48b2b3f3b7cf047cbc676166e59b80a9aea26e67f2a964fcd4a5a945dec27a6f836040516126559190615038565b60405180910390a350612697565b505b3d80801561268f576040519150601f19603f3d011682016040523d82523d6000602084013e612694565b606091505b50505b6126a081614f05565b905061251a565b5050505050565b6002600054036127005760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a3b565b600260008181558281526006602081815260409283902083516101608101855281546001600160a01b03811680835260ff600160a01b83048116151595840195909552600160a81b90910490931615159481019490945260018101546060850152938401546080840152600384015460a0840152600484015460c0840152600584015460e08401529083015461010083015260078301546101208301526008909201546101408201529033146127f85760405162461bcd60e51b815260206004820152601c60248201527f4f726465724d616e616765723a20216f726465722e6163636f756e74000000006044820152606401610a3b565b61287b336305f5e1007f00000000000000000000000000000000000000000000000000000000000000008460c0015185608001516128369190614ebd565b6128409190614ed0565b61284a9190614f1e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691906144bf565b60008281526006602081905260408220805475ffffffffffffffffffffffffffffffffffffffffffff191681556001808201849055600282018490556003820184905560048201849055600582018490559181018390556007810183905560080191909155610100820151156128f9576128f6600282614ebd565b90505b610120820151156129125761290f600282614ebd565b90505b6000336001600160a01b03168260055461292c9190614ed0565b604051600081818185875af1925050503d8060008114612968576040519150601f19603f3d011682016040523d82523d6000602084013e61296d565b606091505b50509050806129d15760405162461bcd60e51b815260206004820152602a60248201527f4f726465724d616e616765723a206661696c656420746f2073656e6420657865604482015269637574696f6e2066656560b01b6064820152608401610a3b565b82600001516001600160a01b0316847f49358803a7ae36469d52afc763a7489ec58204d535ff56c6af7af33492244b4985602001518660400151876060015188608001518960a001518a60c001518b60e001518c61010001518d61012001518e6101400151604051612a8e9a999897969594939291909915158a5297151560208a015260408901969096526060880194909452608087019290925260a086015260c085015260e08401526101008301526101208201526101400190565b60405180910390a3505060016000555050565b600080600080600060076000612b0a8b8b8b8b6040516001600160601b0319606086901b1660208201526034810184905282151560f81b605482015260558101829052600090607501604051602081830303815290604052805190602001209050949350505050565b81526020808201929092526040908101600020815160e08101835281546001600160a01b038116825260ff600160a01b82048116151595830195909552600160a81b9004909316151591830182905260018101546060840152600281015460808401819052600382015460a0850181905260049092015460c0909401849052975095509350915050945094509450949050565b60005b8251811015612bdb57612bcb838281518110612bbe57612bbe614eef565b60200260200101516126ae565b612bd481614f05565b9050612ba0565b5060005b8151811015612c1a57612c0a828281518110612bfd57612bfd614eef565b6020026020010151611624565b612c1381614f05565b9050612bdf565b505050565b33301480612c3c57503360009081526008602052604090205460ff165b612c885760405162461bcd60e51b815260206004820152601560248201527f4f726465724d616e616765723a20216b656570657200000000000000000000006044820152606401610a3b565b600081815260076020908152604091829020825160e08101845281546001600160a01b03811680835260ff600160a01b83048116151595840195909552600160a81b9091049093161515938101939093526001810154606084015260028101546080840152600381015460a08401526004015460c0830152612d08575050565b6000612d2782602001511583604001518460a0015185606001516131ef565b50825160608401516020850151604051634df8059360e11b81526001600160a01b0380851660048301526024820184905282151560448301529495507f0000000000000000000000000000000000000000000000000000000000000000909416936314d8353f939291908590639bf00b2690606401602060405180830381865afa158015612db9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddd9190614e75565b6305f5e1008860800151612df19190614ed0565b612dfb9190614f1e565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b1681526001600160a01b0390941660048501526024840192909252151560448301526064820152608401600060405180830381600087803b158015612e6857600080fd5b505af1158015612e7c573d6000803e3d6000fd5b505050600084815260076020526040808220805475ffffffffffffffffffffffffffffffffffffffffffff19168155600181018390556002810183905560038101839055600401829055600554905191925032918381818185875af1925050503d8060008114612f08576040519150601f19603f3d011682016040523d82523d6000602084013e612f0d565b606091505b5050905080612f715760405162461bcd60e51b815260206004820152602a60248201527f4f726465724d616e616765723a206661696c656420746f2073656e6420657865604482015269637574696f6e2066656560b01b6064820152608401610a3b565b82600001516001600160a01b0316847f47036c05d3bcca301b675f2154fca0f55a59c635efd8b997a417d10b0c3ce1d185602001518660400151876060015188608001518960a001518a60c001518a60405161300097969594939291909615158752941515602087015260408601939093526060850191909152608084015260a083015260c082015260e00190565b60405180910390a350505050565b6002600054036130605760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a3b565b600260005560055434146130c15760405162461bcd60e51b815260206004820152602260248201527f4f726465724d616e616765723a20696e76616c696420657865637574696f6e46604482015261656560f01b6064820152608401610a3b565b6130cf338686868686613ad1565b50506001600055505050565b6001546001600160a01b0316331461312d5760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a3b565b600154600160a01b900460ff16156131915760405162461bcd60e51b815260206004820152602160248201527f4f726465724d616e616765723a20616c726561647920696e697469616c697a656044820152601960fa1b6064820152608401610a3b565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16600160a01b179055600280546001600160a01b0390921673ffffffffffffffffffffffffffffffffffffffff19909216919091179055565b604051632b82db0d60e11b8152600481018290528415156024820152600090819081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635705b61a90604401602060405180830381865afa158015613263573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132879190614e75565b9050600086613299578582111561329e565b858210155b9050806133135760405162461bcd60e51b815260206004820152602960248201527f4f726465724d616e616765723a20696e76616c696420707269636520666f722060448201527f657865637574696f6e00000000000000000000000000000000000000000000006064820152608401610a3b565b9097909650945050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146133985760405162461bcd60e51b815260206004820152601260248201527f4f726465724d616e616765723a202164657800000000000000000000000000006044820152606401610a3b565b600454600090815b8181101561343c57604080516001600160601b0319606089901b166020808301919091526034820188905286151560f81b60548301526055808301859052835180840390910181526075909201835281519181019190912060008181526007909252919020546001600160a01b03161561342b5761341d81613eb0565b613428600185614ebd565b93505b5061343581614f05565b90506133a0565b5081156126a75760055460006001600160a01b03871661345c8584614ed0565b604051600081818185875af1925050503d8060008114613498576040519150601f19603f3d011682016040523d82523d6000602084013e61349d565b606091505b50509050806135a0576001600160a01b0387167f2c0da876dc58358df21667a74f33f9ace39dadb7cb51b147d8957f8874db42b06134db8685614ed0565b60405190815260200160405180910390a26000326134f98685614ed0565b604051600081818185875af1925050503d8060008114613535576040519150601f19603f3d011682016040523d82523d6000602084013e61353a565b606091505b505090508061359e5760405162461bcd60e51b815260206004820152602a60248201527f4f726465724d616e616765723a206661696c656420746f2073656e6420657865604482015269637574696f6e2066656560b01b6064820152608401610a3b565b505b50505050505050565b6001546001600160a01b031633146135fb5760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a3b565b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f91a8c1cc2d4a3bb60738481947a00cbb9899c822916694cf8bb1d68172fdcd5490600090a250565b6001546001600160a01b031633146136a45760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a3b565b6001600160a01b038216600081815260086020908152604091829020805460ff19168515159081179091558251938452908301527f8c2ff6748f99f65f4ebf8a1e973a289bad216c4d5b20fda1940d9e01118ae42a910160405180910390a15050565b600354600090815b8181101561107557604080516001600160601b0319606089901b166020808301919091526034820188905286151560f81b6054830152605580830185905283518084039091018152607590920183528151918101919091206000908152600690915220546001600160a01b031661378b5760019250505061107c565b61379481614f05565b905061370f565b600454600090815b8181101561219557604080516001600160601b0319606089901b166020808301919091526034820188905286151560f81b6054830152605580830185905283518084039091018152607590920183528151918101919091206000908152600790915220546001600160a01b03166138225761381f600184614ebd565b92505b61382b81614f05565b90506137a3565b6002600054036138845760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a3b565b6002600090815582815260076020526040902080546001600160a01b031633146138f05760405162461bcd60e51b815260206004820152601c60248201527f4f726465724d616e616765723a20216f726465722e6163636f756e74000000006044820152606401610a3b565b6003810182905542600482018190558154600183015460028401546040805160ff600160a01b8604811615158252600160a81b860416151560208201529081019290925260608201526080810185905260a08101929092526001600160a01b03169084907f6911fa079056e89ec24445683aa16240daff19f20221857b69ace7f7f2167f8a9060c00160405180910390a35050600160005550565b6000806000806000806000806000600660006139fa8f8f8f8f6040516001600160601b0319606086901b1660208201526034810184905282151560f81b605482015260558101829052600090607501604051602081830303815290604052805190602001209050949350505050565b8152602080820192909252604090810160002081516101608101835281546001600160a01b038116825260ff600160a01b82048116151595830195909552600160a81b9004909316151591830182905260018101546060840152600281015460808401819052600382015460a08501819052600483015460c08601819052600584015460e087018190526006850154610100880181905260078601546101208901819052600890960154610140909801889052939f50919d509b509950919750909550935091505094995094995094999196509450565b60008111613b475760405162461bcd60e51b815260206004820152602660248201527f4f726465724d616e616765723a207472696767657250726963652063616e6e6f60448201527f74206265203000000000000000000000000000000000000000000000000000006064820152608401610a3b565b60045460005b81811015613d2957604080516001600160601b031960608b901b166020808301919091526034820188905289151560f81b60548301526055808301859052835180840390910181526075909201835281519181019190912060008181526007909252919020546001600160a01b0316613d18576040805160e0810182526001600160a01b03808c168083528b151560208085019182528c1515858701908152606086018d8152608087018d815260a088018d81524260c08a0181815260008d81526007909752958b902099518a54975195511515600160a81b027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff961515600160a01b027fffffffffffffffffffffff00000000000000000000000000000000000000000090991691909a16179690961793909316969096178755516001870155935160028601559251600385015591516004909301929092559151909183917fd1d8633d045dfd8d52789d0505215f098a1777a0a0a8ac150c94a16d0231df1091613d08918d918d918d918d918d91909515158652931515602086015260408501929092526060840152608083015260a082015260c00190565b60405180910390a3505050610fd9565b50613d2281614f05565b9050613b4d565b5060405162461bcd60e51b815260206004820152602560248201527f4f726465724d616e616765723a206d6178436c6f73654f72646572732065786360448201527f65656465640000000000000000000000000000000000000000000000000000006064820152608401610a3b565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015613de9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e0d9190614e75565b613e179190614ebd565b6040516001600160a01b038516602482015260448101829052909150613eaa90859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526144ef565b50505050565b6000600760008381526020019081526020016000206040518060e00160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016000820160149054906101000a900460ff161515151581526020016000820160159054906101000a900460ff16151515158152602001600182015481526020016002820154815260200160038201548152602001600482015481525050905060076000838152602001908152602001600020600080820160006101000a8154906001600160a01b0302191690556000820160146101000a81549060ff02191690556000820160156101000a81549060ff02191690556001820160009055600282016000905560038201600090556004820160009055505080600001516001600160a01b0316827ff88686450cd096feaf4c9c73e01e80cc376845eac25202501d46a386ceef7cd583602001518460400151856060015186608001518760a001518860c0015160405161405c969594939291909515158652931515602086015260408501929092526060840152608083015260a082015260c00190565b60405180910390a35050565b60405163021707f360e41b81526004810186905260248101859052604481018790527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906321707f309060640160006040518083038186803b1580156140d657600080fd5b505afa1580156140ea573d6000803e3d6000fd5b50506003549150600090505b8181101561445f57604080516001600160601b031960608e901b16602080830191909152603482018b90528c151560f81b60548301526055808301859052835180840390910181526075909201835281519181019190912060008181526006909252919020546001600160a01b031661444e57604051636519c9d560e01b81526004810189905260248101889052604481018a90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636519c9d590606401602060405180830381865afa1580156141df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142039190614e75565b90506142808d306305f5e1007f000000000000000000000000000000000000000000000000000000000000000061423a868f614ebd565b6142449190614ed0565b61424e9190614f1e565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169291906145d4565b6040518061016001604052808e6001600160a01b031681526020018d151581526020018c151581526020018b81526020018a8152602001898152602001828152602001888152602001878152602001868152602001428152506006600084815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548160ff02191690831515021790555060408201518160000160156101000a81548160ff021916908315150217905550606082015181600101556080820151816002015560a0820151816003015560c0820151816004015560e082015181600501556101008201518160060155610120820151816007015561014082015181600801559050508c6001600160a01b0316827fde124635deb0e2ebcbdd019f4c341021e58f79aafb89ae9949be65bc717cc30f8e8e8e8e8e888f8f8f4260405161443d9a999897969594939291909915158a5297151560208a015260408901969096526060880194909452608087019290925260a086015260c085015260e08401526101008301526101208201526101400190565b60405180910390a3505050506144b4565b5061445881614f05565b90506140f6565b5060405162461bcd60e51b8152602060048201526024808201527f4f726465724d616e616765723a206d61784f70656e4f726465727320657863656044820152631959195960e21b6064820152608401610a3b565b505050505050505050565b6040516001600160a01b038316602482015260448101829052612c1a90849063a9059cbb60e01b90606401613e46565b6000614544826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661460c9092919063ffffffff16565b805190915015612c1a5780806020019051810190614562919061506b565b612c1a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610a3b565b6040516001600160a01b0380851660248301528316604482015260648101829052613eaa9085906323b872dd60e01b90608401613e46565b606061461b8484600085614623565b949350505050565b60608247101561469b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a3b565b6001600160a01b0385163b6146f25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a3b565b600080866001600160a01b0316858760405161470e9190615088565b60006040518083038185875af1925050503d806000811461474b576040519150601f19603f3d011682016040523d82523d6000602084013e614750565b606091505b509150915061476082828661476b565b979650505050505050565b6060831561477a57508161107c565b82511561478a5782518084602001fd5b8160405162461bcd60e51b8152600401610a3b9190615038565b80356001600160a01b03811681146147bb57600080fd5b919050565b6000806000606084860312156147d557600080fd5b6147de846147a4565b95602085013595506040909401359392505050565b600081518084526020808501945080840160005b8381101561482357815187529582019590820190600101614807565b509495945050505050565b60006040808352614841818401866147f3565b83810360208581019190915285518083528682019282019060005b818110156148ed57845180516001600160a01b031684528481015115158585015286810151151587850152606080820151908501526080808201519085015260a0808201519085015260c0808201519085015260e08082015190850152610100808201519085015261012080820151908501526101409081015190840152938301936101609092019160010161485c565b509098975050505050505050565b801515811461490957600080fd5b50565b60008060008060008060c0878903121561492557600080fd5b61492e876147a4565b9550602087013561493e816148fb565b9450604087013561494e816148fb565b959894975094956060810135955060808101359460a0909101359350915050565b60008060006060848603121561498457600080fd5b61498d846147a4565b92506020840135915060408401356149a4816148fb565b809150509250925092565b6000602082840312156149c157600080fd5b5035919050565b600080604083850312156149db57600080fd5b50508035926020909101359150565b600080600080600080600060e0888a031215614a0557600080fd5b873596506020880135614a17816148fb565b9550604088013594506060880135614a2e816148fb565b93506080880135925060a0880135614a45816148fb565b8092505060c0880135905092959891949750929550565b600060208284031215614a6e57600080fd5b61107c826147a4565b60006040808352614a8a818401866147f3565b83810360208581019190915285518083528682019282019060005b818110156148ed57845180516001600160a01b031684528481015115158585015286810151151587850152606080820151908501526080808201519085015260a0808201519085015260c090810151908401529383019360e090920191600101614aa5565b600080600080600080600080610100898b031215614b2757600080fd5b883597506020890135614b39816148fb565b96506040890135614b49816148fb565b979a96995096976060810135975060808101359660a0820135965060c0820135955060e0909101359350915050565b634e487b7160e01b600052604160045260246000fd5b601f8201601f1916810167ffffffffffffffff81118282101715614bb457614bb4614b78565b6040525050565b600067ffffffffffffffff821115614bd557614bd5614b78565b5060051b60200190565b600082601f830112614bf057600080fd5b81356020614bfd82614bbb565b604051614c0a8282614b8e565b83815260059390931b8501820192828101915086841115614c2a57600080fd5b8286015b84811015614c455780358352918301918301614c2e565b509695505050505050565b60008060008060808587031215614c6657600080fd5b843567ffffffffffffffff80821115614c7e57600080fd5b614c8a88838901614bdf565b95506020870135915080821115614ca057600080fd5b614cac88838901614bdf565b94506040870135915080821115614cc257600080fd5b614cce88838901614bdf565b93506060870135915080821115614ce457600080fd5b50614cf187828801614bdf565b91505092959194509250565b60008060008060808587031215614d1357600080fd5b614d1c856147a4565b9350602085013592506040850135614d33816148fb565b9396929550929360600135925050565b60008060408385031215614d5657600080fd5b823567ffffffffffffffff80821115614d6e57600080fd5b614d7a86838701614bdf565b93506020850135915080821115614d9057600080fd5b50614d9d85828601614bdf565b9150509250929050565b600080600080600060a08688031215614dbf57600080fd5b8535614dca816148fb565b94506020860135614dda816148fb565b94979496505050506040830135926060810135926080909101359150565b60008060008060808587031215614e0e57600080fd5b8435614e19816148fb565b93506020850135614e29816148fb565b93969395505050506040820135916060013590565b60008060408385031215614e5157600080fd5b614e5a836147a4565b91506020830135614e6a816148fb565b809150509250929050565b600060208284031215614e8757600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b81810381811115614eb757614eb7614e8e565b92915050565b80820180821115614eb757614eb7614e8e565b6000816000190483118215151615614eea57614eea614e8e565b500290565b634e487b7160e01b600052603260045260246000fd5b600060018201614f1757614f17614e8e565b5060010190565b600082614f3b57634e487b7160e01b600052601260045260246000fd5b500490565b604081526000614f5360408301856147f3565b8281036020840152614f6581856147f3565b95945050505050565b600060033d1115614f875760046000803e5060005160e01c5b90565b600060443d1015614f985790565b6040516003193d81016004833e81513d67ffffffffffffffff8160248401118184111715614fc857505050505090565b8285019150815181811115614fe05750505050505090565b843d8701016020828501011115614ffa5750505050505090565b61500960208286010187614b8e565b509095945050505050565b60005b8381101561502f578181015183820152602001615017565b50506000910152565b6020815260008251806020840152615057816040850160208701615014565b601f01601f19169190910160400192915050565b60006020828403121561507d57600080fd5b815161107c816148fb565b6000825161509a818460208701615014565b919091019291505056fea2646970667358221220ad12422bf0389de26d070485b560eb5befa0708ce24ff8f0f0c0afbb6f52d87864736f6c634300081000330000000000000000000000008d3e5d7e0d0ec9bd2677e1e1d049b2b1ef5ff503000000000000000000000000f0a64022fff41fa8859ef44ec993b96f4c08f05f000000000000000000000000f77a62affc8e92ee3b8ca07734c83b0beb55e4530000000000000000000000000000000000000000000000000de0b6b3a7640000
Deployed ByteCode
0x6080604052600436106102a05760003560e01c8063791b98bc1161016e578063c4d66de8116100cb578063e084f3581161007f578063ee0d84e211610064578063ee0d84e21461094f578063f3fadffb1461096f578063fa6165181461098f57600080fd5b8063e084f35814610885578063e57593131461092f57600080fd5b8063cb33d0be116100b0578063cb33d0be14610825578063cfad57a214610845578063d1b9e8531461086557600080fd5b8063c4d66de8146107d0578063c817b238146107f057600080fd5b80639af9255c11610122578063aae4b73411610107578063aae4b73414610769578063b2016bd414610789578063c0848ebe146107bd57600080fd5b80639af9255c146106d8578063a1f20fbf1461074957600080fd5b80637e7e3159116101535780637e7e3159146106525780638c4dc9d91461067257806390bb9e6a1461069257600080fd5b8063791b98bc146105fe5780637dc0d1d01461061e57600080fd5b806341e276e91161021c5780636962fe56116101d05780636f314266116101b55780636f3142661461059d57806373e15834146105cb57806375b77945146105eb57600080fd5b80636962fe561461055a5780636ba42aaa1461056d57600080fd5b806352a1c2a71161020157806352a1c2a71461042657806366cb458114610446578063692058c21461052657600080fd5b806341e276e9146103f05780634aa38c6d1461040657600080fd5b8063237aae9c1161027357806337a063d21161025857806337a063d214610399578063392e53cd146103b957806340e9903b146103da57600080fd5b8063237aae9c1461035557806336e5e4e21461037557600080fd5b806312d43a51146102a55780631683d218146102e25780631844f44f1461031057806320cd610414610325575b600080fd5b3480156102b157600080fd5b506001546102c5906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102ee57600080fd5b506103026102fd3660046147c0565b6109ec565b6040516102d992919061482e565b61032361031e36600461490c565b610f15565b005b34801561033157600080fd5b5061034561034036600461496f565b610fe1565b60405190151581526020016102d9565b34801561036157600080fd5b506103236103703660046149af565b611083565b34801561038157600080fd5b5061038b60045481565b6040519081526020016102d9565b3480156103a557600080fd5b506103236103b43660046149af565b6115b8565b3480156103c557600080fd5b5060015461034590600160a01b900460ff1681565b3480156103e657600080fd5b5061038b60055481565b3480156103fc57600080fd5b5061038b60035481565b34801561041257600080fd5b506103236104213660046149af565b611624565b34801561043257600080fd5b506103236104413660046149c8565b61179f565b34801561045257600080fd5b506104c36104613660046149af565b60066020819052600091825260409091208054600182015460028301546003840154600485015460058601549686015460078701546008909701546001600160a01b0387169860ff600160a01b8904811699600160a81b90990416979092918b565b604080516001600160a01b03909c168c5299151560208c0152971515988a01989098526060890195909552608088019390935260a087019190915260c086015260e0850152610100840152610120830191909152610140820152610160016102d9565b34801561053257600080fd5b506102c57f0000000000000000000000008d3e5d7e0d0ec9bd2677e1e1d049b2b1ef5ff50381565b6103236105683660046149ea565b61185e565b34801561057957600080fd5b50610345610588366004614a5c565b60086020526000908152604090205460ff1681565b3480156105a957600080fd5b506105bd6105b83660046147c0565b611c5a565b6040516102d9929190614a77565b3480156105d757600080fd5b5061038b6105e636600461496f565b6120fe565b6103236105f9366004614b0a565b61219e565b34801561060a57600080fd5b506002546102c5906001600160a01b031681565b34801561062a57600080fd5b506102c57f000000000000000000000000f0a64022fff41fa8859ef44ec993b96f4c08f05f81565b34801561065e57600080fd5b5061032361066d366004614c50565b6122a7565b34801561067e57600080fd5b5061032361068d3660046149af565b6126ae565b34801561069e57600080fd5b506106b26106ad366004614cfd565b612aa1565b6040805194855260208501939093529015159183019190915260608201526080016102d9565b3480156106e457600080fd5b5061038b6106f3366004614cfd565b6040516001600160601b0319606086901b1660208201526034810184905282151560f81b605482015260558101829052600090607501604051602081830303815290604052805190602001209050949350505050565b34801561075557600080fd5b50610323610764366004614d43565b612b9d565b34801561077557600080fd5b506103236107843660046149af565b612c1f565b34801561079557600080fd5b506102c57f000000000000000000000000f77a62affc8e92ee3b8ca07734c83b0beb55e45381565b6103236107cb366004614da7565b61300e565b3480156107dc57600080fd5b506103236107eb366004614a5c565b6130db565b3480156107fc57600080fd5b5061081061080b366004614df8565b6131ef565b604080519283529015156020830152016102d9565b34801561083157600080fd5b5061032361084036600461496f565b613320565b34801561085157600080fd5b50610323610860366004614a5c565b6135a9565b34801561087157600080fd5b50610323610880366004614e3e565b613652565b34801561089157600080fd5b506108ea6108a03660046149af565b600760205260009081526040902080546001820154600283015460038401546004909401546001600160a01b0384169460ff600160a01b8604811695600160a81b90041693929187565b604080516001600160a01b0390981688529515156020880152931515948601949094526060850191909152608084015260a083019190915260c082015260e0016102d9565b34801561093b57600080fd5b5061034561094a36600461496f565b613707565b34801561095b57600080fd5b5061038b61096a36600461496f565b61379b565b34801561097b57600080fd5b5061032361098a3660046149c8565b613832565b34801561099b57600080fd5b506109af6109aa366004614cfd565b61398b565b6040805198895260208901979097529587019490945260608601929092521515608085015260a084015260c083015260e0820152610100016102d9565b60608060008411610a445760405162461bcd60e51b815260206004820152601660248201527f4f726465724d616e616765723a2021737461727449640000000000000000000060448201526064015b60405180910390fd5b60007f0000000000000000000000008d3e5d7e0d0ec9bd2677e1e1d049b2b1ef5ff5036001600160a01b0316639b9d326d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610aa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac89190614e75565b905080841115610ad6578093505b60035480610ae48787614ea4565b610aef906001614ebd565b610af99190614ed0565b610b04906002614ed0565b67ffffffffffffffff811115610b1c57610b1c614b78565b604051908082528060200260200182016040528015610b45578160200160208202803683370190505b50935080610b538787614ea4565b610b5e906001614ebd565b610b689190614ed0565b610b73906002614ed0565b67ffffffffffffffff811115610b8b57610b8b614b78565b604051908082528060200260200182016040528015610c2657816020015b610c1360405180610160016040528060006001600160a01b0316815260200160001515815260200160001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b815260200190600190039081610ba95790505b509250600080875b878111610f085760005b84811015610ef7576040805160608d901b6001600160601b03191660208083019190915260348201859052600160f81b6054830152605580830185905283518084039091018152607590920190925280519101206000818152600660205260409020549094506001600160a01b031615610d955783888481518110610cbf57610cbf614eef565b6020908102919091018101919091526000858152600680835260409182902082516101608101845281546001600160a01b038116825260ff600160a01b82048116151596830196909652600160a81b90049094161515928401929092526001820154606084015260028201546080840152600382015460a0840152600482015460c0840152600582015460e08401528101546101008301526007810154610120830152600801546101408201528784610d7781614f05565b955081518110610d8957610d89614eef565b60200260200101819052505b6040805160608d901b6001600160601b0319166020808301919091526034820185905260006054830152605580830185905283518084039091018152607590920190925280519101206000818152600660205260409020549094506001600160a01b031615610ee75783888481518110610e1157610e11614eef565b6020908102919091018101919091526000858152600680835260409182902082516101608101845281546001600160a01b038116825260ff600160a01b82048116151596830196909652600160a81b90049094161515928401929092526001820154606084015260028201546080840152600382015460a0840152600482015460c0840152600582015460e08401528101546101008301526007810154610120830152600801546101408201528784610ec981614f05565b955081518110610edb57610edb614eef565b60200260200101819052505b610ef081614f05565b9050610c38565b50610f0181614f05565b9050610c2e565b5050505050935093915050565b6002546001600160a01b03163314610f6f5760405162461bcd60e51b815260206004820152601e60248201527f4f726465724d616e616765723a2021706f736974696f6e4d616e6167657200006044820152606401610a3b565b6005543414610fcb5760405162461bcd60e51b815260206004820152602260248201527f4f726465724d616e616765723a20696e76616c696420657865637574696f6e46604482015261656560f01b6064820152608401610a3b565b610fd9868686868686613ad1565b505050505050565b600454600090815b8181101561107557604080516001600160601b0319606089901b166020808301919091526034820188905286151560f81b6054830152605580830185905283518084039091018152607590920183528151918101919091206000908152600790915220546001600160a01b03166110655760019250505061107c565b61106e81614f05565b9050610fe9565b5060009150505b9392505050565b333014806110a057503360009081526008602052604090205460ff165b6110ec5760405162461bcd60e51b815260206004820152601560248201527f4f726465724d616e616765723a20216b656570657200000000000000000000006044820152606401610a3b565b60008181526006602081815260409283902083516101608101855281546001600160a01b03811680835260ff600160a01b83048116151595840195909552600160a81b9091049093161515948101949094526001810154606085015260028101546080850152600381015460a0850152600481015460c0850152600581015460e0850152918201546101008401526007820154610120840152600890910154610140830152611199575050565b60006111b7826020015183604001518460e0015185606001516131ef565b50905061125d7f0000000000000000000000008d3e5d7e0d0ec9bd2677e1e1d049b2b1ef5ff5036305f5e1007f0000000000000000000000000000000000000000000000000de0b6b3a76400008560c0015186608001516112189190614ebd565b6112229190614ed0565b61122c9190614f1e565b6001600160a01b037f000000000000000000000000f77a62affc8e92ee3b8ca07734c83b0beb55e453169190613d98565b815160608301516020840151608085015160a0860151604051639267fbbd60e01b81526001600160a01b03958616600482015260248101949094529115156044840152606483015260848201527f0000000000000000000000008d3e5d7e0d0ec9bd2677e1e1d049b2b1ef5ff50390911690639267fbbd9060a401600060405180830381600087803b1580156112f257600080fd5b505af1158015611306573d6000803e3d6000fd5b505050610100830151600191501561136b5761135d83600001518460200151856020015186606001516305f5e1008860a0015189608001516113489190614ed0565b6113529190614f1e565b886101000151613ad1565b611368600182614ebd565b90505b610120830151156113ca576113bc8360000151846020015185602001511586606001516305f5e1008860a0015189608001516113a79190614ed0565b6113b19190614f1e565b886101200151613ad1565b6113c7600182614ebd565b90505b60008481526006602081905260408220805475ffffffffffffffffffffffffffffffffffffffffffff191681556001810183905560028101839055600381018390556004810183905560058082018490559181018390556007810183905560080182905554329061143c908490614ed0565b604051600081818185875af1925050503d8060008114611478576040519150601f19603f3d011682016040523d82523d6000602084013e61147d565b606091505b50509050806114e15760405162461bcd60e51b815260206004820152602a60248201527f4f726465724d616e616765723a206661696c656420746f2073656e6420657865604482015269637574696f6e2066656560b01b6064820152608401610a3b565b83600001516001600160a01b0316857f07cc7aa86de748bd1ef6a42d07028c18d69cb3cf9556ff2d219aae37aa94350d86602001518760400151886060015189608001518a60a001518b60c001518c60e001518d61010001518e61012001518f61014001518f6040516115a99b9a999897969594939291909a15158b5298151560208b015260408a01979097526060890195909552608088019390935260a087019190915260c086015260e08501526101008401526101208301526101408201526101600190565b60405180910390a35050505050565b6001546001600160a01b0316331461160a5760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a3b565b670de0b6b3a764000081111561161f57600080fd5b600555565b6002600054036116765760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a3b565b60026000908155818152600760205260409020546001600160a01b031633146116e15760405162461bcd60e51b815260206004820152601c60248201527f4f726465724d616e616765723a20216f726465722e6163636f756e74000000006044820152606401610a3b565b6116ea81613eb0565b60055460405160009133918381818185875af1925050503d806000811461172d576040519150601f19603f3d011682016040523d82523d6000602084013e611732565b606091505b50509050806117965760405162461bcd60e51b815260206004820152602a60248201527f4f726465724d616e616765723a206661696c656420746f2073656e6420657865604482015269637574696f6e2066656560b01b6064820152608401610a3b565b50506001600055565b6001546001600160a01b031633146117f15760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a3b565b6005600354101580156118075750600560045410155b6118535760405162461bcd60e51b815260206004820152601d60248201527f4f726465724d616e616765723a20216d61784e756d4f664f72646572730000006044820152606401610a3b565b600391909155600455565b6002600054036118b05760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a3b565b6002600090815587815260066020526040902080546001600160a01b0316331461191c5760405162461bcd60e51b815260206004820152601c60248201527f4f726465724d616e616765723a20216f726465722e6163636f756e74000000006044820152606401610a3b565b861561192a57600581018690555b60008515611a2757816006015460000361195e5784156119595760068201859055611956600182614ebd565b90505b611a27565b84600003611a1f576006820185905560055460405160009133918381818185875af1925050503d80600081146119b0576040519150601f19603f3d011682016040523d82523d6000602084013e6119b5565b606091505b5050905080611a195760405162461bcd60e51b815260206004820152602a60248201527f4f726465724d616e616765723a206661696c656420746f2073656e6420657865604482015269637574696f6e2066656560b01b6064820152608401610a3b565b50611a27565b600682018590555b8315611b22578160070154600003611a59578215611a545760078201839055611a51600182614ebd565b90505b611b22565b82600003611b1a576007820183905560055460405160009133918381818185875af1925050503d8060008114611aab576040519150601f19603f3d011682016040523d82523d6000602084013e611ab0565b606091505b5050905080611b145760405162461bcd60e51b815260206004820152602a60248201527f4f726465724d616e616765723a206661696c656420746f2073656e6420657865604482015269637574696f6e2066656560b01b6064820152608401610a3b565b50611b22565b600782018390555b80600554611b309190614ed0565b3414611b895760405162461bcd60e51b815260206004820152602260248201527f4f726465724d616e616765723a20696e76616c696420657865637574696f6e46604482015261656560f01b6064820152608401610a3b565b4260088301819055825460018401546002850154600386015460048701546005880154600689015460078a01546040805160ff600160a01b8b04811615158252600160a81b8b041615156020820152908101979097526060870195909552608086019390935260a085019190915260c084015260e08301526101008201526101208101929092526001600160a01b0316908a907f0a5e00c5dd98a039848cc82972d5b769df4d9e8889c0d7dda308a38f7cdb18a9906101400160405180910390a35050600160005550505050505050565b60608060008411611cad5760405162461bcd60e51b815260206004820152601660248201527f4f726465724d616e616765723a202173746172744964000000000000000000006044820152606401610a3b565b60007f0000000000000000000000008d3e5d7e0d0ec9bd2677e1e1d049b2b1ef5ff5036001600160a01b0316639b9d326d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d319190614e75565b905080841115611d3f578093505b60045480611d4d8787614ea4565b611d58906001614ebd565b611d629190614ed0565b611d6d906002614ed0565b67ffffffffffffffff811115611d8557611d85614b78565b604051908082528060200260200182016040528015611dae578160200160208202803683370190505b50935080611dbc8787614ea4565b611dc7906001614ebd565b611dd19190614ed0565b611ddc906002614ed0565b67ffffffffffffffff811115611df457611df4614b78565b604051908082528060200260200182016040528015611e7257816020015b611e5f6040518060e0016040528060006001600160a01b03168152602001600015158152602001600015158152602001600081526020016000815260200160008152602001600081525090565b815260200190600190039081611e125790505b509250600080875b878111610f085760005b848110156120ed576040805160608d901b6001600160601b03191660208083019190915260348201859052600160f81b6054830152605580830185905283518084039091018152607590920190925280519101206000818152600760205260409020549094506001600160a01b031615611fb65783888481518110611f0b57611f0b614eef565b602090810291909101810191909152600085815260078252604090819020815160e08101835281546001600160a01b038116825260ff600160a01b82048116151595830195909552600160a81b90049093161515918301919091526001810154606083015260028101546080830152600381015460a08301526004015460c08201528784611f9881614f05565b955081518110611faa57611faa614eef565b60200260200101819052505b6040805160608d901b6001600160601b0319166020808301919091526034820185905260006054830152605580830185905283518084039091018152607590920190925280519101206000818152600760205260409020549094506001600160a01b0316156120dd578388848151811061203257612032614eef565b602090810291909101810191909152600085815260078252604090819020815160e08101835281546001600160a01b038116825260ff600160a01b82048116151595830195909552600160a81b90049093161515918301919091526001810154606083015260028101546080830152600381015460a08301526004015460c082015287846120bf81614f05565b9550815181106120d1576120d1614eef565b60200260200101819052505b6120e681614f05565b9050611e84565b506120f781614f05565b9050611e7a565b600354600090815b8181101561219557604080516001600160601b0319606089901b166020808301919091526034820188905286151560f81b6054830152605580830185905283518084039091018152607590920183528151918101919091206000908152600690915220546001600160a01b031661218557612182600184614ebd565b92505b61218e81614f05565b9050612106565b50509392505050565b6002600054036121f05760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a3b565b60026000556001821561220b57612208600282614ebd565b90505b811561221f5761221c600282614ebd565b90505b8060055461222d9190614ed0565b34146122865760405162461bcd60e51b815260206004820152602260248201527f4f726465724d616e616765723a20696e76616c696420657865637574696f6e46604482015261656560f01b6064820152608401610a3b565b6122973389898c8a8a8a8a8a614068565b5050600160005550505050505050565b3360009081526008602052604090205460ff166123065760405162461bcd60e51b815260206004820152601560248201527f4f726465724d616e616765723a20216b656570657200000000000000000000006044820152606401610a3b565b604051630682f55760e51b81526001600160a01b037f000000000000000000000000f0a64022fff41fa8859ef44ec993b96f4c08f05f169063d05eaae0906123549087908790600401614f40565b600060405180830381600087803b15801561236e57600080fd5b505af1158015612382573d6000803e3d6000fd5b5050505060005b825181101561251657306001600160a01b031663237aae9c8483815181106123b3576123b3614eef565b60200260200101516040518263ffffffff1660e01b81526004016123d991815260200190565b600060405180830381600087803b1580156123f357600080fd5b505af1925050508015612404575060015b61250657612410614f6e565b806308c379a0036124d25750612424614f8a565b8061242f57506124d4565b6006600085848151811061244557612445614eef565b6020026020010151815260200190815260200160002060000160009054906101000a90046001600160a01b03166001600160a01b031684838151811061248d5761248d614eef565b60200260200101517f81302fc3204662085acace33c36464c982ee6cd7aa54f729176650cc51a4b861836040516124c49190615038565b60405180910390a350612506565b505b3d8080156124fe576040519150601f19603f3d011682016040523d82523d6000602084013e612503565b606091505b50505b61250f81614f05565b9050612389565b5060005b81518110156126a757306001600160a01b031663aae4b73483838151811061254457612544614eef565b60200260200101516040518263ffffffff1660e01b815260040161256a91815260200190565b600060405180830381600087803b15801561258457600080fd5b505af1925050508015612595575060015b612697576125a1614f6e565b806308c379a00361266357506125b5614f8a565b806125c05750612665565b600760008484815181106125d6576125d6614eef565b6020026020010151815260200190815260200160002060000160009054906101000a90046001600160a01b03166001600160a01b031683838151811061261e5761261e614eef565b60200260200101517f48b2b3f3b7cf047cbc676166e59b80a9aea26e67f2a964fcd4a5a945dec27a6f836040516126559190615038565b60405180910390a350612697565b505b3d80801561268f576040519150601f19603f3d011682016040523d82523d6000602084013e612694565b606091505b50505b6126a081614f05565b905061251a565b5050505050565b6002600054036127005760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a3b565b600260008181558281526006602081815260409283902083516101608101855281546001600160a01b03811680835260ff600160a01b83048116151595840195909552600160a81b90910490931615159481019490945260018101546060850152938401546080840152600384015460a0840152600484015460c0840152600584015460e08401529083015461010083015260078301546101208301526008909201546101408201529033146127f85760405162461bcd60e51b815260206004820152601c60248201527f4f726465724d616e616765723a20216f726465722e6163636f756e74000000006044820152606401610a3b565b61287b336305f5e1007f0000000000000000000000000000000000000000000000000de0b6b3a76400008460c0015185608001516128369190614ebd565b6128409190614ed0565b61284a9190614f1e565b6001600160a01b037f000000000000000000000000f77a62affc8e92ee3b8ca07734c83b0beb55e4531691906144bf565b60008281526006602081905260408220805475ffffffffffffffffffffffffffffffffffffffffffff191681556001808201849055600282018490556003820184905560048201849055600582018490559181018390556007810183905560080191909155610100820151156128f9576128f6600282614ebd565b90505b610120820151156129125761290f600282614ebd565b90505b6000336001600160a01b03168260055461292c9190614ed0565b604051600081818185875af1925050503d8060008114612968576040519150601f19603f3d011682016040523d82523d6000602084013e61296d565b606091505b50509050806129d15760405162461bcd60e51b815260206004820152602a60248201527f4f726465724d616e616765723a206661696c656420746f2073656e6420657865604482015269637574696f6e2066656560b01b6064820152608401610a3b565b82600001516001600160a01b0316847f49358803a7ae36469d52afc763a7489ec58204d535ff56c6af7af33492244b4985602001518660400151876060015188608001518960a001518a60c001518b60e001518c61010001518d61012001518e6101400151604051612a8e9a999897969594939291909915158a5297151560208a015260408901969096526060880194909452608087019290925260a086015260c085015260e08401526101008301526101208201526101400190565b60405180910390a3505060016000555050565b600080600080600060076000612b0a8b8b8b8b6040516001600160601b0319606086901b1660208201526034810184905282151560f81b605482015260558101829052600090607501604051602081830303815290604052805190602001209050949350505050565b81526020808201929092526040908101600020815160e08101835281546001600160a01b038116825260ff600160a01b82048116151595830195909552600160a81b9004909316151591830182905260018101546060840152600281015460808401819052600382015460a0850181905260049092015460c0909401849052975095509350915050945094509450949050565b60005b8251811015612bdb57612bcb838281518110612bbe57612bbe614eef565b60200260200101516126ae565b612bd481614f05565b9050612ba0565b5060005b8151811015612c1a57612c0a828281518110612bfd57612bfd614eef565b6020026020010151611624565b612c1381614f05565b9050612bdf565b505050565b33301480612c3c57503360009081526008602052604090205460ff165b612c885760405162461bcd60e51b815260206004820152601560248201527f4f726465724d616e616765723a20216b656570657200000000000000000000006044820152606401610a3b565b600081815260076020908152604091829020825160e08101845281546001600160a01b03811680835260ff600160a01b83048116151595840195909552600160a81b9091049093161515938101939093526001810154606084015260028101546080840152600381015460a08401526004015460c0830152612d08575050565b6000612d2782602001511583604001518460a0015185606001516131ef565b50825160608401516020850151604051634df8059360e11b81526001600160a01b0380851660048301526024820184905282151560448301529495507f0000000000000000000000008d3e5d7e0d0ec9bd2677e1e1d049b2b1ef5ff503909416936314d8353f939291908590639bf00b2690606401602060405180830381865afa158015612db9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddd9190614e75565b6305f5e1008860800151612df19190614ed0565b612dfb9190614f1e565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b1681526001600160a01b0390941660048501526024840192909252151560448301526064820152608401600060405180830381600087803b158015612e6857600080fd5b505af1158015612e7c573d6000803e3d6000fd5b505050600084815260076020526040808220805475ffffffffffffffffffffffffffffffffffffffffffff19168155600181018390556002810183905560038101839055600401829055600554905191925032918381818185875af1925050503d8060008114612f08576040519150601f19603f3d011682016040523d82523d6000602084013e612f0d565b606091505b5050905080612f715760405162461bcd60e51b815260206004820152602a60248201527f4f726465724d616e616765723a206661696c656420746f2073656e6420657865604482015269637574696f6e2066656560b01b6064820152608401610a3b565b82600001516001600160a01b0316847f47036c05d3bcca301b675f2154fca0f55a59c635efd8b997a417d10b0c3ce1d185602001518660400151876060015188608001518960a001518a60c001518a60405161300097969594939291909615158752941515602087015260408601939093526060850191909152608084015260a083015260c082015260e00190565b60405180910390a350505050565b6002600054036130605760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a3b565b600260005560055434146130c15760405162461bcd60e51b815260206004820152602260248201527f4f726465724d616e616765723a20696e76616c696420657865637574696f6e46604482015261656560f01b6064820152608401610a3b565b6130cf338686868686613ad1565b50506001600055505050565b6001546001600160a01b0316331461312d5760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a3b565b600154600160a01b900460ff16156131915760405162461bcd60e51b815260206004820152602160248201527f4f726465724d616e616765723a20616c726561647920696e697469616c697a656044820152601960fa1b6064820152608401610a3b565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16600160a01b179055600280546001600160a01b0390921673ffffffffffffffffffffffffffffffffffffffff19909216919091179055565b604051632b82db0d60e11b8152600481018290528415156024820152600090819081906001600160a01b037f000000000000000000000000f0a64022fff41fa8859ef44ec993b96f4c08f05f1690635705b61a90604401602060405180830381865afa158015613263573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132879190614e75565b9050600086613299578582111561329e565b858210155b9050806133135760405162461bcd60e51b815260206004820152602960248201527f4f726465724d616e616765723a20696e76616c696420707269636520666f722060448201527f657865637574696f6e00000000000000000000000000000000000000000000006064820152608401610a3b565b9097909650945050505050565b336001600160a01b037f0000000000000000000000008d3e5d7e0d0ec9bd2677e1e1d049b2b1ef5ff50316146133985760405162461bcd60e51b815260206004820152601260248201527f4f726465724d616e616765723a202164657800000000000000000000000000006044820152606401610a3b565b600454600090815b8181101561343c57604080516001600160601b0319606089901b166020808301919091526034820188905286151560f81b60548301526055808301859052835180840390910181526075909201835281519181019190912060008181526007909252919020546001600160a01b03161561342b5761341d81613eb0565b613428600185614ebd565b93505b5061343581614f05565b90506133a0565b5081156126a75760055460006001600160a01b03871661345c8584614ed0565b604051600081818185875af1925050503d8060008114613498576040519150601f19603f3d011682016040523d82523d6000602084013e61349d565b606091505b50509050806135a0576001600160a01b0387167f2c0da876dc58358df21667a74f33f9ace39dadb7cb51b147d8957f8874db42b06134db8685614ed0565b60405190815260200160405180910390a26000326134f98685614ed0565b604051600081818185875af1925050503d8060008114613535576040519150601f19603f3d011682016040523d82523d6000602084013e61353a565b606091505b505090508061359e5760405162461bcd60e51b815260206004820152602a60248201527f4f726465724d616e616765723a206661696c656420746f2073656e6420657865604482015269637574696f6e2066656560b01b6064820152608401610a3b565b505b50505050505050565b6001546001600160a01b031633146135fb5760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a3b565b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f91a8c1cc2d4a3bb60738481947a00cbb9899c822916694cf8bb1d68172fdcd5490600090a250565b6001546001600160a01b031633146136a45760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a3b565b6001600160a01b038216600081815260086020908152604091829020805460ff19168515159081179091558251938452908301527f8c2ff6748f99f65f4ebf8a1e973a289bad216c4d5b20fda1940d9e01118ae42a910160405180910390a15050565b600354600090815b8181101561107557604080516001600160601b0319606089901b166020808301919091526034820188905286151560f81b6054830152605580830185905283518084039091018152607590920183528151918101919091206000908152600690915220546001600160a01b031661378b5760019250505061107c565b61379481614f05565b905061370f565b600454600090815b8181101561219557604080516001600160601b0319606089901b166020808301919091526034820188905286151560f81b6054830152605580830185905283518084039091018152607590920183528151918101919091206000908152600790915220546001600160a01b03166138225761381f600184614ebd565b92505b61382b81614f05565b90506137a3565b6002600054036138845760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a3b565b6002600090815582815260076020526040902080546001600160a01b031633146138f05760405162461bcd60e51b815260206004820152601c60248201527f4f726465724d616e616765723a20216f726465722e6163636f756e74000000006044820152606401610a3b565b6003810182905542600482018190558154600183015460028401546040805160ff600160a01b8604811615158252600160a81b860416151560208201529081019290925260608201526080810185905260a08101929092526001600160a01b03169084907f6911fa079056e89ec24445683aa16240daff19f20221857b69ace7f7f2167f8a9060c00160405180910390a35050600160005550565b6000806000806000806000806000600660006139fa8f8f8f8f6040516001600160601b0319606086901b1660208201526034810184905282151560f81b605482015260558101829052600090607501604051602081830303815290604052805190602001209050949350505050565b8152602080820192909252604090810160002081516101608101835281546001600160a01b038116825260ff600160a01b82048116151595830195909552600160a81b9004909316151591830182905260018101546060840152600281015460808401819052600382015460a08501819052600483015460c08601819052600584015460e087018190526006850154610100880181905260078601546101208901819052600890960154610140909801889052939f50919d509b509950919750909550935091505094995094995094999196509450565b60008111613b475760405162461bcd60e51b815260206004820152602660248201527f4f726465724d616e616765723a207472696767657250726963652063616e6e6f60448201527f74206265203000000000000000000000000000000000000000000000000000006064820152608401610a3b565b60045460005b81811015613d2957604080516001600160601b031960608b901b166020808301919091526034820188905289151560f81b60548301526055808301859052835180840390910181526075909201835281519181019190912060008181526007909252919020546001600160a01b0316613d18576040805160e0810182526001600160a01b03808c168083528b151560208085019182528c1515858701908152606086018d8152608087018d815260a088018d81524260c08a0181815260008d81526007909752958b902099518a54975195511515600160a81b027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff961515600160a01b027fffffffffffffffffffffff00000000000000000000000000000000000000000090991691909a16179690961793909316969096178755516001870155935160028601559251600385015591516004909301929092559151909183917fd1d8633d045dfd8d52789d0505215f098a1777a0a0a8ac150c94a16d0231df1091613d08918d918d918d918d918d91909515158652931515602086015260408501929092526060840152608083015260a082015260c00190565b60405180910390a3505050610fd9565b50613d2281614f05565b9050613b4d565b5060405162461bcd60e51b815260206004820152602560248201527f4f726465724d616e616765723a206d6178436c6f73654f72646572732065786360448201527f65656465640000000000000000000000000000000000000000000000000000006064820152608401610a3b565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015613de9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e0d9190614e75565b613e179190614ebd565b6040516001600160a01b038516602482015260448101829052909150613eaa90859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526144ef565b50505050565b6000600760008381526020019081526020016000206040518060e00160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016000820160149054906101000a900460ff161515151581526020016000820160159054906101000a900460ff16151515158152602001600182015481526020016002820154815260200160038201548152602001600482015481525050905060076000838152602001908152602001600020600080820160006101000a8154906001600160a01b0302191690556000820160146101000a81549060ff02191690556000820160156101000a81549060ff02191690556001820160009055600282016000905560038201600090556004820160009055505080600001516001600160a01b0316827ff88686450cd096feaf4c9c73e01e80cc376845eac25202501d46a386ceef7cd583602001518460400151856060015186608001518760a001518860c0015160405161405c969594939291909515158652931515602086015260408501929092526060840152608083015260a082015260c00190565b60405180910390a35050565b60405163021707f360e41b81526004810186905260248101859052604481018790527f0000000000000000000000008d3e5d7e0d0ec9bd2677e1e1d049b2b1ef5ff5036001600160a01b0316906321707f309060640160006040518083038186803b1580156140d657600080fd5b505afa1580156140ea573d6000803e3d6000fd5b50506003549150600090505b8181101561445f57604080516001600160601b031960608e901b16602080830191909152603482018b90528c151560f81b60548301526055808301859052835180840390910181526075909201835281519181019190912060008181526006909252919020546001600160a01b031661444e57604051636519c9d560e01b81526004810189905260248101889052604481018a90526000907f0000000000000000000000008d3e5d7e0d0ec9bd2677e1e1d049b2b1ef5ff5036001600160a01b031690636519c9d590606401602060405180830381865afa1580156141df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142039190614e75565b90506142808d306305f5e1007f0000000000000000000000000000000000000000000000000de0b6b3a764000061423a868f614ebd565b6142449190614ed0565b61424e9190614f1e565b6001600160a01b037f000000000000000000000000f77a62affc8e92ee3b8ca07734c83b0beb55e453169291906145d4565b6040518061016001604052808e6001600160a01b031681526020018d151581526020018c151581526020018b81526020018a8152602001898152602001828152602001888152602001878152602001868152602001428152506006600084815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548160ff02191690831515021790555060408201518160000160156101000a81548160ff021916908315150217905550606082015181600101556080820151816002015560a0820151816003015560c0820151816004015560e082015181600501556101008201518160060155610120820151816007015561014082015181600801559050508c6001600160a01b0316827fde124635deb0e2ebcbdd019f4c341021e58f79aafb89ae9949be65bc717cc30f8e8e8e8e8e888f8f8f4260405161443d9a999897969594939291909915158a5297151560208a015260408901969096526060880194909452608087019290925260a086015260c085015260e08401526101008301526101208201526101400190565b60405180910390a3505050506144b4565b5061445881614f05565b90506140f6565b5060405162461bcd60e51b8152602060048201526024808201527f4f726465724d616e616765723a206d61784f70656e4f726465727320657863656044820152631959195960e21b6064820152608401610a3b565b505050505050505050565b6040516001600160a01b038316602482015260448101829052612c1a90849063a9059cbb60e01b90606401613e46565b6000614544826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661460c9092919063ffffffff16565b805190915015612c1a5780806020019051810190614562919061506b565b612c1a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610a3b565b6040516001600160a01b0380851660248301528316604482015260648101829052613eaa9085906323b872dd60e01b90608401613e46565b606061461b8484600085614623565b949350505050565b60608247101561469b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a3b565b6001600160a01b0385163b6146f25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a3b565b600080866001600160a01b0316858760405161470e9190615088565b60006040518083038185875af1925050503d806000811461474b576040519150601f19603f3d011682016040523d82523d6000602084013e614750565b606091505b509150915061476082828661476b565b979650505050505050565b6060831561477a57508161107c565b82511561478a5782518084602001fd5b8160405162461bcd60e51b8152600401610a3b9190615038565b80356001600160a01b03811681146147bb57600080fd5b919050565b6000806000606084860312156147d557600080fd5b6147de846147a4565b95602085013595506040909401359392505050565b600081518084526020808501945080840160005b8381101561482357815187529582019590820190600101614807565b509495945050505050565b60006040808352614841818401866147f3565b83810360208581019190915285518083528682019282019060005b818110156148ed57845180516001600160a01b031684528481015115158585015286810151151587850152606080820151908501526080808201519085015260a0808201519085015260c0808201519085015260e08082015190850152610100808201519085015261012080820151908501526101409081015190840152938301936101609092019160010161485c565b509098975050505050505050565b801515811461490957600080fd5b50565b60008060008060008060c0878903121561492557600080fd5b61492e876147a4565b9550602087013561493e816148fb565b9450604087013561494e816148fb565b959894975094956060810135955060808101359460a0909101359350915050565b60008060006060848603121561498457600080fd5b61498d846147a4565b92506020840135915060408401356149a4816148fb565b809150509250925092565b6000602082840312156149c157600080fd5b5035919050565b600080604083850312156149db57600080fd5b50508035926020909101359150565b600080600080600080600060e0888a031215614a0557600080fd5b873596506020880135614a17816148fb565b9550604088013594506060880135614a2e816148fb565b93506080880135925060a0880135614a45816148fb565b8092505060c0880135905092959891949750929550565b600060208284031215614a6e57600080fd5b61107c826147a4565b60006040808352614a8a818401866147f3565b83810360208581019190915285518083528682019282019060005b818110156148ed57845180516001600160a01b031684528481015115158585015286810151151587850152606080820151908501526080808201519085015260a0808201519085015260c090810151908401529383019360e090920191600101614aa5565b600080600080600080600080610100898b031215614b2757600080fd5b883597506020890135614b39816148fb565b96506040890135614b49816148fb565b979a96995096976060810135975060808101359660a0820135965060c0820135955060e0909101359350915050565b634e487b7160e01b600052604160045260246000fd5b601f8201601f1916810167ffffffffffffffff81118282101715614bb457614bb4614b78565b6040525050565b600067ffffffffffffffff821115614bd557614bd5614b78565b5060051b60200190565b600082601f830112614bf057600080fd5b81356020614bfd82614bbb565b604051614c0a8282614b8e565b83815260059390931b8501820192828101915086841115614c2a57600080fd5b8286015b84811015614c455780358352918301918301614c2e565b509695505050505050565b60008060008060808587031215614c6657600080fd5b843567ffffffffffffffff80821115614c7e57600080fd5b614c8a88838901614bdf565b95506020870135915080821115614ca057600080fd5b614cac88838901614bdf565b94506040870135915080821115614cc257600080fd5b614cce88838901614bdf565b93506060870135915080821115614ce457600080fd5b50614cf187828801614bdf565b91505092959194509250565b60008060008060808587031215614d1357600080fd5b614d1c856147a4565b9350602085013592506040850135614d33816148fb565b9396929550929360600135925050565b60008060408385031215614d5657600080fd5b823567ffffffffffffffff80821115614d6e57600080fd5b614d7a86838701614bdf565b93506020850135915080821115614d9057600080fd5b50614d9d85828601614bdf565b9150509250929050565b600080600080600060a08688031215614dbf57600080fd5b8535614dca816148fb565b94506020860135614dda816148fb565b94979496505050506040830135926060810135926080909101359150565b60008060008060808587031215614e0e57600080fd5b8435614e19816148fb565b93506020850135614e29816148fb565b93969395505050506040820135916060013590565b60008060408385031215614e5157600080fd5b614e5a836147a4565b91506020830135614e6a816148fb565b809150509250929050565b600060208284031215614e8757600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b81810381811115614eb757614eb7614e8e565b92915050565b80820180821115614eb757614eb7614e8e565b6000816000190483118215151615614eea57614eea614e8e565b500290565b634e487b7160e01b600052603260045260246000fd5b600060018201614f1757614f17614e8e565b5060010190565b600082614f3b57634e487b7160e01b600052601260045260246000fd5b500490565b604081526000614f5360408301856147f3565b8281036020840152614f6581856147f3565b95945050505050565b600060033d1115614f875760046000803e5060005160e01c5b90565b600060443d1015614f985790565b6040516003193d81016004833e81513d67ffffffffffffffff8160248401118184111715614fc857505050505090565b8285019150815181811115614fe05750505050505090565b843d8701016020828501011115614ffa5750505050505090565b61500960208286010187614b8e565b509095945050505050565b60005b8381101561502f578181015183820152602001615017565b50506000910152565b6020815260008251806020840152615057816040850160208701615014565b601f01601f19169190910160400192915050565b60006020828403121561507d57600080fd5b815161107c816148fb565b6000825161509a818460208701615014565b919091019291505056fea2646970667358221220ad12422bf0389de26d070485b560eb5befa0708ce24ff8f0f0c0afbb6f52d87864736f6c63430008100033