Contract Overview
Balance:
0 ETH
ETH Value:
$0.00
My Name Tag:
Not Available
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
UniswapFarmV1Deployer
Compiler Version
v0.8.10+commit.fc410830
Contract Source Code (Solidity)
/** *Submitted for verification at Arbiscan.io on 2022-10-27 */ // File: @openzeppelin/contracts/proxy/Clones.sol // OpenZeppelin Contracts (last updated v4.7.0) (proxy/Clones.sol) pragma solidity ^0.8.0; /** * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for * deploying minimal proxy contracts, also known as "clones". * * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies * > a minimal bytecode implementation that delegates all calls to a known, fixed address. * * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the * deterministic method. * * _Available since v3.4._ */ library Clones { /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create opcode, which should never revert. */ function clone(address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, implementation)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) instance := create(0, ptr, 0x37) } require(instance != address(0), "ERC1167: create failed"); } /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create2 opcode and a `salt` to deterministically deploy * the clone. Using the same `implementation` and `salt` multiple time will revert, since * the clones cannot be deployed twice at the same address. */ function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, implementation)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) instance := create2(0, ptr, 0x37, salt) } require(instance != address(0), "ERC1167: create2 failed"); } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, implementation)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000) mstore(add(ptr, 0x38), shl(0x60, deployer)) mstore(add(ptr, 0x4c), salt) mstore(add(ptr, 0x6c), keccak256(ptr, 0x37)) predicted := keccak256(add(ptr, 0x37), 0x55) } } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress(address implementation, bytes32 salt) internal view returns (address predicted) { return predictDeterministicAddress(implementation, salt, address(this)); } } // File: @openzeppelin/contracts/utils/introspection/IERC165.sol // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } // File: @openzeppelin/contracts/token/ERC721/IERC721.sol // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); } // File: interfaces/UniswapV3.sol pragma solidity 0.8.10; /// @title Non-fungible token for positions /// @notice Wraps Uniswap V3 positions in a non-fungible token interface which allows for them to be transferred /// and authorized. interface IPoolInitializer { /// @notice Creates a new pool if it does not exist, then initializes if not initialized /// @dev This method can be bundled with others via IMulticall for the first action (e.g. mint) performed against a pool /// @param token0 The contract address of token0 of the pool /// @param token1 The contract address of token1 of the pool /// @param fee The fee amount of the v3 pool for the specified token pair /// @param sqrtPriceX96 The initial square root price of the pool as a Q64.96 value /// @return pool Returns the pool address based on the pair of tokens and fee, will return the newly created pool address if necessary function createAndInitializePoolIfNecessary( address token0, address token1, uint24 fee, uint160 sqrtPriceX96 ) external payable returns (address pool); } interface INFPM is IPoolInitializer, IERC721 { struct MintParams { address token0; address token1; uint24 fee; int24 tickLower; int24 tickUpper; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; address recipient; uint256 deadline; } /// @notice Creates a new position wrapped in a NFT /// @dev Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized /// a method does not exist, i.e. the pool is assumed to be initialized. /// @param params The params necessary to mint a position, encoded as `MintParams` in calldata /// @return tokenId The ID of the token that represents the minted position /// @return liquidity The amount of liquidity for this position /// @return amount0 The amount of token0 /// @return amount1 The amount of token1 function mint(MintParams calldata params) external payable returns ( uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1 ); /// @notice Returns the position information associated with a given token ID. /// @dev Throws if the token ID is not valid. /// @param tokenId The ID of the token that represents the position /// @return nonce The nonce for permits /// @return operator The address that is approved for spending /// @return token0 The address of the token0 for a specific pool /// @return token1 The address of the token1 for a specific pool /// @return fee The fee associated with the pool /// @return tickLower The lower end of the tick range for the position /// @return tickUpper The higher end of the tick range for the position /// @return liquidity The liquidity of the position /// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position /// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position /// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation /// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation function positions(uint256 tokenId) external view returns ( uint96 nonce, address operator, address token0, address token1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1 ); } interface IUniswapV3Factory { /// @notice Returns the pool address for a given pair of tokens and a fee, or address 0 if it does not exist /// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order /// @param tokenA The contract address of either token0 or token1 /// @param tokenB The contract address of the other token /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip /// @return pool The pool address function getPool( address tokenA, address tokenB, uint24 fee ) external view returns (address pool); } interface IUniswapV3TickSpacing { function tickSpacing() external view returns (int24); } // File: @openzeppelin/contracts/security/ReentrancyGuard.sol // 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; } } // File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); } // File: @openzeppelin/contracts/utils/Context.sol // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } } // File: @openzeppelin/contracts/access/Ownable.sol // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } } // File: @openzeppelin/contracts/utils/Address.sol // 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); } } } } // File: @openzeppelin/contracts/proxy/utils/Initializable.sol // OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original * initialization step. This is essential to configure modules that are added through upgrades and that require * initialization. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } } // File: @openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol // 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); } // File: @openzeppelin/contracts/token/ERC20/IERC20.sol // 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); } // File: @openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; /** * @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"); } } } // File: contracts/UniswapFarmV1.sol pragma solidity 0.8.10; //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@// //@@@@@@@@&....(@@@@@@@@@@@@@..../@@@@@@@@@// //@@@@@@........../@@@@@@@........../@@@@@@// //@@@@@............(@@@@@............(@@@@@// //@@@@@(............@@@@@(...........&@@@@@// //@@@@@@@...........&@@@@@@.........@@@@@@@// //@@@@@@@@@@@@@@%..../@@@@@@@@@@@@@@@@@@@@@// //@@@@@@@@@@@@@@@@@@@...@@@@@@@@@@@@@@@@@@@// //@@@@@@@@@@@@@@@@@@@@@......(&@@@@@@@@@@@@// //@@@@@@#.........@@@@@@#...........@@@@@@@// //@@@@@/...........%@@@@@............%@@@@@// //@@@@@............#@@@@@............%@@@@@// //@@@@@@..........#@@@@@@@/.........#@@@@@@// //@@@@@@@@@&/.(@@@@@@@@@@@@@@&/.(&@@@@@@@@@// //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@// // Defines the Uniswap pool init data for constructor. // tokenA - Address of tokenA // tokenB - Address of tokenB // feeTier - Fee tier for the Uniswap pool // tickLowerAllowed - Lower bound of the tick range for farm // tickUpperAllowed - Upper bound of the tick range for farm struct UniswapPoolData { address tokenA; address tokenB; uint24 feeTier; int24 tickLowerAllowed; int24 tickUpperAllowed; } // Defines the reward data for constructor. // token - Address of the token // tknManager - Authority to update rewardToken related Params. struct RewardTokenData { address token; address tknManager; } contract UniswapFarmV1 is Ownable, ReentrancyGuard, Initializable, IERC721Receiver { using SafeERC20 for IERC20; // Defines the reward funds for the farm // totalLiquidity - amount of liquidity sharing the rewards in the fund // rewardsPerSec - the emission rate of the fund // accRewardPerShare - the accumulated reward per share struct RewardFund { uint256 totalLiquidity; uint256[] rewardsPerSec; uint256[] accRewardPerShare; } // Keeps track of a deposit's share in a reward fund. // fund id - id of the subscribed reward fund // rewardDebt - rewards claimed for a deposit corresponding to // latest accRewardPerShare value of the budget // rewardClaimed - rewards claimed for a deposit from the reward fund struct Subscription { uint8 fundId; uint256[] rewardDebt; uint256[] rewardClaimed; } // Deposit information // locked - determines if the deposit is locked or not // liquidity - amount of liquidity in the deposit // tokenId - maps to uniswap NFT token id // startTime - time of deposit // expiryDate - expiry time (if deposit is locked) // totalRewardsClaimed - total rewards claimed for the deposit struct Deposit { bool locked; uint256 liquidity; uint256 tokenId; uint256 startTime; uint256 expiryDate; uint256[] totalRewardsClaimed; } // Reward token related information // tknManager Address that manages the rewardToken. // accRewardBal The rewards accrued but pending to be claimed. struct RewardData { address tknManager; uint8 id; uint256 accRewardBal; } // constants address public constant SPA = 0x5575552988A3A80504bBaeB1311674fCFd40aD4B; address public constant SPA_TOKEN_MANAGER = 0x6d5240f086637fb408c7F727010A10cf57D51B62; address public constant NFPM = 0xC36442b4a4522E871399CD717aBDD847Ab11FE88; address public constant UNIV3_FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984; uint8 public constant COMMON_FUND_ID = 0; uint8 public constant LOCKUP_FUND_ID = 1; uint256 public constant PREC = 1e18; uint256 public constant MIN_COOLDOWN_PERIOD = 1; // In days uint256 public constant MAX_NUM_REWARDS = 4; // Global Params bool public isPaused; bool public isClosed; // UniswapV3 params int24 public tickLowerAllowed; int24 public tickUpperAllowed; address public uniswapPool; uint256 public cooldownPeriod; uint256 public lastFundUpdateTime; uint256 public farmStartTime; // Reward info RewardFund[] public rewardFunds; address[] public rewardTokens; mapping(address => RewardData) public rewardData; mapping(address => Deposit[]) public deposits; mapping(uint256 => Subscription[]) public subscriptions; event Deposited( address indexed account, bool locked, uint256 tokenId, uint256 liquidity ); event CooldownInitiated( address indexed account, uint256 tokenId, uint256 expiryDate ); event DepositWithdrawn( address indexed account, uint256 tokenId, uint256 startTime, uint256 liquidity, uint256[] totalRewardsClaimed ); event RewardsClaimed( address indexed account, uint8 fundId, uint256 tokenId, uint256 liquidity, uint256 fundLiquidity, uint256[] rewardAmount ); event PoolUnsubscribed( address indexed account, uint8 fundId, uint256 depositId, uint256 startTime, uint256[] totalRewardsClaimed ); event FarmStartTimeUpdated(uint256 newStartTime); event CooldownPeriodUpdated( uint256 oldCooldownPeriod, uint256 newCooldownPeriod ); event RewardRateUpdated( address rwdToken, uint256[] oldRewardRate, uint256[] newRewardRate ); event RewardAdded(address rwdToken, uint256 amount); event FarmClosed(); event RecoveredERC20(address token, uint256 amount); event FundsRecovered( address indexed account, address rwdToken, uint256 amount ); event TokenManagerUpdated( address rwdToken, address oldTokenManager, address newTokenManager ); event RewardTokenAdded(address rwdToken, address rwdTokenManager); event FarmPaused(bool paused); modifier notPaused() { require(!isPaused, "Farm is paused"); _; } modifier farmNotClosed() { require(!isClosed, "Farm closed"); _; } modifier isTokenManager(address _rwdToken) { require( msg.sender == rewardData[_rwdToken].tknManager, "Not the token manager" ); _; } // Disallow initialization of a implementation contract constructor() { _disableInitializers(); } /// @notice constructor /// @param _farmStartTime - time of farm start /// @param _cooldownPeriod - cooldown period for locked deposits in days /// @dev _cooldownPeriod = 0 Disables lockup functionality for the farm. /// @param _uniswapPoolData - init data for UniswapV3 pool /// @param _rwdTokenData - init data for reward tokens function initialize( uint256 _farmStartTime, uint256 _cooldownPeriod, UniswapPoolData memory _uniswapPoolData, RewardTokenData[] memory _rwdTokenData ) external initializer { require(_farmStartTime >= block.timestamp, "Invalid farm startTime"); _transferOwnership(msg.sender); // Initialize farm global params lastFundUpdateTime = _farmStartTime; farmStartTime = _farmStartTime; isPaused = false; isClosed = false; // initialize uniswap related data uniswapPool = IUniswapV3Factory(UNIV3_FACTORY).getPool( _uniswapPoolData.tokenB, _uniswapPoolData.tokenA, _uniswapPoolData.feeTier ); require(uniswapPool != address(0), "Invalid uniswap pool config"); _validateTickRange( _uniswapPoolData.tickLowerAllowed, _uniswapPoolData.tickUpperAllowed ); tickLowerAllowed = _uniswapPoolData.tickLowerAllowed; tickUpperAllowed = _uniswapPoolData.tickUpperAllowed; // Check for lockup functionality // @dev If _cooldownPeriod is 0, then the lockup functionality is disabled for // the farm. uint8 numFunds = 1; if (_cooldownPeriod > 0) { require( _cooldownPeriod > MIN_COOLDOWN_PERIOD, "Cooldown < MinCooldownPeriod" ); cooldownPeriod = _cooldownPeriod; numFunds = 2; } _setupFarm(numFunds, _rwdTokenData); } /// @notice Function is called when user transfers the NFT to the contract. /// @param _from The address of the owner. /// @param _tokenId nft Id generated by uniswap v3. /// @param _data The data should be the lockup flag (bool). function onERC721Received( address, // unused variable. not named address _from, uint256 _tokenId, bytes calldata _data ) external override notPaused returns (bytes4) { require(msg.sender == NFPM, "onERC721Received: not a univ3 nft"); require(_data.length > 0, "onERC721Received: no data"); bool lockup = abi.decode(_data, (bool)); if (cooldownPeriod == 0) { require(!lockup, "Lockup functionality is disabled"); } // update the reward funds _updateFarmRewardData(); // Validate the position and get the liquidity uint256 liquidity = _getLiquidity(_tokenId); // Prepare data to be stored. Deposit memory userDeposit = Deposit({ locked: lockup, tokenId: _tokenId, startTime: block.timestamp, expiryDate: 0, totalRewardsClaimed: new uint256[](rewardTokens.length), liquidity: liquidity }); // @dev Add the deposit to the user's deposit list deposits[_from].push(userDeposit); // Add common fund subscription to the user's deposit _subscribeRewardFund(COMMON_FUND_ID, _tokenId, liquidity); if (lockup) { // Add lockup fund subscription to the user's deposit _subscribeRewardFund(LOCKUP_FUND_ID, _tokenId, liquidity); } emit Deposited(_from, lockup, _tokenId, liquidity); return this.onERC721Received.selector; } /// @notice Function to lock a staked deposit /// @param _depositId The id of the deposit to be locked /// @dev _depositId is corresponding to the user's deposit function initiateCooldown(uint256 _depositId) external notPaused nonReentrant { address account = msg.sender; _isValidDeposit(account, _depositId); Deposit storage userDeposit = deposits[account][_depositId]; // validate if the deposit is in locked state require(userDeposit.locked, "Can not initiate cooldown"); // update the deposit expiry time & lock status userDeposit.expiryDate = block.timestamp + (cooldownPeriod * 1 days); userDeposit.locked = false; // claim the pending rewards for the user _claimRewards(account, _depositId); // Unsubscribe the deposit from the lockup reward fund _unsubscribeRewardFund(LOCKUP_FUND_ID, account, _depositId); emit CooldownInitiated( account, userDeposit.tokenId, userDeposit.expiryDate ); } /// @notice Function to withdraw a deposit from the farm. /// @param _depositId The id of the deposit to be withdrawn function withdraw(uint256 _depositId) external nonReentrant { address account = msg.sender; _isValidDeposit(account, _depositId); Deposit memory userDeposit = deposits[account][_depositId]; // Check for the withdrawal criteria // Note: If farm is paused, skip the cooldown check if (!isPaused) { require(!userDeposit.locked, "Please initiate cooldown"); if (userDeposit.expiryDate > 0) { // Cooldown is initiated for the user require( userDeposit.expiryDate <= block.timestamp, "Deposit is in cooldown" ); } } // Compute the user's unclaimed rewards _claimRewards(account, _depositId); // Store the total rewards earned uint256[] memory totalRewards = deposits[account][_depositId] .totalRewardsClaimed; // unsubscribe the user from the common reward fund _unsubscribeRewardFund(COMMON_FUND_ID, account, _depositId); if (subscriptions[userDeposit.tokenId].length > 0) { // To handle a lockup withdraw without cooldown (during farmPause) _unsubscribeRewardFund(LOCKUP_FUND_ID, account, _depositId); } // Update the user's deposit list deposits[account][_depositId] = deposits[account][ deposits[account].length - 1 ]; deposits[account].pop(); // Transfer the nft back to the user. INFPM(NFPM).safeTransferFrom( address(this), account, userDeposit.tokenId ); emit DepositWithdrawn( account, userDeposit.tokenId, userDeposit.startTime, userDeposit.liquidity, totalRewards ); } /// @notice Claim rewards for the user. /// @param _account The user's address /// @param _depositId The id of the deposit /// @dev Anyone can call this function to claim rewards for the user function claimRewards(address _account, uint256 _depositId) external farmNotClosed nonReentrant { _isValidDeposit(_account, _depositId); _claimRewards(_account, _depositId); } /// @notice Claim rewards for the user. /// @param _depositId The id of the deposit function claimRewards(uint256 _depositId) external farmNotClosed nonReentrant { address account = msg.sender; _isValidDeposit(account, _depositId); _claimRewards(account, _depositId); } /// @notice Add rewards to the farm. /// @param _rwdToken the reward token's address. /// @param _amount the amount of reward tokens to add. function addRewards(address _rwdToken, uint256 _amount) external nonReentrant { require( rewardData[_rwdToken].tknManager != address(0), "Invalid reward token" ); _updateFarmRewardData(); IERC20(_rwdToken).safeTransferFrom(msg.sender, address(this), _amount); emit RewardAdded(_rwdToken, _amount); } // --------------------- Admin Functions --------------------- /// @notice Update the cooldown period /// @param _newCooldownPeriod The new cooldown period (in days) function updateCooldownPeriod(uint256 _newCooldownPeriod) external onlyOwner { require(cooldownPeriod != 0, "Farm does not support lockup"); require( _newCooldownPeriod > MIN_COOLDOWN_PERIOD, "Cooldown period too low" ); emit CooldownPeriodUpdated(cooldownPeriod, _newCooldownPeriod); cooldownPeriod = _newCooldownPeriod; } /// @notice Update the farm start time. /// @dev Can be updated only before the farm start /// New start time should be in future. /// @param _newStartTime The new farm start time. function updateFarmStartTime(uint256 _newStartTime) external onlyOwner { require(block.timestamp < farmStartTime, "Farm already started"); require(_newStartTime >= block.timestamp, "Time < now"); farmStartTime = _newStartTime; lastFundUpdateTime = _newStartTime; emit FarmStartTimeUpdated(_newStartTime); } /// @notice Pause / UnPause the deposit function farmPauseSwitch(bool _isPaused) external onlyOwner farmNotClosed { require(isPaused != _isPaused, "Farm already in required state"); _updateFarmRewardData(); isPaused = _isPaused; emit FarmPaused(isPaused); } /// @notice Recover rewardToken from the farm in case of EMERGENCY /// @dev Shuts down the farm completely function closeFarm() external onlyOwner nonReentrant { _updateFarmRewardData(); cooldownPeriod = 0; isPaused = true; isClosed = true; for (uint8 iRwd = 0; iRwd < rewardTokens.length; ++iRwd) { _recoverRewardFunds(rewardTokens[iRwd], type(uint256).max); } emit FarmClosed(); } /// @notice Recover erc20 tokens other than the reward Tokens. /// @param _token Address of token to be recovered function recoverERC20(address _token) external onlyOwner nonReentrant { require( rewardData[_token].tknManager == address(0), "Can't withdraw rewardToken" ); uint256 balance = IERC20(_token).balanceOf(address(this)); require(balance > 0, "Can't withdraw 0 amount"); IERC20(_token).safeTransfer(owner(), balance); emit RecoveredERC20(_token, balance); } // --------------------- Token Manager Functions --------------------- /// @notice Get the remaining balance out of the farm /// @param _rwdToken The reward token's address /// @param _amount The amount of the reward token to be withdrawn /// @dev Function recovers minOf(_amount, rewardsLeft) function recoverRewardFunds(address _rwdToken, uint256 _amount) external isTokenManager(_rwdToken) nonReentrant { _updateFarmRewardData(); _recoverRewardFunds(_rwdToken, _amount); } /// @notice Function to update reward params for a fund. /// @param _rwdToken The reward token's address /// @param _newRewardRates The new reward rate for the fund (includes the precision) function setRewardRate(address _rwdToken, uint256[] memory _newRewardRates) external isTokenManager(_rwdToken) { _updateFarmRewardData(); _setRewardRate(_rwdToken, _newRewardRates); } /// @notice Transfer the tokenManagerRole to other user. /// @dev Only the existing tokenManager for a reward can call this function. /// @param _rwdToken The reward token's address. /// @param _newTknManager Address of the new token manager. function updateTokenManager(address _rwdToken, address _newTknManager) external isTokenManager(_rwdToken) { _isNonZeroAddr(_newTknManager); rewardData[_rwdToken].tknManager = _newTknManager; emit TokenManagerUpdated(_rwdToken, msg.sender, _newTknManager); } /// @notice Function to compute the total accrued rewards for a deposit /// @param _account The user's address /// @param _depositId The id of the deposit /// @return rewards The total accrued rewards for the deposit (uint256[]) function computeRewards(address _account, uint256 _depositId) external view returns (uint256[] memory rewards) { _isValidDeposit(_account, _depositId); Deposit memory userDeposit = deposits[_account][_depositId]; Subscription[] memory depositSubs = subscriptions[userDeposit.tokenId]; RewardFund[] memory funds = rewardFunds; uint256 numRewards = rewardTokens.length; rewards = new uint256[](numRewards); uint256 time = 0; // In case the reward is not updated if (block.timestamp > lastFundUpdateTime) { time = block.timestamp - lastFundUpdateTime; } // Update the two reward funds. for (uint8 iSub = 0; iSub < depositSubs.length; ++iSub) { uint8 fundId = depositSubs[iSub].fundId; for (uint8 iRwd = 0; iRwd < numRewards; ++iRwd) { if (funds[fundId].totalLiquidity > 0) { uint256 accRewards = _getAccRewards(iRwd, fundId, time); // update the accRewardPerShare for delta time. funds[fundId].accRewardPerShare[iRwd] += (accRewards * PREC) / funds[fundId].totalLiquidity; } rewards[iRwd] += ((userDeposit.liquidity * funds[fundId].accRewardPerShare[iRwd]) / PREC) - depositSubs[iSub].rewardDebt[iRwd]; } } return rewards; } /// @notice get number of deposits for an account /// @param _account The user's address function getNumDeposits(address _account) external view returns (uint256) { return deposits[_account].length; } /// @notice get deposit info for an account /// @notice _account The user's address /// @notice _depositId The id of the deposit function getDeposit(address _account, uint256 _depositId) external view returns (Deposit memory) { return deposits[_account][_depositId]; } /// @notice get number of deposits for an account /// @param _tokenId The token's id function getNumSubscriptions(uint256 _tokenId) external view returns (uint256) { return subscriptions[_tokenId].length; } /// @notice get subscription stats for a deposit. /// @param _tokenId The token's id /// @param _subscriptionId The subscription's id function getSubscriptionInfo(uint256 _tokenId, uint256 _subscriptionId) external view returns (Subscription memory) { require( _subscriptionId < subscriptions[_tokenId].length, "Subscription does not exist" ); return subscriptions[_tokenId][_subscriptionId]; } /// @notice get reward rates for a rewardToken. /// @param _rwdToken The reward token's address /// @return The reward rates for the reward token (uint256[]) function getRewardRates(address _rwdToken) external view returns (uint256[] memory) { uint256 numFunds = rewardFunds.length; uint256[] memory rates = new uint256[](numFunds); uint8 id = rewardData[_rwdToken].id; for (uint8 iFund = 0; iFund < numFunds; ++iFund) { rates[iFund] = rewardFunds[iFund].rewardsPerSec[id]; } return rates; } /// @notice Get list of reward tokens. /// @return The list of reward tokens. function getRewardTokens() external view returns (address[] memory) { return rewardTokens; } /// @notice get farm reward fund info. /// @param _fundId The fund's id function getRewardFundInfo(uint8 _fundId) external view returns (RewardFund memory) { require(_fundId < rewardFunds.length, "Reward fund does not exist"); return rewardFunds[_fundId]; } /// @notice Get the remaining reward balance for the farm. /// @param _rwdToken The reward token's address function getRewardBalance(address _rwdToken) public view returns (uint256) { uint256 rwdId = rewardData[_rwdToken].id; require(rewardTokens[rwdId] == _rwdToken, "Invalid _rwdToken"); uint256 numFunds = rewardFunds.length; uint256 rewardsAcc = rewardData[_rwdToken].accRewardBal; uint256 supply = IERC20(_rwdToken).balanceOf(address(this)); if (block.timestamp > lastFundUpdateTime) { uint256 time = block.timestamp - lastFundUpdateTime; // Compute the accrued reward balance for time for (uint8 iFund = 0; iFund < numFunds; ++iFund) { if (rewardFunds[iFund].totalLiquidity > 0) { rewardsAcc += rewardFunds[iFund].rewardsPerSec[rwdId] * time; } } } if (rewardsAcc >= supply) { return 0; } return (supply - rewardsAcc); } /// @notice Claim rewards for the user. /// @param _account The user's address /// @param _depositId The id of the deposit /// @dev NOTE: any function calling this private /// function should be marked as non-reentrant function _claimRewards(address _account, uint256 _depositId) private { _updateFarmRewardData(); Deposit storage userDeposit = deposits[_account][_depositId]; Subscription[] storage depositSubs = subscriptions[userDeposit.tokenId]; uint256 numRewards = rewardTokens.length; uint256 numSubs = depositSubs.length; uint256[] memory totalRewards = new uint256[](numRewards); // Compute the rewards for each subscription. for (uint8 iSub = 0; iSub < numSubs; ++iSub) { uint8 fundId = depositSubs[iSub].fundId; uint256[] memory rewards = new uint256[](numRewards); for (uint256 iRwd = 0; iRwd < numRewards; ++iRwd) { // rewards = (liquidity * accRewardPerShare) / PREC - rewardDebt uint256 accRewards = (userDeposit.liquidity * rewardFunds[fundId].accRewardPerShare[iRwd]) / PREC; rewards[iRwd] = accRewards - depositSubs[iSub].rewardDebt[iRwd]; depositSubs[iSub].rewardClaimed[iRwd] += rewards[iRwd]; totalRewards[iRwd] += rewards[iRwd]; // Update userRewardDebt for the subscriptions // rewardDebt = liquidity * accRewardPerShare depositSubs[iSub].rewardDebt[iRwd] = accRewards; } emit RewardsClaimed( _account, fundId, userDeposit.tokenId, userDeposit.liquidity, rewardFunds[fundId].totalLiquidity, rewards ); } // Transfer the claimed rewards to the User if any. for (uint8 iRwd = 0; iRwd < numRewards; ++iRwd) { if (totalRewards[iRwd] > 0) { rewardData[rewardTokens[iRwd]].accRewardBal -= totalRewards[ iRwd ]; // Update the total rewards earned for the deposit userDeposit.totalRewardsClaimed[iRwd] += totalRewards[iRwd]; IERC20(rewardTokens[iRwd]).safeTransfer( _account, totalRewards[iRwd] ); } } } /// @notice Get the remaining balance out of the farm /// @param _rwdToken The reward token's address /// @param _amount The amount of the reward token to be withdrawn /// @dev Function recovers minOf(_amount, rewardsLeft) /// @dev In case of partial withdraw of funds, the reward rate has to be set manually again. function _recoverRewardFunds(address _rwdToken, uint256 _amount) private { address emergencyRet = rewardData[_rwdToken].tknManager; uint256 rewardsLeft = getRewardBalance(_rwdToken); uint256 amountToRecover = _amount; if (_amount >= rewardsLeft) { amountToRecover = rewardsLeft; } if (amountToRecover > 0) { IERC20(_rwdToken).safeTransfer(emergencyRet, amountToRecover); emit FundsRecovered(emergencyRet, _rwdToken, amountToRecover); } } /// @notice Function to update reward params for a fund. /// @param _rwdToken The reward token's address /// @param _newRewardRates The new reward rate for the fund (includes the precision) function _setRewardRate(address _rwdToken, uint256[] memory _newRewardRates) private { uint8 id = rewardData[_rwdToken].id; uint256 numFunds = rewardFunds.length; require( _newRewardRates.length == numFunds, "Invalid reward rates length" ); uint256[] memory oldRewardRates = new uint256[](numFunds); // Update the reward rate for (uint8 iFund = 0; iFund < numFunds; ++iFund) { oldRewardRates[iFund] = rewardFunds[iFund].rewardsPerSec[id]; rewardFunds[iFund].rewardsPerSec[id] = _newRewardRates[iFund]; } emit RewardRateUpdated(_rwdToken, oldRewardRates, _newRewardRates); } /// @notice Add subscription to the reward fund for a deposit /// @param _tokenId The tokenId of the deposit /// @param _fundId The reward fund id /// @param _liquidity The liquidity of the deposit function _subscribeRewardFund( uint8 _fundId, uint256 _tokenId, uint256 _liquidity ) private { require(_fundId < rewardFunds.length, "Invalid fund id"); // Subscribe to the reward fund uint256 numRewards = rewardTokens.length; subscriptions[_tokenId].push( Subscription({ fundId: _fundId, rewardDebt: new uint256[](numRewards), rewardClaimed: new uint256[](numRewards) }) ); uint256 subId = subscriptions[_tokenId].length - 1; // initialize user's reward debt for (uint8 iRwd = 0; iRwd < numRewards; ++iRwd) { subscriptions[_tokenId][subId].rewardDebt[iRwd] = (_liquidity * rewardFunds[_fundId].accRewardPerShare[iRwd]) / PREC; } // Update the totalLiquidity for the fund rewardFunds[_fundId].totalLiquidity += _liquidity; } /// @notice Unsubscribe a reward fund from a deposit /// @param _fundId The reward fund id /// @param _account The user's address /// @param _depositId The deposit id corresponding to the user /// @dev The rewards claimed from the reward fund is persisted in the event function _unsubscribeRewardFund( uint8 _fundId, address _account, uint256 _depositId ) private { require(_fundId < rewardFunds.length, "Invalid fund id"); Deposit memory userDeposit = deposits[_account][_depositId]; uint256 numRewards = rewardTokens.length; // Unsubscribe from the reward fund Subscription[] storage depositSubs = subscriptions[userDeposit.tokenId]; uint256 numSubs = depositSubs.length; for (uint256 iSub = 0; iSub < numSubs; ++iSub) { if (depositSubs[iSub].fundId == _fundId) { // Persist the reward information uint256[] memory rewardClaimed = new uint256[](numRewards); for (uint8 iRwd = 0; iRwd < numRewards; ++iRwd) { rewardClaimed[iRwd] = depositSubs[iSub].rewardClaimed[iRwd]; } // Delete the subscription from the list depositSubs[iSub] = depositSubs[numSubs - 1]; depositSubs.pop(); // Remove the liquidity from the reward fund rewardFunds[_fundId].totalLiquidity -= userDeposit.liquidity; emit PoolUnsubscribed( _account, _fundId, userDeposit.tokenId, userDeposit.startTime, rewardClaimed ); break; } } } /// @notice Function to update the FarmRewardData for all funds function _updateFarmRewardData() private { if (block.timestamp > lastFundUpdateTime) { // if farm is paused don't accrue any rewards. // only update the lastFundUpdateTime. if (!isPaused) { uint256 time = block.timestamp - lastFundUpdateTime; uint256 numRewards = rewardTokens.length; // Update the reward funds. for (uint8 iFund = 0; iFund < rewardFunds.length; ++iFund) { RewardFund memory fund = rewardFunds[iFund]; if (fund.totalLiquidity > 0) { for (uint8 iRwd = 0; iRwd < numRewards; ++iRwd) { // Get the accrued rewards for the time. uint256 accRewards = _getAccRewards( iRwd, iFund, time ); rewardData[rewardTokens[iRwd]] .accRewardBal += accRewards; fund.accRewardPerShare[iRwd] += (accRewards * PREC) / fund.totalLiquidity; } } rewardFunds[iFund] = fund; } } lastFundUpdateTime = block.timestamp; } } /// @notice Function to setup the reward funds during construction. /// @param _numFunds - Number of reward funds to setup. /// @param _rwdTokenData - Reward data for each reward token. function _setupFarm(uint8 _numFunds, RewardTokenData[] memory _rwdTokenData) private { // Setup reward related information. uint256 numRewards = _rwdTokenData.length; require(numRewards <= MAX_NUM_REWARDS - 1, "Invalid reward data"); // Initialize fund storage for (uint8 i = 0; i < _numFunds; ++i) { RewardFund memory _rewardFund = RewardFund({ totalLiquidity: 0, rewardsPerSec: new uint256[](numRewards + 1), accRewardPerShare: new uint256[](numRewards + 1) }); rewardFunds.push(_rewardFund); } // Add SPA as default reward token in the farm _addRewardData(SPA, SPA_TOKEN_MANAGER); // Initialize reward Data for (uint8 iRwd = 0; iRwd < numRewards; ++iRwd) { _addRewardData( _rwdTokenData[iRwd].token, _rwdTokenData[iRwd].tknManager ); } } /// @notice Adds new reward token to the farm /// @param _token Address of the reward token to be added. /// @param _tknManager Address of the reward token Manager. function _addRewardData(address _token, address _tknManager) private { // Validate if addresses are correct _isNonZeroAddr(_token); _isNonZeroAddr(_tknManager); require( rewardData[_token].tknManager == address(0), "Reward token already added" ); rewardData[_token] = RewardData({ id: uint8(rewardTokens.length), tknManager: _tknManager, accRewardBal: 0 }); // Add reward token in the list rewardTokens.push(_token); emit RewardTokenAdded(_token, _tknManager); } /// @notice Computes the accrued reward for a given fund id and time interval. /// @param _rwdId Id of the reward token. /// @param _fundId Id of the reward fund. /// @param _time Time interval for the reward computation. function _getAccRewards( uint8 _rwdId, uint8 _fundId, uint256 _time ) private view returns (uint256) { RewardFund memory fund = rewardFunds[_fundId]; if (fund.rewardsPerSec[_rwdId] == 0) { return 0; } address rwdToken = rewardTokens[_rwdId]; uint256 rwdSupply = IERC20(rwdToken).balanceOf(address(this)); uint256 rwdAccrued = rewardData[rwdToken].accRewardBal; uint256 rwdBal = 0; // Calculate the available reward funds in the farm. if (rwdSupply > rwdAccrued) { rwdBal = rwdSupply - rwdAccrued; } // Calculate the rewards accrued in time. uint256 accRewards = fund.rewardsPerSec[_rwdId] * _time; // Cap the reward with the available balance. if (accRewards > rwdBal) { accRewards = rwdBal; } return accRewards; } /// @notice Validate the position for the pool and get Liquidity /// @param _tokenId The tokenId of the position /// @dev the position must adhere to the price ranges /// @dev Only allow specific pool token to be staked. function _getLiquidity(uint256 _tokenId) private view returns (uint256) { /// @dev Get the info of the required token ( , , address token0, address token1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 liquidity, , , , ) = INFPM(NFPM).positions(_tokenId); /// @dev Check if the token belongs to correct pool require( uniswapPool == IUniswapV3Factory(UNIV3_FACTORY).getPool(token0, token1, fee), "Incorrect pool token" ); /// @dev Check if the token adheres to the tick range require( tickLower == tickLowerAllowed && tickUpper == tickUpperAllowed, "Incorrect tick range" ); return uint256(liquidity); } function _validateTickRange(int24 _tickLower, int24 _tickUpper) private view { int24 spacing = IUniswapV3TickSpacing(uniswapPool).tickSpacing(); require( _tickLower < _tickUpper && _tickLower >= -887272 && _tickLower % spacing == 0 && _tickUpper <= 887272 && _tickUpper % spacing == 0, "Invalid tick range" ); } /// @notice Validate the deposit for account function _isValidDeposit(address _account, uint256 _depositId) private view { require( _depositId < deposits[_account].length, "Deposit does not exist" ); } /// @notice Validate address function _isNonZeroAddr(address _addr) private pure { require(_addr != address(0), "Invalid address"); } } // File: contracts/BaseFarmDeployer.sol pragma solidity 0.8.10; abstract contract BaseFarmDeployer is Ownable { address public constant SPA = 0x5575552988A3A80504bBaeB1311674fCFd40aD4B; address public constant USDs = 0xD74f5255D557944cf7Dd0E45FF521520002D5748; address public factory; // Stores the address of farmImplementation. address public farmImplementation; event FarmCreated(address farm, address creator, address indexed admin); event FeeCollected( address indexed creator, address token, uint256 amount, bool indexed claimable ); /// @notice A function to calculate fees based on the tokens /// @param tokenA One token of the pool /// @param tokenB Other token of the pool /// @dev return feeReceiver, feeToken, feeAmount, bool claimable function calculateFees(address tokenA, address tokenB) external view virtual returns ( address feeReceiver, address feeToken, uint256 feeAmount, bool claimable ); /// @notice A function to collect fees from the creator of the farm /// @param tokenA One token of the pool /// @param tokenB Other token of the pool /// @dev Transfer fees from msg.sender to feeReceiver from FarmFactory in this function function _collectFee(address tokenA, address tokenB) internal virtual; /// @notice Validate address function _isNonZeroAddr(address _addr) internal pure { require(_addr != address(0), "Invalid address"); } } // File: contracts/interfaces/IFarmFactory.sol pragma solidity 0.8.10; interface IFarmFactory { function registerFarm(address farm, address creator) external; function getFeeParams() external view returns ( address feeFeceiver, address feeToken, uint256 feeAmount ); } // File: contracts/UniswapFarmV1Deployer.sol pragma solidity 0.8.10; contract UniswapFarmV1Deployer is BaseFarmDeployer, ReentrancyGuard { using SafeERC20 for IERC20; // farmAdmin - Address to which ownership of farm is transferred to post deployment // farmStartTime - Time after which the rewards start accruing for the deposits in the farm. // cooldownPeriod - cooldown period for locked deposits (in days) // make cooldownPeriod = 0 for disabling lockup functionality of the farm. // uniswapPoolData - Init data for UniswapV3 pool. // (tokenA, tokenB, feeTier, tickLower, tickUpper) // rewardTokenData - [(rewardTokenAddress, tknManagerAddress), ... ] struct FarmData { address farmAdmin; uint256 farmStartTime; uint256 cooldownPeriod; UniswapPoolData uniswapPoolData; RewardTokenData[] rewardData; } string public constant DEPLOYER_NAME = "UniswapV3FarmDeployer"; uint256 public discountedFee; // List of deployers for which fee won't be charged. mapping(address => bool) public isPrivilegedDeployer; event PrivilegeUpdated(address deployer, bool privilege); event DiscountedFeeUpdated( uint256 oldDiscountedFee, uint256 newDiscountedFee ); constructor(address _factory) { _isNonZeroAddr(_factory); factory = _factory; discountedFee = 100e18; // 100 USDs farmImplementation = address(new UniswapFarmV1()); } /// @notice Deploys a new UniswapV3 farm. /// @param _data data for deployment. function createFarm(FarmData memory _data) external nonReentrant returns (address) { _isNonZeroAddr(_data.farmAdmin); UniswapFarmV1 farmInstance = UniswapFarmV1( Clones.clone(farmImplementation) ); farmInstance.initialize( _data.farmStartTime, _data.cooldownPeriod, _data.uniswapPoolData, _data.rewardData ); farmInstance.transferOwnership(_data.farmAdmin); address farm = address(farmInstance); // Calculate and collect fee if required _collectFee(_data.uniswapPoolData.tokenA, _data.uniswapPoolData.tokenB); IFarmFactory(factory).registerFarm(farm, msg.sender); emit FarmCreated(farm, msg.sender, _data.farmAdmin); return farm; } /// @notice A function to add/ remove privileged deployer /// @param _deployer Deployer(address) to add to privileged deployers list /// @param _privilege Privilege(bool) whether true or false /// @dev to be only called by owner function updatePrivilege(address _deployer, bool _privilege) external onlyOwner { require( isPrivilegedDeployer[_deployer] != _privilege, "Privilege is same as desired" ); isPrivilegedDeployer[_deployer] = _privilege; emit PrivilegeUpdated(_deployer, _privilege); } /// @notice An external function to update discountOnSpaUSDsFarms /// @param _discountedFee New desired discount on Spa/ USDs farms /// @dev _discountedFee cannot be more than 100 function updateDiscountedFee(uint256 _discountedFee) external onlyOwner { emit DiscountedFeeUpdated(discountedFee, _discountedFee); discountedFee = _discountedFee; } /// @notice A public view function to calculate fees /// @param _tokenA address of token A /// @param _tokenB address of token B /// @notice Order does not matter /// @return Fees to be paid in feeToken set in FarmFactory (mostly USDs) function calculateFees(address _tokenA, address _tokenB) external view override returns ( address, address, uint256, bool ) { _isNonZeroAddr(_tokenA); _isNonZeroAddr(_tokenB); require(_tokenA != _tokenB, "Invalid token pair"); return _calculateFees(_tokenA, _tokenB); } /// @notice Collect fee and transfer it to feeReceiver. /// @dev Function fetches all the fee params from farmFactory. function _collectFee(address _tokenA, address _tokenB) internal override { ( address feeReceiver, address feeToken, uint256 feeAmount, bool claimable ) = _calculateFees(_tokenA, _tokenB); if (feeAmount > 0) { IERC20(feeToken).safeTransferFrom( msg.sender, feeReceiver, feeAmount ); emit FeeCollected(msg.sender, feeToken, feeAmount, claimable); } } /// @notice An internal function to calculate fees /// @notice and return feeReceiver, feeToken, feeAmount and claimable function _calculateFees(address _tokenA, address _tokenB) internal view returns ( address, address, uint256, bool ) { ( address feeReceiver, address feeToken, uint256 feeAmount ) = IFarmFactory(factory).getFeeParams(); if (isPrivilegedDeployer[msg.sender]) { // No fees for privileged deployers feeAmount = 0; return (feeReceiver, feeToken, feeAmount, false); } if (!_validateToken(_tokenA) && !_validateToken(_tokenB)) { // No discount because neither of the token is SPA or USDs return (feeReceiver, feeToken, feeAmount, false); } else { // DiscountedFee if either of the token is SPA or USDs // This fees is claimable return (feeReceiver, feeToken, discountedFee, true); } } /// @notice Validate if a token is either SPA | USDs. /// @param _token Address of the desired token. function _validateToken(address _token) private pure returns (bool) { return _token == SPA || _token == USDs; } }
[{"inputs":[{"internalType":"address","name":"_factory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldDiscountedFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newDiscountedFee","type":"uint256"}],"name":"DiscountedFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"farm","type":"address"},{"indexed":false,"internalType":"address","name":"creator","type":"address"},{"indexed":true,"internalType":"address","name":"admin","type":"address"}],"name":"FarmCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"bool","name":"claimable","type":"bool"}],"name":"FeeCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"deployer","type":"address"},{"indexed":false,"internalType":"bool","name":"privilege","type":"bool"}],"name":"PrivilegeUpdated","type":"event"},{"inputs":[],"name":"DEPLOYER_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SPA","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDs","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenA","type":"address"},{"internalType":"address","name":"_tokenB","type":"address"}],"name":"calculateFees","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"farmAdmin","type":"address"},{"internalType":"uint256","name":"farmStartTime","type":"uint256"},{"internalType":"uint256","name":"cooldownPeriod","type":"uint256"},{"components":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint24","name":"feeTier","type":"uint24"},{"internalType":"int24","name":"tickLowerAllowed","type":"int24"},{"internalType":"int24","name":"tickUpperAllowed","type":"int24"}],"internalType":"struct UniswapPoolData","name":"uniswapPoolData","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"tknManager","type":"address"}],"internalType":"struct RewardTokenData[]","name":"rewardData","type":"tuple[]"}],"internalType":"struct UniswapFarmV1Deployer.FarmData","name":"_data","type":"tuple"}],"name":"createFarm","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"discountedFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"farmImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isPrivilegedDeployer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_discountedFee","type":"uint256"}],"name":"updateDiscountedFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_deployer","type":"address"},{"internalType":"bool","name":"_privilege","type":"bool"}],"name":"updatePrivilege","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506040516200691538038062006915833981016040819052620000349162000178565b6200003f33620000ca565b60016003556200004f816200011a565b600180546001600160a01b0319166001600160a01b03831617905568056bc75e2d6310000060045560405162000085906200016a565b604051809103906000f080158015620000a2573d6000803e3d6000fd5b50600280546001600160a01b0319166001600160a01b039290921691909117905550620001aa565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b038116620001675760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b604482015260640160405180910390fd5b50565b61555680620013bf83390190565b6000602082840312156200018b57600080fd5b81516001600160a01b0381168114620001a357600080fd5b9392505050565b61120580620001ba6000396000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c806379a416501161008c5780639a49a505116100665780639a49a50514610219578063c3f9cfdf14610259578063c45a015514610274578063f2fde38b1461028757600080fd5b806379a41650146101de5780638da5cb5b146101f157806392d055ee1461020257600080fd5b806350967558116100c85780635096755814610147578063538daac41461017a5780636d93de7d14610195578063715018a6146101d657600080fd5b8063125c67dd146100ef5780631ba236ef1461011f5780632c30cd9114610134575b600080fd5b600254610102906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61013261012d366004610d34565b61029a565b005b610132610142366004610d6d565b610379565b61016a610155366004610d86565b60056020526000908152604090205460ff1681565b6040519015158152602001610116565b610102735575552988a3a80504bbaeb1311674fcfd40ad4b81565b6101c9604051806040016040528060158152602001742ab734b9bbb0b82b19a330b936a232b83637bcb2b960591b81525081565b6040516101169190610dcf565b6101326103c2565b6101026101ec366004610f5d565b6103d6565b6000546001600160a01b0316610102565b61020b60045481565b604051908152602001610116565b61022c610227366004611078565b6105f5565b604080516001600160a01b0395861681529490931660208501529183015215156060820152608001610116565b61010273d74f5255d557944cf7dd0e45ff521520002d574881565b600154610102906001600160a01b031681565b610132610295366004610d86565b610680565b6102a26106f9565b6001600160a01b03821660009081526005602052604090205460ff16151581151514156103165760405162461bcd60e51b815260206004820152601c60248201527f50726976696c6567652069732073616d6520617320646573697265640000000060448201526064015b60405180910390fd5b6001600160a01b038216600081815260056020908152604091829020805460ff19168515159081179091558251938452908301527fa366e4d9fb2dc9821d016721b96bd4f57108f71ed3d167ec76ee851c3bdb4b71910160405180910390a15050565b6103816106f9565b60045460408051918252602082018390527f23ab621b3fc290514891dcbd1fc12299d286b975a7b54345fda5f828e6590ee2910160405180910390a1600455565b6103ca6106f9565b6103d46000610753565b565b60006002600354141561042b5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161030d565b6002600355815161043b906107a3565b600254600090610453906001600160a01b03166107eb565b9050806001600160a01b031663688cdfe984602001518560400151866060015187608001516040518563ffffffff1660e01b815260040161049794939291906110a6565b600060405180830381600087803b1580156104b157600080fd5b505af11580156104c5573d6000803e3d6000fd5b5050845160405163f2fde38b60e01b81526001600160a01b039182166004820152908416925063f2fde38b9150602401600060405180830381600087803b15801561050f57600080fd5b505af1158015610523573d6000803e3d6000fd5b5050505060608301518051602090910151829161053f91610888565b6001546040516268af8960e41b81526001600160a01b0383811660048301523360248301529091169063068af89090604401600060405180830381600087803b15801561058b57600080fd5b505af115801561059f573d6000803e3d6000fd5b50508551604080516001600160a01b0386811682523360208301528251931694507f6e766a2e8ac6e7ecbc0956ba73fdf9e546312daf00a15a6817b8ca66159bd7ab93508290030190a260016003559392505050565b600080600080610604866107a3565b61060d856107a3565b846001600160a01b0316866001600160a01b031614156106645760405162461bcd60e51b815260206004820152601260248201527124b73b30b634b2103a37b5b2b7103830b4b960711b604482015260640161030d565b61066e868661090f565b93509350935093505b92959194509250565b6106886106f9565b6001600160a01b0381166106ed5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161030d565b6106f681610753565b50565b6000546001600160a01b031633146103d45760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161030d565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0381166106f65760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b604482015260640161030d565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528260601b60148201526e5af43d82803e903d91602b57fd5bf360881b60288201526037816000f09150506001600160a01b0381166108835760405162461bcd60e51b8152602060048201526016602482015275115490cc4c4d8dce8818dc99585d194819985a5b195960521b604482015260640161030d565b919050565b600080600080610898868661090f565b93509350935093506000821115610907576108be6001600160a01b038416338685610a08565b604080516001600160a01b0385168152602081018490528215159133917f59d6713734b6d7abb3d28e0ecdab7c005f4438de560ac404ff25d175a822990b910160405180910390a35b505050505050565b6000806000806000806000600160009054906101000a90046001600160a01b03166001600160a01b031663be6fc1816040518163ffffffff1660e01b8152600401606060405180830381865afa15801561096d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109919190611153565b33600090815260056020526040902054929550909350915060ff16156109c35750909450925060009150819050610677565b6109cc89610a68565b1580156109df57506109dd88610a68565b155b156109f4579195509350915060009050610677565b506004549195509350915060019050610677565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052610a62908590610ab7565b50505050565b60006001600160a01b038216735575552988a3a80504bbaeb1311674fcfd40ad4b1480610ab157506001600160a01b03821673d74f5255d557944cf7dd0e45ff521520002d5748145b92915050565b6000610b0c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610b8e9092919063ffffffff16565b805190915015610b895780806020019051810190610b2a9190611196565b610b895760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161030d565b505050565b6060610b9d8484600085610ba7565b90505b9392505050565b606082471015610c085760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161030d565b6001600160a01b0385163b610c5f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161030d565b600080866001600160a01b03168587604051610c7b91906111b3565b60006040518083038185875af1925050503d8060008114610cb8576040519150601f19603f3d011682016040523d82523d6000602084013e610cbd565b606091505b5091509150610ccd828286610cd8565b979650505050505050565b60608315610ce7575081610ba0565b825115610cf75782518084602001fd5b8160405162461bcd60e51b815260040161030d9190610dcf565b6001600160a01b03811681146106f657600080fd5b80151581146106f657600080fd5b60008060408385031215610d4757600080fd5b8235610d5281610d11565b91506020830135610d6281610d26565b809150509250929050565b600060208284031215610d7f57600080fd5b5035919050565b600060208284031215610d9857600080fd5b8135610ba081610d11565b60005b83811015610dbe578181015183820152602001610da6565b83811115610a625750506000910152565b6020815260008251806020840152610dee816040850160208701610da3565b601f01601f19169190910160400192915050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610e3b57610e3b610e02565b60405290565b60405160a0810167ffffffffffffffff81118282101715610e3b57610e3b610e02565b604051601f8201601f1916810167ffffffffffffffff81118282101715610e8d57610e8d610e02565b604052919050565b8035600281900b811461088357600080fd5b600082601f830112610eb857600080fd5b8135602067ffffffffffffffff821115610ed457610ed4610e02565b610ee2818360051b01610e64565b82815260069290921b84018101918181019086841115610f0157600080fd5b8286015b84811015610f525760408189031215610f1e5760008081fd5b610f26610e18565b8135610f3181610d11565b815281850135610f4081610d11565b81860152835291830191604001610f05565b509695505050505050565b600060208284031215610f6f57600080fd5b813567ffffffffffffffff80821115610f8757600080fd5b90830190818503610120811215610f9d57600080fd5b610fa5610e41565b8335610fb081610d11565b8152602084810135908201526040808501359082015260a0605f1983011215610fd857600080fd5b610fe0610e41565b91506060840135610ff081610d11565b8252608084013561100081610d11565b602083015260a084013562ffffff8116811461101b57600080fd5b604083015261102c60c08501610e95565b606083015261103d60e08501610e95565b608083015281606082015261010084013591508282111561105d57600080fd5b61106987838601610ea7565b60808201529695505050505050565b6000806040838503121561108b57600080fd5b823561109681610d11565b91506020830135610d6281610d11565b600061010080830187845260208781860152604060018060a01b03808951168288015280838a015116606088015262ffffff828a0151166080880152606089015160020b60a0880152608089015160020b60c08801528460e0880152839450875180855261012088019550838901945060005b818110156111425785518051841688528501518316858801529583019594840194600101611119565b50949b9a5050505050505050505050565b60008060006060848603121561116857600080fd5b835161117381610d11565b602085015190935061118481610d11565b80925050604084015190509250925092565b6000602082840312156111a857600080fd5b8151610ba081610d26565b600082516111c5818460208701610da3565b919091019291505056fea2646970667358221220dd05e5636d26105955ccc8ac61577003ed6d7b8b3f094eb8ec5107717aa72b4d64736f6c634300080a003360806040523480156200001157600080fd5b506200001d3362000031565b600180556200002b62000081565b62000143565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600254610100900460ff1615620000ee5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60025460ff908116101562000141576002805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b61540380620001536000396000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806388e69d9911610182578063c2b6b58c116100e9578063df064dd5116100a2578063f1ffc1781161007c578063f1ffc1781461073a578063f2fde38b1461074f578063f56e895d14610762578063fca267901461076a57600080fd5b8063df064dd514610721578063ec05d7c01461072a578063f019f6021461073257600080fd5b8063c2b6b58c1461066c578063c4f59f9b14610680578063d5a849e914610695578063d6d68177146106a8578063d6e91e91146106e5578063d8e573741461070e57600080fd5b80639e8c708e1161013b5780639e8c708e146105e1578063a74a8699146105f4578063a9fc507b14610614578063b17c29ad14610627578063b187bd261461062f578063bdd3d8251461065257600080fd5b806388e69d991461057c5780638da5cb5b1461058f578063923cfb48146105a05780639365fbbe146105b357806393c45462146105c65780639a99b4f0146105ce57600080fd5b806348e5d9f811610226578063715018a6116101df578063715018a6146105175780637a89cdd31461051f5780637bb7bed11461053a578063841654f01461054d578063861f6bfd14610556578063869d44a31461056957600080fd5b806348e5d9f81461042157806353089dd214610485578063538daac4146104a55780635fc41158146104c0578063681d8a7c146104e9578063688cdfe91461050457600080fd5b80632726b506116102785780632726b506146103635780632e1a7d4d146103835780632f28452c1461039657806331f0acdf146103c9578063365cfcbf146103e957806343d19ca91461040e57600080fd5b806303a35865146102c057806304646a49146102e95780630962ef7914610300578063136b621214610315578063150b7a02146103285780632282870e14610354575b600080fd5b6102d36102ce36600461496e565b61077d565b6040516102e091906149cb565b60405180910390f35b6102f260035481565b6040519081526020016102e0565b61031361030e366004614a1a565b610900565b005b610313610323366004614a1a565b61096f565b61033b610336366004614a48565b610b14565b6040516001600160e01b031990911681526020016102e0565b6102f2670de0b6b3a764000081565b610376610371366004614ae6565b610e16565b6040516102e09190614b12565b610313610391366004614a1a565b610f24565b6103b173c36442b4a4522e871399cd717abdd847ab11fe8881565b6040516001600160a01b0390911681526020016102e0565b6103dc6103d7366004614ae6565b6113d0565b6040516102e09190614b61565b6103fc6103f736600461496e565b611955565b60405160ff90911681526020016102e0565b61031361041c366004614ae6565b61198c565b61045e61042f366004614b74565b600860205260009081526040902080546001909101546001600160a01b03821691600160a01b900460ff169083565b604080516001600160a01b03909416845260ff9092166020840152908201526060016102e0565b6102f2610493366004614a1a565b6000908152600a602052604090205490565b6103b1735575552988a3a80504bbaeb1311674fcfd40ad4b81565b600280546104d691640100000000909104900b81565b60405160029190910b81526020016102e0565b6103b1736d5240f086637fb408c7f727010a10cf57d51b6281565b610313610512366004614d05565b611a0a565b610313611d73565b6103b1731f98431c8ad98523631ae4a59f267346ea31f98481565b6103b1610548366004614a1a565b611d87565b6102f260045481565b610313610564366004614a1a565b611db1565b610313610577366004614a1a565b611e99565b6103dc61058a366004614b74565b611f67565b6000546001600160a01b03166103b1565b6103136105ae366004614de0565b612065565b6103136105c1366004614dfd565b612152565b6103136121a4565b6103136105dc366004614ae6565b61227a565b6103136105ef366004614b74565b6122e0565b610607610602366004614ea2565b6124a6565b6040516102e09190614ec5565b610313610622366004614ae6565b61260e565b6102f2600481565b6002546106429062010000900460ff1681565b60405190151581526020016102e0565b6002546103b190600160501b90046001600160a01b031681565b600254610642906301000000900460ff1681565b6106886126f0565b6040516102e09190614eeb565b6102f26106a3366004614b74565b612752565b6106bb6106b6366004614ae6565b612953565b6040805195151586526020860194909452928401919091526060830152608082015260a0016102e0565b6102f26106f3366004614b74565b6001600160a01b031660009081526009602052604090205490565b61031361071c366004614f38565b6129a5565b6102f260055481565b6103fc600181565b6103fc600081565b600280546104d691600160381b909104900b81565b61031361075d366004614b74565b612a5c565b6102f2600181565b6102f2610778366004614a1a565b612ad5565b6107a46040518060600160405280600060ff16815260200160608152602001606081525090565b6000838152600a602052604090205482106108065760405162461bcd60e51b815260206004820152601b60248201527f537562736372697074696f6e20646f6573206e6f74206578697374000000000060448201526064015b60405180910390fd5b6000838152600a6020526040902080548390811061082657610826614f71565b6000918252602091829020604080516060810182526003909302909101805460ff16835260018101805483518187028101870190945280845293949193858301939283018282801561089757602002820191906000526020600020905b815481526020019060010190808311610883575b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156108ef57602002820191906000526020600020905b8154815260200190600101908083116108db575b505050505081525050905092915050565b6002546301000000900460ff161561092a5760405162461bcd60e51b81526004016107fd90614f87565b6002600154141561094d5760405162461bcd60e51b81526004016107fd90614fac565b60026001553361095d8183612afb565b6109678183612b5f565b505060018055565b60025462010000900460ff16156109b95760405162461bcd60e51b815260206004820152600e60248201526d11985c9b481a5cc81c185d5cd95960921b60448201526064016107fd565b600260015414156109dc5760405162461bcd60e51b81526004016107fd90614fac565b6002600155336109ec8183612afb565b6001600160a01b0381166000908152600960205260408120805484908110610a1657610a16614f71565b60009182526020909120600690910201805490915060ff16610a7a5760405162461bcd60e51b815260206004820152601960248201527f43616e206e6f7420696e69746961746520636f6f6c646f776e0000000000000060448201526064016107fd565b600354610a8a9062015180614ff9565b610a949042615018565b6004820155805460ff19168155610aab8284612b5f565b610ab760018385613062565b816001600160a01b03167f810500030f51f04e0a6a7c0323c84654a386b2572d248a7ae15432d4496cc9d182600201548360040154604051610b03929190918252602082015260400190565b60405180910390a250506001805550565b60025460009062010000900460ff1615610b615760405162461bcd60e51b815260206004820152600e60248201526d11985c9b481a5cc81c185d5cd95960921b60448201526064016107fd565b3373c36442b4a4522e871399cd717abdd847ab11fe8814610bce5760405162461bcd60e51b815260206004820152602160248201527f6f6e45524337323152656365697665643a206e6f74206120756e697633206e666044820152601d60fa1b60648201526084016107fd565b81610c1b5760405162461bcd60e51b815260206004820152601960248201527f6f6e45524337323152656365697665643a206e6f20646174610000000000000060448201526064016107fd565b6000610c2983850185614de0565b905060035460001415610c84578015610c845760405162461bcd60e51b815260206004820181905260248201527f4c6f636b75702066756e6374696f6e616c6974792069732064697361626c656460448201526064016107fd565b610c8c613415565b6000610c97866136a8565b905060006040518060c001604052808415158152602001838152602001888152602001428152602001600081526020016007805490506001600160401b03811115610ce457610ce4614b91565b604051908082528060200260200182016040528015610d0d578160200160208202803683370190505b5090526001600160a01b0389166000908152600960209081526040808320805460018082018355918552938390208551600690950201805460ff191694151594909417845584830151908401558301516002830155606083015160038301556080830151600483015560a083015180519394508493610d9292600585019201906148b4565b505050610da1600088846138be565b8215610db357610db3600188846138be565b604080518415158152602081018990529081018390526001600160a01b038916907fb08217ce123adc0cf2ed190b91bd4d1d6f87597fcd0c789711088e9f85fab41e9060600160405180910390a250630a85bd0160e11b98975050505050505050565b610e516040518060c0016040528060001515815260200160008152602001600081526020016000815260200160008152602001606081525090565b6001600160a01b0383166000908152600960205260409020805483908110610e7b57610e7b614f71565b60009182526020918290206040805160c0810182526006909302909101805460ff161515835260018101548385015260028101548383015260038101546060840152600481015460808401526005810180548351818702810187019094528084529394919360a0860193928301828280156108ef57602002820191906000526020600020908154815260200190600101908083116108db57505050505081525050905092915050565b60026001541415610f475760405162461bcd60e51b81526004016107fd90614fac565b600260015533610f578183612afb565b6001600160a01b0381166000908152600960205260408120805484908110610f8157610f81614f71565b60009182526020918290206040805160c0810182526006909302909101805460ff161515835260018101548385015260028101548383015260038101546060840152600481015460808401526005810180548351818702810187019094528084529394919360a08601939283018282801561101b57602002820191906000526020600020905b815481526020019060010190808311611007575b505050505081525050905060028054906101000a900460ff166110de578051156110875760405162461bcd60e51b815260206004820152601860248201527f506c6561736520696e69746961746520636f6f6c646f776e000000000000000060448201526064016107fd565b6080810151156110de5742816080015111156110de5760405162461bcd60e51b81526020600482015260166024820152752232b837b9b4ba1034b99034b71031b7b7b63237bbb760511b60448201526064016107fd565b6110e88284612b5f565b6001600160a01b038216600090815260096020526040812080548590811061111257611112614f71565b906000526020600020906006020160050180548060200260200160405190810160405280929190818152602001828054801561116d57602002820191906000526020600020905b815481526020019060010190808311611159575b5050505050905061118060008486613062565b6040808301516000908152600a6020522054156111a3576111a360018486613062565b6001600160a01b038316600090815260096020526040902080546111c990600190615030565b815481106111d9576111d9614f71565b906000526020600020906006020160096000856001600160a01b03166001600160a01b03168152602001908152602001600020858154811061121d5761121d614f71565b600091825260209091208254600690920201805460ff191660ff9092161515919091178155600180830154908201556002808301549082015560038083015490820155600480830154908201556005808301805461127e92840191906148ff565b5050506001600160a01b03831660009081526009602052604090208054806112a8576112a8615047565b600082815260208120600660001990930192830201805460ff1916815560018101829055600281018290556003810182905560048101829055906112ef600583018261493f565b505090556040828101519051632142170760e11b81523060048201526001600160a01b0385166024820152604481019190915273c36442b4a4522e871399cd717abdd847ab11fe88906342842e0e90606401600060405180830381600087803b15801561135b57600080fd5b505af115801561136f573d6000803e3d6000fd5b50505050826001600160a01b03167f763d7dfa8d94fbde5da5f6cb94c05ef14f357ca06c4c1a430b41dd86497d36c3836040015184606001518560200151856040516113be949392919061505d565b60405180910390a25050600180555050565b60606113dc8383612afb565b6001600160a01b038316600090815260096020526040812080548490811061140657611406614f71565b60009182526020918290206040805160c0810182526006909302909101805460ff161515835260018101548385015260028101548383015260038101546060840152600481015460808401526005810180548351818702810187019094528084529394919360a0860193928301828280156114a057602002820191906000526020600020905b81548152602001906001019080831161148c575b50505050508152505090506000600a600083604001518152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156115cc5760008481526020908190206040805160608101825260038602909201805460ff16835260018101805483518187028101870190945280845293949193858301939283018282801561155c57602002820191906000526020600020905b815481526020019060010190808311611548575b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156115b457602002820191906000526020600020905b8154815260200190600101908083116115a0575b505050505081525050815260200190600101906114e4565b50505050905060006006805480602002602001604051908101604052809291908181526020016000905b828210156116e25783829060005260206000209060030201604051806060016040529081600082015481526020016001820180548060200260200160405190810160405280929190818152602001828054801561167257602002820191906000526020600020905b81548152602001906001019080831161165e575b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156116ca57602002820191906000526020600020905b8154815260200190600101908083116116b6575b505050505081525050815260200190600101906115f6565b5050600754929350829150506001600160401b0381111561170557611705614b91565b60405190808252806020026020018201604052801561172e578160200160208202803683370190505b509450600060045442111561174d5760045461174a9042615030565b90505b60005b84518160ff161015611949576000858260ff168151811061177357611773614f71565b602002602001015160000151905060005b848160ff161015611936576000868360ff16815181106117a6576117a6614f71565b60200260200101516000015111156118545760006117c5828487613b53565b9050868360ff16815181106117dc576117dc614f71565b602002602001015160000151670de0b6b3a7640000826117fc9190614ff9565b6118069190615098565b878460ff168151811061181b5761181b614f71565b6020026020010151604001518360ff168151811061183b5761183b614f71565b6020026020010181815161184f9190615018565b905250505b868360ff168151811061186957611869614f71565b6020026020010151602001518160ff168151811061188957611889614f71565b6020026020010151670de0b6b3a7640000878460ff16815181106118af576118af614f71565b6020026020010151604001518360ff16815181106118cf576118cf614f71565b60200260200101518a602001516118e69190614ff9565b6118f09190615098565b6118fa9190615030565b898260ff168151811061190f5761190f614f71565b602002602001018181516119239190615018565b90525061192f816150ac565b9050611784565b505080611942906150ac565b9050611750565b50505050505092915050565b600a602052816000526040600020818154811061197157600080fd5b600091825260209091206003909102015460ff169150829050565b6001600160a01b0382811660009081526008602052604090205483911633146119c75760405162461bcd60e51b81526004016107fd906150cc565b600260015414156119ea5760405162461bcd60e51b81526004016107fd90614fac565b60026001556119f7613415565b611a018383613d81565b50506001805550565b600254610100900460ff1615808015611a2a5750600254600160ff909116105b80611a445750303b158015611a44575060025460ff166001145b611aa75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016107fd565b6002805460ff191660011790558015611aca576002805461ff0019166101001790555b42851015611b135760405162461bcd60e51b8152602060048201526016602482015275496e76616c6964206661726d20737461727454696d6560501b60448201526064016107fd565b611b1c33613e1c565b600485815560058690556002805463ffff000019169055602084015184516040808701519051630b4c774160e11b81526001600160a01b03938416948101949094529116602483015262ffffff166044820152731f98431c8ad98523631ae4a59f267346ea31f98490631698ee8290606401602060405180830381865afa158015611bab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bcf919061510b565b600280547fffff0000000000000000000000000000000000000000ffffffffffffffffffff16600160501b6001600160a01b0393841681029190911791829055900416611c5e5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420756e697377617020706f6f6c20636f6e666967000000000060448201526064016107fd565b611c7083606001518460800151613e6c565b606083015160028054608086015162ffffff908116600160381b0269ffffff000000000000001991909416640100000000021669ffffffffffff00000000199091161791909117905560018415611d1a5760018511611d115760405162461bcd60e51b815260206004820152601c60248201527f436f6f6c646f776e203c204d696e436f6f6c646f776e506572696f640000000060448201526064016107fd565b50600384905560025b611d248184613f82565b508015611d6c576002805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15b5050505050565b611d7b6141e8565b611d856000613e1c565b565b60078181548110611d9757600080fd5b6000918252602090912001546001600160a01b0316905081565b611db96141e8565b600354611e085760405162461bcd60e51b815260206004820152601c60248201527f4661726d20646f6573206e6f7420737570706f7274206c6f636b75700000000060448201526064016107fd565b60018111611e585760405162461bcd60e51b815260206004820152601760248201527f436f6f6c646f776e20706572696f6420746f6f206c6f7700000000000000000060448201526064016107fd565b60035460408051918252602082018390527f98eaabfe135a9c40c420208962bf81e7926b4d6df3e23502164c0554b7b35224910160405180910390a1600355565b611ea16141e8565b6005544210611ee95760405162461bcd60e51b815260206004820152601460248201527311985c9b48185b1c9958591e481cdd185c9d195960621b60448201526064016107fd565b42811015611f265760405162461bcd60e51b815260206004820152600a60248201526954696d65203c206e6f7760b01b60448201526064016107fd565b600581905560048190556040518181527f130f25fa5bdf314167bf39be054338299d55a00b55e4033be861dbd24a633c14906020015b60405180910390a150565b6006546060906000816001600160401b03811115611f8757611f87614b91565b604051908082528060200260200182016040528015611fb0578160200160208202803683370190505b506001600160a01b038516600090815260086020526040812054919250600160a01b90910460ff16905b838160ff16101561205b5760068160ff1681548110611ffb57611ffb614f71565b90600052602060002090600302016001018260ff168154811061202057612020614f71565b9060005260206000200154838260ff168151811061204057612040614f71565b6020908102919091010152612054816150ac565b9050611fda565b5090949350505050565b61206d6141e8565b6002546301000000900460ff16156120975760405162461bcd60e51b81526004016107fd90614f87565b60025460ff6201000090910416151581151514156120f75760405162461bcd60e51b815260206004820152601e60248201527f4661726d20616c726561647920696e207265717569726564207374617465000060448201526064016107fd565b6120ff613415565b6002805462ff00001916620100008315158102919091179182905560405160ff9190920416151581527f6ff9bde12009774494378420e3298e7a01f52dd41f4f60e814eb683dec08846390602001611f5c565b6001600160a01b03828116600090815260086020526040902054839116331461218d5760405162461bcd60e51b81526004016107fd906150cc565b612195613415565b61219f8383614242565b505050565b6121ac6141e8565b600260015414156121cf5760405162461bcd60e51b81526004016107fd90614fac565b60026001556121dc613415565b600060038190556002805463ffff0000191663010100001790555b60075460ff8216101561224a5761223a60078260ff168154811061221d5761221d614f71565b6000918252602090912001546001600160a01b0316600019613d81565b612243816150ac565b90506121f7565b506040517f5e1f165b802e7ec1eb767f0054488b42a684b23139c36385321abeb2164cbf2490600090a160018055565b6002546301000000900460ff16156122a45760405162461bcd60e51b81526004016107fd90614f87565b600260015414156122c75760405162461bcd60e51b81526004016107fd90614fac565b60026001556122d68282612afb565b6109678282612b5f565b6122e86141e8565b6002600154141561230b5760405162461bcd60e51b81526004016107fd90614fac565b60026001556001600160a01b0381811660009081526008602052604090205416156123785760405162461bcd60e51b815260206004820152601a60248201527f43616e277420776974686472617720726577617264546f6b656e00000000000060448201526064016107fd565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156123bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123e39190615128565b9050600081116124355760405162461bcd60e51b815260206004820152601760248201527f43616e2774207769746864726177203020616d6f756e7400000000000000000060448201526064016107fd565b61245b61244a6000546001600160a01b031690565b6001600160a01b038416908361441d565b604080516001600160a01b0384168152602081018390527f55350610fe57096d8c0ffa30beede987326bccfcb0b4415804164d0dd50ce8b191015b60405180910390a1505060018055565b6124ca60405180606001604052806000815260200160608152602001606081525090565b60065460ff83161061251e5760405162461bcd60e51b815260206004820152601a60248201527f5265776172642066756e6420646f6573206e6f7420657869737400000000000060448201526064016107fd565b60068260ff168154811061253457612534614f71565b906000526020600020906003020160405180606001604052908160008201548152602001600182018054806020026020016040519081016040528092919081815260200182805480156125a657602002820191906000526020600020905b815481526020019060010190808311612592575b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156125fe57602002820191906000526020600020905b8154815260200190600101908083116125ea575b5050505050815250509050919050565b600260015414156126315760405162461bcd60e51b81526004016107fd90614fac565b60026001556001600160a01b03828116600090815260086020526040902054166126945760405162461bcd60e51b815260206004820152601460248201527324b73b30b634b2103932bbb0b932103a37b5b2b760611b60448201526064016107fd565b61269c613415565b6126b16001600160a01b038316333084614480565b604080516001600160a01b0384168152602081018390527fac24935fd910bc682b5ccb1a07b718cadf8cf2f6d1404c4f3ddc3662dae40e299101612496565b6060600780548060200260200160405190810160405280929190818152602001828054801561274857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161272a575b5050505050905090565b6001600160a01b038116600081815260086020526040812054600780549293600160a01b90920460ff16928390811061278d5761278d614f71565b6000918252602090912001546001600160a01b0316146127e35760405162461bcd60e51b815260206004820152601160248201527024b73b30b634b2102fb93bb22a37b5b2b760791b60448201526064016107fd565b6006546001600160a01b0384166000818152600860205260408082206001015490516370a0823160e01b81523060048201529092906370a0823190602401602060405180830381865afa15801561283e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128629190615128565b905060045442111561292c5760006004544261287e9190615030565b905060005b848160ff16101561292957600060068260ff16815481106128a6576128a6614f71565b9060005260206000209060030201600001541115612919578160068260ff16815481106128d5576128d5614f71565b906000526020600020906003020160010187815481106128f7576128f7614f71565b906000526020600020015461290c9190614ff9565b6129169085615018565b93505b612922816150ac565b9050612883565b50505b80821061293f5750600095945050505050565b6129498282615030565b9695505050505050565b6009602052816000526040600020818154811061296f57600080fd5b60009182526020909120600690910201805460018201546002830154600384015460049094015460ff9093169550909350919085565b6001600160a01b0382811660009081526008602052604090205483911633146129e05760405162461bcd60e51b81526004016107fd906150cc565b6129e9826144b8565b6001600160a01b0383811660008181526008602090815260409182902080546001600160a01b0319169487169485179055815192835233908301528101919091527f5c0557fb633aff9396d4a8ccdac0fb278766dbf365162825b0b593f520b3bfb29060600160405180910390a1505050565b612a646141e8565b6001600160a01b038116612ac95760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016107fd565b612ad281613e1c565b50565b60068181548110612ae557600080fd5b6000918252602090912060039091020154905081565b6001600160a01b0382166000908152600960205260409020548110612b5b5760405162461bcd60e51b815260206004820152601660248201527511195c1bdcda5d08191bd95cc81b9bdd08195e1a5cdd60521b60448201526064016107fd565b5050565b612b67613415565b6001600160a01b0382166000908152600960205260408120805483908110612b9157612b91614f71565b600091825260208083206002600690930201918201548352600a90526040822060075481549294509092909190826001600160401b03811115612bd657612bd6614b91565b604051908082528060200260200182016040528015612bff578160200160208202803683370190505b50905060005b828160ff161015612ef7576000858260ff1681548110612c2757612c27614f71565b6000918252602082206003909102015460ff169150856001600160401b03811115612c5457612c54614b91565b604051908082528060200260200182016040528015612c7d578160200160208202803683370190505b50905060005b86811015612e6b576000670de0b6b3a764000060068560ff1681548110612cac57612cac614f71565b90600052602060002090600302016002018381548110612cce57612cce614f71565b90600052602060002001548b60010154612ce89190614ff9565b612cf29190615098565b9050888560ff1681548110612d0957612d09614f71565b90600052602060002090600302016001018281548110612d2b57612d2b614f71565b906000526020600020015481612d419190615030565b838381518110612d5357612d53614f71565b602002602001018181525050828281518110612d7157612d71614f71565b6020026020010151898660ff1681548110612d8e57612d8e614f71565b90600052602060002090600302016002018381548110612db057612db0614f71565b906000526020600020016000828254612dc99190615018565b92505081905550828281518110612de257612de2614f71565b6020026020010151868381518110612dfc57612dfc614f71565b60200260200101818151612e109190615018565b905250885481908a9060ff8816908110612e2c57612e2c614f71565b90600052602060002090600302016001018381548110612e4e57612e4e614f71565b60009182526020909120015550612e6481615141565b9050612c83565b50896001600160a01b03167f1cae27cc7b140076d3acecff4a7b68d47935ad1ea499376ef4f72d52633d0b1d838a600201548b6001015460068760ff1681548110612eb857612eb8614f71565b90600052602060002090600302016000015486604051612edc95949392919061515c565b60405180910390a2505080612ef0906150ac565b9050612c05565b5060005b838160ff161015613058576000828260ff1681518110612f1d57612f1d614f71565b6020026020010151111561304857818160ff1681518110612f4057612f40614f71565b60200260200101516008600060078460ff1681548110612f6257612f62614f71565b60009182526020808320909101546001600160a01b0316835282019290925260400181206001018054909190612f99908490615030565b92505081905550818160ff1681518110612fb557612fb5614f71565b6020026020010151866005018260ff1681548110612fd557612fd5614f71565b906000526020600020016000828254612fee9190615018565b9250508190555061304888838360ff168151811061300e5761300e614f71565b602002602001015160078460ff168154811061302c5761302c614f71565b6000918252602090912001546001600160a01b0316919061441d565b613051816150ac565b9050612efb565b5050505050505050565b60065460ff8416106130a85760405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a5908199d5b99081a59608a1b60448201526064016107fd565b6001600160a01b03821660009081526009602052604081208054839081106130d2576130d2614f71565b60009182526020918290206040805160c0810182526006909302909101805460ff161515835260018101548385015260028101548383015260038101546060840152600481015460808401526005810180548351818702810187019094528084529394919360a08601939283018282801561316c57602002820191906000526020600020905b815481526020019060010190808311613158575b5050509190925250506007546040808401516000908152600a602052908120805494955091939192505b81811015613058578760ff168382815481106131b4576131b4614f71565b600091825260209091206003909102015460ff161415613405576000846001600160401b038111156131e8576131e8614b91565b604051908082528060200260200182016040528015613211578160200160208202803683370190505b50905060005b858160ff1610156132945784838154811061323457613234614f71565b90600052602060002090600302016002018160ff168154811061325957613259614f71565b9060005260206000200154828260ff168151811061327957613279614f71565b602090810291909101015261328d816150ac565b9050613217565b50836132a1600185615030565b815481106132b1576132b1614f71565b90600052602060002090600302018483815481106132d1576132d1614f71565b600091825260209091208254600390920201805460ff191660ff9092169190911781556001808301805461330892840191906148ff565b506002828101805461331d92840191906148ff565b509050508380548061333157613331615047565b600082815260208120600360001990930192830201805460ff191681559061335c600183018261493f565b61336a60028301600061493f565b50509055856020015160068a60ff168154811061338957613389614f71565b906000526020600020906003020160000160008282546133a99190615030565b92505081905550876001600160a01b03167f602bb7b33d527bb4aaea01da006083162e4055fa16af04ad5c33219400b790a28a88604001518960600151856040516133f7949392919061518a565b60405180910390a250613058565b61340e81615141565b9050613196565b600454421115611d855760025462010000900460ff166136a25760006004544261343f9190615030565b60075490915060005b60065460ff8216101561369e57600060068260ff168154811061346d5761346d614f71565b906000526020600020906003020160405180606001604052908160008201548152602001600182018054806020026020016040519081016040528092919081815260200182805480156134df57602002820191906000526020600020905b8154815260200190600101908083116134cb575b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561353757602002820191906000526020600020905b815481526020019060010190808311613523575b505050919092525050815191925050156136215760005b838160ff16101561361f576000613566828588613b53565b9050806008600060078560ff168154811061358357613583614f71565b60009182526020808320909101546001600160a01b03168352820192909252604001812060010180549091906135ba908490615018565b909155505082516135d3670de0b6b3a764000083614ff9565b6135dd9190615098565b83604001518360ff16815181106135f6576135f6614f71565b6020026020010181815161360a9190615018565b9052506136189050816150ac565b905061354e565b505b8060068360ff168154811061363857613638614f71565b906000526020600020906003020160008201518160000155602082015181600101908051906020019061366c9291906148b4565b50604082015180516136889160028401916020909101906148b4565b509050505080613697906150ac565b9050613448565b5050505b42600455565b600080600080600080600073c36442b4a4522e871399cd717abdd847ab11fe886001600160a01b03166399fbab88896040518263ffffffff1660e01b81526004016136f591815260200190565b61018060405180830381865afa158015613713573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061373791906151df565b5050604051630b4c774160e11b81526001600160a01b03808a1660048301528816602482015262ffffff87166044820152979f50959d50939b5091995097509550731f98431c8ad98523631ae4a59f267346ea31f9849450631698ee8293505060649091019050602060405180830381865afa1580156137bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137df919061510b565b600254600160501b90046001600160a01b0390811691161461383a5760405162461bcd60e51b815260206004820152601460248201527324b731b7b93932b1ba103837b7b6103a37b5b2b760611b60448201526064016107fd565b600280546401000000009004810b9084900b148015613867575060028054600160381b9004810b9083900b145b6138aa5760405162461bcd60e51b8152602060048201526014602482015273496e636f7272656374207469636b2072616e676560601b60448201526064016107fd565b6001600160801b0316979650505050505050565b60065460ff8416106139045760405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a5908199d5b99081a59608a1b60448201526064016107fd565b6007546000838152600a602090815260409182902082516060810190935260ff8716835291908101836001600160401b0381111561394457613944614b91565b60405190808252806020026020018201604052801561396d578160200160208202803683370190505b508152602001836001600160401b0381111561398b5761398b614b91565b6040519080825280602002602001820160405280156139b4578160200160208202803683370190505b50905281546001808201845560009384526020938490208351600390930201805460ff191660ff90931692909217825582840151805193949293613a00939285019291909101906148b4565b5060408201518051613a1c9160028401916020909101906148b4565b5050506000838152600a6020526040812054613a3a90600190615030565b905060005b828160ff161015613b0f57670de0b6b3a764000060068760ff1681548110613a6957613a69614f71565b90600052602060002090600302016002018260ff1681548110613a8e57613a8e614f71565b906000526020600020015485613aa49190614ff9565b613aae9190615098565b6000868152600a60205260409020805484908110613ace57613ace614f71565b90600052602060002090600302016001018260ff1681548110613af357613af3614f71565b600091825260209091200155613b08816150ac565b9050613a3f565b508260068660ff1681548110613b2757613b27614f71565b90600052602060002090600302016000016000828254613b479190615018565b90915550505050505050565b60008060068460ff1681548110613b6c57613b6c614f71565b90600052602060002090600302016040518060600160405290816000820154815260200160018201805480602002602001604051908101604052809291908181526020018280548015613bde57602002820191906000526020600020905b815481526020019060010190808311613bca575b5050505050815260200160028201805480602002602001604051908101604052809291908181526020018280548015613c3657602002820191906000526020600020905b815481526020019060010190808311613c22575b505050505081525050905080602001518560ff1681518110613c5a57613c5a614f71565b602002602001015160001415613c74576000915050613d7a565b600060078660ff1681548110613c8c57613c8c614f71565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a0823190602401602060405180830381865afa158015613cdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d039190615128565b6001600160a01b03831660009081526008602052604081206001015491925081831115613d3757613d348284615030565b90505b60008786602001518b60ff1681518110613d5357613d53614f71565b6020026020010151613d659190614ff9565b905081811115613d725750805b955050505050505b9392505050565b6001600160a01b0380831660009081526008602052604081205490911690613da884612752565b905082818110613db55750805b8015611d6c57613dcf6001600160a01b038616848361441d565b604080516001600160a01b038781168252602082018490528516917f13e06184555481b6d2cb327155e8d2e1d0b1f0252a7fe6621e32cf9988148835910160405180910390a25050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006002600a9054906101000a90046001600160a01b03166001600160a01b031663d0c93a7c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613ec1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ee591906152c0565b90508160020b8360020b128015613f035750620d89e7198360020b12155b8015613f195750613f1481846152dd565b60020b155b8015613f2b5750620d89e88260020b13155b8015613f415750613f3c81836152dd565b60020b155b61219f5760405162461bcd60e51b8152602060048201526012602482015271496e76616c6964207469636b2072616e676560701b60448201526064016107fd565b8051613f9060016004615030565b811115613fd55760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420726577617264206461746160681b60448201526064016107fd565b60005b8360ff168160ff1610156141475760006040518060600160405280600081526020018460016140079190615018565b6001600160401b0381111561401e5761401e614b91565b604051908082528060200260200182016040528015614047578160200160208202803683370190505b508152602001614058856001615018565b6001600160401b0381111561406f5761406f614b91565b604051908082528060200260200182016040528015614098578160200160208202803683370190505b50905260068054600181018255600091909152815160039091027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f810191825560208084015180519495508594614116937ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d40019291909101906148b4565b50604082015180516141329160028401916020909101906148b4565b5050505080614140906150ac565b9050613fd8565b5061417a735575552988a3a80504bbaeb1311674fcfd40ad4b736d5240f086637fb408c7f727010a10cf57d51b62614500565b60005b818160ff1610156141e2576141d2838260ff16815181106141a0576141a0614f71565b602002602001015160000151848360ff16815181106141c1576141c1614f71565b602002602001015160200151614500565b6141db816150ac565b905061417d565b50505050565b6000546001600160a01b03163314611d855760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016107fd565b6001600160a01b0382166000908152600860205260409020546006548251600160a01b90920460ff169181146142ba5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726577617264207261746573206c656e677468000000000060448201526064016107fd565b6000816001600160401b038111156142d4576142d4614b91565b6040519080825280602002602001820160405280156142fd578160200160208202803683370190505b50905060005b828160ff1610156143e95760068160ff168154811061432457614324614f71565b90600052602060002090600302016001018460ff168154811061434957614349614f71565b9060005260206000200154828260ff168151811061436957614369614f71565b602002602001018181525050848160ff168151811061438a5761438a614f71565b602002602001015160068260ff16815481106143a8576143a8614f71565b90600052602060002090600302016001018560ff16815481106143cd576143cd614f71565b6000918252602090912001556143e2816150ac565b9050614303565b507f11bdba784675a1ae0fcb4a62299fe0409fdb243ebda575bd1f182747874d8861858286604051611d63939291906152ff565b6040516001600160a01b03831660248201526044810182905261219f90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614661565b6040516001600160a01b03808516602483015283166044820152606481018290526141e29085906323b872dd60e01b90608401614449565b6001600160a01b038116612ad25760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064016107fd565b614509826144b8565b614512816144b8565b6001600160a01b03828116600090815260086020526040902054161561457a5760405162461bcd60e51b815260206004820152601a60248201527f52657761726420746f6b656e20616c726561647920616464656400000000000060448201526064016107fd565b604080516060810182526001600160a01b038381168083526007805460ff908116602080870191825260008789018181528b8816808352600884528a832099518a54955199166001600160a81b031990951694909417600160a01b98909516979097029390931787559451600196870155825495860183559190527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68890930180546001600160a01b031916841790558351928352908201527f3344e0a0f48738979c56a1b9f2cd3425597f76766d53e83439cab3fc30b067c7910160405180910390a15050565b60006146b6826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166147339092919063ffffffff16565b80519091501561219f57808060200190518101906146d49190615335565b61219f5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016107fd565b6060614742848460008561474a565b949350505050565b6060824710156147ab5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016107fd565b6001600160a01b0385163b6148025760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107fd565b600080866001600160a01b0316858760405161481e919061537e565b60006040518083038185875af1925050503d806000811461485b576040519150601f19603f3d011682016040523d82523d6000602084013e614860565b606091505b509150915061487082828661487b565b979650505050505050565b6060831561488a575081613d7a565b82511561489a5782518084602001fd5b8160405162461bcd60e51b81526004016107fd919061539a565b8280548282559060005260206000209081019282156148ef579160200282015b828111156148ef5782518255916020019190600101906148d4565b506148fb929150614959565b5090565b8280548282559060005260206000209081019282156148ef5760005260206000209182015b828111156148ef578254825591600101919060010190614924565b5080546000825590600052602060002090810190612ad291905b5b808211156148fb576000815560010161495a565b6000806040838503121561498157600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b838110156149c0578151875295820195908201906001016149a4565b509495945050505050565b6020815260ff825116602082015260006020830151606060408401526149f46080840182614990565b90506040840151601f19848303016060850152614a118282614990565b95945050505050565b600060208284031215614a2c57600080fd5b5035919050565b6001600160a01b0381168114612ad257600080fd5b600080600080600060808688031215614a6057600080fd5b8535614a6b81614a33565b94506020860135614a7b81614a33565b93506040860135925060608601356001600160401b0380821115614a9e57600080fd5b818801915088601f830112614ab257600080fd5b813581811115614ac157600080fd5b896020828501011115614ad357600080fd5b9699959850939650602001949392505050565b60008060408385031215614af957600080fd5b8235614b0481614a33565b946020939093013593505050565b60208152815115156020820152602082015160408201526040820151606082015260608201516080820152608082015160a0820152600060a083015160c08084015261474260e0840182614990565b602081526000613d7a6020830184614990565b600060208284031215614b8657600080fd5b8135613d7a81614a33565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715614bc957614bc9614b91565b60405290565b60405160a081016001600160401b0381118282101715614bc957614bc9614b91565b604051601f8201601f191681016001600160401b0381118282101715614c1957614c19614b91565b604052919050565b62ffffff81168114612ad257600080fd5b8060020b8114612ad257600080fd5b60006001600160401b03821115614c5a57614c5a614b91565b5060051b60200190565b600082601f830112614c7557600080fd5b81356020614c8a614c8583614c41565b614bf1565b82815260069290921b84018101918181019086841115614ca957600080fd5b8286015b84811015614cfa5760408189031215614cc65760008081fd5b614cce614ba7565b8135614cd981614a33565b815281850135614ce881614a33565b81860152835291830191604001614cad565b509695505050505050565b600080600080848603610100811215614d1d57600080fd5b853594506020860135935060a0603f1982011215614d3a57600080fd5b50614d43614bcf565b6040860135614d5181614a33565b81526060860135614d6181614a33565b60208201526080860135614d7481614c21565b604082015260a0860135614d8781614c32565b606082015260c0860135614d9a81614c32565b6080820152915060e08501356001600160401b03811115614dba57600080fd5b614dc687828801614c64565b91505092959194509250565b8015158114612ad257600080fd5b600060208284031215614df257600080fd5b8135613d7a81614dd2565b60008060408385031215614e1057600080fd5b8235614e1b81614a33565b91506020838101356001600160401b03811115614e3757600080fd5b8401601f81018613614e4857600080fd5b8035614e56614c8582614c41565b81815260059190911b82018301908381019088831115614e7557600080fd5b928401925b82841015614e9357833582529284019290840190614e7a565b80955050505050509250929050565b600060208284031215614eb457600080fd5b813560ff81168114613d7a57600080fd5b602081528151602082015260006020830151606060408401526149f46080840182614990565b6020808252825182820181905260009190848201906040850190845b81811015614f2c5783516001600160a01b031683529284019291840191600101614f07565b50909695505050505050565b60008060408385031215614f4b57600080fd5b8235614f5681614a33565b91506020830135614f6681614a33565b809150509250929050565b634e487b7160e01b600052603260045260246000fd5b6020808252600b908201526a11985c9b4818db1bdcd95960aa1b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561501357615013614fe3565b500290565b6000821982111561502b5761502b614fe3565b500190565b60008282101561504257615042614fe3565b500390565b634e487b7160e01b600052603160045260246000fd5b8481528360208201528260408201526080606082015260006129496080830184614990565b634e487b7160e01b600052601260045260246000fd5b6000826150a7576150a7615082565b500490565b600060ff821660ff8114156150c3576150c3614fe3565b60010192915050565b6020808252601590820152742737ba103a3432903a37b5b2b71036b0b730b3b2b960591b604082015260600190565b805161510681614a33565b919050565b60006020828403121561511d57600080fd5b8151613d7a81614a33565b60006020828403121561513a57600080fd5b5051919050565b600060001982141561515557615155614fe3565b5060010190565b60ff8616815284602082015283604082015282606082015260a06080820152600061487060a0830184614990565b60ff851681528360208201528260408201526080606082015260006129496080830184614990565b805161510681614c21565b805161510681614c32565b80516001600160801b038116811461510657600080fd5b6000806000806000806000806000806000806101808d8f03121561520257600080fd5b8c516bffffffffffffffffffffffff8116811461521e57600080fd5b9b5061522c60208e016150fb565b9a5061523a60408e016150fb565b995061524860608e016150fb565b985061525660808e016151b2565b975061526460a08e016151bd565b965061527260c08e016151bd565b955061528060e08e016151c8565b94506101008d015193506101208d0151925061529f6101408e016151c8565b91506152ae6101608e016151c8565b90509295989b509295989b509295989b565b6000602082840312156152d257600080fd5b8151613d7a81614c32565b60008260020b806152f0576152f0615082565b808360020b0791505092915050565b6001600160a01b038416815260606020820181905260009061532390830185614990565b82810360408401526129498185614990565b60006020828403121561534757600080fd5b8151613d7a81614dd2565b60005b8381101561536d578181015183820152602001615355565b838111156141e25750506000910152565b60008251615390818460208701615352565b9190910192915050565b60208152600082518060208401526153b9816040850160208701615352565b601f01601f1916919091016040019291505056fea2646970667358221220f88813749133ce299e89049bd0083fbaf53d64fd7970387515c329f38cf607cc64736f6c634300080a0033000000000000000000000000c4fb09e0cd212367642974f6ba81d8e23780a659
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c4fb09e0cd212367642974f6ba81d8e23780a659
-----Decoded View---------------
Arg [0] : _factory (address): 0xC4fb09E0CD212367642974F6bA81D8e23780A659
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000c4fb09e0cd212367642974f6ba81d8e23780a659
Deployed ByteCode Sourcemap
86712:6138:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;85000:33;;;;;-1:-1:-1;;;;;85000:33:0;;;;;;-1:-1:-1;;;;;178:32:1;;;160:51;;148:2;133:18;85000:33:0;;;;;;;;89387:355;;;;;;:::i;:::-;;:::i;:::-;;89945:188;;;;;;:::i;:::-;;:::i;87748:52::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;1470:14:1;;1463:22;1445:41;;1433:2;1418:18;87748:52:0;1305:187:1;84762:72:0;;84792:42;84762:72;;87586:62;;;;;;;;;;;;;;;-1:-1:-1;;;87586:62:0;;;;;;;;;;;;:::i;20991:103::-;;;:::i;88289:841::-;;;;;;:::i;:::-;;:::i;20343:87::-;20389:7;20416:6;-1:-1:-1;;;;;20416:6:0;20343:87;;87655:28;;;;;;;;;6154:25:1;;;6142:2;6127:18;87655:28:0;6008:177:1;90402:412:0;;;;;;:::i;:::-;;:::i;:::-;;;;-1:-1:-1;;;;;6864:15:1;;;6846:34;;6916:15;;;;6911:2;6896:18;;6889:43;6948:18;;;6941:34;7018:14;7011:22;7006:2;6991:18;;6984:50;6795:3;6780:19;90402:412:0;6583:457:1;84841:73:0;;84872:42;84841:73;;84921:22;;;;;-1:-1:-1;;;;;84921:22:0;;;21249:201;;;;;;:::i;:::-;;:::i;89387:355::-;20229:13;:11;:13::i;:::-;-1:-1:-1;;;;;89523:31:0;::::1;;::::0;;;:20:::1;:31;::::0;;;;;::::1;;:45;;::::0;::::1;;;;89501:123;;;::::0;-1:-1:-1;;;89501:123:0;;7247:2:1;89501:123:0::1;::::0;::::1;7229:21:1::0;7286:2;7266:18;;;7259:30;7325;7305:18;;;7298:58;7373:18;;89501:123:0::1;;;;;;;;;-1:-1:-1::0;;;;;89635:31:0;::::1;;::::0;;;:20:::1;:31;::::0;;;;;;;;:44;;-1:-1:-1;;89635:44:0::1;::::0;::::1;;::::0;;::::1;::::0;;;89695:39;;7570:51:1;;;7637:18;;;7630:50;89695:39:0::1;::::0;7543:18:1;89695:39:0::1;;;;;;;89387:355:::0;;:::o;89945:188::-;20229:13;:11;:13::i;:::-;90054::::1;::::0;90033:51:::1;::::0;;7865:25:1;;;7921:2;7906:18;;7899:34;;;90033:51:0::1;::::0;7838:18:1;90033:51:0::1;;;;;;;90095:13;:30:::0;89945:188::o;20991:103::-;20229:13;:11;:13::i;:::-;21056:30:::1;21083:1;21056:18;:30::i;:::-;20991:103::o:0;88289:841::-;88390:7;16214:1;16812:7;;:19;;16804:63;;;;-1:-1:-1;;;16804:63:0;;8146:2:1;16804:63:0;;;8128:21:1;8185:2;8165:18;;;8158:30;8224:33;8204:18;;;8197:61;8275:18;;16804:63:0;7944:355:1;16804:63:0;16214:1;16945:7;:18;88430:15;;88415:31:::1;::::0;:14:::1;:31::i;:::-;88527:18;::::0;88457:26:::1;::::0;88514:32:::1;::::0;-1:-1:-1;;;;;88527:18:0::1;88514:12;:32::i;:::-;88457:100;;88568:12;-1:-1:-1::0;;;;;88568:23:0::1;;88606:5;:19;;;88640:5;:20;;;88675:5;:21;;;88711:5;:16;;;88568:170;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;88780:15:0;;88749:47:::1;::::0;-1:-1:-1;;;88749:47:0;;-1:-1:-1;;;;;178:32:1;;;88749:47:0::1;::::0;::::1;160:51:1::0;88749:30:0;;::::1;::::0;-1:-1:-1;88749:30:0::1;::::0;-1:-1:-1;133:18:1;;88749:47:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;;;88916:21:0::1;::::0;::::1;::::0;:28;;88946::::1;::::0;;::::1;::::0;88830:12;;88904:71:::1;::::0;:11:::1;:71::i;:::-;88999:7;::::0;88986:52:::1;::::0;-1:-1:-1;;;88986:52:0;;-1:-1:-1;;;;;10012:15:1;;;88986:52:0::1;::::0;::::1;9994:34:1::0;89027:10:0::1;10044:18:1::0;;;10037:43;88999:7:0;;::::1;::::0;88986:34:::1;::::0;9929:18:1;;88986:52:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;89084:15:0;;89054:46:::1;::::0;;-1:-1:-1;;;;;10012:15:1;;;9994:34;;89072:10:0::1;10059:2:1::0;10044:18;;10037:43;89054:46:0;;;::::1;::::0;-1:-1:-1;89054:46:0::1;::::0;-1:-1:-1;89054:46:0;;;;;::::1;16170:1:::0;17124:7;:22;89118:4;88289:841;-1:-1:-1;;;88289:841:0:o;90402:412::-;90541:7;90563;90585;90607:4;90639:23;90654:7;90639:14;:23::i;:::-;90673;90688:7;90673:14;:23::i;:::-;90726:7;-1:-1:-1;;;;;90715:18:0;:7;-1:-1:-1;;;;;90715:18:0;;;90707:49;;;;-1:-1:-1;;;90707:49:0;;10293:2:1;90707:49:0;;;10275:21:1;10332:2;10312:18;;;10305:30;-1:-1:-1;;;10351:18:1;;;10344:48;10409:18;;90707:49:0;10091:342:1;90707:49:0;90774:32;90789:7;90798;90774:14;:32::i;:::-;90767:39;;;;;;;;90402:412;;;;;;;;:::o;21249:201::-;20229:13;:11;:13::i;:::-;-1:-1:-1;;;;;21338:22:0;::::1;21330:73;;;::::0;-1:-1:-1;;;21330:73:0;;10640:2:1;21330:73:0::1;::::0;::::1;10622:21:1::0;10679:2;10659:18;;;10652:30;10718:34;10698:18;;;10691:62;-1:-1:-1;;;10769:18:1;;;10762:36;10815:19;;21330:73:0::1;10438:402:1::0;21330:73:0::1;21414:28;21433:8;21414:18;:28::i;:::-;21249:201:::0;:::o;20508:132::-;20389:7;20416:6;-1:-1:-1;;;;;20416:6:0;18974:10;20572:23;20564:68;;;;-1:-1:-1;;;20564:68:0;;11047:2:1;20564:68:0;;;11029:21:1;;;11066:18;;;11059:30;11125:34;11105:18;;;11098:62;11177:18;;20564:68:0;10845:356:1;21610:191:0;21684:16;21703:6;;-1:-1:-1;;;;;21720:17:0;;;-1:-1:-1;;;;;;21720:17:0;;;;;;21753:40;;21703:6;;;;;;;21753:40;;21684:16;21753:40;21673:128;21610:191;:::o;86135:119::-;-1:-1:-1;;;;;86207:19:0;;86199:47;;;;-1:-1:-1;;;86199:47:0;;11408:2:1;86199:47:0;;;11390:21:1;11447:2;11427:18;;;11420:30;-1:-1:-1;;;11466:18:1;;;11459:45;11521:18;;86199:47:0;11206:339:1;1019:568:0;1076:16;1190:4;1184:11;-1:-1:-1;;;1216:3:0;1209:79;1335:14;1329:4;1325:25;1318:4;1313:3;1309:14;1302:49;-1:-1:-1;;;1381:4:0;1376:3;1372:14;1365:90;1496:4;1491:3;1488:1;1481:20;1469:32;-1:-1:-1;;;;;;;1530:22:0;;1522:57;;;;-1:-1:-1;;;1522:57:0;;11752:2:1;1522:57:0;;;11734:21:1;11791:2;11771:18;;;11764:30;-1:-1:-1;;;11810:18:1;;;11803:52;11872:18;;1522:57:0;11550:346:1;1522:57:0;1019:568;;;:::o;90951:531::-;91050:19;91084:16;91115:17;91147:14;91175:32;91190:7;91199;91175:14;:32::i;:::-;91035:172;;;;;;;;91234:1;91222:9;:13;91218:257;;;91252:135;-1:-1:-1;;;;;91252:33:0;;91304:10;91333:11;91363:9;91252:33;:135::i;:::-;91407:56;;;-1:-1:-1;;;;;12093:32:1;;12075:51;;12157:2;12142:18;;12135:34;;;91407:56:0;;;;91420:10;;91407:56;;12048:18:1;91407:56:0;;;;;;;91218:257;91024:458;;;;90951:531;;:::o;91621:981::-;91743:7;91765;91787;91809:4;91856:19;91890:16;91921:17;91965:7;;;;;;;;;-1:-1:-1;;;;;91965:7:0;-1:-1:-1;;;;;91952:34:0;;:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;92024:10;92003:32;;;;:20;:32;;;;;;91841:147;;-1:-1:-1;91841:147:0;;-1:-1:-1;91841:147:0;-1:-1:-1;92003:32:0;;91999:190;;;-1:-1:-1;92137:11:0;;-1:-1:-1;92150:8:0;-1:-1:-1;92113:1:0;;-1:-1:-1;92113:1:0;;-1:-1:-1;92129:48:0;;91999:190;92204:23;92219:7;92204:14;:23::i;:::-;92203:24;:52;;;;;92232:23;92247:7;92232:14;:23::i;:::-;92231:24;92203:52;92199:396;;;92352:11;;-1:-1:-1;92365:8:0;-1:-1:-1;92375:9:0;-1:-1:-1;92386:5:0;;-1:-1:-1;92344:48:0;;92199:396;-1:-1:-1;92563:13:0;;92540:11;;-1:-1:-1;92553:8:0;-1:-1:-1;92563:13:0;-1:-1:-1;92578:4:0;;-1:-1:-1;92532:51:0;;42326:248;42497:68;;;-1:-1:-1;;;;;12889:15:1;;;42497:68:0;;;12871:34:1;12941:15;;12921:18;;;12914:43;12973:18;;;;12966:34;;;42497:68:0;;;;;;;;;;12806:18:1;;;;42497:68:0;;;;;;;;-1:-1:-1;;;;;42497:68:0;-1:-1:-1;;;42497:68:0;;;42470:96;;42490:5;;42470:19;:96::i;:::-;42326:248;;;;:::o;92722:125::-;92784:4;-1:-1:-1;;;;;92808:13:0;;84792:42;92808:13;;:31;;-1:-1:-1;;;;;;92825:14:0;;84872:42;92825:14;92808:31;92801:38;92722:125;-1:-1:-1;;92722:125:0:o;45174:716::-;45598:23;45624:69;45652:4;45624:69;;;;;;;;;;;;;;;;;45632:5;-1:-1:-1;;;;;45624:27:0;;;:69;;;;;:::i;:::-;45708:17;;45598:95;;-1:-1:-1;45708:21:0;45704:179;;45805:10;45794:30;;;;;;;;;;;;:::i;:::-;45786:85;;;;-1:-1:-1;;;45786:85:0;;13463:2:1;45786:85:0;;;13445:21:1;13502:2;13482:18;;;13475:30;13541:34;13521:18;;;13514:62;-1:-1:-1;;;13592:18:1;;;13585:40;13642:19;;45786:85:0;13261:406:1;45786:85:0;45244:646;45174:716;;:::o;25786:229::-;25923:12;25955:52;25977:6;25985:4;25991:1;25994:12;25955:21;:52::i;:::-;25948:59;;25786:229;;;;;;:::o;26906:510::-;27076:12;27134:5;27109:21;:30;;27101:81;;;;-1:-1:-1;;;27101:81:0;;13874:2:1;27101:81:0;;;13856:21:1;13913:2;13893:18;;;13886:30;13952:34;13932:18;;;13925:62;-1:-1:-1;;;14003:18:1;;;13996:36;14049:19;;27101:81:0;13672:402:1;27101:81:0;-1:-1:-1;;;;;23336:19:0;;;27193:60;;;;-1:-1:-1;;;27193:60:0;;14281:2:1;27193:60:0;;;14263:21:1;14320:2;14300:18;;;14293:30;14359:31;14339:18;;;14332:59;14408:18;;27193:60:0;14079:353:1;27193:60:0;27267:12;27281:23;27308:6;-1:-1:-1;;;;;27308:11:0;27327:5;27334:4;27308:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27266:73;;;;27357:51;27374:7;27383:10;27395:12;27357:16;:51::i;:::-;27350:58;26906:510;-1:-1:-1;;;;;;;26906:510:0:o;29592:762::-;29742:12;29771:7;29767:580;;;-1:-1:-1;29802:10:0;29795:17;;29767:580;29916:17;;:21;29912:424;;30164:10;30158:17;30225:15;30212:10;30208:2;30204:19;30197:44;29912:424;30307:12;30300:20;;-1:-1:-1;;;30300:20:0;;;;;;;;:::i;222:131:1:-;-1:-1:-1;;;;;297:31:1;;287:42;;277:70;;343:1;340;333:12;358:118;444:5;437:13;430:21;423:5;420:32;410:60;;466:1;463;456:12;481:382;546:6;554;607:2;595:9;586:7;582:23;578:32;575:52;;;623:1;620;613:12;575:52;662:9;649:23;681:31;706:5;681:31;:::i;:::-;731:5;-1:-1:-1;788:2:1;773:18;;760:32;801:30;760:32;801:30;:::i;:::-;850:7;840:17;;;481:382;;;;;:::o;868:180::-;927:6;980:2;968:9;959:7;955:23;951:32;948:52;;;996:1;993;986:12;948:52;-1:-1:-1;1019:23:1;;868:180;-1:-1:-1;868:180:1:o;1053:247::-;1112:6;1165:2;1153:9;1144:7;1140:23;1136:32;1133:52;;;1181:1;1178;1171:12;1133:52;1220:9;1207:23;1239:31;1264:5;1239:31;:::i;1497:258::-;1569:1;1579:113;1593:6;1590:1;1587:13;1579:113;;;1669:11;;;1663:18;1650:11;;;1643:39;1615:2;1608:10;1579:113;;;1710:6;1707:1;1704:13;1701:48;;;-1:-1:-1;;1745:1:1;1727:16;;1720:27;1497:258::o;1760:383::-;1909:2;1898:9;1891:21;1872:4;1941:6;1935:13;1984:6;1979:2;1968:9;1964:18;1957:34;2000:66;2059:6;2054:2;2043:9;2039:18;2034:2;2026:6;2022:15;2000:66;:::i;:::-;2127:2;2106:15;-1:-1:-1;;2102:29:1;2087:45;;;;2134:2;2083:54;;1760:383;-1:-1:-1;;1760:383:1:o;2148:127::-;2209:10;2204:3;2200:20;2197:1;2190:31;2240:4;2237:1;2230:15;2264:4;2261:1;2254:15;2280:257;2352:4;2346:11;;;2384:17;;2431:18;2416:34;;2452:22;;;2413:62;2410:88;;;2478:18;;:::i;:::-;2514:4;2507:24;2280:257;:::o;2542:253::-;2614:2;2608:9;2656:4;2644:17;;2691:18;2676:34;;2712:22;;;2673:62;2670:88;;;2738:18;;:::i;2800:275::-;2871:2;2865:9;2936:2;2917:13;;-1:-1:-1;;2913:27:1;2901:40;;2971:18;2956:34;;2992:22;;;2953:62;2950:88;;;3018:18;;:::i;:::-;3054:2;3047:22;2800:275;;-1:-1:-1;2800:275:1:o;3080:160::-;3146:20;;3206:1;3195:20;;;3185:31;;3175:59;;3230:1;3227;3220:12;3245:1149;3314:5;3367:3;3360:4;3352:6;3348:17;3344:27;3334:55;;3385:1;3382;3375:12;3334:55;3421:6;3408:20;3447:4;3470:18;3466:2;3463:26;3460:52;;;3492:18;;:::i;:::-;3532:36;3564:2;3559;3556:1;3552:10;3548:19;3532:36;:::i;:::-;3602:15;;;3688:1;3684:10;;;;3672:23;;3668:32;;;3633:12;;;;3712:15;;;3709:35;;;3740:1;3737;3730:12;3709:35;3776:2;3768:6;3764:15;3788:577;3804:6;3799:3;3796:15;3788:577;;;3882:4;3876:3;3871;3867:13;3863:24;3860:114;;;3928:1;3957:2;3953;3946:14;3860:114;4000:22;;:::i;:::-;4063:3;4050:17;4080:33;4105:7;4080:33;:::i;:::-;4126:22;;4189:12;;;4176:26;4215:33;4176:26;4215:33;:::i;:::-;4268:14;;;4261:31;4305:18;;4343:12;;;;3830:4;3821:14;3788:577;;;-1:-1:-1;4383:5:1;3245:1149;-1:-1:-1;;;;;;3245:1149:1:o;4399:1604::-;4484:6;4537:2;4525:9;4516:7;4512:23;4508:32;4505:52;;;4553:1;4550;4543:12;4505:52;4593:9;4580:23;4622:18;4663:2;4655:6;4652:14;4649:34;;;4679:1;4676;4669:12;4649:34;4702:22;;;;4743:16;;;4779:6;4771:15;;4768:35;;;4799:1;4796;4789:12;4768:35;4825:22;;:::i;:::-;4884:2;4871:16;4896:33;4921:7;4896:33;:::i;:::-;4938:22;;5013:2;5005:11;;;4992:25;4976:14;;;4969:49;5071:2;5063:11;;;5050:25;5034:14;;;5027:49;5110:4;-1:-1:-1;;5092:16:1;;5088:27;5085:47;;;5128:1;5125;5118:12;5085:47;5156:22;;:::i;:::-;5141:37;;5223:2;5219;5215:11;5202:25;5236:33;5261:7;5236:33;:::i;:::-;5278:24;;5347:3;5339:12;;5326:26;5361:33;5326:26;5361:33;:::i;:::-;5423:2;5410:16;;5403:33;5481:4;5473:13;;5460:27;5531:8;5518:22;;5506:35;;5496:63;;5555:1;5552;5545:12;5496:63;5588:2;5575:16;;5568:33;5635:30;5660:3;5652:12;;5635:30;:::i;:::-;5630:2;5621:7;5617:16;5610:56;5701:30;5726:3;5722:2;5718:12;5701:30;:::i;:::-;5695:3;5686:7;5682:17;5675:57;5764:7;5759:2;5752:5;5748:14;5741:31;5818:3;5814:2;5810:12;5797:26;5781:42;;5848:2;5838:8;5835:16;5832:36;;;5864:1;5861;5854:12;5832:36;5901:71;5964:7;5953:8;5949:2;5945:17;5901:71;:::i;:::-;5895:3;5884:15;;5877:96;5888:5;4399:1604;-1:-1:-1;;;;;;4399:1604:1:o;6190:388::-;6258:6;6266;6319:2;6307:9;6298:7;6294:23;6290:32;6287:52;;;6335:1;6332;6325:12;6287:52;6374:9;6361:23;6393:31;6418:5;6393:31;:::i;:::-;6443:5;-1:-1:-1;6500:2:1;6485:18;;6472:32;6513:33;6472:32;6513:33;:::i;8304:1473::-;8662:4;8691:3;8732:2;8721:9;8717:18;8762:6;8751:9;8744:25;8788:2;8826:6;8821:2;8810:9;8806:18;8799:34;8852:2;8890:1;8886;8881:3;8877:11;8873:19;8947:2;8938:6;8932:13;8928:22;8923:2;8912:9;8908:18;8901:50;9015:2;9009;9001:6;8997:15;8991:22;8987:31;8982:2;8971:9;8967:18;8960:59;9084:8;9078:2;9070:6;9066:15;9060:22;9056:37;9050:3;9039:9;9035:19;9028:66;9163:2;9155:6;9151:15;9145:22;9142:1;9131:37;9125:3;9114:9;9110:19;9103:66;9238:3;9230:6;9226:16;9220:23;9217:1;9206:38;9200:3;9189:9;9185:19;9178:67;9282:2;9276:3;9265:9;9261:19;9254:31;9305:6;9294:17;;9340:6;9334:13;9371:6;9363;9356:22;9409:3;9398:9;9394:19;9387:26;;9448:2;9440:6;9436:15;9422:29;;9469:1;9479:272;9493:6;9490:1;9487:13;9479:272;;;9552:13;;9594:9;;9590:18;;9578:31;;9653:11;;9647:18;9643:27;;9629:12;;;9622:49;9691:12;;;;9726:15;;;;9515:1;9508:9;9479:272;;;-1:-1:-1;9768:3:1;;8304:1473;-1:-1:-1;;;;;;;;;;;8304:1473:1:o;12180:446::-;12268:6;12276;12284;12337:2;12325:9;12316:7;12312:23;12308:32;12305:52;;;12353:1;12350;12343:12;12305:52;12385:9;12379:16;12404:31;12429:5;12404:31;:::i;:::-;12504:2;12489:18;;12483:25;12454:5;;-1:-1:-1;12517:33:1;12483:25;12517:33;:::i;:::-;12569:7;12559:17;;;12616:2;12605:9;12601:18;12595:25;12585:35;;12180:446;;;;;:::o;13011:245::-;13078:6;13131:2;13119:9;13110:7;13106:23;13102:32;13099:52;;;13147:1;13144;13137:12;13099:52;13179:9;13173:16;13198:28;13220:5;13198:28;:::i;14437:274::-;14566:3;14604:6;14598:13;14620:53;14666:6;14661:3;14654:4;14646:6;14642:17;14620:53;:::i;:::-;14689:16;;;;;14437:274;-1:-1:-1;;14437:274:1:o
Metadata Hash
f88813749133ce299e89049bd0083fbaf53d64fd7970387515c329f38cf607cc
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.