Address Details
contract
0xB1925E72863Fec9143f4B8783A1b50bE92De1D49
- Contract Name
- PositionManager
- Creator
- 0xd3c2ab–ffc681 at 0x817b9f–6505ea
- Balance
- 0.013 CELO ( )
- Locked CELO Balance
- 0.00 CELO
- Voting CELO Balance
- 0.00 CELO
- Pending Unlocked Gold
- 0.00 CELO
- Tokens
-
Fetching tokens...
- Transactions
- 1,877 Transactions
- Transfers
- 3,026 Transfers
- Gas Used
- 484,018,067
- Last Balance Update
- 18276812
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:
- PositionManager
- Optimization enabled
- true
- Compiler version
- v0.8.16+commit.07a7930e
- Optimization runs
- 800
- EVM Version
- london
- Verified at
- 2023-05-19T08:41:18.207971Z
contracts/core/PositionManager.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"; import "../interfaces/IOrderManager.sol"; contract PositionManager is Governable, ReentrancyGuard { using SafeERC20 for IERC20; struct OpenPosition { address account; bool isLong; uint256 productId; uint256 margin; uint256 leverage; uint256 tradeFee; uint256 acceptablePrice; uint256 tpPrice; uint256 slPrice; uint256 index; uint256 timestamp; } struct ClosePosition { address account; bool isLong; uint256 productId; uint256 margin; uint256 acceptablePrice; uint256 index; uint256 timestamp; } address public immutable dex; address public immutable oracle; address public immutable orderManager; address public immutable collateralToken; uint256 public positionValidDuration = 60; uint256 public executeCooldownPublic = 180; uint256 public executionFee = 1e15; uint256 private immutable tokenBase; uint256 private constant BASE = 10**8; uint256 public openPositionKeysIndex; bytes32[] public openPositionKeys; uint256 public closePositionKeysIndex; bytes32[] public closePositionKeys; mapping(address => uint256) public openPositionsIndex; mapping(bytes32 => OpenPosition) public openPositions; mapping(address => uint256) public closePositionsIndex; mapping(bytes32 => ClosePosition) public closePositions; mapping(address => bool) public isKeeper; event CreateOpenPosition( address indexed account, uint256 productId, uint256 margin, uint256 leverage, uint256 tradeFee, bool isLong, uint256 acceptablePrice, uint256 tpPrice, uint256 slPrice, uint256 index, uint256 timestamp ); event ExecuteOpenPosition( address indexed account, uint256 productId, uint256 margin, uint256 leverage, uint256 tradeFee, bool isLong, uint256 acceptablePrice, uint256 tpPrice, uint256 slPrice, uint256 index, uint256 timeUsed ); event CancelOpenPosition( address indexed account, uint256 productId, uint256 margin, uint256 leverage, uint256 tradeFee, bool isLong, uint256 acceptablePrice, uint256 tpPrice, uint256 slPrice, uint256 index, uint256 timeUsed ); event CreateClosePosition( address indexed account, uint256 productId, uint256 margin, bool isLong, uint256 acceptablePrice, uint256 index, uint256 timestamp ); event ExecuteClosePosition( address indexed account, uint256 productId, uint256 margin, bool isLong, uint256 acceptablePrice, uint256 index, uint256 timeUsed ); event CancelClosePosition( address indexed account, uint256 productId, uint256 margin, bool isLong, uint256 acceptablePrice, uint256 index, uint256 timeUsed ); event ExecuteOpenPositionError(address indexed account, uint256 index, string executionError); event ExecuteClosePositionError(address indexed account, uint256 index, string executionError); event ExecutionFeeRefundError(address indexed account, uint256 totalExecutionFee); event SetPositionKeysIndex(uint256 openPositionKeysIndex, uint256 closePositionKeysIndex); event SetDuration(uint256 positionValidDuration, uint256 executeCooldownPublic); event SetKeeper(address indexed account, bool isActive); modifier onlyKeeper() { require(isKeeper[msg.sender], "PositionManager: !Keeper"); _; } constructor( address _dex, address _oracle, address _orderManager, address _collateralToken, uint256 _tokenBase ) { dex = _dex; oracle = _oracle; orderManager = _orderManager; collateralToken = _collateralToken; tokenBase = _tokenBase; } function createOpenPosition( bool isLong, uint256 productId, uint256 margin, uint256 leverage, uint256 acceptablePrice, uint256 tpPrice, uint256 slPrice ) external payable nonReentrant { uint256 numOfExecutions = 1; if (tpPrice > 0) numOfExecutions += 2; if (slPrice > 0) numOfExecutions += 2; require(msg.value == executionFee * numOfExecutions, "PositionManager: invalid executionFee"); _createOpenPosition(msg.sender, isLong, productId, margin, leverage, acceptablePrice, tpPrice, slPrice); } function _createOpenPosition( address account, bool isLong, uint256 productId, uint256 margin, uint256 leverage, uint256 acceptablePrice, uint256 tpPrice, uint256 slPrice ) private { IDex(dex).validateOpenPositionRequirements(margin, leverage, productId); uint256 tradeFee = IDex(dex).getTradeFee(margin, leverage, productId); IERC20(collateralToken).safeTransferFrom(account, address(this), ((margin + tradeFee) * tokenBase) / BASE); uint256 index = openPositionsIndex[account]; openPositionsIndex[account] += 1; bytes32 key = getPositionKey(account, index); openPositions[key] = OpenPosition( account, isLong, productId, margin, leverage, tradeFee, acceptablePrice, tpPrice, slPrice, index, block.timestamp ); openPositionKeys.push(key); emit CreateOpenPosition( account, productId, margin, leverage, tradeFee, isLong, acceptablePrice, tpPrice, slPrice, index, block.timestamp ); } function executeOpenPosition(bytes32 key) external nonReentrant { require(msg.sender == address(this) || isKeeper[msg.sender], "PositionManager: !executor"); OpenPosition memory position = openPositions[key]; if (position.account == address(0)) return; require(position.timestamp + positionValidDuration > block.timestamp, "PositionManager: position has expired"); _validateExecution(position.productId, position.isLong, position.acceptablePrice); IERC20(collateralToken).safeIncreaseAllowance(dex, ((position.margin + position.tradeFee) * tokenBase) / BASE); IDex(dex).openPosition( position.account, position.productId, position.isLong, position.margin, position.leverage ); uint256 numOfExecutions = 1; uint256 _executionFee = executionFee; if (position.tpPrice != 0) { IOrderManager(orderManager).createCloseOrderForTPSL{value: _executionFee}( position.account, position.isLong, position.isLong, position.productId, (position.margin * position.leverage) / BASE, position.tpPrice ); numOfExecutions += 1; } if (position.slPrice != 0) { IOrderManager(orderManager).createCloseOrderForTPSL{value: _executionFee}( position.account, position.isLong, !position.isLong, position.productId, (position.margin * position.leverage) / BASE, position.slPrice ); numOfExecutions += 1; } delete openPositions[key]; (bool success, ) = payable(tx.origin).call{value: _executionFee * numOfExecutions}(""); require(success, "PositionManager: failed to send execution fee"); emit ExecuteOpenPosition( position.account, position.productId, position.margin, position.leverage, position.tradeFee, position.isLong, position.acceptablePrice, position.tpPrice, position.slPrice, position.index, block.timestamp - position.timestamp ); } function _cancelOpenPosition(bytes32 key) private { OpenPosition memory position = openPositions[key]; if (position.account == address(0)) return; IERC20(collateralToken).safeTransfer( position.account, ((position.margin + position.tradeFee) * tokenBase) / BASE ); uint256 _executionFee = executionFee; uint256 numOfExecutions = 0; if (position.tpPrice > 0) numOfExecutions += 2; if (position.slPrice > 0) numOfExecutions += 2; if (numOfExecutions != 0) { (bool success, ) = payable(position.account).call{gas: 2300, value: _executionFee * numOfExecutions}(""); if (!success) { emit ExecutionFeeRefundError(position.account, _executionFee * numOfExecutions); (bool success2, ) = payable(msg.sender).call{value: _executionFee * numOfExecutions}(""); require(success2, "PositionManager: failed to send execution fee"); } } delete openPositions[key]; (bool success3, ) = payable(msg.sender).call{value: _executionFee}(""); require(success3, "PositionManager: failed to send execution fee"); emit CancelOpenPosition( position.account, position.productId, position.margin, position.leverage, position.tradeFee, position.isLong, position.acceptablePrice, position.tpPrice, position.slPrice, position.index, block.timestamp - position.timestamp ); } function _executeOpenPositions(uint256 endIndex) private { uint256 index = openPositionKeysIndex; uint256 length = openPositionKeys.length; if (index >= length) return; if (endIndex > length) endIndex = length; while (index < endIndex) { bytes32 key = openPositionKeys[index]; try this.executeOpenPosition(key) {} catch Error(string memory executionError) { _cancelOpenPosition(key); emit ExecuteOpenPositionError(openPositions[key].account, index, executionError); } catch (bytes memory) { _cancelOpenPosition(key); } delete openPositionKeys[index]; ++index; } openPositionKeysIndex = index; } function createClosePosition( bool isLong, uint256 productId, uint256 margin, uint256 acceptablePrice ) external payable nonReentrant { require(msg.value == executionFee, "PositionManager: invalid executionFee"); _createClosePosition(msg.sender, isLong, productId, margin, acceptablePrice); } function _createClosePosition( address account, bool isLong, uint256 productId, uint256 margin, uint256 acceptablePrice ) private { uint256 index = closePositionsIndex[account]; closePositionsIndex[account] += 1; bytes32 key = getPositionKey(account, index); closePositions[key] = ClosePosition( account, isLong, productId, margin, acceptablePrice, index, block.timestamp ); closePositionKeys.push(key); emit CreateClosePosition(account, productId, margin, isLong, acceptablePrice, index, block.timestamp); } function executeClosePosition(bytes32 key) external nonReentrant { require(msg.sender == address(this) || isKeeper[msg.sender], "PositionManager: !executor"); ClosePosition memory position = closePositions[key]; if (position.account == address(0)) return; require(position.timestamp + positionValidDuration > block.timestamp, "PositionManager: position has expired"); _validateExecution(position.productId, !position.isLong, position.acceptablePrice); IDex(dex).closePosition(position.account, position.productId, position.isLong, position.margin); delete closePositions[key]; (bool success, ) = payable(tx.origin).call{value: executionFee}(""); require(success, "PositionManager: failed to send execution fee"); emit ExecuteClosePosition( position.account, position.productId, position.margin, position.isLong, position.acceptablePrice, position.index, block.timestamp - position.timestamp ); } function executeClosePositionByOwner(bytes32 key) external nonReentrant { ClosePosition memory position = closePositions[key]; require(msg.sender == position.account, "PositionManager: !account"); require( position.timestamp + executeCooldownPublic <= block.timestamp, "PositionManager: cooldown has not passed yet" ); _validateExecution(position.productId, !position.isLong, position.acceptablePrice); IDex(dex).closePosition(position.account, position.productId, position.isLong, position.margin); delete closePositions[key]; (bool success, ) = payable(msg.sender).call{value: executionFee}(""); require(success, "PositionManager: failed to send execution fee"); emit ExecuteClosePosition( position.account, position.productId, position.margin, position.isLong, position.acceptablePrice, position.index, block.timestamp - position.timestamp ); } function _cancelClosePosition(bytes32 key) private { ClosePosition memory position = closePositions[key]; if (position.account == address(0)) return; delete closePositions[key]; (bool success, ) = payable(msg.sender).call{value: executionFee}(""); require(success, "PositionManager: failed to send execution fee"); emit CancelClosePosition( position.account, position.productId, position.margin, position.isLong, position.acceptablePrice, position.index, block.timestamp - position.timestamp ); } function _executeClosePositions(uint256 endIndex) private { uint256 index = closePositionKeysIndex; uint256 length = closePositionKeys.length; if (index >= length) return; if (endIndex > length) endIndex = length; while (index < endIndex) { bytes32 key = closePositionKeys[index]; try this.executeClosePosition(key) {} catch Error(string memory executionError) { _cancelClosePosition(key); emit ExecuteClosePositionError(closePositions[key].account, index, executionError); } catch (bytes memory) { _cancelClosePosition(key); } delete closePositionKeys[index]; ++index; } closePositionKeysIndex = index; } function executeNPositionsWithPrices( uint256[] memory productIds, uint256[] memory prices, uint256 n ) external onlyKeeper { IOracle(oracle).setPrices(productIds, prices); _executeOpenPositions(openPositionKeysIndex + n); _executeClosePositions(closePositionKeysIndex + n); } function executePositionsWithPrices( uint256[] memory productIds, uint256[] memory prices, uint256 openEndIndex, uint256 closeEndIndex ) external onlyKeeper { IOracle(oracle).setPrices(productIds, prices); _executeOpenPositions(openEndIndex); _executeClosePositions(closeEndIndex); } function _validateExecution( uint256 productId, bool isLong, uint256 acceptablePrice ) private view { uint256 price = IOracle(oracle).getPrice(productId, isLong); if (isLong) { require(price <= acceptablePrice, "PositionManager: long => slippage exceeded"); } else { require(price >= acceptablePrice, "PositionManager: short => slippage exceeded"); } } function getPositionKey(address account, uint256 index) public pure returns (bytes32) { return keccak256(abi.encodePacked(account, index)); } function getOpenPosition(address account, uint256 index) external view returns (OpenPosition memory) { return openPositions[getPositionKey(account, index)]; } function getClosePosition(address account, uint256 index) external view returns (ClosePosition memory) { return closePositions[getPositionKey(account, index)]; } function getPositionKeysInfo() external view returns ( uint256, uint256, uint256, uint256 ) { return (openPositionKeysIndex, openPositionKeys.length, closePositionKeysIndex, closePositionKeys.length); } function canKeeperExecute() external view returns (bool) { return openPositionKeysIndex < openPositionKeys.length || closePositionKeysIndex < closePositionKeys.length; } function setDuration(uint256 _positionValidDuration, uint256 _executeCooldownPublic) external onlyGov { require(_positionValidDuration >= 15 && _positionValidDuration <= 60, "PositionManager: invalid duration"); require(_executeCooldownPublic <= 300, "PositionManager: invalid duration"); positionValidDuration = _positionValidDuration; executeCooldownPublic = _executeCooldownPublic; emit SetDuration(_positionValidDuration, _executeCooldownPublic); } function setExecutionFee(uint256 _executionFee) external onlyGov { require(_executionFee <= 1e18); executionFee = _executionFee; } function setPositionKeysIndex(uint256 _openPositionKeysIndex, uint256 _closePositionKeysIndex) external onlyGov { openPositionKeysIndex = _openPositionKeysIndex; closePositionKeysIndex = _closePositionKeysIndex; emit SetPositionKeysIndex(_openPositionKeysIndex, _closePositionKeysIndex); } 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; }
/contracts/interfaces/IOrderManager.sol
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IOrderManager { function createCloseOrderForTPSL( address account, bool isLong, bool isTriggerAbove, uint256 productId, uint256 size, uint256 triggerPrice ) external payable; function cancelActiveCloseOrders( address account, uint256 productId, bool isLong ) external; }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_dex","internalType":"address"},{"type":"address","name":"_oracle","internalType":"address"},{"type":"address","name":"_orderManager","internalType":"address"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"uint256","name":"_tokenBase","internalType":"uint256"}]},{"type":"event","name":"CancelClosePosition","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"uint256","name":"productId","internalType":"uint256","indexed":false},{"type":"uint256","name":"margin","internalType":"uint256","indexed":false},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"uint256","name":"acceptablePrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"index","internalType":"uint256","indexed":false},{"type":"uint256","name":"timeUsed","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"CancelOpenPosition","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"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":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"uint256","name":"acceptablePrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"tpPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"slPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"index","internalType":"uint256","indexed":false},{"type":"uint256","name":"timeUsed","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"CreateClosePosition","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"uint256","name":"productId","internalType":"uint256","indexed":false},{"type":"uint256","name":"margin","internalType":"uint256","indexed":false},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"uint256","name":"acceptablePrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"index","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"CreateOpenPosition","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"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":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"uint256","name":"acceptablePrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"tpPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"slPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"index","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExecuteClosePosition","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"uint256","name":"productId","internalType":"uint256","indexed":false},{"type":"uint256","name":"margin","internalType":"uint256","indexed":false},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"uint256","name":"acceptablePrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"index","internalType":"uint256","indexed":false},{"type":"uint256","name":"timeUsed","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExecuteClosePositionError","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"uint256","name":"index","internalType":"uint256","indexed":false},{"type":"string","name":"executionError","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"ExecuteOpenPosition","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"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":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"uint256","name":"acceptablePrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"tpPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"slPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"index","internalType":"uint256","indexed":false},{"type":"uint256","name":"timeUsed","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExecuteOpenPositionError","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"uint256","name":"index","internalType":"uint256","indexed":false},{"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":"SetDuration","inputs":[{"type":"uint256","name":"positionValidDuration","internalType":"uint256","indexed":false},{"type":"uint256","name":"executeCooldownPublic","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":"account","internalType":"address","indexed":true},{"type":"bool","name":"isActive","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"SetPositionKeysIndex","inputs":[{"type":"uint256","name":"openPositionKeysIndex","internalType":"uint256","indexed":false},{"type":"uint256","name":"closePositionKeysIndex","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"canKeeperExecute","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"closePositionKeys","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"closePositionKeysIndex","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"account","internalType":"address"},{"type":"bool","name":"isLong","internalType":"bool"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"uint256","name":"margin","internalType":"uint256"},{"type":"uint256","name":"acceptablePrice","internalType":"uint256"},{"type":"uint256","name":"index","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}],"name":"closePositions","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"closePositionsIndex","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"collateralToken","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"createClosePosition","inputs":[{"type":"bool","name":"isLong","internalType":"bool"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"uint256","name":"margin","internalType":"uint256"},{"type":"uint256","name":"acceptablePrice","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"createOpenPosition","inputs":[{"type":"bool","name":"isLong","internalType":"bool"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"uint256","name":"margin","internalType":"uint256"},{"type":"uint256","name":"leverage","internalType":"uint256"},{"type":"uint256","name":"acceptablePrice","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":"executeClosePosition","inputs":[{"type":"bytes32","name":"key","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeClosePositionByOwner","inputs":[{"type":"bytes32","name":"key","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"executeCooldownPublic","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeNPositionsWithPrices","inputs":[{"type":"uint256[]","name":"productIds","internalType":"uint256[]"},{"type":"uint256[]","name":"prices","internalType":"uint256[]"},{"type":"uint256","name":"n","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeOpenPosition","inputs":[{"type":"bytes32","name":"key","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executePositionsWithPrices","inputs":[{"type":"uint256[]","name":"productIds","internalType":"uint256[]"},{"type":"uint256[]","name":"prices","internalType":"uint256[]"},{"type":"uint256","name":"openEndIndex","internalType":"uint256"},{"type":"uint256","name":"closeEndIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"executionFee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct PositionManager.ClosePosition","components":[{"type":"address","name":"account","internalType":"address"},{"type":"bool","name":"isLong","internalType":"bool"},{"type":"uint256","name":"productId","internalType":"uint256"},{"type":"uint256","name":"margin","internalType":"uint256"},{"type":"uint256","name":"acceptablePrice","internalType":"uint256"},{"type":"uint256","name":"index","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}]}],"name":"getClosePosition","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct PositionManager.OpenPosition","components":[{"type":"address","name":"account","internalType":"address"},{"type":"bool","name":"isLong","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":"acceptablePrice","internalType":"uint256"},{"type":"uint256","name":"tpPrice","internalType":"uint256"},{"type":"uint256","name":"slPrice","internalType":"uint256"},{"type":"uint256","name":"index","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}]}],"name":"getOpenPosition","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getPositionKey","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"index","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"}],"name":"getPositionKeysInfo","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"gov","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":"bytes32","name":"","internalType":"bytes32"}],"name":"openPositionKeys","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"openPositionKeysIndex","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"account","internalType":"address"},{"type":"bool","name":"isLong","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":"acceptablePrice","internalType":"uint256"},{"type":"uint256","name":"tpPrice","internalType":"uint256"},{"type":"uint256","name":"slPrice","internalType":"uint256"},{"type":"uint256","name":"index","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}],"name":"openPositions","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"openPositionsIndex","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"oracle","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"orderManager","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"positionValidDuration","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDuration","inputs":[{"type":"uint256","name":"_positionValidDuration","internalType":"uint256"},{"type":"uint256","name":"_executeCooldownPublic","internalType":"uint256"}]},{"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":"setPositionKeysIndex","inputs":[{"type":"uint256","name":"_openPositionKeysIndex","internalType":"uint256"},{"type":"uint256","name":"_closePositionKeysIndex","internalType":"uint256"}]}]
Contract Creation Code
0x610120604052603c60025560b460035566038d7ea4c680006004553480156200002757600080fd5b5060405162003da238038062003da28339810160408190526200004a91620000a7565b600080546001600160a01b03191633179055600180556001600160a01b0394851660805292841660a05290831660c05290911660e052610100526200010e565b80516001600160a01b0381168114620000a257600080fd5b919050565b600080600080600060a08688031215620000c057600080fd5b620000cb866200008a565b9450620000db602087016200008a565b9350620000eb604087016200008a565b9250620000fb606087016200008a565b9150608086015190509295509295909350565b60805160a05160c05160e05161010051613bdf620001c360003960008181610bea015281816127ac0152612da401526000818161073401528181610c3b015281816127f30152612df501526000818161089901528181610d260152610e29015260008181610615015281816115e201528181611a1501526120ea01526000818161058b01528181610bc401528181610cb401528181611388015281816118d6015281816126a2015261272a0152613bdf6000f3fe6080604052600436106102195760003560e01c80638af2bf571161011d578063b2016bd4116100b0578063d9567e871161007f578063dd68c1e211610064578063dd68c1e214610805578063e799c63e14610867578063f9b6117f1461088757600080fd5b8063d9567e87146107b6578063db53ec4f146107ef57600080fd5b8063b2016bd414610722578063cd7ea09514610756578063cfad57a214610776578063d1b9e8531461079657600080fd5b80639e89a8ba116100ec5780639e89a8ba146106af578063abca3de0146106c2578063ac69d957146106ef578063af90352b1461070f57600080fd5b80638af2bf57146106375780638f303b76146106645780639654e63a146106795780639cb324601461069957600080fd5b806336841616116101b05780635dda64e01161017f5780636ba42aaa116101645780636ba42aaa146105ad57806370e67e0d146105ed5780637dc0d1d01461060357600080fd5b80635dda64e014610559578063692058c21461057957600080fd5b806336841616146103b357806337a063d2146104845780633b8679fd146104a457806340e9903b1461054357600080fd5b80631eb98848116101ec5780631eb98848146103265780632288216014610346578063299c9d0914610366578063365d89151461039357600080fd5b806307bbe15a1461021e57806312d43a51146102a85780631830d5f0146102e05780631bb9e60f14610302575b600080fd5b34801561022a57600080fd5b5061023e610239366004613597565b6108bb565b60405161029f9190600060e0820190506001600160a01b03835116825260208301511515602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015292915050565b60405180910390f35b3480156102b457600080fd5b506000546102c8906001600160a01b031681565b6040516001600160a01b03909116815260200161029f565b3480156102ec57600080fd5b506103006102fb3660046135c1565b6109ce565b005b34801561030e57600080fd5b5061031860025481565b60405190815260200161029f565b34801561033257600080fd5b506103006103413660046135da565b6110f2565b34801561035257600080fd5b506103006103613660046135c1565b61118c565b34801561037257600080fd5b506103186103813660046135fc565b600b6020526000908152604090205481565b34801561039f57600080fd5b506103006103ae3660046136db565b61156c565b3480156103bf57600080fd5b506104276103ce3660046135c1565b600a6020526000908152604090208054600182015460028301546003840154600485015460058601546006870154600788015460088901546009909901546001600160a01b03891699600160a01b90990460ff1698908b565b604080516001600160a01b03909c168c5299151560208c0152988a01979097526060890195909552608088019390935260a087019190915260c086015260e08501526101008401526101208301526101408201526101600161029f565b34801561049057600080fd5b5061030061049f3660046135c1565b611663565b3480156104b057600080fd5b506105046104bf3660046135c1565b600c602052600090815260409020805460018201546002830154600384015460048501546005909501546001600160a01b03851695600160a01b90950460ff16949087565b604080516001600160a01b0390981688529515156020880152948601939093526060850191909152608084015260a083015260c082015260e00161029f565b34801561054f57600080fd5b5061031860045481565b34801561056557600080fd5b506103006105743660046135c1565b6116cf565b34801561058557600080fd5b506102c87f000000000000000000000000000000000000000000000000000000000000000081565b3480156105b957600080fd5b506105dd6105c83660046135fc565b600d6020526000908152604090205460ff1681565b604051901515815260200161029f565b3480156105f957600080fd5b5061031860035481565b34801561060f57600080fd5b506102c87f000000000000000000000000000000000000000000000000000000000000000081565b34801561064357600080fd5b506103186106523660046135fc565b60096020526000908152604090205481565b34801561067057600080fd5b506105dd611982565b34801561068557600080fd5b5061030061069436600461374f565b61199f565b3480156106a557600080fd5b5061031860055481565b6103006106bd3660046137cd565b611aaf565b3480156106ce57600080fd5b506106e26106dd366004613597565b611bb8565b60405161029f9190613822565b3480156106fb57600080fd5b5061031861070a3660046135c1565b611d12565b61030061071d3660046138ae565b611d33565b34801561072e57600080fd5b506102c87f000000000000000000000000000000000000000000000000000000000000000081565b34801561076257600080fd5b506103006107713660046135da565b611e00565b34801561078257600080fd5b506103006107913660046135fc565b611f56565b3480156107a257600080fd5b506103006107b13660046138e9565b612008565b3480156107c257600080fd5b5060055460065460075460085460408051948552602085019390935291830152606082015260800161029f565b3480156107fb57600080fd5b5061031860075481565b34801561081157600080fd5b50610318610820366004613597565b6040516bffffffffffffffffffffffff19606084901b1660208201526034810182905260009060540160405160208183030381529060405280519060200120905092915050565b34801561087357600080fd5b506103186108823660046135c1565b6120b9565b34801561089357600080fd5b506102c87f000000000000000000000000000000000000000000000000000000000000000081565b6109066040518060e0016040528060006001600160a01b0316815260200160001515815260200160008152602001600081526020016000815260200160008152602001600081525090565b600c600061095685856040516bffffffffffffffffffffffff19606084901b1660208201526034810182905260009060540160405160208183030381529060405280519060200120905092915050565b81526020808201929092526040908101600020815160e08101835281546001600160a01b0381168252600160a01b900460ff161515938101939093526001810154918301919091526002810154606083015260038101546080830152600481015460a08301526005015460c082015290505b92915050565b600260015403610a255760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b600260015533301480610a475750336000908152600d602052604090205460ff165b610a935760405162461bcd60e51b815260206004820152601a60248201527f506f736974696f6e4d616e616765723a20216578656375746f720000000000006044820152606401610a1c565b6000818152600a602090815260409182902082516101608101845281546001600160a01b038116808352600160a01b90910460ff161515938201939093526001820154938101939093526002810154606084015260038101546080840152600481015460a0840152600581015460c0840152600681015460e08401526007810154610100840152600881015461012084015260090154610140830152610b3957506110eb565b42600254826101400151610b4d9190613936565b11610ba85760405162461bcd60e51b815260206004820152602560248201527f506f736974696f6e4d616e616765723a20706f736974696f6e206861732065786044820152641c1a5c995960da1b6064820152608401610a1c565b610bbf816040015182602001518360c001516120c9565b610c627f00000000000000000000000000000000000000000000000000000000000000006305f5e1007f00000000000000000000000000000000000000000000000000000000000000008460a001518560600151610c1d9190613936565b610c279190613949565b610c319190613968565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169190612256565b80516040808301516020840151606085015160808601519351639267fbbd60e01b81526001600160a01b03958616600482015260248101939093529015156044830152606482015260848101919091527f000000000000000000000000000000000000000000000000000000000000000090911690639267fbbd9060a401600060405180830381600087803b158015610cfa57600080fd5b505af1158015610d0e573d6000803e3d6000fd5b505060045460e08401516001935090915015610e1c577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631844f44f8285600001518660200151876020015188604001516305f5e1008a608001518b60600151610d819190613949565b610d8b9190613968565b60e08b8101516040519189901b6001600160e01b03191682526001600160a01b03969096166004820152931515602485015291151560448401526064830152608482015260a481019190915260c4016000604051808303818588803b158015610df357600080fd5b505af1158015610e07573d6000803e3d6000fd5b5050505050600182610e199190613936565b91505b61010083015115610f1d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631844f44f828560000151866020015187602001511588604001516305f5e1008a608001518b60600151610e859190613949565b610e8f9190613968565b6101008b01516040516001600160e01b031960e08a901b1681526001600160a01b039096166004870152931515602486015291151560448501526064840152608483015260a482015260c4016000604051808303818588803b158015610ef457600080fd5b505af1158015610f08573d6000803e3d6000fd5b5050505050600182610f1a9190613936565b91505b6000848152600a6020526040812080546001600160a81b0319168155600181018290556002810182905560038101829055600481018290556005810182905560068101829055600781018290556008810182905560090181905532610f828484613949565b604051600081818185875af1925050503d8060008114610fbe576040519150601f19603f3d011682016040523d82523d6000602084013e610fc3565b606091505b505090508061102a5760405162461bcd60e51b815260206004820152602d60248201527f506f736974696f6e4d616e616765723a206661696c656420746f2073656e642060448201526c657865637574696f6e2066656560981b6064820152608401610a1c565b83600001516001600160a01b03167fc5b9318d477559e5a19fc064b667a7f44e91bd26a16bd850b8ca7e9fc9c2ad378560400151866060015187608001518860a0015189602001518a60c001518b60e001518c61010001518d61012001518e610140015142611099919061398a565b604080519a8b5260208b0199909952978901969096526060880194909452911515608087015260a086015260c085015260e08401526101008301526101208201526101400160405180910390a2505050505b5060018055565b6000546001600160a01b031633146111445760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a1c565b6005829055600781905560408051838152602081018390527fb7543daceab18d4df8f94a486d44ba4a593a9106e53abe0b85e15461d73827bb91015b60405180910390a15050565b6002600154036111de5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a1c565b600260018181556000838152600c6020908152604091829020825160e08101845281546001600160a01b038116808352600160a01b90910460ff16151593820193909352938101549284019290925292810154606083015260038101546080830152600481015460a08301526005015460c08201529033146112a25760405162461bcd60e51b815260206004820152601960248201527f506f736974696f6e4d616e616765723a20216163636f756e74000000000000006044820152606401610a1c565b426003548260c001516112b59190613936565b11156113295760405162461bcd60e51b815260206004820152602c60248201527f506f736974696f6e4d616e616765723a20636f6f6c646f776e20686173206e6f60448201527f74207061737365642079657400000000000000000000000000000000000000006064820152608401610a1c565b611341816040015182602001511583608001516120c9565b80516040808301516020840151606085015192516314d8353f60e01b81526001600160a01b03948516600482015260248101929092521515604482015260648101919091527f0000000000000000000000000000000000000000000000000000000000000000909116906314d8353f90608401600060405180830381600087803b1580156113ce57600080fd5b505af11580156113e2573d6000803e3d6000fd5b5050506000838152600c602052604080822080546001600160a81b03191681556001810183905560028101839055600381018390556004808201849055600590910183905554905191925033915b60006040518083038185875af1925050503d806000811461146d576040519150601f19603f3d011682016040523d82523d6000602084013e611472565b606091505b50509050806114d95760405162461bcd60e51b815260206004820152602d60248201527f506f736974696f6e4d616e616765723a206661696c656420746f2073656e642060448201526c657865637574696f6e2066656560981b6064820152608401610a1c565b81600001516001600160a01b03167fd931167b93a7d82b94c5544ed2e7c0904e4a572acecca3c97ad6e441d43faa4e83604001518460600151856020015186608001518760a001518860c0015142611531919061398a565b604080519687526020870195909552921515858501526060850191909152608084015260a0830152519081900360c00190a250506001805550565b336000908152600d602052604090205460ff166115cb5760405162461bcd60e51b815260206004820152601860248201527f506f736974696f6e4d616e616765723a20214b656570657200000000000000006044820152606401610a1c565b604051630682f55760e51b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d05eaae09061161990879087906004016139d8565b600060405180830381600087803b15801561163357600080fd5b505af1158015611647573d6000803e3d6000fd5b5050505061165482612350565b61165d816124e7565b50505050565b6000546001600160a01b031633146116b55760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a1c565b670de0b6b3a76400008111156116ca57600080fd5b600455565b6002600154036117215760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a1c565b6002600155333014806117435750336000908152600d602052604090205460ff165b61178f5760405162461bcd60e51b815260206004820152601a60248201527f506f736974696f6e4d616e616765723a20216578656375746f720000000000006044820152606401610a1c565b6000818152600c6020908152604091829020825160e08101845281546001600160a01b038116808352600160a01b90910460ff161515938201939093526001820154938101939093526002810154606084015260038101546080840152600481015460a08401526005015460c083015261180957506110eb565b426002548260c0015161181c9190613936565b116118775760405162461bcd60e51b815260206004820152602560248201527f506f736974696f6e4d616e616765723a20706f736974696f6e206861732065786044820152641c1a5c995960da1b6064820152608401610a1c565b61188f816040015182602001511583608001516120c9565b80516040808301516020840151606085015192516314d8353f60e01b81526001600160a01b03948516600482015260248101929092521515604482015260648101919091527f0000000000000000000000000000000000000000000000000000000000000000909116906314d8353f90608401600060405180830381600087803b15801561191c57600080fd5b505af1158015611930573d6000803e3d6000fd5b5050506000838152600c602052604080822080546001600160a81b0319168155600181018390556002810183905560038101839055600480820184905560059091018390555490519192503291611430565b600654600554600091118061199a5750600854600754105b905090565b336000908152600d602052604090205460ff166119fe5760405162461bcd60e51b815260206004820152601860248201527f506f736974696f6e4d616e616765723a20214b656570657200000000000000006044820152606401610a1c565b604051630682f55760e51b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d05eaae090611a4c90869086906004016139d8565b600060405180830381600087803b158015611a6657600080fd5b505af1158015611a7a573d6000803e3d6000fd5b50505050611a9481600554611a8f9190613936565b612350565b611aaa81600754611aa59190613936565b6124e7565b505050565b600260015403611b015760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a1c565b600260019081558215611b1c57611b19600282613936565b90505b8115611b3057611b2d600282613936565b90505b80600454611b3e9190613949565b3414611b9a5760405162461bcd60e51b815260206004820152602560248201527f506f736974696f6e4d616e616765723a20696e76616c696420657865637574696044820152646f6e46656560d81b6064820152608401610a1c565b611baa338989898989898961267e565b505060018055505050505050565b611c2060405180610160016040528060006001600160a01b031681526020016000151581526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b600a6000611c7085856040516bffffffffffffffffffffffff19606084901b1660208201526034810182905260009060540160405160208183030381529060405280519060200120905092915050565b8152602080820192909252604090810160002081516101608101835281546001600160a01b0381168252600160a01b900460ff161515938101939093526001810154918301919091526002810154606083015260038101546080830152600481015460a0830152600581015460c0830152600681015460e083015260078101546101008301526008810154610120830152600901546101408201529392505050565b60068181548110611d2257600080fd5b600091825260209091200154905081565b600260015403611d855760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a1c565b60026001556004543414611de95760405162461bcd60e51b815260206004820152602560248201527f506f736974696f6e4d616e616765723a20696e76616c696420657865637574696044820152646f6e46656560d81b6064820152608401610a1c565b611df63385858585612a69565b5050600180555050565b6000546001600160a01b03163314611e525760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a1c565b600f8210158015611e645750603c8211155b611eba5760405162461bcd60e51b815260206004820152602160248201527f506f736974696f6e4d616e616765723a20696e76616c6964206475726174696f6044820152603760f91b6064820152608401610a1c565b61012c811115611f165760405162461bcd60e51b815260206004820152602160248201527f506f736974696f6e4d616e616765723a20696e76616c6964206475726174696f6044820152603760f91b6064820152608401610a1c565b6002829055600381905560408051838152602081018390527ffc98b13136ef4ddc2d972a3a19201b9ffa00cebd341e5381ee06ed617a6297d69101611180565b6000546001600160a01b03163314611fa85760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a1c565b600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117825560405190917f91a8c1cc2d4a3bb60738481947a00cbb9899c822916694cf8bb1d68172fdcd5491a250565b6000546001600160a01b0316331461205a5760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a1c565b6001600160a01b0382166000818152600d6020908152604091829020805460ff191685151590811790915591519182527f8c2ff6748f99f65f4ebf8a1e973a289bad216c4d5b20fda1940d9e01118ae42a910160405180910390a25050565b60088181548110611d2257600080fd5b604051632b82db0d60e11b81526004810184905282151560248201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635705b61a90604401602060405180830381865afa158015612139573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215d9190613a06565b905082156121e057818111156121db5760405162461bcd60e51b815260206004820152602a60248201527f506f736974696f6e4d616e616765723a206c6f6e67203d3e20736c697070616760448201527f65206578636565646564000000000000000000000000000000000000000000006064820152608401610a1c565b61165d565b8181101561165d5760405162461bcd60e51b815260206004820152602b60248201527f506f736974696f6e4d616e616765723a2073686f7274203d3e20736c6970706160448201527f67652065786365656465640000000000000000000000000000000000000000006064820152608401610a1c565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156122a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122cb9190613a06565b6122d59190613936565b6040516001600160a01b03851660248201526044810182905290915061165d90859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152612c0c565b60055460065480821061236257505050565b8083111561236e578092505b828210156124e05760006006838154811061238b5761238b613a1f565b6000918252602090912001546040516301830d5f60e41b8152600481018290529091503090631830d5f090602401600060405180830381600087803b1580156123d357600080fd5b505af19250505080156123e4575060015b6124b1576123f0613a35565b806308c379a0036124745750612404613a51565b8061240f5750612476565b61241882612cf1565b6000828152600a6020526040908190205490516001600160a01b03909116907fcbcbe4acd0386acabd867b6d4bcf646526b9d0931e4dd69b059a54d9c282bb15906124669087908590613b2b565b60405180910390a2506124b1565b505b3d8080156124a0576040519150601f19603f3d011682016040523d82523d6000602084013e6124a5565b606091505b506124af82612cf1565b505b600683815481106124c4576124c4613a1f565b60009182526020822001556124d883613b44565b92505061236e565b5060055550565b6007546008548082106124f957505050565b80831115612505578092505b828210156126775760006008838154811061252257612522613a1f565b6000918252602090912001546040516302eed32760e51b8152600481018290529091503090635dda64e090602401600060405180830381600087803b15801561256a57600080fd5b505af192505050801561257b575060015b61264857612587613a35565b806308c379a00361260b575061259b613a51565b806125a6575061260d565b6125af82613186565b6000828152600c6020526040908190205490516001600160a01b03909116907f4d9305d9d9a1ba4872e8662ffc2378824f77df4194681e60ff1946f1533a153f906125fd9087908590613b2b565b60405180910390a250612648565b505b3d808015612637576040519150601f19603f3d011682016040523d82523d6000602084013e61263c565b606091505b5061264682613186565b505b6008838154811061265b5761265b613a1f565b600091825260208220015561266f83613b44565b925050612505565b5060075550565b60405163021707f360e41b81526004810186905260248101859052604481018790527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906321707f309060640160006040518083038186803b1580156126ec57600080fd5b505afa158015612700573d6000803e3d6000fd5b5050604051636519c9d560e01b8152600481018890526024810187905260448101899052600092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169150636519c9d590606401602060405180830381865afa15801561277a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061279e9190613a06565b905061281b89306305f5e1007f00000000000000000000000000000000000000000000000000000000000000006127d5868c613936565b6127df9190613949565b6127e99190613968565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016929190613379565b6001600160a01b0389166000908152600960205260408120805491600191906128448385613936565b90915550506040805160608c901b6bffffffffffffffffffffffff1916602080830191909152603480830185905283518084039091018152605490920190925280519101206040518061016001604052808c6001600160a01b031681526020018b151581526020018a815260200189815260200188815260200184815260200187815260200186815260200185815260200183815260200142815250600a600083815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548160ff02191690831515021790555060408201518160010155606082015181600201556080820151816003015560a0820151816004015560c0820151816005015560e0820151816006015561010082015181600701556101208201518160080155610140820151816009015590505060068190806001815401808255809150506001900390600052602060002001600090919091909150558a6001600160a01b03167f6544adbd090dec8a2b5f99e819a2e8f71db7ef1f32b575b4447ee458b391c8f18a8a8a878f8c8c8c8b42604051612a549a99989796959493929190998a5260208a019890985260408901969096526060880194909452911515608087015260a086015260c085015260e08401526101008301526101208201526101400190565b60405180910390a25050505050505050505050565b6001600160a01b0385166000908152600b6020526040812080549160019190612a928385613936565b909155505060408051606088811b6bffffffffffffffffffffffff191660208084019190915260348084018690528451808503909101815260548401808652815191830191909120610134850186526001600160a01b03808d168084528c151560748801818152609489018e815260b48a018e815260d48b018e815260f48c018e815242610114909d018d815260008a8152600c8d528f81209b518c5497511515600160a01b026001600160a81b03199098169a1699909917959095178a5592516001808b0191909155915160028a01555160038901559051600488015590516005909601959095556008805495860181559092527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee390930182905586518b81529384018a9052958301959095529181018690526080810185905260a0810192909252907f8269cf861978295ca1248832540c6dfb72961a0d5c0e0ce91242e0e8b53feacf9060c00160405180910390a250505050505050565b6000612c61826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166133b19092919063ffffffff16565b805190915015611aaa5780806020019051810190612c7f9190613b5d565b611aaa5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610a1c565b6000818152600a602090815260409182902082516101608101845281546001600160a01b038116808352600160a01b90910460ff161515938201939093526001820154938101939093526002810154606084015260038101546080840152600481015460a0840152600581015460c0840152600681015460e08401526007810154610100840152600881015461012084015260090154610140830152612d95575050565b612e1c81600001516305f5e1007f00000000000000000000000000000000000000000000000000000000000000008460a001518560600151612dd79190613936565b612de19190613949565b612deb9190613968565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691906133ca565b60045460e082015160009015612e3a57612e37600282613936565b90505b61010083015115612e5357612e50600282613936565b90505b8015612fbf5782516000906001600160a01b03166108fc612e748486613949565b6040516000818181858888f193505050503d8060008114612eb1576040519150601f19603f3d011682016040523d82523d6000602084013e612eb6565b606091505b5050905080612fbd5783516001600160a01b03167f2c0da876dc58358df21667a74f33f9ace39dadb7cb51b147d8957f8874db42b0612ef58486613949565b60405190815260200160405180910390a2600033612f138486613949565b604051600081818185875af1925050503d8060008114612f4f576040519150601f19603f3d011682016040523d82523d6000602084013e612f54565b606091505b5050905080612fbb5760405162461bcd60e51b815260206004820152602d60248201527f506f736974696f6e4d616e616765723a206661696c656420746f2073656e642060448201526c657865637574696f6e2066656560981b6064820152608401610a1c565b505b505b6000848152600a602052604080822080546001600160a81b0319168155600181018390556002810183905560038101839055600481018390556005810183905560068101839055600781018390556008810183905560090182905551339084908381818185875af1925050503d8060008114613057576040519150601f19603f3d011682016040523d82523d6000602084013e61305c565b606091505b50509050806130c35760405162461bcd60e51b815260206004820152602d60248201527f506f736974696f6e4d616e616765723a206661696c656420746f2073656e642060448201526c657865637574696f6e2066656560981b6064820152608401610a1c565b83600001516001600160a01b03167f8a7811729d375743691a44aa980ceddc3e670397b5047ed835683390094398ae8560400151866060015187608001518860a0015189602001518a60c001518b60e001518c61010001518d61012001518e610140015142613132919061398a565b604080519a8b5260208b0199909952978901969096526060880194909452911515608087015260a086015260c085015260e08401526101008301526101208201526101400160405180910390a25050505050565b6000818152600c6020908152604091829020825160e08101845281546001600160a01b038116808352600160a01b90910460ff161515938201939093526001820154938101939093526002810154606084015260038101546080840152600481015460a08401526005015460c08301526131fe575050565b6000828152600c602052604080822080546001600160a81b0319168155600181018390556002810183905560038101839055600480820184905560059091018390555490513391908381818185875af1925050503d806000811461327e576040519150601f19603f3d011682016040523d82523d6000602084013e613283565b606091505b50509050806132ea5760405162461bcd60e51b815260206004820152602d60248201527f506f736974696f6e4d616e616765723a206661696c656420746f2073656e642060448201526c657865637574696f6e2066656560981b6064820152608401610a1c565b81600001516001600160a01b03167fc242dc0064a2ce2d5200a7383305b19c42b24248a4910bfdb6fcdc440b6c791983604001518460600151856020015186608001518760a001518860c0015142613342919061398a565b604080519687526020870195909552921515858501526060850191909152608084015260a0830152519081900360c00190a2505050565b6040516001600160a01b038085166024830152831660448201526064810182905261165d9085906323b872dd60e01b90608401612304565b60606133c084846000856133fa565b90505b9392505050565b6040516001600160a01b038316602482015260448101829052611aaa90849063a9059cbb60e01b90606401612304565b6060824710156134725760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a1c565b6001600160a01b0385163b6134c95760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a1c565b600080866001600160a01b031685876040516134e59190613b7a565b60006040518083038185875af1925050503d8060008114613522576040519150601f19603f3d011682016040523d82523d6000602084013e613527565b606091505b5091509150613537828286613542565b979650505050505050565b606083156135515750816133c3565b8251156135615782518084602001fd5b8160405162461bcd60e51b8152600401610a1c9190613b96565b80356001600160a01b038116811461359257600080fd5b919050565b600080604083850312156135aa57600080fd5b6135b38361357b565b946020939093013593505050565b6000602082840312156135d357600080fd5b5035919050565b600080604083850312156135ed57600080fd5b50508035926020909101359150565b60006020828403121561360e57600080fd5b6133c38261357b565b634e487b7160e01b600052604160045260246000fd5b601f8201601f1916810167ffffffffffffffff8111828210171561365357613653613617565b6040525050565b600082601f83011261366b57600080fd5b8135602067ffffffffffffffff82111561368757613687613617565b8160051b60405161369a8383018261362d565b928352848101820192828101878511156136b357600080fd5b83870192505b848310156136d057823581529183019183016136b9565b509695505050505050565b600080600080608085870312156136f157600080fd5b843567ffffffffffffffff8082111561370957600080fd5b6137158883890161365a565b9550602087013591508082111561372b57600080fd5b506137388782880161365a565b949794965050505060408301359260600135919050565b60008060006060848603121561376457600080fd5b833567ffffffffffffffff8082111561377c57600080fd5b6137888783880161365a565b9450602086013591508082111561379e57600080fd5b506137ab8682870161365a565b925050604084013590509250925092565b80151581146137ca57600080fd5b50565b600080600080600080600060e0888a0312156137e857600080fd5b87356137f3816137bc565b9960208901359950604089013598606081013598506080810135975060a0810135965060c00135945092505050565b81516001600160a01b0316815261016081016020830151613847602084018215159052565b5060408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525061014080840151818401525092915050565b600080600080608085870312156138c457600080fd5b84356138cf816137bc565b966020860135965060408601359560600135945092505050565b600080604083850312156138fc57600080fd5b6139058361357b565b91506020830135613915816137bc565b809150509250929050565b634e487b7160e01b600052601160045260246000fd5b808201808211156109c8576109c8613920565b600081600019048311821515161561396357613963613920565b500290565b60008261398557634e487b7160e01b600052601260045260246000fd5b500490565b818103818111156109c8576109c8613920565b600081518084526020808501945080840160005b838110156139cd578151875295820195908201906001016139b1565b509495945050505050565b6040815260006139eb604083018561399d565b82810360208401526139fd818561399d565b95945050505050565b600060208284031215613a1857600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b600060033d1115613a4e5760046000803e5060005160e01c5b90565b600060443d1015613a5f5790565b6040516003193d81016004833e81513d67ffffffffffffffff8160248401118184111715613a8f57505050505090565b8285019150815181811115613aa75750505050505090565b843d8701016020828501011115613ac15750505050505090565b613ad06020828601018761362d565b509095945050505050565b60005b83811015613af6578181015183820152602001613ade565b50506000910152565b60008151808452613b17816020860160208601613adb565b601f01601f19169290920160200192915050565b8281526040602082015260006133c06040830184613aff565b600060018201613b5657613b56613920565b5060010190565b600060208284031215613b6f57600080fd5b81516133c3816137bc565b60008251613b8c818460208701613adb565b9190910192915050565b6020815260006133c36020830184613aff56fea26469706673582212208f4215fcf381d248b740b30b3d6c501b7448328d26213ef5b40806f984c6e64064736f6c634300081000330000000000000000000000009b6869733e4b2d1db6c1183dd7008136f6fa553c000000000000000000000000137de6b9f0b91f4ede8ffecec41cd91341ae5472000000000000000000000000736fdfbd8d7fdcf1440cc70a4372a297051b2ad00000000000000000000000002d6823fc318843265c3178c67a99c63acd0ec85b0000000000000000000000000000000000000000000000000de0b6b3a7640000
Deployed ByteCode
0x6080604052600436106102195760003560e01c80638af2bf571161011d578063b2016bd4116100b0578063d9567e871161007f578063dd68c1e211610064578063dd68c1e214610805578063e799c63e14610867578063f9b6117f1461088757600080fd5b8063d9567e87146107b6578063db53ec4f146107ef57600080fd5b8063b2016bd414610722578063cd7ea09514610756578063cfad57a214610776578063d1b9e8531461079657600080fd5b80639e89a8ba116100ec5780639e89a8ba146106af578063abca3de0146106c2578063ac69d957146106ef578063af90352b1461070f57600080fd5b80638af2bf57146106375780638f303b76146106645780639654e63a146106795780639cb324601461069957600080fd5b806336841616116101b05780635dda64e01161017f5780636ba42aaa116101645780636ba42aaa146105ad57806370e67e0d146105ed5780637dc0d1d01461060357600080fd5b80635dda64e014610559578063692058c21461057957600080fd5b806336841616146103b357806337a063d2146104845780633b8679fd146104a457806340e9903b1461054357600080fd5b80631eb98848116101ec5780631eb98848146103265780632288216014610346578063299c9d0914610366578063365d89151461039357600080fd5b806307bbe15a1461021e57806312d43a51146102a85780631830d5f0146102e05780631bb9e60f14610302575b600080fd5b34801561022a57600080fd5b5061023e610239366004613597565b6108bb565b60405161029f9190600060e0820190506001600160a01b03835116825260208301511515602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015292915050565b60405180910390f35b3480156102b457600080fd5b506000546102c8906001600160a01b031681565b6040516001600160a01b03909116815260200161029f565b3480156102ec57600080fd5b506103006102fb3660046135c1565b6109ce565b005b34801561030e57600080fd5b5061031860025481565b60405190815260200161029f565b34801561033257600080fd5b506103006103413660046135da565b6110f2565b34801561035257600080fd5b506103006103613660046135c1565b61118c565b34801561037257600080fd5b506103186103813660046135fc565b600b6020526000908152604090205481565b34801561039f57600080fd5b506103006103ae3660046136db565b61156c565b3480156103bf57600080fd5b506104276103ce3660046135c1565b600a6020526000908152604090208054600182015460028301546003840154600485015460058601546006870154600788015460088901546009909901546001600160a01b03891699600160a01b90990460ff1698908b565b604080516001600160a01b03909c168c5299151560208c0152988a01979097526060890195909552608088019390935260a087019190915260c086015260e08501526101008401526101208301526101408201526101600161029f565b34801561049057600080fd5b5061030061049f3660046135c1565b611663565b3480156104b057600080fd5b506105046104bf3660046135c1565b600c602052600090815260409020805460018201546002830154600384015460048501546005909501546001600160a01b03851695600160a01b90950460ff16949087565b604080516001600160a01b0390981688529515156020880152948601939093526060850191909152608084015260a083015260c082015260e00161029f565b34801561054f57600080fd5b5061031860045481565b34801561056557600080fd5b506103006105743660046135c1565b6116cf565b34801561058557600080fd5b506102c87f0000000000000000000000009b6869733e4b2d1db6c1183dd7008136f6fa553c81565b3480156105b957600080fd5b506105dd6105c83660046135fc565b600d6020526000908152604090205460ff1681565b604051901515815260200161029f565b3480156105f957600080fd5b5061031860035481565b34801561060f57600080fd5b506102c87f000000000000000000000000137de6b9f0b91f4ede8ffecec41cd91341ae547281565b34801561064357600080fd5b506103186106523660046135fc565b60096020526000908152604090205481565b34801561067057600080fd5b506105dd611982565b34801561068557600080fd5b5061030061069436600461374f565b61199f565b3480156106a557600080fd5b5061031860055481565b6103006106bd3660046137cd565b611aaf565b3480156106ce57600080fd5b506106e26106dd366004613597565b611bb8565b60405161029f9190613822565b3480156106fb57600080fd5b5061031861070a3660046135c1565b611d12565b61030061071d3660046138ae565b611d33565b34801561072e57600080fd5b506102c87f0000000000000000000000002d6823fc318843265c3178c67a99c63acd0ec85b81565b34801561076257600080fd5b506103006107713660046135da565b611e00565b34801561078257600080fd5b506103006107913660046135fc565b611f56565b3480156107a257600080fd5b506103006107b13660046138e9565b612008565b3480156107c257600080fd5b5060055460065460075460085460408051948552602085019390935291830152606082015260800161029f565b3480156107fb57600080fd5b5061031860075481565b34801561081157600080fd5b50610318610820366004613597565b6040516bffffffffffffffffffffffff19606084901b1660208201526034810182905260009060540160405160208183030381529060405280519060200120905092915050565b34801561087357600080fd5b506103186108823660046135c1565b6120b9565b34801561089357600080fd5b506102c87f000000000000000000000000736fdfbd8d7fdcf1440cc70a4372a297051b2ad081565b6109066040518060e0016040528060006001600160a01b0316815260200160001515815260200160008152602001600081526020016000815260200160008152602001600081525090565b600c600061095685856040516bffffffffffffffffffffffff19606084901b1660208201526034810182905260009060540160405160208183030381529060405280519060200120905092915050565b81526020808201929092526040908101600020815160e08101835281546001600160a01b0381168252600160a01b900460ff161515938101939093526001810154918301919091526002810154606083015260038101546080830152600481015460a08301526005015460c082015290505b92915050565b600260015403610a255760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b600260015533301480610a475750336000908152600d602052604090205460ff165b610a935760405162461bcd60e51b815260206004820152601a60248201527f506f736974696f6e4d616e616765723a20216578656375746f720000000000006044820152606401610a1c565b6000818152600a602090815260409182902082516101608101845281546001600160a01b038116808352600160a01b90910460ff161515938201939093526001820154938101939093526002810154606084015260038101546080840152600481015460a0840152600581015460c0840152600681015460e08401526007810154610100840152600881015461012084015260090154610140830152610b3957506110eb565b42600254826101400151610b4d9190613936565b11610ba85760405162461bcd60e51b815260206004820152602560248201527f506f736974696f6e4d616e616765723a20706f736974696f6e206861732065786044820152641c1a5c995960da1b6064820152608401610a1c565b610bbf816040015182602001518360c001516120c9565b610c627f0000000000000000000000009b6869733e4b2d1db6c1183dd7008136f6fa553c6305f5e1007f0000000000000000000000000000000000000000000000000de0b6b3a76400008460a001518560600151610c1d9190613936565b610c279190613949565b610c319190613968565b6001600160a01b037f0000000000000000000000002d6823fc318843265c3178c67a99c63acd0ec85b169190612256565b80516040808301516020840151606085015160808601519351639267fbbd60e01b81526001600160a01b03958616600482015260248101939093529015156044830152606482015260848101919091527f0000000000000000000000009b6869733e4b2d1db6c1183dd7008136f6fa553c90911690639267fbbd9060a401600060405180830381600087803b158015610cfa57600080fd5b505af1158015610d0e573d6000803e3d6000fd5b505060045460e08401516001935090915015610e1c577f000000000000000000000000736fdfbd8d7fdcf1440cc70a4372a297051b2ad06001600160a01b0316631844f44f8285600001518660200151876020015188604001516305f5e1008a608001518b60600151610d819190613949565b610d8b9190613968565b60e08b8101516040519189901b6001600160e01b03191682526001600160a01b03969096166004820152931515602485015291151560448401526064830152608482015260a481019190915260c4016000604051808303818588803b158015610df357600080fd5b505af1158015610e07573d6000803e3d6000fd5b5050505050600182610e199190613936565b91505b61010083015115610f1d577f000000000000000000000000736fdfbd8d7fdcf1440cc70a4372a297051b2ad06001600160a01b0316631844f44f828560000151866020015187602001511588604001516305f5e1008a608001518b60600151610e859190613949565b610e8f9190613968565b6101008b01516040516001600160e01b031960e08a901b1681526001600160a01b039096166004870152931515602486015291151560448501526064840152608483015260a482015260c4016000604051808303818588803b158015610ef457600080fd5b505af1158015610f08573d6000803e3d6000fd5b5050505050600182610f1a9190613936565b91505b6000848152600a6020526040812080546001600160a81b0319168155600181018290556002810182905560038101829055600481018290556005810182905560068101829055600781018290556008810182905560090181905532610f828484613949565b604051600081818185875af1925050503d8060008114610fbe576040519150601f19603f3d011682016040523d82523d6000602084013e610fc3565b606091505b505090508061102a5760405162461bcd60e51b815260206004820152602d60248201527f506f736974696f6e4d616e616765723a206661696c656420746f2073656e642060448201526c657865637574696f6e2066656560981b6064820152608401610a1c565b83600001516001600160a01b03167fc5b9318d477559e5a19fc064b667a7f44e91bd26a16bd850b8ca7e9fc9c2ad378560400151866060015187608001518860a0015189602001518a60c001518b60e001518c61010001518d61012001518e610140015142611099919061398a565b604080519a8b5260208b0199909952978901969096526060880194909452911515608087015260a086015260c085015260e08401526101008301526101208201526101400160405180910390a2505050505b5060018055565b6000546001600160a01b031633146111445760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a1c565b6005829055600781905560408051838152602081018390527fb7543daceab18d4df8f94a486d44ba4a593a9106e53abe0b85e15461d73827bb91015b60405180910390a15050565b6002600154036111de5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a1c565b600260018181556000838152600c6020908152604091829020825160e08101845281546001600160a01b038116808352600160a01b90910460ff16151593820193909352938101549284019290925292810154606083015260038101546080830152600481015460a08301526005015460c08201529033146112a25760405162461bcd60e51b815260206004820152601960248201527f506f736974696f6e4d616e616765723a20216163636f756e74000000000000006044820152606401610a1c565b426003548260c001516112b59190613936565b11156113295760405162461bcd60e51b815260206004820152602c60248201527f506f736974696f6e4d616e616765723a20636f6f6c646f776e20686173206e6f60448201527f74207061737365642079657400000000000000000000000000000000000000006064820152608401610a1c565b611341816040015182602001511583608001516120c9565b80516040808301516020840151606085015192516314d8353f60e01b81526001600160a01b03948516600482015260248101929092521515604482015260648101919091527f0000000000000000000000009b6869733e4b2d1db6c1183dd7008136f6fa553c909116906314d8353f90608401600060405180830381600087803b1580156113ce57600080fd5b505af11580156113e2573d6000803e3d6000fd5b5050506000838152600c602052604080822080546001600160a81b03191681556001810183905560028101839055600381018390556004808201849055600590910183905554905191925033915b60006040518083038185875af1925050503d806000811461146d576040519150601f19603f3d011682016040523d82523d6000602084013e611472565b606091505b50509050806114d95760405162461bcd60e51b815260206004820152602d60248201527f506f736974696f6e4d616e616765723a206661696c656420746f2073656e642060448201526c657865637574696f6e2066656560981b6064820152608401610a1c565b81600001516001600160a01b03167fd931167b93a7d82b94c5544ed2e7c0904e4a572acecca3c97ad6e441d43faa4e83604001518460600151856020015186608001518760a001518860c0015142611531919061398a565b604080519687526020870195909552921515858501526060850191909152608084015260a0830152519081900360c00190a250506001805550565b336000908152600d602052604090205460ff166115cb5760405162461bcd60e51b815260206004820152601860248201527f506f736974696f6e4d616e616765723a20214b656570657200000000000000006044820152606401610a1c565b604051630682f55760e51b81526001600160a01b037f000000000000000000000000137de6b9f0b91f4ede8ffecec41cd91341ae5472169063d05eaae09061161990879087906004016139d8565b600060405180830381600087803b15801561163357600080fd5b505af1158015611647573d6000803e3d6000fd5b5050505061165482612350565b61165d816124e7565b50505050565b6000546001600160a01b031633146116b55760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a1c565b670de0b6b3a76400008111156116ca57600080fd5b600455565b6002600154036117215760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a1c565b6002600155333014806117435750336000908152600d602052604090205460ff165b61178f5760405162461bcd60e51b815260206004820152601a60248201527f506f736974696f6e4d616e616765723a20216578656375746f720000000000006044820152606401610a1c565b6000818152600c6020908152604091829020825160e08101845281546001600160a01b038116808352600160a01b90910460ff161515938201939093526001820154938101939093526002810154606084015260038101546080840152600481015460a08401526005015460c083015261180957506110eb565b426002548260c0015161181c9190613936565b116118775760405162461bcd60e51b815260206004820152602560248201527f506f736974696f6e4d616e616765723a20706f736974696f6e206861732065786044820152641c1a5c995960da1b6064820152608401610a1c565b61188f816040015182602001511583608001516120c9565b80516040808301516020840151606085015192516314d8353f60e01b81526001600160a01b03948516600482015260248101929092521515604482015260648101919091527f0000000000000000000000009b6869733e4b2d1db6c1183dd7008136f6fa553c909116906314d8353f90608401600060405180830381600087803b15801561191c57600080fd5b505af1158015611930573d6000803e3d6000fd5b5050506000838152600c602052604080822080546001600160a81b0319168155600181018390556002810183905560038101839055600480820184905560059091018390555490519192503291611430565b600654600554600091118061199a5750600854600754105b905090565b336000908152600d602052604090205460ff166119fe5760405162461bcd60e51b815260206004820152601860248201527f506f736974696f6e4d616e616765723a20214b656570657200000000000000006044820152606401610a1c565b604051630682f55760e51b81526001600160a01b037f000000000000000000000000137de6b9f0b91f4ede8ffecec41cd91341ae5472169063d05eaae090611a4c90869086906004016139d8565b600060405180830381600087803b158015611a6657600080fd5b505af1158015611a7a573d6000803e3d6000fd5b50505050611a9481600554611a8f9190613936565b612350565b611aaa81600754611aa59190613936565b6124e7565b505050565b600260015403611b015760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a1c565b600260019081558215611b1c57611b19600282613936565b90505b8115611b3057611b2d600282613936565b90505b80600454611b3e9190613949565b3414611b9a5760405162461bcd60e51b815260206004820152602560248201527f506f736974696f6e4d616e616765723a20696e76616c696420657865637574696044820152646f6e46656560d81b6064820152608401610a1c565b611baa338989898989898961267e565b505060018055505050505050565b611c2060405180610160016040528060006001600160a01b031681526020016000151581526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b600a6000611c7085856040516bffffffffffffffffffffffff19606084901b1660208201526034810182905260009060540160405160208183030381529060405280519060200120905092915050565b8152602080820192909252604090810160002081516101608101835281546001600160a01b0381168252600160a01b900460ff161515938101939093526001810154918301919091526002810154606083015260038101546080830152600481015460a0830152600581015460c0830152600681015460e083015260078101546101008301526008810154610120830152600901546101408201529392505050565b60068181548110611d2257600080fd5b600091825260209091200154905081565b600260015403611d855760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a1c565b60026001556004543414611de95760405162461bcd60e51b815260206004820152602560248201527f506f736974696f6e4d616e616765723a20696e76616c696420657865637574696044820152646f6e46656560d81b6064820152608401610a1c565b611df63385858585612a69565b5050600180555050565b6000546001600160a01b03163314611e525760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a1c565b600f8210158015611e645750603c8211155b611eba5760405162461bcd60e51b815260206004820152602160248201527f506f736974696f6e4d616e616765723a20696e76616c6964206475726174696f6044820152603760f91b6064820152608401610a1c565b61012c811115611f165760405162461bcd60e51b815260206004820152602160248201527f506f736974696f6e4d616e616765723a20696e76616c6964206475726174696f6044820152603760f91b6064820152608401610a1c565b6002829055600381905560408051838152602081018390527ffc98b13136ef4ddc2d972a3a19201b9ffa00cebd341e5381ee06ed617a6297d69101611180565b6000546001600160a01b03163314611fa85760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a1c565b600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117825560405190917f91a8c1cc2d4a3bb60738481947a00cbb9899c822916694cf8bb1d68172fdcd5491a250565b6000546001600160a01b0316331461205a5760405162461bcd60e51b815260206004820152601560248201527423b7bb32b93730b136329d103337b93134b23232b760591b6044820152606401610a1c565b6001600160a01b0382166000818152600d6020908152604091829020805460ff191685151590811790915591519182527f8c2ff6748f99f65f4ebf8a1e973a289bad216c4d5b20fda1940d9e01118ae42a910160405180910390a25050565b60088181548110611d2257600080fd5b604051632b82db0d60e11b81526004810184905282151560248201526000907f000000000000000000000000137de6b9f0b91f4ede8ffecec41cd91341ae54726001600160a01b031690635705b61a90604401602060405180830381865afa158015612139573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215d9190613a06565b905082156121e057818111156121db5760405162461bcd60e51b815260206004820152602a60248201527f506f736974696f6e4d616e616765723a206c6f6e67203d3e20736c697070616760448201527f65206578636565646564000000000000000000000000000000000000000000006064820152608401610a1c565b61165d565b8181101561165d5760405162461bcd60e51b815260206004820152602b60248201527f506f736974696f6e4d616e616765723a2073686f7274203d3e20736c6970706160448201527f67652065786365656465640000000000000000000000000000000000000000006064820152608401610a1c565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa1580156122a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122cb9190613a06565b6122d59190613936565b6040516001600160a01b03851660248201526044810182905290915061165d90859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152612c0c565b60055460065480821061236257505050565b8083111561236e578092505b828210156124e05760006006838154811061238b5761238b613a1f565b6000918252602090912001546040516301830d5f60e41b8152600481018290529091503090631830d5f090602401600060405180830381600087803b1580156123d357600080fd5b505af19250505080156123e4575060015b6124b1576123f0613a35565b806308c379a0036124745750612404613a51565b8061240f5750612476565b61241882612cf1565b6000828152600a6020526040908190205490516001600160a01b03909116907fcbcbe4acd0386acabd867b6d4bcf646526b9d0931e4dd69b059a54d9c282bb15906124669087908590613b2b565b60405180910390a2506124b1565b505b3d8080156124a0576040519150601f19603f3d011682016040523d82523d6000602084013e6124a5565b606091505b506124af82612cf1565b505b600683815481106124c4576124c4613a1f565b60009182526020822001556124d883613b44565b92505061236e565b5060055550565b6007546008548082106124f957505050565b80831115612505578092505b828210156126775760006008838154811061252257612522613a1f565b6000918252602090912001546040516302eed32760e51b8152600481018290529091503090635dda64e090602401600060405180830381600087803b15801561256a57600080fd5b505af192505050801561257b575060015b61264857612587613a35565b806308c379a00361260b575061259b613a51565b806125a6575061260d565b6125af82613186565b6000828152600c6020526040908190205490516001600160a01b03909116907f4d9305d9d9a1ba4872e8662ffc2378824f77df4194681e60ff1946f1533a153f906125fd9087908590613b2b565b60405180910390a250612648565b505b3d808015612637576040519150601f19603f3d011682016040523d82523d6000602084013e61263c565b606091505b5061264682613186565b505b6008838154811061265b5761265b613a1f565b600091825260208220015561266f83613b44565b925050612505565b5060075550565b60405163021707f360e41b81526004810186905260248101859052604481018790527f0000000000000000000000009b6869733e4b2d1db6c1183dd7008136f6fa553c6001600160a01b0316906321707f309060640160006040518083038186803b1580156126ec57600080fd5b505afa158015612700573d6000803e3d6000fd5b5050604051636519c9d560e01b8152600481018890526024810187905260448101899052600092507f0000000000000000000000009b6869733e4b2d1db6c1183dd7008136f6fa553c6001600160a01b03169150636519c9d590606401602060405180830381865afa15801561277a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061279e9190613a06565b905061281b89306305f5e1007f0000000000000000000000000000000000000000000000000de0b6b3a76400006127d5868c613936565b6127df9190613949565b6127e99190613968565b6001600160a01b037f0000000000000000000000002d6823fc318843265c3178c67a99c63acd0ec85b16929190613379565b6001600160a01b0389166000908152600960205260408120805491600191906128448385613936565b90915550506040805160608c901b6bffffffffffffffffffffffff1916602080830191909152603480830185905283518084039091018152605490920190925280519101206040518061016001604052808c6001600160a01b031681526020018b151581526020018a815260200189815260200188815260200184815260200187815260200186815260200185815260200183815260200142815250600a600083815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548160ff02191690831515021790555060408201518160010155606082015181600201556080820151816003015560a0820151816004015560c0820151816005015560e0820151816006015561010082015181600701556101208201518160080155610140820151816009015590505060068190806001815401808255809150506001900390600052602060002001600090919091909150558a6001600160a01b03167f6544adbd090dec8a2b5f99e819a2e8f71db7ef1f32b575b4447ee458b391c8f18a8a8a878f8c8c8c8b42604051612a549a99989796959493929190998a5260208a019890985260408901969096526060880194909452911515608087015260a086015260c085015260e08401526101008301526101208201526101400190565b60405180910390a25050505050505050505050565b6001600160a01b0385166000908152600b6020526040812080549160019190612a928385613936565b909155505060408051606088811b6bffffffffffffffffffffffff191660208084019190915260348084018690528451808503909101815260548401808652815191830191909120610134850186526001600160a01b03808d168084528c151560748801818152609489018e815260b48a018e815260d48b018e815260f48c018e815242610114909d018d815260008a8152600c8d528f81209b518c5497511515600160a01b026001600160a81b03199098169a1699909917959095178a5592516001808b0191909155915160028a01555160038901559051600488015590516005909601959095556008805495860181559092527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee390930182905586518b81529384018a9052958301959095529181018690526080810185905260a0810192909252907f8269cf861978295ca1248832540c6dfb72961a0d5c0e0ce91242e0e8b53feacf9060c00160405180910390a250505050505050565b6000612c61826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166133b19092919063ffffffff16565b805190915015611aaa5780806020019051810190612c7f9190613b5d565b611aaa5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610a1c565b6000818152600a602090815260409182902082516101608101845281546001600160a01b038116808352600160a01b90910460ff161515938201939093526001820154938101939093526002810154606084015260038101546080840152600481015460a0840152600581015460c0840152600681015460e08401526007810154610100840152600881015461012084015260090154610140830152612d95575050565b612e1c81600001516305f5e1007f0000000000000000000000000000000000000000000000000de0b6b3a76400008460a001518560600151612dd79190613936565b612de19190613949565b612deb9190613968565b6001600160a01b037f0000000000000000000000002d6823fc318843265c3178c67a99c63acd0ec85b1691906133ca565b60045460e082015160009015612e3a57612e37600282613936565b90505b61010083015115612e5357612e50600282613936565b90505b8015612fbf5782516000906001600160a01b03166108fc612e748486613949565b6040516000818181858888f193505050503d8060008114612eb1576040519150601f19603f3d011682016040523d82523d6000602084013e612eb6565b606091505b5050905080612fbd5783516001600160a01b03167f2c0da876dc58358df21667a74f33f9ace39dadb7cb51b147d8957f8874db42b0612ef58486613949565b60405190815260200160405180910390a2600033612f138486613949565b604051600081818185875af1925050503d8060008114612f4f576040519150601f19603f3d011682016040523d82523d6000602084013e612f54565b606091505b5050905080612fbb5760405162461bcd60e51b815260206004820152602d60248201527f506f736974696f6e4d616e616765723a206661696c656420746f2073656e642060448201526c657865637574696f6e2066656560981b6064820152608401610a1c565b505b505b6000848152600a602052604080822080546001600160a81b0319168155600181018390556002810183905560038101839055600481018390556005810183905560068101839055600781018390556008810183905560090182905551339084908381818185875af1925050503d8060008114613057576040519150601f19603f3d011682016040523d82523d6000602084013e61305c565b606091505b50509050806130c35760405162461bcd60e51b815260206004820152602d60248201527f506f736974696f6e4d616e616765723a206661696c656420746f2073656e642060448201526c657865637574696f6e2066656560981b6064820152608401610a1c565b83600001516001600160a01b03167f8a7811729d375743691a44aa980ceddc3e670397b5047ed835683390094398ae8560400151866060015187608001518860a0015189602001518a60c001518b60e001518c61010001518d61012001518e610140015142613132919061398a565b604080519a8b5260208b0199909952978901969096526060880194909452911515608087015260a086015260c085015260e08401526101008301526101208201526101400160405180910390a25050505050565b6000818152600c6020908152604091829020825160e08101845281546001600160a01b038116808352600160a01b90910460ff161515938201939093526001820154938101939093526002810154606084015260038101546080840152600481015460a08401526005015460c08301526131fe575050565b6000828152600c602052604080822080546001600160a81b0319168155600181018390556002810183905560038101839055600480820184905560059091018390555490513391908381818185875af1925050503d806000811461327e576040519150601f19603f3d011682016040523d82523d6000602084013e613283565b606091505b50509050806132ea5760405162461bcd60e51b815260206004820152602d60248201527f506f736974696f6e4d616e616765723a206661696c656420746f2073656e642060448201526c657865637574696f6e2066656560981b6064820152608401610a1c565b81600001516001600160a01b03167fc242dc0064a2ce2d5200a7383305b19c42b24248a4910bfdb6fcdc440b6c791983604001518460600151856020015186608001518760a001518860c0015142613342919061398a565b604080519687526020870195909552921515858501526060850191909152608084015260a0830152519081900360c00190a2505050565b6040516001600160a01b038085166024830152831660448201526064810182905261165d9085906323b872dd60e01b90608401612304565b60606133c084846000856133fa565b90505b9392505050565b6040516001600160a01b038316602482015260448101829052611aaa90849063a9059cbb60e01b90606401612304565b6060824710156134725760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a1c565b6001600160a01b0385163b6134c95760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a1c565b600080866001600160a01b031685876040516134e59190613b7a565b60006040518083038185875af1925050503d8060008114613522576040519150601f19603f3d011682016040523d82523d6000602084013e613527565b606091505b5091509150613537828286613542565b979650505050505050565b606083156135515750816133c3565b8251156135615782518084602001fd5b8160405162461bcd60e51b8152600401610a1c9190613b96565b80356001600160a01b038116811461359257600080fd5b919050565b600080604083850312156135aa57600080fd5b6135b38361357b565b946020939093013593505050565b6000602082840312156135d357600080fd5b5035919050565b600080604083850312156135ed57600080fd5b50508035926020909101359150565b60006020828403121561360e57600080fd5b6133c38261357b565b634e487b7160e01b600052604160045260246000fd5b601f8201601f1916810167ffffffffffffffff8111828210171561365357613653613617565b6040525050565b600082601f83011261366b57600080fd5b8135602067ffffffffffffffff82111561368757613687613617565b8160051b60405161369a8383018261362d565b928352848101820192828101878511156136b357600080fd5b83870192505b848310156136d057823581529183019183016136b9565b509695505050505050565b600080600080608085870312156136f157600080fd5b843567ffffffffffffffff8082111561370957600080fd5b6137158883890161365a565b9550602087013591508082111561372b57600080fd5b506137388782880161365a565b949794965050505060408301359260600135919050565b60008060006060848603121561376457600080fd5b833567ffffffffffffffff8082111561377c57600080fd5b6137888783880161365a565b9450602086013591508082111561379e57600080fd5b506137ab8682870161365a565b925050604084013590509250925092565b80151581146137ca57600080fd5b50565b600080600080600080600060e0888a0312156137e857600080fd5b87356137f3816137bc565b9960208901359950604089013598606081013598506080810135975060a0810135965060c00135945092505050565b81516001600160a01b0316815261016081016020830151613847602084018215159052565b5060408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525061014080840151818401525092915050565b600080600080608085870312156138c457600080fd5b84356138cf816137bc565b966020860135965060408601359560600135945092505050565b600080604083850312156138fc57600080fd5b6139058361357b565b91506020830135613915816137bc565b809150509250929050565b634e487b7160e01b600052601160045260246000fd5b808201808211156109c8576109c8613920565b600081600019048311821515161561396357613963613920565b500290565b60008261398557634e487b7160e01b600052601260045260246000fd5b500490565b818103818111156109c8576109c8613920565b600081518084526020808501945080840160005b838110156139cd578151875295820195908201906001016139b1565b509495945050505050565b6040815260006139eb604083018561399d565b82810360208401526139fd818561399d565b95945050505050565b600060208284031215613a1857600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b600060033d1115613a4e5760046000803e5060005160e01c5b90565b600060443d1015613a5f5790565b6040516003193d81016004833e81513d67ffffffffffffffff8160248401118184111715613a8f57505050505090565b8285019150815181811115613aa75750505050505090565b843d8701016020828501011115613ac15750505050505090565b613ad06020828601018761362d565b509095945050505050565b60005b83811015613af6578181015183820152602001613ade565b50506000910152565b60008151808452613b17816020860160208601613adb565b601f01601f19169290920160200192915050565b8281526040602082015260006133c06040830184613aff565b600060018201613b5657613b56613920565b5060010190565b600060208284031215613b6f57600080fd5b81516133c3816137bc565b60008251613b8c818460208701613adb565b9190910192915050565b6020815260006133c36020830184613aff56fea26469706673582212208f4215fcf381d248b740b30b3d6c501b7448328d26213ef5b40806f984c6e64064736f6c63430008100033